From 134f86e8d5c414409631b25b8c6f0ee45fbd8631 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Thu, 3 Nov 2016 21:44:39 +1000 Subject: Initial update to OpenSim 0.8.2.1 source code. --- OpenSim/Addons/Groups/ForeignImporter.cs | 78 + OpenSim/Addons/Groups/GroupsExtendedData.cs | 533 + OpenSim/Addons/Groups/GroupsMessagingModule.cs | 848 + OpenSim/Addons/Groups/GroupsModule.cs | 1467 ++ .../Groups/Hypergrid/GroupsServiceHGConnector.cs | 289 + .../Hypergrid/GroupsServiceHGConnectorModule.cs | 707 + .../Hypergrid/HGGroupsServiceRobustConnector.cs | 444 + OpenSim/Addons/Groups/IGroupsServicesConnector.cs | 112 + .../Local/GroupsServiceLocalConnectorModule.cs | 326 + OpenSim/Addons/Groups/Properties/AssemblyInfo.cs | 36 + .../Groups/Remote/GroupsServiceRemoteConnector.cs | 696 + .../Remote/GroupsServiceRemoteConnectorModule.cs | 408 + .../Groups/Remote/GroupsServiceRobustConnector.cs | 816 + .../Addons/Groups/RemoteConnectorCacheWrapper.cs | 888 + OpenSim/Addons/Groups/Service/GroupsService.cs | 1060 ++ OpenSim/Addons/Groups/Service/GroupsServiceBase.cs | 101 + OpenSim/Addons/Groups/Service/HGGroupsService.cs | 361 + OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs | 268 + .../Addons/OfflineIM/Properties/AssemblyInfo.cs | 36 + .../Remote/OfflineIMServiceRemoteConnector.cs | 171 + .../Remote/OfflineIMServiceRobustConnector.cs | 223 + .../Addons/OfflineIM/Service/OfflineIMService.cs | 135 + .../OfflineIM/Service/OfflineIMServiceBase.cs | 83 + .../LoadRegions/IRegionLoader.cs | 38 + .../LoadRegions/LoadRegionsPlugin.cs | 28 +- .../LoadRegions/Properties/AssemblyInfo.cs | 13 +- .../LoadRegions/RegionLoaderFileSystem.cs | 117 + .../LoadRegions/RegionLoaderWebServer.cs | 148 + .../Resources/LoadRegionsPlugin.addin.xml | 11 - .../Properties/AssemblyInfo.cs | 7 +- .../RegionModulesControllerPlugin.cs | 95 +- .../RegionModulesControllerPlugin.addin.xml | 13 - .../RemoteController/Properties/AssemblyInfo.cs | 7 +- .../RemoteController/RemoteAdminPlugin.cs | 407 +- .../Resources/RemoteAdminPlugin.addin.xml | 11 - OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs | 43 - .../Rest/Inventory/IRestHandler.cs | 59 - .../Rest/Inventory/RequestData.cs | 1465 -- .../Rest/Inventory/Resources/RestHandler.addin.xml | 11 - OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs | 551 - .../Rest/Inventory/RestAppearanceServices.cs | 860 - .../Rest/Inventory/RestAssetServices.cs | 383 - .../Rest/Inventory/RestFileServices.cs | 448 - .../Rest/Inventory/RestHandler.cs | 662 - .../Rest/Inventory/RestInventoryServices.cs | 2343 --- .../Rest/Inventory/RestTestServices.cs | 246 - .../Rest/Inventory/tests/ITest.cs | 46 - .../Rest/Inventory/tests/Remote.cs | 204 - .../ApplicationPlugins/Rest/Regions/GETHandler.cs | 228 - .../Rest/Regions/GETRegionInfoHandler.cs | 136 - .../ApplicationPlugins/Rest/Regions/POSTHandler.cs | 122 - .../Rest/Regions/RegionDetails.cs | 98 - .../Regions/Resources/RestRegionPlugin.addin.xml | 11 - .../Rest/Regions/RestRegionPlugin.cs | 94 - OpenSim/ApplicationPlugins/Rest/RestPlugin.cs | 417 - OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs | 72 - OpenSim/ApplicationPlugins/Rest/rest.xsd | 276 - OpenSim/Capabilities/Caps.cs | 102 +- OpenSim/Capabilities/CapsHandlers.cs | 19 +- .../AvatarPickerSearchHandler.cs | 116 + .../Handlers/FetchInventory/FetchInvDescHandler.cs | 848 + .../FetchInventory/FetchInvDescServerConnector.cs | 82 + .../FetchInventory/FetchInventory2Handler.cs | 141 + .../Tests/FetchInventory2HandlerTests.cs | 170 + .../FetchInventoryDescendents2HandlerTests.cs | 292 + .../FetchInventory2/FetchInventory2Handler.cs | 124 - .../FetchInventory2ServerConnector.cs | 71 - .../GetDisplayNames/GetDisplayNamesHandler.cs | 120 + .../GetDisplayNamesServerConnector.cs | 71 + .../Handlers/GetMesh/GetMeshHandler.cs | 239 +- .../Handlers/GetMesh/GetMeshServerConnector.cs | 29 +- .../Handlers/GetTexture/GetTextureHandler.cs | 17 +- .../GetTexture/GetTextureServerConnector.cs | 4 +- .../GetTexture/Tests/GetTextureHandlerTests.cs | 3 +- .../Handlers/Properties/AssemblyInfo.cs | 4 +- .../UploadBakedTextureServerConnector.cs | 76 + .../WebFetchInvDescHandler.cs | 438 - .../WebFetchInvDescServerConnector.cs | 82 - OpenSim/Capabilities/LLSD.cs | 29 +- OpenSim/Capabilities/LLSDAvatarPicker.cs | 51 + OpenSim/Capabilities/LLSDStreamHandler.cs | 2 +- OpenSim/Capabilities/Properties/AssemblyInfo.cs | 2 +- OpenSim/ConsoleClient/Properties/AssemblyInfo.cs | 2 +- OpenSim/ConsoleClient/Requester.cs | 19 +- OpenSim/Data/AssetDataBase.cs | 3 +- OpenSim/Data/IAgentPreferencesData.cs | 46 + OpenSim/Data/IAssetData.cs | 2 +- OpenSim/Data/IEstateDataStore.cs | 120 + OpenSim/Data/IFSAssetData.cs | 47 + OpenSim/Data/IGridUserData.cs | 1 + OpenSim/Data/IGroupsData.cs | 144 + OpenSim/Data/IHGTravelingData.cs | 59 + OpenSim/Data/IOfflineIMData.cs | 50 + OpenSim/Data/IProfilesData.cs | 58 + OpenSim/Data/IRegionData.cs | 9 +- OpenSim/Data/IXAssetDataPlugin.cs | 2 +- OpenSim/Data/IXGroupData.cs | 59 +- OpenSim/Data/MSSQL/MSSQLAssetData.cs | 289 - OpenSim/Data/MSSQL/MSSQLAuthenticationData.cs | 227 - OpenSim/Data/MSSQL/MSSQLAvatarData.cs | 71 - OpenSim/Data/MSSQL/MSSQLEstateData.cs | 577 - OpenSim/Data/MSSQL/MSSQLFriendsData.cs | 99 - OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs | 384 - OpenSim/Data/MSSQL/MSSQLGridUserData.cs | 64 - OpenSim/Data/MSSQL/MSSQLInventoryData.cs | 831 - OpenSim/Data/MSSQL/MSSQLManager.cs | 219 - OpenSim/Data/MSSQL/MSSQLMigration.cs | 99 - OpenSim/Data/MSSQL/MSSQLPresenceData.cs | 117 - OpenSim/Data/MSSQL/MSSQLRegionData.cs | 347 - OpenSim/Data/MSSQL/MSSQLSimulationData.cs | 2219 --- OpenSim/Data/MSSQL/MSSQLUserAccountData.cs | 246 - OpenSim/Data/MSSQL/MSSQLXInventoryData.cs | 305 - OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs | 65 - OpenSim/Data/MSSQL/Resources/AssetStore.migrations | 106 - OpenSim/Data/MSSQL/Resources/AuthStore.migrations | 32 - OpenSim/Data/MSSQL/Resources/Avatar.migrations | 64 - .../Data/MSSQL/Resources/EstateStore.migrations | 334 - .../Data/MSSQL/Resources/FriendsStore.migrations | 50 - OpenSim/Data/MSSQL/Resources/GridStore.migrations | 245 - .../Data/MSSQL/Resources/GridUserStore.migrations | 65 - .../Data/MSSQL/Resources/InventoryStore.migrations | 279 - OpenSim/Data/MSSQL/Resources/LogStore.migrations | 19 - OpenSim/Data/MSSQL/Resources/Presence.migrations | 31 - .../Data/MSSQL/Resources/RegionStore.migrations | 1150 -- .../Data/MSSQL/Resources/UserAccount.migrations | 55 - OpenSim/Data/MSSQL/Resources/UserStore.migrations | 421 - OpenSim/Data/MySQL/MySQLAgentPreferencesData.cs | 56 + OpenSim/Data/MySQL/MySQLAssetData.cs | 324 +- OpenSim/Data/MySQL/MySQLEstateData.cs | 45 +- OpenSim/Data/MySQL/MySQLFSAssetData.cs | 414 + OpenSim/Data/MySQL/MySQLFramework.cs | 33 +- OpenSim/Data/MySQL/MySQLFriendsData.cs | 2 +- OpenSim/Data/MySQL/MySQLGenericTableHandler.cs | 60 + OpenSim/Data/MySQL/MySQLGridUserData.cs | 7 +- OpenSim/Data/MySQL/MySQLGroupsData.cs | 484 + OpenSim/Data/MySQL/MySQLHGTravelData.cs | 80 + OpenSim/Data/MySQL/MySQLOfflineIMData.cs | 59 + OpenSim/Data/MySQL/MySQLRegionData.cs | 5 + OpenSim/Data/MySQL/MySQLSimulationData.cs | 805 +- OpenSim/Data/MySQL/MySQLUserProfilesData.cs | 1086 ++ OpenSim/Data/MySQL/MySQLXAssetData.cs | 431 +- OpenSim/Data/MySQL/Properties/AssemblyInfo.cs | 4 +- OpenSim/Data/MySQL/Resources/AgentPrefs.migrations | 18 + OpenSim/Data/MySQL/Resources/AssetStore.migrations | 6 +- OpenSim/Data/MySQL/Resources/AuthStore.migrations | 4 +- .../Data/MySQL/Resources/EstateStore.migrations | 18 +- .../Data/MySQL/Resources/FSAssetStore.migrations | 18 + .../Data/MySQL/Resources/FriendsStore.migrations | 2 +- OpenSim/Data/MySQL/Resources/GridStore.migrations | 6 +- .../Data/MySQL/Resources/GridUserStore.migrations | 2 +- .../Data/MySQL/Resources/HGTravelStore.migrations | 18 + OpenSim/Data/MySQL/Resources/IM_Store.migrations | 42 + .../Data/MySQL/Resources/InventoryStore.migrations | 4 +- OpenSim/Data/MySQL/Resources/LogStore.migrations | 2 +- OpenSim/Data/MySQL/Resources/Presence.migrations | 12 +- .../Data/MySQL/Resources/RegionStore.migrations | 70 +- .../Data/MySQL/Resources/UserAccount.migrations | 2 +- .../Data/MySQL/Resources/UserProfiles.migrations | 98 + OpenSim/Data/MySQL/Resources/UserStore.migrations | 10 +- .../Data/MySQL/Resources/XAssetStore.migrations | 41 +- .../MySQL/Resources/os_groups_Store.migrations | 115 + OpenSim/Data/Null/NullEstateData.cs | 28 +- OpenSim/Data/Null/NullPresenceData.cs | 2 +- OpenSim/Data/Null/NullRegionData.cs | 5 + OpenSim/Data/Null/NullSimulationData.cs | 42 +- OpenSim/Data/Null/NullXGroupData.cs | 34 +- OpenSim/Data/Null/Properties/AssemblyInfo.cs | 4 +- OpenSim/Data/PGSQL/PGSQLAgentPreferencesData.cs | 64 + OpenSim/Data/PGSQL/PGSQLAssetData.cs | 316 + OpenSim/Data/PGSQL/PGSQLAuthenticationData.cs | 254 + OpenSim/Data/PGSQL/PGSQLAvatarData.cs | 72 + OpenSim/Data/PGSQL/PGSQLEstateData.cs | 602 + OpenSim/Data/PGSQL/PGSQLFramework.cs | 111 + OpenSim/Data/PGSQL/PGSQLFriendsData.cs | 116 + OpenSim/Data/PGSQL/PGSQLGenericTableHandler.cs | 537 + OpenSim/Data/PGSQL/PGSQLGridUserData.cs | 68 + OpenSim/Data/PGSQL/PGSQLGroupsData.cs | 485 + OpenSim/Data/PGSQL/PGSQLHGTravelData.cs | 80 + OpenSim/Data/PGSQL/PGSQLInventoryData.cs | 831 + OpenSim/Data/PGSQL/PGSQLManager.cs | 354 + OpenSim/Data/PGSQL/PGSQLMigration.cs | 102 + OpenSim/Data/PGSQL/PGSQLOfflineIMData.cs | 56 + OpenSim/Data/PGSQL/PGSQLPresenceData.cs | 116 + OpenSim/Data/PGSQL/PGSQLRegionData.cs | 392 + OpenSim/Data/PGSQL/PGSQLSimulationData.cs | 2243 +++ OpenSim/Data/PGSQL/PGSQLUserAccountData.cs | 329 + OpenSim/Data/PGSQL/PGSQLUserProfilesData.cs | 1064 ++ OpenSim/Data/PGSQL/PGSQLXAssetData.cs | 587 + OpenSim/Data/PGSQL/PGSQLXInventoryData.cs | 330 + OpenSim/Data/PGSQL/Properties/AssemblyInfo.cs | 65 + OpenSim/Data/PGSQL/Resources/AssetStore.migrations | 99 + OpenSim/Data/PGSQL/Resources/AuthStore.migrations | 32 + OpenSim/Data/PGSQL/Resources/Avatar.migrations | 59 + .../Data/PGSQL/Resources/EstateStore.migrations | 307 + .../Data/PGSQL/Resources/FriendsStore.migrations | 44 + OpenSim/Data/PGSQL/Resources/GridStore.migrations | 242 + .../Data/PGSQL/Resources/GridUserStore.migrations | 60 + .../Data/PGSQL/Resources/HGTravelStore.migrations | 17 + OpenSim/Data/PGSQL/Resources/IM_Store.migrations | 45 + .../Data/PGSQL/Resources/InventoryStore.migrations | 220 + OpenSim/Data/PGSQL/Resources/LogStore.migrations | 16 + OpenSim/Data/PGSQL/Resources/Presence.migrations | 42 + .../Data/PGSQL/Resources/RegionStore.migrations | 1162 ++ .../Data/PGSQL/Resources/UserAccount.migrations | 51 + .../Data/PGSQL/Resources/UserProfiles.migrations | 155 + OpenSim/Data/PGSQL/Resources/UserStore.migrations | 404 + .../Data/PGSQL/Resources/XAssetStore.migrations | 80 + .../PGSQL/Resources/os_groups_Store.migrations | 211 + OpenSim/Data/Properties/AssemblyInfo.cs | 4 +- OpenSim/Data/SQLite/Properties/AssemblyInfo.cs | 4 +- .../Data/SQLite/Resources/AgentPrefs.migrations | 36 + .../Data/SQLite/Resources/EstateStore.migrations | 9 + .../Data/SQLite/Resources/HGTravelStore.migrations | 18 + .../Data/SQLite/Resources/RegionStore.migrations | 37 + .../Data/SQLite/Resources/UserProfiles.migrations | 102 + OpenSim/Data/SQLite/SQLiteAgentPreferencesData.cs | 60 + OpenSim/Data/SQLite/SQLiteAssetData.cs | 67 +- OpenSim/Data/SQLite/SQLiteFriendsData.cs | 2 +- OpenSim/Data/SQLite/SQLiteGridUserData.cs | 4 + OpenSim/Data/SQLite/SQLiteHGTravelData.cs | 82 + OpenSim/Data/SQLite/SQLiteInventoryStore.cs | 4 +- OpenSim/Data/SQLite/SQLiteSimulationData.cs | 183 +- OpenSim/Data/SQLite/SQLiteUserProfilesData.cs | 981 + OpenSim/Data/Tests/AssetTests.cs | 24 +- OpenSim/Data/Tests/BasicDataServiceTest.cs | 3 + OpenSim/Data/Tests/EstateTests.cs | 8 - OpenSim/Data/Tests/InventoryTests.cs | 8 - OpenSim/Data/Tests/RegionTests.cs | 8 - OpenSim/Framework/AgentCircuitData.cs | 28 +- OpenSim/Framework/Animation.cs | 24 + OpenSim/Framework/AssemblyInfo.cs | 3 +- OpenSim/Framework/AssetBase.cs | 13 +- .../Filesystem/Properties/AssemblyInfo.cs | 4 +- OpenSim/Framework/AvatarAppearance.cs | 335 +- OpenSim/Framework/AvatarWearable.cs | 4 +- OpenSim/Framework/BasicDOSProtector.cs | 275 + OpenSim/Framework/BlockingQueue.cs | 32 +- OpenSim/Framework/CachedTextureEventArg.cs | 46 + OpenSim/Framework/ChildAgentDataUpdate.cs | 60 +- OpenSim/Framework/CircularBuffer.cs | 312 + OpenSim/Framework/ClientInfo.cs | 16 +- .../Framework/Communications/GenericAsyncResult.cs | 185 - OpenSim/Framework/Communications/IUserService.cs | 157 - .../Communications/Limit/IRequestLimitStrategy.cs | 66 - .../Communications/Limit/NullLimitStrategy.cs | 40 - .../Communications/Limit/RepeatLimitStrategy.cs | 109 - .../Communications/Limit/TimeLimitStrategy.cs | 140 - .../Communications/Properties/AssemblyInfo.cs | 65 - OpenSim/Framework/Communications/RestClient.cs | 438 - OpenSim/Framework/Communications/XMPP/XmppError.cs | 39 - .../Framework/Communications/XMPP/XmppIqStanza.cs | 60 - .../Communications/XMPP/XmppMessageStanza.cs | 93 - .../Communications/XMPP/XmppPresenceStanza.cs | 69 - .../Communications/XMPP/XmppSerializer.cs | 79 - .../Framework/Communications/XMPP/XmppStanza.cs | 70 - .../Framework/Communications/XMPP/XmppWriter.cs | 57 - OpenSim/Framework/ConfigSettings.cs | 1 - .../Configuration/HTTP/HTTPConfiguration.cs | 119 - .../Configuration/HTTP/Properties/AssemblyInfo.cs | 33 - .../Configuration/HTTP/RemoteConfigSettings.cs | 63 - .../Configuration/XML/Properties/AssemblyInfo.cs | 33 - .../Configuration/XML/XmlConfiguration.cs | 141 - OpenSim/Framework/ConfigurationMember.cs | 530 - OpenSim/Framework/Console/AssemblyInfo.cs | 2 +- OpenSim/Framework/Console/CommandConsole.cs | 46 +- OpenSim/Framework/Console/ConsoleDisplayUtil.cs | 48 + OpenSim/Framework/Console/ConsoleUtil.cs | 175 +- OpenSim/Framework/Console/LocalConsole.cs | 85 +- OpenSim/Framework/Console/MockConsole.cs | 3 + OpenSim/Framework/Console/RemoteConsole.cs | 4 +- OpenSim/Framework/Constants.cs | 11 +- OpenSim/Framework/DAMap.cs | 328 + OpenSim/Framework/DOMap.cs | 98 + OpenSim/Framework/EstateBan.cs | 49 + OpenSim/Framework/EstateSettings.cs | 147 + OpenSim/Framework/ExtraPhysicsData.cs | 50 + OpenSim/Framework/ForeignUserProfileData.cs | 77 - OpenSim/Framework/GridInstantMessage.cs | 18 + OpenSim/Framework/IClientAPI.cs | 29 +- OpenSim/Framework/ICommandConsole.cs | 11 +- OpenSim/Framework/IImprovedAssetCache.cs | 27 +- OpenSim/Framework/ILandChannel.cs | 7 + OpenSim/Framework/ILandObject.cs | 2 + OpenSim/Framework/IMoneyModule.cs | 3 +- OpenSim/Framework/IPeople.cs | 49 + OpenSim/Framework/IRegionLoader.cs | 37 - OpenSim/Framework/IScene.cs | 21 +- OpenSim/Framework/ISceneAgent.cs | 7 +- OpenSim/Framework/ISceneObject.cs | 2 + OpenSim/Framework/InventoryCollection.cs | 4 +- OpenSim/Framework/InventoryFolderBase.cs | 3 + OpenSim/Framework/InventoryItemBase.cs | 9 +- OpenSim/Framework/Location.cs | 16 +- OpenSim/Framework/LogWriter.cs | 181 + OpenSim/Framework/MapBlockData.cs | 18 + OpenSim/Framework/MapItemReplyStruct.cs | 33 + OpenSim/Framework/MetricsCollector.cs | 223 + .../Framework/Monitoring/AssetStatsCollector.cs | 26 + OpenSim/Framework/Monitoring/BaseStatsCollector.cs | 19 +- OpenSim/Framework/Monitoring/Checks/Check.cs | 118 + OpenSim/Framework/Monitoring/ChecksManager.cs | 262 + .../Monitoring/Interfaces/IStatsCollector.cs | 9 + OpenSim/Framework/Monitoring/JobEngine.cs | 341 + OpenSim/Framework/Monitoring/MemoryWatchdog.cs | 8 +- .../Monitoring/Properties/AssemblyInfo.cs | 4 +- .../Framework/Monitoring/ServerStatsCollector.cs | 346 + .../Framework/Monitoring/SimExtraStatsCollector.cs | 106 +- OpenSim/Framework/Monitoring/Stats/CounterStat.cs | 119 + .../Framework/Monitoring/Stats/EventHistogram.cs | 173 + .../Framework/Monitoring/Stats/PercentageStat.cs | 16 + OpenSim/Framework/Monitoring/Stats/Stat.cs | 102 +- OpenSim/Framework/Monitoring/StatsLogger.cs | 151 + OpenSim/Framework/Monitoring/StatsManager.cs | 403 +- OpenSim/Framework/Monitoring/UserStatsCollector.cs | 18 + OpenSim/Framework/Monitoring/Watchdog.cs | 106 +- OpenSim/Framework/Monitoring/WorkManager.cs | 290 + OpenSim/Framework/OutboundUrlFilter.cs | 256 + OpenSim/Framework/PermissionsUtil.cs | 87 + OpenSim/Framework/PluginLoader.cs | 17 +- OpenSim/Framework/PluginManager.cs | 4 +- OpenSim/Framework/PrimitiveBaseShape.cs | 22 +- OpenSim/Framework/RegionFlags.cs | 3 +- OpenSim/Framework/RegionInfo.cs | 463 +- .../Filesystem/Properties/AssemblyInfo.cs | 33 - .../Filesystem/RegionLoaderFileSystem.cs | 116 - .../RegionLoader/Web/Properties/AssemblyInfo.cs | 33 - .../RegionLoader/Web/RegionLoaderWebServer.cs | 130 - OpenSim/Framework/RegionSettings.cs | 23 +- OpenSim/Framework/RestClient.cs | 676 + OpenSim/Framework/SLUtil.cs | 430 +- .../Framework/Serialization/ArchiveConstants.cs | 11 +- .../External/ExternalRepresentationUtils.cs | 267 +- .../Serialization/External/LandDataSerializer.cs | 28 +- .../External/UserInventoryItemSerializer.cs | 49 +- .../Serialization/Properties/AssemblyInfo.cs | 4 +- .../Serialization/Tests/LandDataSerializerTests.cs | 3 +- OpenSim/Framework/Servers/BaseOpenSimServer.cs | 82 +- .../Framework/Servers/HttpServer/BaseHttpServer.cs | 383 +- .../Servers/HttpServer/BaseOutputStreamHandler.cs | 60 + .../Servers/HttpServer/BaseRequestHandler.cs | 23 + .../Servers/HttpServer/BaseStreamHandler.cs | 49 +- .../BaseStreamHandlerBasicDOSProtector.cs | 107 + .../Servers/HttpServer/BinaryStreamHandler.cs | 2 +- .../HttpServer/GenericHTTPBasicDOSProtector.cs | 119 + .../Servers/HttpServer/Interfaces/IHttpServer.cs | 14 + .../HttpServer/Interfaces/IStreamHandler.cs | 15 +- .../Framework/Servers/HttpServer/JsonRPCMethod.cs | 34 + .../Servers/HttpServer/JsonRpcRequestManager.cs | 190 + .../Servers/HttpServer/JsonRpcResponse.cs | 150 + .../Framework/Servers/HttpServer/OSHttpRequest.cs | 13 +- .../Servers/HttpServer/OSHttpRequestPump.cs | 4 +- .../Framework/Servers/HttpServer/OSHttpServer.cs | 2 +- .../Servers/HttpServer/PollServiceEventArgs.cs | 31 +- .../Servers/HttpServer/PollServiceHttpRequest.cs | 45 + .../HttpServer/PollServiceRequestManager.cs | 318 +- .../Servers/HttpServer/PollServiceWorkerThread.cs | 165 - .../Servers/HttpServer/Properties/AssemblyInfo.cs | 4 +- .../Servers/HttpServer/RestDeserialiseHandler.cs | 4 +- .../Servers/HttpServer/RestObjectPoster.cs | 28 +- .../Servers/HttpServer/RestObjectPosterResponse.cs | 29 +- .../Servers/HttpServer/RestSessionService.cs | 89 +- .../Servers/HttpServer/RestStreamHandler.cs | 2 +- .../Servers/HttpServer/WebsocketServerHandler.cs | 1159 ++ .../Servers/HttpServer/XmlRpcBasicDOSProtector.cs | 91 + OpenSim/Framework/Servers/MainServer.cs | 24 +- .../Framework/Servers/Properties/AssemblyInfo.cs | 2 +- OpenSim/Framework/Servers/ServerBase.cs | 381 +- OpenSim/Framework/Servers/Tests/OSHttpTests.cs | 315 +- .../Framework/Servers/Tests/VersionInfoTests.cs | 2 +- OpenSim/Framework/Servers/VersionInfo.cs | 77 - .../ServiceAuth/BasicHttpAuthentication.cs | 113 + .../ServiceAuth/CompoundAuthentication.cs | 82 + .../Framework/ServiceAuth/DisallowLlHttpRequest.cs | 59 + OpenSim/Framework/ServiceAuth/IServiceAuth.cs | 48 + OpenSim/Framework/ServiceAuth/ServiceAuth.cs | 68 + OpenSim/Framework/TaskInventoryItem.cs | 2 +- OpenSim/Framework/TerrainData.cs | 464 + OpenSim/Framework/Tests/AnimationTests.cs | 1 - OpenSim/Framework/Tests/AssetBaseTest.cs | 4 - OpenSim/Framework/Tests/LocationTest.cs | 21 +- OpenSim/Framework/Tests/MundaneFrameworkTests.cs | 2 +- OpenSim/Framework/Tests/UtilTest.cs | 101 +- OpenSim/Framework/ThreadSafeRandom.cs | 72 + OpenSim/Framework/ThrottleOutPacketType.cs | 4 - OpenSim/Framework/UntrustedWebRequest.cs | 230 - OpenSim/Framework/UserProfileData.cs | 14 +- OpenSim/Framework/UserProfiles.cs | 126 + OpenSim/Framework/Util.cs | 1512 +- OpenSim/Framework/VersionInfo.cs | 92 + OpenSim/Framework/WearableCacheItem.cs | 157 + OpenSim/Framework/WebUtil.cs | 928 +- OpenSim/Region/Application/Application.cs | 67 +- OpenSim/Region/Application/ConfigurationLoader.cs | 98 +- OpenSim/Region/Application/IApplicationPlugin.cs | 2 + OpenSim/Region/Application/OpenSim.cs | 641 +- OpenSim/Region/Application/OpenSimBackground.cs | 2 +- OpenSim/Region/Application/OpenSimBase.cs | 305 +- .../Region/Application/Properties/AssemblyInfo.cs | 36 + .../Region/Application/RegionApplicationBase.cs | 103 + OpenSim/Region/ClientStack/ClientStackManager.cs | 128 - OpenSim/Region/ClientStack/IClientNetworkServer.cs | 48 - .../Linden/Caps/AgentPreferencesModule.cs | 182 + .../Linden/Caps/AvatarPickerSearchModule.cs | 136 + .../Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 175 +- .../Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs | 4 +- .../Linden/Caps/EventQueue/EventQueueGetModule.cs | 207 +- .../Linden/Caps/EventQueue/EventQueueHelper.cs | 56 +- .../Caps/EventQueue/Tests/EventQueueTests.cs | 103 +- .../Linden/Caps/FetchInventory2Module.cs | 20 +- .../Linden/Caps/GetDisplayNamesModule.cs | 144 + .../ClientStack/Linden/Caps/GetMeshModule.cs | 58 +- .../ClientStack/Linden/Caps/GetTextureModule.cs | 13 +- .../Linden/Caps/MeshUploadFlagModule.cs | 12 +- .../NewFileAgentInventoryVariablePriceModule.cs | 1 + .../Linden/Caps/ObjectCaps/ObjectAdd.cs | 4 + .../Caps/ObjectCaps/UploadObjectAssetModule.cs | 1 + .../Linden/Caps/Properties/AssemblyInfo.cs | 4 +- .../ClientStack/Linden/Caps/RegionConsoleModule.cs | 10 +- .../Linden/Caps/SimulatorFeaturesModule.cs | 149 +- .../Caps/Tests/WebFetchInvDescModuleTests.cs | 159 + .../Linden/Caps/UploadBakedTextureModule.cs | 198 +- .../Linden/Caps/WebFetchInvDescModule.cs | 350 +- OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs | 4 +- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 1423 +- .../ClientStack/Linden/UDP/LLImageManager.cs | 7 + .../Region/ClientStack/Linden/UDP/LLUDPClient.cs | 243 +- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 974 +- .../ClientStack/Linden/UDP/LLUDPServerCommands.cs | 901 + .../ClientStack/Linden/UDP/OpenSimUDPBase.cs | 206 +- .../Region/ClientStack/Linden/UDP/PacketPool.cs | 25 +- .../Linden/UDP/Properties/AssemblyInfo.cs | 7 +- .../Linden/UDP/Tests/BasicCircuitTests.cs | 110 +- .../Linden/UDP/Tests/LLImageManagerTests.cs | 17 +- .../ClientStack/Linden/UDP/Tests/MockScene.cs | 78 - .../Linden/UDP/Tests/PacketHandlerTests.cs | 1 - .../Linden/UDP/Tests/TestLLUDPServer.cs | 170 - .../ClientStack/Linden/UDP/Tests/ThrottleTests.cs | 427 + .../Region/ClientStack/Linden/UDP/ThrottleRates.cs | 17 +- .../Region/ClientStack/Linden/UDP/TokenBucket.cs | 292 +- .../Linden/UDP/UnackedPacketCollection.cs | 19 +- .../Region/ClientStack/Properties/AssemblyInfo.cs | 2 +- .../Region/ClientStack/RegionApplicationBase.cs | 135 - .../AssetTransaction/AgentAssetsTransactions.cs | 9 + .../AssetTransaction/AssetTransactionModule.cs | 2 +- .../Agent/AssetTransaction/AssetXferUploader.cs | 21 +- .../Agent/TextureSender/J2KDecoderModule.cs | 28 +- .../Region/CoreModules/Asset/CenomeAssetCache.cs | 17 +- OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs | 5 + .../Region/CoreModules/Asset/FlotsamAssetCache.cs | 400 +- .../CoreModules/Asset/GlynnTuckerAssetCache.cs | 5 + .../Asset/Tests/FlotsamAssetCacheTests.cs | 1 - .../Avatar/Attachments/AttachmentsModule.cs | 792 +- .../Attachments/Tests/AttachmentsModuleTests.cs | 430 +- .../Avatar/AvatarFactory/AvatarFactoryModule.cs | 544 +- .../Tests/AvatarFactoryModuleTests.cs | 93 +- .../Avatar/BakedTextures/XBakesModule.cs | 200 + .../Region/CoreModules/Avatar/Chat/ChatModule.cs | 168 +- .../Avatar/Chat/Tests/ChatModuleTests.cs | 285 + .../CoreModules/Avatar/Combat/CombatModule.cs | 5 + .../CoreModules/Avatar/Dialog/DialogModule.cs | 30 +- .../Avatar/Friends/CallingCardModule.cs | 5 +- .../CoreModules/Avatar/Friends/FriendsModule.cs | 50 +- .../Avatar/Friends/FriendsRequestHandler.cs | 31 +- .../CoreModules/Avatar/Friends/HGFriendsModule.cs | 20 +- .../Avatar/Friends/Tests/FriendModuleTests.cs | 1 - .../Region/CoreModules/Avatar/Gods/GodsModule.cs | 198 +- .../InstantMessage/HGMessageTransferModule.cs | 18 +- .../Avatar/InstantMessage/MessageTransferModule.cs | 170 +- .../Avatar/InstantMessage/MuteListModule.cs | 1 - .../Avatar/InstantMessage/OfflineMessageModule.cs | 10 +- .../Avatar/InstantMessage/PresenceModule.cs | 2 + .../Archiver/InventoryArchiveReadRequest.cs | 155 +- .../Inventory/Archiver/InventoryArchiveUtils.cs | 86 +- .../Archiver/InventoryArchiveWriteRequest.cs | 120 +- .../Inventory/Archiver/InventoryArchiverModule.cs | 106 +- .../Tests/InventoryArchiveLoadPathTests.cs | 360 + .../Archiver/Tests/InventoryArchiveLoadTests.cs | 192 + .../Archiver/Tests/InventoryArchiveSaveTests.cs | 422 + .../Archiver/Tests/InventoryArchiveTestCase.cs | 8 +- .../Archiver/Tests/InventoryArchiverTests.cs | 417 - .../Avatar/Inventory/Archiver/Tests/PathTests.cs | 477 - .../Inventory/Transfer/InventoryTransferModule.cs | 166 +- .../Transfer/Tests/InventoryTransferModuleTests.cs | 448 + .../Region/CoreModules/Avatar/Lure/HGLureModule.cs | 23 +- .../Region/CoreModules/Avatar/Lure/LureModule.cs | 2 +- .../Avatar/Profile/BasicProfileModule.cs | 3 + .../Avatar/UserProfiles/UserProfileModule.cs | 1406 ++ .../Framework/Caps/CapabilitiesModule.cs | 419 +- .../Framework/DynamicAttributes/DAExampleModule.cs | 124 + .../Framework/DynamicAttributes/DOExampleModule.cs | 139 + .../EntityTransfer/EntityTransferModule.cs | 2058 +- .../EntityTransfer/EntityTransferStateMachine.cs | 148 +- .../EntityTransfer/HGEntityTransferModule.cs | 290 +- .../Framework/InventoryAccess/HGAssetMapper.cs | 224 +- .../InventoryAccess/HGInventoryAccessModule.cs | 198 +- .../InventoryAccess/InventoryAccessModule.cs | 359 +- .../InventoryAccess/Tests/HGAssetMapperTests.cs | 146 + .../Tests/InventoryAccessModuleTests.cs | 7 +- .../CoreModules/Framework/Library/LibraryModule.cs | 6 +- .../Framework/Library/LocalInventoryService.cs | 48 +- .../Framework/Monitoring/MonitorModule.cs | 46 +- .../Framework/Search/BasicSearchModule.cs | 199 + .../ServiceThrottle/ServiceThrottleModule.cs | 256 + .../Statistics/Logging/BinaryLoggingModule.cs | 2 +- .../Framework/Statistics/Logging/LogWriter.cs | 170 - .../UserManagement/HGUserManagementModule.cs | 19 +- .../Tests/HGUserManagementModuleTests.cs | 75 + .../UserManagement/UserManagementModule.cs | 619 +- .../CoreModules/Hypergrid/HGWorldMapModule.cs | 72 +- .../Region/CoreModules/Properties/AssemblyInfo.cs | 8 +- .../DynamicTexture/DynamicTextureModule.cs | 6 +- .../Scripting/EMailModules/EmailModule.cs | 4 +- .../Scripting/HttpRequest/ScriptsHttpRequests.cs | 355 +- .../HttpRequest/Tests/ScriptsHttpRequestsTests.cs | 199 + .../CoreModules/Scripting/LSLHttp/UrlModule.cs | 96 +- .../Scripting/LoadImageURL/LoadImageURLModule.cs | 57 +- .../ScriptModuleComms/ScriptModuleCommsModule.cs | 23 +- .../VectorRender/Tests/VectorRenderModuleTests.cs | 5 +- .../Scripting/VectorRender/VectorRenderModule.cs | 21 +- .../Scripting/WorldComm/WorldCommModule.cs | 10 +- .../CoreModules/Scripting/XMLRPC/XMLRPCModule.cs | 31 +- .../LocalUserProfilesServiceConnector.cs | 228 + .../LocalAgentPreferencesServiceConnector.cs | 153 + .../RemoteAgentPreferencesServiceConnector.cs | 116 + .../ServiceConnectorsOut/Asset/HGAssetBroker.cs | 47 +- .../Asset/LocalAssetServiceConnector.cs | 13 +- .../Asset/Tests/AssetConnectorTests.cs | 46 +- .../Authorization/AuthorizationService.cs | 34 +- .../Grid/LocalGridServiceConnector.cs | 100 +- .../ServiceConnectorsOut/Grid/RegionCache.cs | 9 +- .../Grid/RemoteGridServiceConnector.cs | 57 +- .../Grid/Tests/GridConnectorsTests.cs | 3 +- .../GridUser/ActivityDetector.cs | 28 +- .../Inventory/HGInventoryBroker.cs | 131 +- .../Inventory/InventoryCache.cs | 84 +- .../Inventory/LocalInventoryServiceConnector.cs | 38 +- .../Inventory/RemoteXInventoryServiceConnector.cs | 50 +- .../MapImage/MapImageServiceModule.cs | 137 +- .../Neighbour/LocalNeighbourServiceConnector.cs | 4 +- .../Presence/PresenceDetector.cs | 5 +- .../Simulation/LocalSimulationConnector.cs | 86 +- .../Simulation/RemoteSimulationConnector.cs | 74 +- .../LocalUserAccountServiceConnector.cs | 10 +- .../UserAccounts/UserAccountCache.cs | 7 +- .../CoreModules/World/Access/AccessModule.cs | 10 +- .../World/Archiver/ArchiveReadRequest.cs | 314 +- .../World/Archiver/ArchiveWriteRequest.cs | 84 +- .../CoreModules/World/Archiver/ArchiverModule.cs | 109 +- .../CoreModules/World/Archiver/AssetsArchiver.cs | 9 +- .../CoreModules/World/Archiver/AssetsRequest.cs | 36 +- .../World/Archiver/Tests/ArchiverTests.cs | 23 +- .../World/Estate/EstateManagementCommands.cs | 45 +- .../World/Estate/EstateManagementModule.cs | 519 +- .../World/Estate/EstateTerrainXferHandler.cs | 6 +- .../CoreModules/World/Estate/XEstateConnector.cs | 218 + .../CoreModules/World/Estate/XEstateModule.cs | 255 + .../World/Estate/XEstateRequestHandler.cs | 288 + .../Region/CoreModules/World/Land/DwellModule.cs | 22 +- .../Region/CoreModules/World/Land/LandChannel.cs | 5 + .../CoreModules/World/Land/LandManagementModule.cs | 938 +- .../Region/CoreModules/World/Land/LandObject.cs | 324 +- .../CoreModules/World/Land/PrimCountModule.cs | 11 +- .../World/Land/Tests/LandManagementModuleTests.cs | 266 + .../World/Land/Tests/PrimCountModuleTests.cs | 1 - .../CoreModules/World/LegacyMap/MapImageModule.cs | 694 +- .../World/LegacyMap/ShadedMapTileRenderer.cs | 41 +- .../World/LegacyMap/TexturedMapTileRenderer.cs | 64 +- .../World/LightShare/LightShareModule.cs | 7 +- .../CoreModules/World/Media/Moap/MoapModule.cs | 3 + .../World/Media/Moap/Tests/MoapTests.cs | 1 - .../World/Objects/BuySell/BuySellModule.cs | 21 +- .../World/Objects/Commands/ObjectCommandsModule.cs | 32 +- .../World/Permissions/PermissionsModule.cs | 153 +- .../World/Region/RegionCommandsModule.cs | 160 +- .../CoreModules/World/Region/RestartModule.cs | 32 +- .../World/Serialiser/SerialiseObjects.cs | 30 +- .../World/Serialiser/Tests/SerialiserTests.cs | 556 +- .../Region/CoreModules/World/Sound/SoundModule.cs | 9 + OpenSim/Region/CoreModules/World/Sun/SunModule.cs | 225 +- .../Terrain/Effects/DefaultTerrainGenerator.cs | 2 +- .../Terrain/FileLoaders/GenericSystemDrawing.cs | 2 +- .../CoreModules/World/Terrain/FileLoaders/LLRAW.cs | 235 +- .../CoreModules/World/Terrain/FileLoaders/RAW32.cs | 13 +- .../World/Terrain/FileLoaders/Terragen.cs | 49 +- .../World/Terrain/FloodBrushes/NoiseArea.cs | 2 +- .../CoreModules/World/Terrain/ITerrainFeature.cs | 60 + .../CoreModules/World/Terrain/ITerrainModifier.cs | 77 + .../World/Terrain/Modifiers/FillModifier.cs | 93 + .../World/Terrain/Modifiers/LowerModifier.cs | 92 + .../World/Terrain/Modifiers/MaxModifier.cs | 92 + .../World/Terrain/Modifiers/MinModifier.cs | 92 + .../World/Terrain/Modifiers/NoiseModifier.cs | 108 + .../World/Terrain/Modifiers/RaiseModifier.cs | 92 + .../World/Terrain/Modifiers/SmoothModifier.cs | 131 + .../World/Terrain/PaintBrushes/NoiseSphere.cs | 2 +- .../CoreModules/World/Terrain/TerrainModifier.cs | 378 + .../World/Terrain/TerrainModifierData.cs | 17 + .../CoreModules/World/Terrain/TerrainModule.cs | 814 +- .../World/Terrain/Tests/TerrainModuleTests.cs | 75 + .../CoreModules/World/Terrain/Tests/TerrainTest.cs | 36 +- .../CoreModules/World/Warp3DMap/TerrainSplat.cs | 436 +- .../World/Warp3DMap/Warp3DImageModule.cs | 260 +- .../Region/CoreModules/World/Wind/WindModule.cs | 38 +- .../CoreModules/World/WorldMap/MapSearchModule.cs | 94 +- .../CoreModules/World/WorldMap/WorldMapModule.cs | 517 +- OpenSim/Region/DataSnapshot/DataRequestHandler.cs | 99 - OpenSim/Region/DataSnapshot/DataSnapshotManager.cs | 457 - OpenSim/Region/DataSnapshot/EstateSnapshot.cs | 149 - .../DataSnapshot/Interfaces/IDataSnapshot.cs | 36 - .../Interfaces/IDataSnapshotProvider.cs | 46 - OpenSim/Region/DataSnapshot/LLSDDiscovery.cs | 44 - OpenSim/Region/DataSnapshot/LandSnapshot.cs | 433 - OpenSim/Region/DataSnapshot/ObjectSnapshot.cs | 264 - .../Region/DataSnapshot/Properties/AssemblyInfo.cs | 33 - OpenSim/Region/DataSnapshot/SnapshotStore.cs | 337 - .../Framework/Interfaces/IAgentStatefulModule.cs | 61 + .../Framework/Interfaces/IAttachmentsModule.cs | 10 +- .../Framework/Interfaces/IAvatarFactoryModule.cs | 6 +- .../Framework/Interfaces/IBakedTextureModule.cs | 40 + .../Framework/Interfaces/IDynamicFloaterModule.cs | 52 + .../Framework/Interfaces/IDynamicMenuModule.cs | 57 + .../Framework/Interfaces/IEntityInventory.cs | 10 +- .../Framework/Interfaces/IEntityTransferModule.cs | 30 +- .../Framework/Interfaces/IEstateDataService.cs | 115 - .../Framework/Interfaces/IEstateDataStore.cs | 120 - .../Region/Framework/Interfaces/IEstateModule.cs | 15 +- OpenSim/Region/Framework/Interfaces/IEventQueue.cs | 13 +- .../Framework/Interfaces/IExternalCapsModule.cs | 48 + .../Framework/Interfaces/IGroupsMessagingModule.cs | 26 +- .../Region/Framework/Interfaces/IGroupsModule.cs | 2 + .../Region/Framework/Interfaces/IHttpRequests.cs | 48 +- .../Framework/Interfaces/IInterregionComms.cs | 111 - .../Framework/Interfaces/IInventoryAccessModule.cs | 4 +- .../Interfaces/IInventoryArchiverModule.cs | 32 +- OpenSim/Region/Framework/Interfaces/IJ2KDecoder.cs | 10 +- .../Framework/Interfaces/IJsonStoreModule.cs | 37 +- .../Framework/Interfaces/IMapImageUploadModule.cs | 37 + .../Framework/Interfaces/IMessageTransferModule.cs | 20 + OpenSim/Region/Framework/Interfaces/INPCModule.cs | 37 + .../Framework/Interfaces/IRegionArchiverModule.cs | 28 +- .../Framework/Interfaces/IRegionCombinerModule.cs | 5 + .../Framework/Interfaces/IRegionModuleBase.cs | 1 + .../Region/Framework/Interfaces/IScriptModule.cs | 11 + .../Framework/Interfaces/IServiceThrottleModule.cs | 19 + .../Framework/Interfaces/ISimulationDataService.cs | 9 + .../Framework/Interfaces/ISimulationDataStore.cs | 10 + .../Interfaces/ISimulatorFeaturesModule.cs | 6 +- .../Region/Framework/Interfaces/ISoundModule.cs | 8 +- .../Region/Framework/Interfaces/ITerrainChannel.cs | 19 +- .../Region/Framework/Interfaces/ITerrainModule.cs | 10 +- .../Region/Framework/Interfaces/IUserManagement.cs | 96 - .../Framework/Interfaces/IWindModelPlugin.cs | 3 + .../Region/Framework/Interfaces/IWorldMapModule.cs | 5 + .../Region/Framework/Properties/AssemblyInfo.cs | 7 +- .../Framework/Scenes/Animation/AnimationSet.cs | 119 + .../Framework/Scenes/Animation/BinBVHAnimation.cs | 49 +- .../Scenes/Animation/DefaultAvatarAnimations.cs | 26 + .../Scenes/Animation/ScenePresenceAnimator.cs | 38 +- .../Scenes/AsyncSceneObjectGroupDeleter.cs | 10 +- OpenSim/Region/Framework/Scenes/Border.cs | 7 +- OpenSim/Region/Framework/Scenes/EventManager.cs | 291 +- OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | 829 + OpenSim/Region/Framework/Scenes/Prioritizer.cs | 2 +- .../Region/Framework/Scenes/RegionStatsHandler.cs | 27 +- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 575 +- .../Framework/Scenes/Scene.PacketHandlers.cs | 68 +- OpenSim/Region/Framework/Scenes/Scene.cs | 2597 +-- OpenSim/Region/Framework/Scenes/SceneBase.cs | 78 +- .../Framework/Scenes/SceneCommunicationService.cs | 64 +- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 175 +- OpenSim/Region/Framework/Scenes/SceneManager.cs | 48 +- .../Framework/Scenes/SceneObjectGroup.Inventory.cs | 8 + .../Region/Framework/Scenes/SceneObjectGroup.cs | 509 +- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 918 +- .../Framework/Scenes/SceneObjectPartInventory.cs | 132 +- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2595 ++- .../Framework/Scenes/ScenePresenceStateMachine.cs | 113 + .../Framework/Scenes/Scripting/IScriptHost.cs | 46 - .../Framework/Scenes/Scripting/NullScriptHost.cs | 91 - .../Scenes/Scripting/ScriptEngineInterface.cs | 38 - .../Scenes/Scripting/ScriptEngineLoader.cs | 119 - .../Framework/Scenes/Scripting/ScriptUtils.cs | 107 + .../CoalescedSceneObjectsSerializer.cs | 87 +- .../Scenes/Serialization/SceneObjectSerializer.cs | 604 +- .../Scenes/Serialization/SceneXmlLoader.cs | 2 +- .../Region/Framework/Scenes/SimStatsReporter.cs | 259 +- OpenSim/Region/Framework/Scenes/TerrainChannel.cs | 346 +- .../Region/Framework/Scenes/TerrainCompressor.cs | 948 + .../Framework/Scenes/Tests/EntityManagerTests.cs | 1 - .../Framework/Scenes/Tests/SceneGraphTests.cs | 2 - .../Framework/Scenes/Tests/SceneManagerTests.cs | 2 - .../Scenes/Tests/SceneObjectBasicTests.cs | 2 - .../Framework/Scenes/Tests/SceneObjectCopyTests.cs | 346 + .../Scenes/Tests/SceneObjectCrossingTests.cs | 259 + .../Scenes/Tests/SceneObjectDeRezTests.cs | 111 +- .../Scenes/Tests/SceneObjectLinkingTests.cs | 39 +- .../Scenes/Tests/SceneObjectResizeTests.cs | 2 - .../Scenes/Tests/SceneObjectScriptTests.cs | 2 - .../Scenes/Tests/SceneObjectSerializationTests.cs | 135 + .../Scenes/Tests/SceneObjectSpatialTests.cs | 2 - .../Scenes/Tests/SceneObjectStatusTests.cs | 21 +- .../Scenes/Tests/SceneObjectUndoRedoTests.cs | 6 +- .../Scenes/Tests/SceneObjectUserGroupTests.cs | 2 - .../Scenes/Tests/ScenePresenceAgentTests.cs | 218 +- .../Scenes/Tests/ScenePresenceAnimationTests.cs | 4 +- .../Scenes/Tests/ScenePresenceAutopilotTests.cs | 2 - .../Scenes/Tests/ScenePresenceCapabilityTests.cs | 86 + .../Scenes/Tests/ScenePresenceCrossingTests.cs | 247 + .../Scenes/Tests/ScenePresenceSitTests.cs | 81 +- .../Scenes/Tests/ScenePresenceTeleportTests.cs | 302 +- .../Framework/Scenes/Tests/SceneStatisticsTests.cs | 69 + .../Framework/Scenes/Tests/SceneTelehubTests.cs | 118 + .../Region/Framework/Scenes/Tests/SceneTests.cs | 25 +- .../Scenes/Tests/SharedRegionModuleTests.cs | 249 + .../Framework/Scenes/Tests/TaskInventoryTests.cs | 18 +- .../Framework/Scenes/Tests/UserInventoryTests.cs | 18 +- .../Framework/Scenes/Tests/UuidGathererTests.cs | 91 +- OpenSim/Region/Framework/Scenes/UuidGatherer.cs | 604 +- .../Server/IRCClientView.cs | 37 +- .../InternetRelayClientView/Server/IRCServer.cs | 2 +- .../Agent/UDP/Linden/LindenUDPInfoModule.cs | 219 +- .../Avatar/Appearance/AppearanceInfoModule.cs | 196 +- .../Avatar/Attachments/AttachmentsCommandModule.cs | 17 +- .../Avatar/Attachments/TempAttachmentsModule.cs | 5 +- .../OptionalModules/Avatar/Chat/ChannelState.cs | 160 +- .../OptionalModules/Avatar/Chat/IRCBridgeModule.cs | 41 +- .../OptionalModules/Avatar/Chat/IRCConnector.cs | 303 +- .../OptionalModules/Avatar/Chat/RegionState.cs | 98 +- .../Avatar/Concierge/ConciergeModule.cs | 6 +- .../Avatar/SitStand/SitStandCommandsModule.cs | 220 + .../Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs | 41 +- .../Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs | 75 +- .../Avatar/XmlRpcGroups/GroupsMessagingModule.cs | 289 +- .../Avatar/XmlRpcGroups/GroupsModule.cs | 272 +- .../SimianGroupsServicesConnectorModule.cs | 6 +- .../Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs | 214 +- .../XmlRpcGroupsServicesConnectorModule.cs | 71 +- .../DataSnapshot/DataRequestHandler.cs | 99 + .../DataSnapshot/DataSnapshotManager.cs | 487 + .../OptionalModules/DataSnapshot/EstateSnapshot.cs | 149 + .../DataSnapshot/Interfaces/IDataSnapshot.cs | 36 + .../Interfaces/IDataSnapshotProvider.cs | 46 + .../OptionalModules/DataSnapshot/LLSDDiscovery.cs | 44 + .../OptionalModules/DataSnapshot/LandSnapshot.cs | 433 + .../OptionalModules/DataSnapshot/ObjectSnapshot.cs | 264 + .../OptionalModules/DataSnapshot/SnapshotStore.cs | 337 + .../BareBonesNonShared/BareBonesNonSharedModule.cs | 6 + .../BareBonesShared/BareBonesSharedModule.cs | 6 + .../WebSocketEchoTest/WebSocketEchoModule.cs | 175 + .../OptionalModules/Materials/MaterialsModule.cs | 608 + .../PhysicsParameters/PhysicsParameters.cs | 21 +- .../PrimLimitsModule/PrimLimitsModule.cs | 99 +- .../OptionalModules/Properties/AssemblyInfo.cs | 8 +- .../RegionCombinerClientEventForwarder.cs | 94 + .../RegionCombinerIndividualEventForwarder.cs | 139 + .../RegionCombinerLargeLandChannel.cs | 201 + .../RegionCombinerModule/RegionCombinerModule.cs | 880 + .../RegionCombinerPermissionModule.cs | 270 + .../RegionCombinerModule/RegionConnections.cs | 94 + .../RegionCombinerModule/RegionCourseLocation.cs | 43 + .../RegionCombinerModule/RegionData.cs | 40 + .../Scripting/JsonStore/JsonStore.cs | 391 +- .../Scripting/JsonStore/JsonStoreCommands.cs | 195 + .../Scripting/JsonStore/JsonStoreModule.cs | 200 +- .../Scripting/JsonStore/JsonStoreScriptModule.cs | 482 +- .../JsonStore/Tests/JsonStoreScriptModuleTests.cs | 900 + .../Scripting/Minimodule/MRMModule.cs | 2 + .../Scripting/Minimodule/SOPObject.cs | 2 +- .../RegionReadyModule/RegionReadyModule.cs | 19 +- .../XmlRpcRouterModule/XmlRpcGridRouterModule.cs | 1 - .../UserStatistics/ActiveConnectionsAJAX.cs | 308 + .../UserStatistics/Clients_report.cs | 329 + .../UserStatistics/Default_Report.cs | 277 + .../OptionalModules/UserStatistics/HTMLUtil.cs | 263 + .../OptionalModules/UserStatistics/IStatsReport.cs | 39 + .../OptionalModules/UserStatistics/LogLinesAJAX.cs | 159 + .../UserStatistics/Prototype_distributor.cs | 80 + .../UserStatistics/Sessions_Report.cs | 288 + .../OptionalModules/UserStatistics/SimStatsAJAX.cs | 276 + .../UserStatistics/Updater_distributor.cs | 70 + .../UserStatistics/WebStatsModule.cs | 1203 ++ .../ViewerSupport/CameraOnlyModeModule.cs | 176 + .../ViewerSupport/DynamicFloaterModule.cs | 238 + .../ViewerSupport/DynamicMenuModule.cs | 304 + .../ViewerSupport/GodNamesModule.cs | 144 + .../ViewerSupport/SimulatorFeaturesHelper.cs | 171 + .../ViewerSupport/SpecialUIModule.cs | 165 + .../World/AutoBackup/AutoBackupModule.cs | 123 +- .../World/AutoBackup/AutoBackupModuleState.cs | 14 + .../World/MoneyModule/SampleMoneyModule.cs | 34 +- .../Region/OptionalModules/World/NPC/NPCAvatar.cs | 69 +- .../Region/OptionalModules/World/NPC/NPCModule.cs | 98 +- .../World/NPC/Tests/NPCModuleTests.cs | 154 +- .../World/SceneCommands/SceneCommandsModule.cs | 142 +- .../World/TreePopulator/TreePopulatorModule.cs | 4 +- .../World/WorldView/WorldViewRequestHandler.cs | 2 +- .../Physics/BasicPhysicsPlugin/AssemblyInfo.cs | 58 - .../BasicPhysicsPlugin/BasicPhysicsActor.cs | 311 - .../BasicPhysicsPlugin/BasicPhysicsPlugin.cs | 64 - .../Physics/BasicPhysicsPlugin/BasicPhysicsPrim.cs | 315 - .../BasicPhysicsPlugin/BasicPhysicsScene.cs | 194 - .../Region/Physics/BulletSNPlugin/BSCharacter.cs | 814 - .../Region/Physics/BulletSNPlugin/BSConstraint.cs | 135 - .../Physics/BulletSNPlugin/BSConstraint6Dof.cs | 153 - .../BulletSNPlugin/BSConstraintCollection.cs | 180 - .../Physics/BulletSNPlugin/BSConstraintHinge.cs | 57 - .../Region/Physics/BulletSNPlugin/BSDynamics.cs | 1377 -- OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs | 329 - .../Physics/BulletSNPlugin/BSLinksetCompound.cs | 397 - .../Physics/BulletSNPlugin/BSLinksetConstraints.cs | 316 - .../Region/Physics/BulletSNPlugin/BSMaterials.cs | 200 - OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs | 347 - OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs | 559 - .../Region/Physics/BulletSNPlugin/BSPhysObject.cs | 346 - OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs | 81 - OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs | 1494 -- OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs | 957 - .../Physics/BulletSNPlugin/BSShapeCollection.cs | 1015 - OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs | 208 - .../Physics/BulletSNPlugin/BSTerrainHeightmap.cs | 175 - .../Physics/BulletSNPlugin/BSTerrainManager.cs | 461 - .../Region/Physics/BulletSNPlugin/BSTerrainMesh.cs | 267 - .../Region/Physics/BulletSNPlugin/BulletSimAPI.cs | 1603 -- .../Region/Physics/BulletSNPlugin/BulletSimData.cs | 280 - OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs | 1839 -- OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | 1622 -- .../Region/Physics/BulletSPlugin/BSApiTemplate.cs | 662 - .../Region/Physics/BulletSPlugin/BSCharacter.cs | 827 - .../Region/Physics/BulletSPlugin/BSConstraint.cs | 138 - .../Physics/BulletSPlugin/BSConstraint6Dof.cs | 151 - .../BulletSPlugin/BSConstraintCollection.cs | 180 - .../Physics/BulletSPlugin/BSConstraintHinge.cs | 55 - OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 1383 -- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 329 - .../Physics/BulletSPlugin/BSLinksetCompound.cs | 392 - .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 312 - .../Region/Physics/BulletSPlugin/BSMaterials.cs | 200 - OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | 347 - OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 582 - .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 386 - OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs | 76 - OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 1513 -- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 946 - .../Physics/BulletSPlugin/BSShapeCollection.cs | 1009 - OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 232 - .../Physics/BulletSPlugin/BSTerrainHeightmap.cs | 171 - .../Physics/BulletSPlugin/BSTerrainManager.cs | 458 - .../Region/Physics/BulletSPlugin/BSTerrainMesh.cs | 265 - .../Region/Physics/BulletSPlugin/BulletSimData.cs | 263 - .../Region/Physics/BulletSPlugin/BulletSimTODO.txt | 272 - .../BulletSPlugin/Properties/AssemblyInfo.cs | 33 - .../Physics/ConvexDecompositionDotNet/CTri.cs | 341 - .../Physics/ConvexDecompositionDotNet/Concavity.cs | 233 - .../ConvexDecompositionDotNet/ConvexBuilder.cs | 411 - .../ConvexDecomposition.cs | 200 - .../ConvexDecompositionDotNet/ConvexResult.cs | 74 - .../ConvexDecompositionDotNet/HullClasses.cs | 171 - .../ConvexDecompositionDotNet/HullTriangle.cs | 99 - .../Physics/ConvexDecompositionDotNet/HullUtils.cs | 1868 -- .../Physics/ConvexDecompositionDotNet/LICENSE.txt | 28 - .../Physics/ConvexDecompositionDotNet/Plane.cs | 99 - .../Physics/ConvexDecompositionDotNet/PlaneTri.cs | 211 - .../Properties/AssemblyInfo.cs | 36 - .../ConvexDecompositionDotNet/Quaternion.cs | 209 - .../Physics/ConvexDecompositionDotNet/README.txt | 7 - .../ConvexDecompositionDotNet/SplitPlane.cs | 265 - .../ConvexDecompositionDotNet/VertexLookup.cs | 70 - .../Physics/ConvexDecompositionDotNet/float2.cs | 70 - .../Physics/ConvexDecompositionDotNet/float3.cs | 444 - .../Physics/ConvexDecompositionDotNet/float3x3.cs | 195 - .../Physics/ConvexDecompositionDotNet/float4.cs | 170 - .../Physics/ConvexDecompositionDotNet/float4x4.cs | 284 - .../Physics/ConvexDecompositionDotNet/int3.cs | 128 - .../Physics/ConvexDecompositionDotNet/int4.cs | 66 - OpenSim/Region/Physics/Manager/AssemblyInfo.cs | 58 - OpenSim/Region/Physics/Manager/CollisionLocker.cs | 73 - OpenSim/Region/Physics/Manager/IMesher.cs | 70 - .../Region/Physics/Manager/IPhysicsParameters.cs | 73 - OpenSim/Region/Physics/Manager/NullPhysicsScene.cs | 121 - OpenSim/Region/Physics/Manager/PhysicsActor.cs | 567 - OpenSim/Region/Physics/Manager/PhysicsJoint.cs | 55 - .../Region/Physics/Manager/PhysicsPluginManager.cs | 240 - OpenSim/Region/Physics/Manager/PhysicsScene.cs | 283 - OpenSim/Region/Physics/Manager/PhysicsSensor.cs | 78 - OpenSim/Region/Physics/Manager/PhysicsVector.cs | 186 - OpenSim/Region/Physics/Manager/VehicleConstants.cs | 121 - OpenSim/Region/Physics/Manager/ZeroMesher.cs | 83 - OpenSim/Region/Physics/Meshing/HelperTypes.cs | 436 - OpenSim/Region/Physics/Meshing/Mesh.cs | 333 - OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 761 - OpenSim/Region/Physics/Meshing/PrimMesher.cs | 2324 --- .../Physics/Meshing/Properties/AssemblyInfo.cs | 33 - OpenSim/Region/Physics/Meshing/SculptMap.cs | 183 - OpenSim/Region/Physics/Meshing/SculptMesh.cs | 646 - OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs | 58 - OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | 1411 -- .../Physics/OdePlugin/ODEDynamics.c_comments | 630 - OpenSim/Region/Physics/OdePlugin/ODEDynamics.cs | 974 - OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 3380 ---- .../Physics/OdePlugin/ODERayCastRequestManager.cs | 434 - .../Region/Physics/OdePlugin/OdePhysicsJoint.cs | 48 - OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 90 - OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 4323 ----- .../Region/Physics/OdePlugin/Tests/ODETestClass.cs | 128 - OpenSim/Region/Physics/OdePlugin/drawstuff.cs | 98 - OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs | 58 - OpenSim/Region/Physics/POSPlugin/POSCharacter.cs | 340 - OpenSim/Region/Physics/POSPlugin/POSPlugin.cs | 64 - OpenSim/Region/Physics/POSPlugin/POSPrim.cs | 335 - OpenSim/Region/Physics/POSPlugin/POSScene.cs | 270 - .../PhysicsModules/BasicPhysics/AssemblyInfo.cs | 62 + .../BasicPhysics/BasicPhysicsActor.cs | 303 + .../BasicPhysics/BasicPhysicsPrim.cs | 316 + .../BasicPhysics/BasicPhysicsScene.cs | 256 + .../Region/PhysicsModules/BulletS/BSAPIUnman.cs | 2120 +++ OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs | 2589 +++ .../PhysicsModules/BulletS/BSActorAvatarMove.cs | 457 + .../Region/PhysicsModules/BulletS/BSActorHover.cs | 174 + .../PhysicsModules/BulletS/BSActorLockAxis.cs | 219 + .../PhysicsModules/BulletS/BSActorMoveToTarget.cs | 220 + .../PhysicsModules/BulletS/BSActorSetForce.cs | 138 + .../PhysicsModules/BulletS/BSActorSetTorque.cs | 139 + OpenSim/Region/PhysicsModules/BulletS/BSActors.cs | 154 + .../Region/PhysicsModules/BulletS/BSApiTemplate.cs | 763 + .../Region/PhysicsModules/BulletS/BSCharacter.cs | 813 + .../Region/PhysicsModules/BulletS/BSConstraint.cs | 144 + .../PhysicsModules/BulletS/BSConstraint6Dof.cs | 180 + .../BulletS/BSConstraintCollection.cs | 181 + .../BulletS/BSConstraintConeTwist.cs | 54 + .../PhysicsModules/BulletS/BSConstraintHinge.cs | 55 + .../PhysicsModules/BulletS/BSConstraintSlider.cs | 55 + .../PhysicsModules/BulletS/BSConstraintSpring.cs | 103 + .../Region/PhysicsModules/BulletS/BSDynamics.cs | 1800 ++ OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs | 503 + .../PhysicsModules/BulletS/BSLinksetCompound.cs | 477 + .../PhysicsModules/BulletS/BSLinksetConstraints.cs | 852 + .../Region/PhysicsModules/BulletS/BSMaterials.cs | 203 + OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs | 451 + OpenSim/Region/PhysicsModules/BulletS/BSParam.cs | 927 + .../Region/PhysicsModules/BulletS/BSPhysObject.cs | 620 + OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs | 1895 ++ .../PhysicsModules/BulletS/BSPrimDisplaced.cs | 182 + .../PhysicsModules/BulletS/BSPrimLinkable.cs | 349 + OpenSim/Region/PhysicsModules/BulletS/BSScene.cs | 1333 ++ .../PhysicsModules/BulletS/BSShapeCollection.cs | 425 + OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs | 1463 ++ .../PhysicsModules/BulletS/BSTerrainHeightmap.cs | 169 + .../PhysicsModules/BulletS/BSTerrainManager.cs | 584 + .../Region/PhysicsModules/BulletS/BSTerrainMesh.cs | 440 + .../Region/PhysicsModules/BulletS/BulletSimData.cs | 277 + .../PhysicsModules/BulletS/BulletSimTODO.txt | 379 + .../PhysicsModules/BulletS/ExtendedPhysics.cs | 622 + .../BulletS/Properties/AssemblyInfo.cs | 36 + .../PhysicsModules/BulletS/Tests/BasicVehicles.cs | 156 + .../PhysicsModules/BulletS/Tests/BulletSimTests.cs | 56 + .../BulletS/Tests/BulletSimTestsUtil.cs | 109 + .../PhysicsModules/BulletS/Tests/HullCreation.cs | 205 + .../ConvexDecompositionDotNet/CTri.cs | 341 + .../ConvexDecompositionDotNet/Concavity.cs | 233 + .../ConvexDecompositionDotNet/ConvexBuilder.cs | 411 + .../ConvexDecomposition.cs | 200 + .../ConvexDecompositionDotNet/ConvexResult.cs | 74 + .../ConvexDecompositionDotNet/HullClasses.cs | 171 + .../ConvexDecompositionDotNet/HullTriangle.cs | 99 + .../ConvexDecompositionDotNet/HullUtils.cs | 1868 ++ .../ConvexDecompositionDotNet/LICENSE.txt | 28 + .../ConvexDecompositionDotNet/Plane.cs | 99 + .../ConvexDecompositionDotNet/PlaneTri.cs | 211 + .../Properties/AssemblyInfo.cs | 36 + .../ConvexDecompositionDotNet/Quaternion.cs | 209 + .../ConvexDecompositionDotNet/README.txt | 7 + .../ConvexDecompositionDotNet/SplitPlane.cs | 265 + .../ConvexDecompositionDotNet/VertexLookup.cs | 70 + .../ConvexDecompositionDotNet/float2.cs | 70 + .../ConvexDecompositionDotNet/float3.cs | 444 + .../ConvexDecompositionDotNet/float3x3.cs | 195 + .../ConvexDecompositionDotNet/float4.cs | 170 + .../ConvexDecompositionDotNet/float4x4.cs | 284 + .../ConvexDecompositionDotNet/int3.cs | 128 + .../ConvexDecompositionDotNet/int4.cs | 66 + .../Meshing/Meshmerizer/HelperTypes.cs | 436 + .../PhysicsModules/Meshing/Meshmerizer/Mesh.cs | 333 + .../Meshing/Meshmerizer/Meshmerizer.cs | 1010 + .../Meshing/Meshmerizer/PrimMesher.cs | 2324 +++ .../Meshing/Meshmerizer/SculptMap.cs | 183 + .../Meshing/Meshmerizer/SculptMesh.cs | 646 + .../Meshing/Properties/AssemblyInfo.cs | 36 + .../Region/PhysicsModules/Meshing/ZeroMesher.cs | 132 + OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs | 62 + OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs | 1409 ++ .../PhysicsModules/Ode/ODEDynamics.c_comments | 630 + OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs | 974 + OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs | 3382 ++++ .../PhysicsModules/Ode/ODERayCastRequestManager.cs | 441 + .../Region/PhysicsModules/Ode/OdePhysicsJoint.cs | 48 + OpenSim/Region/PhysicsModules/Ode/OdeScene.cs | 4117 ++++ .../PhysicsModules/Ode/Tests/ODETestClass.cs | 151 + OpenSim/Region/PhysicsModules/Ode/drawstuff.cs | 98 + OpenSim/Region/PhysicsModules/POS/AssemblyInfo.cs | 62 + OpenSim/Region/PhysicsModules/POS/POSCharacter.cs | 341 + OpenSim/Region/PhysicsModules/POS/POSPrim.cs | 336 + OpenSim/Region/PhysicsModules/POS/POSScene.cs | 323 + .../PhysicsModules/SharedBase/AssemblyInfo.cs | 58 + .../PhysicsModules/SharedBase/CollisionLocker.cs | 73 + .../Region/PhysicsModules/SharedBase/IMesher.cs | 71 + .../SharedBase/IPhysicsParameters.cs | 73 + .../PhysicsModules/SharedBase/NullPhysicsScene.cs | 117 + .../PhysicsModules/SharedBase/PhysicsActor.cs | 584 + .../PhysicsModules/SharedBase/PhysicsJoint.cs | 55 + .../PhysicsModules/SharedBase/PhysicsScene.cs | 358 + .../PhysicsModules/SharedBase/PhysicsSensor.cs | 78 + .../PhysicsModules/SharedBase/PhysicsVector.cs | 186 + .../PhysicsModules/SharedBase/VehicleConstants.cs | 121 + .../Properties/AssemblyInfo.cs | 33 - .../RegionCombinerClientEventForwarder.cs | 94 - .../RegionCombinerIndividualEventForwarder.cs | 137 - .../RegionCombinerLargeLandChannel.cs | 175 - .../RegionCombinerModule/RegionCombinerModule.cs | 1076 -- .../RegionCombinerPermissionModule.cs | 270 - .../RegionCombinerModule/RegionConnections.cs | 94 - .../RegionCombinerModule/RegionCourseLocation.cs | 43 - OpenSim/Region/RegionCombinerModule/RegionData.cs | 39 - .../Resources/RegionCombinerModule.addin.xml | 14 - .../Region/ScriptEngine/Interfaces/ICompiler.cs | 31 +- .../Region/ScriptEngine/Interfaces/IScriptApi.cs | 17 +- .../ScriptEngine/Interfaces/IScriptEngine.cs | 45 +- .../ScriptEngine/Interfaces/IScriptInstance.cs | 45 +- .../Api/Implementation/AsyncCommandManager.cs | 329 +- .../Shared/Api/Implementation/LSL_Api.cs | 6111 ++++-- .../Shared/Api/Implementation/LS_Api.cs | 431 +- .../Shared/Api/Implementation/MOD_Api.cs | 79 +- .../Shared/Api/Implementation/OSSL_Api.cs | 488 +- .../Api/Implementation/Plugins/SensorRepeat.cs | 18 +- .../Api/Implementation/Properties/AssemblyInfo.cs | 4 +- .../ScriptEngine/Shared/Api/Interface/ILSL_Api.cs | 9 +- .../ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs | 26 + .../ScriptEngine/Shared/Api/Runtime/Executor.cs | 2 + .../Shared/Api/Runtime/LSL_Constants.cs | 75 +- .../ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs | 39 +- .../ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs | 60 +- .../Shared/Api/Runtime/Properties/AssemblyInfo.cs | 2 +- .../Shared/Api/Runtime/YieldProlog/Atom.cs | 218 - .../Shared/Api/Runtime/YieldProlog/BagofAnswers.cs | 239 - .../Api/Runtime/YieldProlog/FindallAnswers.cs | 108 - .../Shared/Api/Runtime/YieldProlog/Functor.cs | 196 - .../Shared/Api/Runtime/YieldProlog/Functor1.cs | 124 - .../Shared/Api/Runtime/YieldProlog/Functor2.cs | 163 - .../Shared/Api/Runtime/YieldProlog/Functor3.cs | 141 - .../Api/Runtime/YieldProlog/IndexedAnswers.cs | 385 - .../Shared/Api/Runtime/YieldProlog/ListPair.cs | 166 - .../Shared/Api/Runtime/YieldProlog/Parser.cs | 4575 ----- .../Api/Runtime/YieldProlog/PrologException.cs | 159 - .../Runtime/YieldProlog/Properties/AssemblyInfo.cs | 33 - .../YieldProlog/UndefinedPredicateException.cs | 62 - .../Shared/Api/Runtime/YieldProlog/Variable.cs | 222 - .../Shared/Api/Runtime/YieldProlog/YP.cs | 2701 --- .../Shared/Api/Runtime/YieldProlog/YPCompiler.cs | 6382 ------- .../Shared/CodeTools/CSCodeGenerator.cs | 151 +- .../ScriptEngine/Shared/CodeTools/Compiler.cs | 314 +- .../Shared/CodeTools/LSL2CSCodeTransformer.cs | 10 + .../Shared/CodeTools/Properties/AssemblyInfo.cs | 4 +- .../Shared/CodeTools/Tests/CSCodeGeneratorTest.cs | 1 + .../Shared/CodeTools/Tests/CompilerTest.cs | 124 +- .../Shared/CodeTools/Tests/LSL_EventTests.cs | 359 + .../Shared/CodeTools/YP2CSConverter.cs | 117 - .../ScriptEngine/Shared/CodeTools/lsl.lexer.cs | 3669 ++-- .../ScriptEngine/Shared/CodeTools/lsl.parser.cs | 18530 +++++++++++-------- OpenSim/Region/ScriptEngine/Shared/Helpers.cs | 18 + .../Shared/Instance/Properties/AssemblyInfo.cs | 4 +- .../ScriptEngine/Shared/Instance/ScriptInstance.cs | 806 +- .../Shared/Instance/Tests/CoopTerminationTests.cs | 513 + OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs | 274 +- .../ScriptEngine/Shared/Properties/AssemblyInfo.cs | 2 +- .../Shared/Tests/LSL_ApiAvatarTests.cs | 158 + .../ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs | 248 + .../Shared/Tests/LSL_ApiInventoryTests.cs | 126 +- .../Shared/Tests/LSL_ApiLinkingTests.cs | 50 +- .../ScriptEngine/Shared/Tests/LSL_ApiListTests.cs | 4 +- .../Shared/Tests/LSL_ApiNotecardTests.cs | 269 + .../Shared/Tests/LSL_ApiObjectTests.cs | 398 + .../ScriptEngine/Shared/Tests/LSL_ApiTest.cs | 240 +- .../ScriptEngine/Shared/Tests/LSL_ApiUserTests.cs | 157 + .../Shared/Tests/OSSL_ApiAppearanceTest.cs | 4 +- .../Shared/Tests/OSSL_ApiAttachmentTests.cs | 17 +- .../ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs | 7 +- .../XEngine/Api/Runtime/XEngineScriptBase.cs | 61 + .../Region/ScriptEngine/XEngine/EventManager.cs | 10 +- .../XEngine/Properties/AssemblyInfo.cs | 7 +- .../XEngine/Resources/XEngine.addin.xml | 13 - .../XEngine/Tests/XEngineBasicTests.cs | 129 + .../XEngine/Tests/XEngineCrossingTests.cs | 195 + .../XEngine/Tests/XEnginePersistenceTests.cs | 152 + .../ScriptEngine/XEngine/Tests/XEngineTest.cs | 130 - OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 609 +- OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs | 10 +- .../Region/UserStatistics/ActiveConnectionsAJAX.cs | 228 - OpenSim/Region/UserStatistics/Clients_report.cs | 302 - OpenSim/Region/UserStatistics/Default_Report.cs | 250 - OpenSim/Region/UserStatistics/HTMLUtil.cs | 263 - OpenSim/Region/UserStatistics/IStatsReport.cs | 38 - OpenSim/Region/UserStatistics/LogLinesAJAX.cs | 130 - .../UserStatistics/Properties/AssemblyInfo.cs | 33 - .../Region/UserStatistics/Prototype_distributor.cs | 65 - OpenSim/Region/UserStatistics/Sessions_Report.cs | 283 - OpenSim/Region/UserStatistics/SimStatsAJAX.cs | 223 - .../Region/UserStatistics/Updater_distributor.cs | 66 - OpenSim/Region/UserStatistics/WebStatsModule.cs | 1183 -- OpenSim/Server/Base/HttpServerBase.cs | 39 +- OpenSim/Server/Base/Properties/AssemblyInfo.cs | 4 +- OpenSim/Server/Base/ProtocolVersions.cs | 8 +- OpenSim/Server/Base/ServerUtils.cs | 53 +- OpenSim/Server/Base/ServicesServerBase.cs | 74 +- .../AgentPreferencesServerPostHandler.cs | 206 + .../AgentPreferencesServiceConnector.cs | 64 + .../Server/Handlers/Asset/AssetServerConnector.cs | 26 +- .../Handlers/Asset/AssetServerDeleteHandler.cs | 9 +- .../Server/Handlers/Asset/AssetServerGetHandler.cs | 100 +- .../Handlers/Asset/AssetServerPostHandler.cs | 28 +- .../Server/Handlers/Asset/AssetsExistHandler.cs | 87 + .../Asset/Tests/AssetServerPostHandlerTests.cs | 1 - .../AuthenticationServerConnector.cs | 5 +- .../AuthenticationServerPostHandler.cs | 27 +- .../Handlers/Authentication/OpenIdServerHandler.cs | 30 +- .../AuthorizationServerPostHandler.cs | 2 +- .../Handlers/Avatar/AvatarServerConnector.cs | 5 +- .../Handlers/Avatar/AvatarServerPostHandler.cs | 22 +- OpenSim/Server/Handlers/BakedTextures/XBakes.cs | 148 + .../Handlers/BakedTextures/XBakesGetHandler.cs | 71 + .../Server/Handlers/BakedTextures/XBakesHandler.cs | 69 + .../Handlers/BakedTextures/XBakesPostHandler.cs | 76 + .../Handlers/Estate/EstateDataRobustConnector.cs | 343 + .../Handlers/Friends/FriendServerConnector.cs | 4 +- .../Handlers/Friends/FriendsServerPostHandler.cs | 22 +- OpenSim/Server/Handlers/Grid/GridInfoHandlers.cs | 21 +- .../Server/Handlers/Grid/GridServerConnector.cs | 5 +- .../Server/Handlers/Grid/GridServerPostHandler.cs | 99 +- .../Handlers/GridUser/GridUserServerConnector.cs | 5 +- .../Handlers/GridUser/GridUserServerPostHandler.cs | 29 +- OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs | 5 +- .../Hypergrid/GatekeeperServerConnector.cs | 8 +- .../Hypergrid/HGFriendsServerPostHandler.cs | 22 +- .../Handlers/Hypergrid/HeloServerConnector.cs | 4 +- .../Server/Handlers/Hypergrid/HomeAgentHandlers.cs | 202 +- .../Server/Handlers/Hypergrid/HypergridHandlers.cs | 20 +- .../Hypergrid/InstantMessageServerConnector.cs | 7 +- .../Handlers/Hypergrid/UserAgentServerConnector.cs | 19 +- .../Inventory/InventoryServerInConnector.cs | 10 - .../Inventory/InventoryServerMoveItemsHandler.cs | 2 +- .../Handlers/Inventory/XInventoryInConnector.cs | 179 +- OpenSim/Server/Handlers/Login/LLLoginHandlers.cs | 67 + .../Handlers/Login/LLLoginServiceInConnector.cs | 25 +- .../Server/Handlers/Map/MapAddServerConnector.cs | 35 +- .../Server/Handlers/Map/MapGetServerConnector.cs | 2 +- .../Server/Handlers/Neighbour/NeighbourHandlers.cs | 8 +- .../Handlers/Presence/PresenceServerConnector.cs | 5 +- .../Handlers/Presence/PresenceServerPostHandler.cs | 22 +- .../Handlers/Profiles/UserProfilesConnector.cs | 109 + .../Handlers/Profiles/UserProfilesHandlers.cs | 513 + OpenSim/Server/Handlers/Properties/AssemblyInfo.cs | 4 +- .../Server/Handlers/Simulation/AgentHandlers.cs | 369 +- .../UserAccounts/UserAccountServerConnector.cs | 5 +- .../UserAccounts/UserAccountServerPostHandler.cs | 27 +- OpenSim/Server/Properties/AssemblyInfo.cs | 2 +- OpenSim/Server/ServerMain.cs | 2 +- OpenSim/Services/AssetService/AssetService.cs | 51 +- .../AssetService/Properties/AssemblyInfo.cs | 4 +- OpenSim/Services/AssetService/XAssetService.cs | 77 +- OpenSim/Services/AssetService/XAssetServiceBase.cs | 47 +- .../Properties/AssemblyInfo.cs | 4 +- .../Properties/AssemblyInfo.cs | 4 +- .../AvatarService/Properties/AssemblyInfo.cs | 4 +- OpenSim/Services/Base/Properties/AssemblyInfo.cs | 4 +- OpenSim/Services/Base/ServiceBase.cs | 13 +- .../AgentPreferences/AgentPreferencesConnector.cs | 230 + .../Connectors/Asset/AssetServicesConnector.cs | 118 +- .../Connectors/Asset/HGAssetServiceConnector.cs | 104 +- .../AuthenticationServicesConnector.cs | 14 +- .../AuthorizationServicesConnector.cs | 3 +- .../Connectors/Avatar/AvatarServicesConnector.cs | 17 +- .../Services/Connectors/BaseServiceConnector.cs | 33 + .../Connectors/Estate/EstateDataConnector.cs | 338 + .../Freeswitch/RemoteFreeswitchConnector.cs | 2 +- .../Connectors/Friends/FriendsServicesConnector.cs | 12 +- .../Connectors/Grid/GridServicesConnector.cs | 121 +- .../GridUser/GridUserServicesConnector.cs | 17 +- .../Hypergrid/GatekeeperServiceConnector.cs | 99 +- .../Hypergrid/HGFriendsServicesConnector.cs | 2 +- .../Connectors/Hypergrid/HeloServicesConnector.cs | 57 +- .../Hypergrid/UserAgentServiceConnector.cs | 591 +- .../InstantMessageServiceConnector.cs | 1 + .../Inventory/XInventoryServicesConnector.cs | 405 +- .../Connectors/Land/LandServicesConnector.cs | 4 +- .../MapImage/MapImageServicesConnector.cs | 83 +- .../Neighbour/NeighbourServicesConnector.cs | 72 +- .../Presence/PresenceServicesConnector.cs | 26 +- .../Services/Connectors/Properties/AssemblyInfo.cs | 4 +- .../SimianGrid/SimianActivityDetector.cs | 4 +- .../SimianGrid/SimianAssetServiceConnector.cs | 526 +- .../SimianAuthenticationServiceConnector.cs | 12 +- .../SimianGrid/SimianAvatarServiceConnector.cs | 8 +- .../SimianGrid/SimianExternalCapsModule.cs | 180 + .../SimianGrid/SimianFriendsServiceConnector.cs | 8 +- .../Services/Connectors/SimianGrid/SimianGrid.cs | 118 +- .../SimianGrid/SimianGridMaptileModule.cs | 118 +- .../SimianGrid/SimianGridServiceConnector.cs | 49 +- .../SimianGrid/SimianInventoryServiceConnector.cs | 119 +- .../SimianGrid/SimianPresenceServiceConnector.cs | 212 +- .../Connectors/SimianGrid/SimianProfiles.cs | 8 +- .../SimianUserAccountServiceConnector.cs | 13 +- .../Connectors/Simulation/EstateDataService.cs | 139 - .../Connectors/Simulation/SimulationDataService.cs | 182 - .../Simulation/SimulationServiceConnector.cs | 165 +- .../UserAccounts/UserAccountServicesConnector.cs | 57 +- .../Services/EstateService/EstateDataService.cs | 136 + OpenSim/Services/FSAssetService/FSAssetService.cs | 723 + .../FreeswitchService/Properties/AssemblyInfo.cs | 4 +- .../Services/Friends/Properties/AssemblyInfo.cs | 4 +- OpenSim/Services/GridService/GridService.cs | 415 +- OpenSim/Services/GridService/HypergridLinker.cs | 236 +- .../GridService/Properties/AssemblyInfo.cs | 4 +- .../Services/HypergridService/GatekeeperService.cs | 121 +- .../Services/HypergridService/HGAssetService.cs | 34 +- .../Services/HypergridService/HGFSAssetService.cs | 189 + .../Services/HypergridService/HGFriendsService.cs | 3 +- .../HypergridService/HGInstantMessageService.cs | 19 +- .../HypergridService/HGInventoryService.cs | 27 +- .../HypergridService/HGSuitcaseInventoryService.cs | 258 +- .../HypergridService/Properties/AssemblyInfo.cs | 4 +- .../Services/HypergridService/UserAccountCache.cs | 7 +- .../Services/HypergridService/UserAgentService.cs | 259 +- .../HypergridService/UserAgentServiceBase.cs | 84 + .../Interfaces/IAgentPreferencesService.cs | 115 + OpenSim/Services/Interfaces/IAssetService.cs | 9 +- OpenSim/Services/Interfaces/IAvatarService.cs | 46 +- .../Services/Interfaces/IBakedTextureService.cs | 38 + OpenSim/Services/Interfaces/IBansService.cs | 48 + OpenSim/Services/Interfaces/IEstateDataService.cs | 115 + OpenSim/Services/Interfaces/IGridService.cs | 286 +- OpenSim/Services/Interfaces/IHypergridServices.cs | 66 +- OpenSim/Services/Interfaces/IInventoryService.cs | 36 +- OpenSim/Services/Interfaces/IMapImageService.cs | 1 + OpenSim/Services/Interfaces/IOfflineIMService.cs | 7 + OpenSim/Services/Interfaces/ISimulationService.cs | 39 +- OpenSim/Services/Interfaces/IUserAccountService.cs | 2 + OpenSim/Services/Interfaces/IUserManagement.cs | 97 + .../Services/Interfaces/IUserProfilesService.cs | 80 + OpenSim/Services/Interfaces/OpenProfileClient.cs | 134 + .../Services/Interfaces/Properties/AssemblyInfo.cs | 4 +- .../Services/InventoryService/LibraryService.cs | 1 + .../InventoryService/Properties/AssemblyInfo.cs | 4 +- .../Services/InventoryService/XInventoryService.cs | 172 +- OpenSim/Services/LLLoginService/LLLoginResponse.cs | 83 +- OpenSim/Services/LLLoginService/LLLoginService.cs | 166 +- .../LLLoginService/Properties/AssemblyInfo.cs | 4 +- .../Services/MapImageService/MapImageService.cs | 110 +- .../MapImageService/Properties/AssemblyInfo.cs | 4 +- .../Services/PresenceService/PresenceService.cs | 87 +- .../PresenceService/Properties/AssemblyInfo.cs | 4 +- .../SimulationService/SimulationDataService.cs | 191 + .../UserAccountService/AgentPreferencesService.cs | 82 + .../AgentPreferencesServiceBase.cs | 73 + .../Services/UserAccountService/GridUserService.cs | 127 +- .../UserAccountService/GridUserServiceBase.cs | 10 +- .../UserAccountService/Properties/AssemblyInfo.cs | 4 +- .../UserAccountService/UserAccountService.cs | 56 +- .../UserProfilesService/UserProfilesService.cs | 263 + .../UserProfilesService/UserProfilesServiceBase.cs | 87 + OpenSim/Tests/Clients/Assets/AssetsClient.cs | 126 + OpenSim/Tests/Clients/Grid/GridClient.cs | 205 - OpenSim/Tests/Clients/Grid/GridForm.html | 11 - OpenSim/Tests/Clients/InstantMessage/IMClient.cs | 75 - OpenSim/Tests/Clients/Presence/OpenSim.Server.ini | 33 - OpenSim/Tests/Clients/Presence/PresenceClient.cs | 115 - .../Tests/Clients/UserAccounts/OpenSim.Server.ini | 33 - .../Clients/UserAccounts/UserAccountsClient.cs | 144 - .../Common/Helpers/BaseRequestHandlerHelpers.cs | 1 - OpenSim/Tests/Common/Helpers/ClientStackHelpers.cs | 95 + .../Tests/Common/Helpers/EntityTransferHelpers.cs | 123 + OpenSim/Tests/Common/Helpers/SceneHelpers.cs | 139 +- .../Tests/Common/Helpers/TaskInventoryHelpers.cs | 121 +- OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs | 2 +- .../Tests/Common/Helpers/UserInventoryHelpers.cs | 142 +- OpenSim/Tests/Common/Mock/BaseAssetRepository.cs | 11 +- OpenSim/Tests/Common/Mock/MockAssetDataPlugin.cs | 2 +- .../Common/Mock/MockGroupsServicesConnector.cs | 178 +- OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs | 29 +- OpenSim/Tests/Common/Mock/MockScriptEngine.cs | 272 + OpenSim/Tests/Common/Mock/TestClient.cs | 179 +- .../Tests/Common/Mock/TestEventQueueGetModule.cs | 182 + OpenSim/Tests/Common/Mock/TestHttpClientContext.cs | 110 + OpenSim/Tests/Common/Mock/TestHttpRequest.cs | 174 + OpenSim/Tests/Common/Mock/TestHttpResponse.cs | 171 + .../Tests/Common/Mock/TestInventoryDataPlugin.cs | 4 +- OpenSim/Tests/Common/Mock/TestLLUDPServer.cs | 171 + OpenSim/Tests/Common/Mock/TestLandChannel.cs | 7 +- OpenSim/Tests/Common/Mock/TestOSHttpRequest.cs | 2 +- OpenSim/Tests/Common/Mock/TestOSHttpResponse.cs | 2 +- OpenSim/Tests/Common/Mock/TestScene.cs | 15 +- .../Tests/Common/Mock/TestXInventoryDataPlugin.cs | 51 +- OpenSim/Tests/Common/OpenSimTestCase.cs | 15 +- OpenSim/Tests/Common/TestHelpers.cs | 38 + OpenSim/Tests/ConfigurationLoaderTest.cs | 4 +- OpenSim/Tests/Performance/NPCPerformanceTests.cs | 7 +- .../Tests/Performance/ObjectPerformanceTests.cs | 1 - .../Tests/Performance/ScriptPerformanceTests.cs | 1 - OpenSim/Tests/Robust/Clients/Grid/GridClient.cs | 133 + OpenSim/Tests/Robust/Clients/Grid/GridForm.html | 11 + .../Robust/Clients/InstantMessage/IMClient.cs | 58 + .../Robust/Clients/Inventory/InventoryClient.cs | 206 + .../Robust/Clients/Presence/PresenceClient.cs | 81 + .../Clients/UserAccounts/UserAccountsClient.cs | 86 + OpenSim/Tests/Robust/Server/DemonServer.cs | 69 + .../Tests/Stress/VectorRenderModuleStressTests.cs | 3 +- OpenSim/Tools/Compiler/Program.cs | 51 +- OpenSim/Tools/Compiler/Properties/AssemblyInfo.cs | 4 +- OpenSim/Tools/Configger/ConfigurationLoader.cs | 17 +- OpenSim/Tools/Configger/Main.cs | 5 +- OpenSim/Tools/Configger/Properties/AssemblyInfo.cs | 4 +- .../OpenSim.32BitLaunch/OpenSim.32BitLaunch.csproj | 58 - OpenSim/Tools/OpenSim.32BitLaunch/Program.cs | 59 - .../OpenSim.32BitLaunch/Properties/AssemblyInfo.cs | 63 - OpenSim/Tools/Robust.32BitLaunch/Program.cs | 60 - .../Robust.32BitLaunch/Properties/AssemblyInfo.cs | 63 - .../Robust.32BitLaunch/Robust.32BitLaunch.csproj | 62 - .../Robust.32BitLaunch/Robust.32BitLaunch.sln | 20 - .../Tools/pCampBot/Behaviours/AbstractBehaviour.cs | 19 +- .../Tools/pCampBot/Behaviours/CrossBehaviour.cs | 6 +- .../Tools/pCampBot/Behaviours/GrabbingBehaviour.cs | 9 +- .../Behaviours/InventoryDownloadBehaviour.cs | 121 + OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs | 60 + .../Tools/pCampBot/Behaviours/PhysicsBehaviour.cs | 9 + .../Tools/pCampBot/Behaviours/PhysicsBehaviour2.cs | 86 + .../Tools/pCampBot/Behaviours/TeleportBehaviour.cs | 9 +- .../Tools/pCampBot/Behaviours/TwitchyBehaviour.cs | 73 + OpenSim/Tools/pCampBot/Bot.cs | 348 +- OpenSim/Tools/pCampBot/BotManager.cs | 903 +- OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs | 21 + OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs | 4 +- OpenSim/Tools/pCampBot/pCampBot.cs | 89 +- 1339 files changed, 181263 insertions(+), 131428 deletions(-) create mode 100644 OpenSim/Addons/Groups/ForeignImporter.cs create mode 100644 OpenSim/Addons/Groups/GroupsExtendedData.cs create mode 100644 OpenSim/Addons/Groups/GroupsMessagingModule.cs create mode 100644 OpenSim/Addons/Groups/GroupsModule.cs create mode 100644 OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnector.cs create mode 100644 OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs create mode 100644 OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs create mode 100644 OpenSim/Addons/Groups/IGroupsServicesConnector.cs create mode 100644 OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs create mode 100644 OpenSim/Addons/Groups/Properties/AssemblyInfo.cs create mode 100644 OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs create mode 100644 OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs create mode 100644 OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs create mode 100644 OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs create mode 100644 OpenSim/Addons/Groups/Service/GroupsService.cs create mode 100644 OpenSim/Addons/Groups/Service/GroupsServiceBase.cs create mode 100644 OpenSim/Addons/Groups/Service/HGGroupsService.cs create mode 100644 OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs create mode 100644 OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs create mode 100644 OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs create mode 100644 OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs create mode 100644 OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs create mode 100644 OpenSim/Addons/OfflineIM/Service/OfflineIMServiceBase.cs create mode 100644 OpenSim/ApplicationPlugins/LoadRegions/IRegionLoader.cs create mode 100644 OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderFileSystem.cs create mode 100644 OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderWebServer.cs delete mode 100644 OpenSim/ApplicationPlugins/LoadRegions/Resources/LoadRegionsPlugin.addin.xml delete mode 100644 OpenSim/ApplicationPlugins/RegionModulesController/Resources/RegionModulesControllerPlugin.addin.xml delete mode 100644 OpenSim/ApplicationPlugins/RemoteController/Resources/RemoteAdminPlugin.addin.xml delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/Resources/RestHandler.addin.xml delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RestTestServices.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/tests/ITest.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Regions/GETRegionInfoHandler.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Regions/Resources/RestRegionPlugin.addin.xml delete mode 100644 OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/RestPlugin.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/rest.xsd create mode 100644 OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs create mode 100644 OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs create mode 100644 OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescServerConnector.cs create mode 100644 OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs create mode 100644 OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs create mode 100644 OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs delete mode 100644 OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs delete mode 100644 OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2ServerConnector.cs create mode 100644 OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesHandler.cs create mode 100644 OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesServerConnector.cs create mode 100644 OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureServerConnector.cs delete mode 100644 OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs delete mode 100644 OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs create mode 100644 OpenSim/Capabilities/LLSDAvatarPicker.cs create mode 100644 OpenSim/Data/IAgentPreferencesData.cs create mode 100644 OpenSim/Data/IEstateDataStore.cs create mode 100644 OpenSim/Data/IFSAssetData.cs create mode 100644 OpenSim/Data/IGroupsData.cs create mode 100644 OpenSim/Data/IHGTravelingData.cs create mode 100644 OpenSim/Data/IOfflineIMData.cs create mode 100644 OpenSim/Data/IProfilesData.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLAssetData.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLAuthenticationData.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLAvatarData.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLEstateData.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLFriendsData.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLGridUserData.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLInventoryData.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLManager.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLMigration.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLPresenceData.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLRegionData.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLSimulationData.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLUserAccountData.cs delete mode 100644 OpenSim/Data/MSSQL/MSSQLXInventoryData.cs delete mode 100644 OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Data/MSSQL/Resources/AssetStore.migrations delete mode 100644 OpenSim/Data/MSSQL/Resources/AuthStore.migrations delete mode 100644 OpenSim/Data/MSSQL/Resources/Avatar.migrations delete mode 100644 OpenSim/Data/MSSQL/Resources/EstateStore.migrations delete mode 100644 OpenSim/Data/MSSQL/Resources/FriendsStore.migrations delete mode 100644 OpenSim/Data/MSSQL/Resources/GridStore.migrations delete mode 100644 OpenSim/Data/MSSQL/Resources/GridUserStore.migrations delete mode 100644 OpenSim/Data/MSSQL/Resources/InventoryStore.migrations delete mode 100644 OpenSim/Data/MSSQL/Resources/LogStore.migrations delete mode 100644 OpenSim/Data/MSSQL/Resources/Presence.migrations delete mode 100644 OpenSim/Data/MSSQL/Resources/RegionStore.migrations delete mode 100644 OpenSim/Data/MSSQL/Resources/UserAccount.migrations delete mode 100644 OpenSim/Data/MSSQL/Resources/UserStore.migrations create mode 100644 OpenSim/Data/MySQL/MySQLAgentPreferencesData.cs create mode 100644 OpenSim/Data/MySQL/MySQLFSAssetData.cs create mode 100644 OpenSim/Data/MySQL/MySQLGroupsData.cs create mode 100644 OpenSim/Data/MySQL/MySQLHGTravelData.cs create mode 100644 OpenSim/Data/MySQL/MySQLOfflineIMData.cs create mode 100644 OpenSim/Data/MySQL/MySQLUserProfilesData.cs create mode 100644 OpenSim/Data/MySQL/Resources/AgentPrefs.migrations create mode 100644 OpenSim/Data/MySQL/Resources/FSAssetStore.migrations create mode 100644 OpenSim/Data/MySQL/Resources/HGTravelStore.migrations create mode 100644 OpenSim/Data/MySQL/Resources/IM_Store.migrations create mode 100644 OpenSim/Data/MySQL/Resources/UserProfiles.migrations create mode 100644 OpenSim/Data/MySQL/Resources/os_groups_Store.migrations create mode 100644 OpenSim/Data/PGSQL/PGSQLAgentPreferencesData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLAssetData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLAuthenticationData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLAvatarData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLEstateData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLFramework.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLFriendsData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLGenericTableHandler.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLGridUserData.cs create mode 100755 OpenSim/Data/PGSQL/PGSQLGroupsData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLHGTravelData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLInventoryData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLManager.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLMigration.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLOfflineIMData.cs create mode 100755 OpenSim/Data/PGSQL/PGSQLPresenceData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLRegionData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLSimulationData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLUserAccountData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLUserProfilesData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLXAssetData.cs create mode 100644 OpenSim/Data/PGSQL/PGSQLXInventoryData.cs create mode 100644 OpenSim/Data/PGSQL/Properties/AssemblyInfo.cs create mode 100644 OpenSim/Data/PGSQL/Resources/AssetStore.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/AuthStore.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/Avatar.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/EstateStore.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/FriendsStore.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/GridStore.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/GridUserStore.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/HGTravelStore.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/IM_Store.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/InventoryStore.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/LogStore.migrations create mode 100755 OpenSim/Data/PGSQL/Resources/Presence.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/RegionStore.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/UserAccount.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/UserProfiles.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/UserStore.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/XAssetStore.migrations create mode 100644 OpenSim/Data/PGSQL/Resources/os_groups_Store.migrations create mode 100644 OpenSim/Data/SQLite/Resources/AgentPrefs.migrations create mode 100644 OpenSim/Data/SQLite/Resources/HGTravelStore.migrations create mode 100644 OpenSim/Data/SQLite/Resources/UserProfiles.migrations create mode 100644 OpenSim/Data/SQLite/SQLiteAgentPreferencesData.cs create mode 100644 OpenSim/Data/SQLite/SQLiteHGTravelData.cs create mode 100644 OpenSim/Data/SQLite/SQLiteUserProfilesData.cs create mode 100644 OpenSim/Framework/BasicDOSProtector.cs create mode 100644 OpenSim/Framework/CachedTextureEventArg.cs create mode 100644 OpenSim/Framework/CircularBuffer.cs delete mode 100644 OpenSim/Framework/Communications/GenericAsyncResult.cs delete mode 100644 OpenSim/Framework/Communications/IUserService.cs delete mode 100644 OpenSim/Framework/Communications/Limit/IRequestLimitStrategy.cs delete mode 100644 OpenSim/Framework/Communications/Limit/NullLimitStrategy.cs delete mode 100644 OpenSim/Framework/Communications/Limit/RepeatLimitStrategy.cs delete mode 100644 OpenSim/Framework/Communications/Limit/TimeLimitStrategy.cs delete mode 100644 OpenSim/Framework/Communications/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Framework/Communications/RestClient.cs delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppError.cs delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppIqStanza.cs delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppMessageStanza.cs delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppPresenceStanza.cs delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppSerializer.cs delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppStanza.cs delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppWriter.cs delete mode 100644 OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs delete mode 100644 OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs delete mode 100644 OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Framework/Configuration/XML/XmlConfiguration.cs delete mode 100644 OpenSim/Framework/ConfigurationMember.cs create mode 100644 OpenSim/Framework/Console/ConsoleDisplayUtil.cs create mode 100644 OpenSim/Framework/DAMap.cs create mode 100644 OpenSim/Framework/DOMap.cs create mode 100644 OpenSim/Framework/ExtraPhysicsData.cs delete mode 100644 OpenSim/Framework/ForeignUserProfileData.cs create mode 100644 OpenSim/Framework/IPeople.cs delete mode 100644 OpenSim/Framework/IRegionLoader.cs create mode 100755 OpenSim/Framework/LogWriter.cs create mode 100644 OpenSim/Framework/MetricsCollector.cs create mode 100644 OpenSim/Framework/Monitoring/Checks/Check.cs create mode 100644 OpenSim/Framework/Monitoring/ChecksManager.cs create mode 100644 OpenSim/Framework/Monitoring/JobEngine.cs create mode 100644 OpenSim/Framework/Monitoring/ServerStatsCollector.cs mode change 100644 => 100755 OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs create mode 100755 OpenSim/Framework/Monitoring/Stats/CounterStat.cs create mode 100755 OpenSim/Framework/Monitoring/Stats/EventHistogram.cs create mode 100644 OpenSim/Framework/Monitoring/StatsLogger.cs create mode 100644 OpenSim/Framework/Monitoring/WorkManager.cs create mode 100644 OpenSim/Framework/OutboundUrlFilter.cs create mode 100644 OpenSim/Framework/PermissionsUtil.cs delete mode 100644 OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs delete mode 100644 OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs create mode 100644 OpenSim/Framework/RestClient.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs delete mode 100644 OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs delete mode 100644 OpenSim/Framework/Servers/VersionInfo.cs create mode 100644 OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs create mode 100644 OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs create mode 100644 OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs create mode 100644 OpenSim/Framework/ServiceAuth/IServiceAuth.cs create mode 100644 OpenSim/Framework/ServiceAuth/ServiceAuth.cs create mode 100644 OpenSim/Framework/TerrainData.cs create mode 100644 OpenSim/Framework/ThreadSafeRandom.cs delete mode 100644 OpenSim/Framework/UntrustedWebRequest.cs create mode 100644 OpenSim/Framework/UserProfiles.cs create mode 100644 OpenSim/Framework/VersionInfo.cs create mode 100644 OpenSim/Framework/WearableCacheItem.cs create mode 100644 OpenSim/Region/Application/Properties/AssemblyInfo.cs create mode 100644 OpenSim/Region/Application/RegionApplicationBase.cs delete mode 100644 OpenSim/Region/ClientStack/ClientStackManager.cs delete mode 100644 OpenSim/Region/ClientStack/IClientNetworkServer.cs create mode 100644 OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs create mode 100644 OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs create mode 100644 OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs create mode 100644 OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs create mode 100644 OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs delete mode 100644 OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs delete mode 100644 OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs create mode 100644 OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs delete mode 100644 OpenSim/Region/ClientStack/RegionApplicationBase.cs create mode 100644 OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs create mode 100644 OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs create mode 100644 OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs create mode 100644 OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadTests.cs create mode 100644 OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs delete mode 100644 OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs delete mode 100644 OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs create mode 100644 OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs create mode 100644 OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs create mode 100644 OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs create mode 100644 OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs create mode 100644 OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs create mode 100644 OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs create mode 100644 OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs delete mode 100755 OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs create mode 100644 OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs create mode 100644 OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs create mode 100644 OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs create mode 100644 OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/LocalAgentPreferencesServiceConnector.cs create mode 100644 OpenSim/Region/CoreModules/ServiceConnectorsOut/AgentPreferences/RemoteAgentPreferencesServiceConnector.cs create mode 100644 OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs create mode 100644 OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs create mode 100644 OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs create mode 100644 OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/ITerrainFeature.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainModuleTests.cs delete mode 100644 OpenSim/Region/DataSnapshot/DataRequestHandler.cs delete mode 100644 OpenSim/Region/DataSnapshot/DataSnapshotManager.cs delete mode 100644 OpenSim/Region/DataSnapshot/EstateSnapshot.cs delete mode 100644 OpenSim/Region/DataSnapshot/Interfaces/IDataSnapshot.cs delete mode 100644 OpenSim/Region/DataSnapshot/Interfaces/IDataSnapshotProvider.cs delete mode 100644 OpenSim/Region/DataSnapshot/LLSDDiscovery.cs delete mode 100644 OpenSim/Region/DataSnapshot/LandSnapshot.cs delete mode 100644 OpenSim/Region/DataSnapshot/ObjectSnapshot.cs delete mode 100644 OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Region/DataSnapshot/SnapshotStore.cs create mode 100644 OpenSim/Region/Framework/Interfaces/IAgentStatefulModule.cs create mode 100644 OpenSim/Region/Framework/Interfaces/IBakedTextureModule.cs create mode 100644 OpenSim/Region/Framework/Interfaces/IDynamicFloaterModule.cs create mode 100644 OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs delete mode 100644 OpenSim/Region/Framework/Interfaces/IEstateDataService.cs delete mode 100644 OpenSim/Region/Framework/Interfaces/IEstateDataStore.cs create mode 100644 OpenSim/Region/Framework/Interfaces/IExternalCapsModule.cs delete mode 100644 OpenSim/Region/Framework/Interfaces/IInterregionComms.cs create mode 100644 OpenSim/Region/Framework/Interfaces/IMapImageUploadModule.cs create mode 100644 OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs delete mode 100644 OpenSim/Region/Framework/Interfaces/IUserManagement.cs create mode 100644 OpenSim/Region/Framework/Scenes/KeyframeMotion.cs mode change 100644 => 100755 OpenSim/Region/Framework/Scenes/Scene.cs mode change 100644 => 100755 OpenSim/Region/Framework/Scenes/SceneGraph.cs create mode 100644 OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs delete mode 100644 OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs delete mode 100644 OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs delete mode 100644 OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs delete mode 100644 OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs create mode 100644 OpenSim/Region/Framework/Scenes/Scripting/ScriptUtils.cs mode change 100644 => 100755 OpenSim/Region/Framework/Scenes/SimStatsReporter.cs create mode 100644 OpenSim/Region/Framework/Scenes/TerrainCompressor.cs create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SceneObjectCopyTests.cs create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SceneObjectSerializationTests.cs create mode 100644 OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs create mode 100644 OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SceneStatisticsTests.cs create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SharedRegionModuleTests.cs create mode 100644 OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs create mode 100644 OpenSim/Region/OptionalModules/DataSnapshot/DataRequestHandler.cs create mode 100644 OpenSim/Region/OptionalModules/DataSnapshot/DataSnapshotManager.cs create mode 100644 OpenSim/Region/OptionalModules/DataSnapshot/EstateSnapshot.cs create mode 100644 OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshot.cs create mode 100644 OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshotProvider.cs create mode 100644 OpenSim/Region/OptionalModules/DataSnapshot/LLSDDiscovery.cs create mode 100644 OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs create mode 100644 OpenSim/Region/OptionalModules/DataSnapshot/ObjectSnapshot.cs create mode 100644 OpenSim/Region/OptionalModules/DataSnapshot/SnapshotStore.cs create mode 100644 OpenSim/Region/OptionalModules/Example/WebSocketEchoTest/WebSocketEchoModule.cs create mode 100644 OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs create mode 100644 OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerClientEventForwarder.cs create mode 100644 OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs create mode 100644 OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerLargeLandChannel.cs create mode 100644 OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs create mode 100644 OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerPermissionModule.cs create mode 100644 OpenSim/Region/OptionalModules/RegionCombinerModule/RegionConnections.cs create mode 100644 OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCourseLocation.cs create mode 100644 OpenSim/Region/OptionalModules/RegionCombinerModule/RegionData.cs create mode 100644 OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreCommands.cs create mode 100644 OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs create mode 100644 OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs create mode 100644 OpenSim/Region/OptionalModules/UserStatistics/Clients_report.cs create mode 100644 OpenSim/Region/OptionalModules/UserStatistics/Default_Report.cs create mode 100644 OpenSim/Region/OptionalModules/UserStatistics/HTMLUtil.cs create mode 100644 OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs create mode 100644 OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs create mode 100644 OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs create mode 100644 OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs create mode 100644 OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs create mode 100644 OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs create mode 100644 OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs create mode 100644 OpenSim/Region/OptionalModules/ViewerSupport/CameraOnlyModeModule.cs create mode 100644 OpenSim/Region/OptionalModules/ViewerSupport/DynamicFloaterModule.cs create mode 100644 OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs create mode 100644 OpenSim/Region/OptionalModules/ViewerSupport/GodNamesModule.cs create mode 100644 OpenSim/Region/OptionalModules/ViewerSupport/SimulatorFeaturesHelper.cs create mode 100644 OpenSim/Region/OptionalModules/ViewerSupport/SpecialUIModule.cs delete mode 100644 OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs delete mode 100644 OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs delete mode 100644 OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs delete mode 100644 OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPrim.cs delete mode 100644 OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs delete mode 100644 OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs delete mode 100644 OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs delete mode 100644 OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs delete mode 100644 OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSParam.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs delete mode 100644 OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs delete mode 100644 OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs delete mode 100644 OpenSim/Region/Physics/BulletSPlugin/BSScene.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs delete mode 100755 OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt delete mode 100644 OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs delete mode 100644 OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs delete mode 100644 OpenSim/Region/Physics/Manager/AssemblyInfo.cs delete mode 100644 OpenSim/Region/Physics/Manager/CollisionLocker.cs delete mode 100644 OpenSim/Region/Physics/Manager/IMesher.cs delete mode 100755 OpenSim/Region/Physics/Manager/IPhysicsParameters.cs delete mode 100644 OpenSim/Region/Physics/Manager/NullPhysicsScene.cs delete mode 100644 OpenSim/Region/Physics/Manager/PhysicsActor.cs delete mode 100644 OpenSim/Region/Physics/Manager/PhysicsJoint.cs delete mode 100644 OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs delete mode 100644 OpenSim/Region/Physics/Manager/PhysicsScene.cs delete mode 100644 OpenSim/Region/Physics/Manager/PhysicsSensor.cs delete mode 100644 OpenSim/Region/Physics/Manager/PhysicsVector.cs delete mode 100644 OpenSim/Region/Physics/Manager/VehicleConstants.cs delete mode 100644 OpenSim/Region/Physics/Manager/ZeroMesher.cs delete mode 100644 OpenSim/Region/Physics/Meshing/HelperTypes.cs delete mode 100644 OpenSim/Region/Physics/Meshing/Mesh.cs delete mode 100644 OpenSim/Region/Physics/Meshing/Meshmerizer.cs delete mode 100644 OpenSim/Region/Physics/Meshing/PrimMesher.cs delete mode 100644 OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Region/Physics/Meshing/SculptMap.cs delete mode 100644 OpenSim/Region/Physics/Meshing/SculptMesh.cs delete mode 100644 OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs delete mode 100644 OpenSim/Region/Physics/OdePlugin/ODECharacter.cs delete mode 100644 OpenSim/Region/Physics/OdePlugin/ODEDynamics.c_comments delete mode 100644 OpenSim/Region/Physics/OdePlugin/ODEDynamics.cs delete mode 100644 OpenSim/Region/Physics/OdePlugin/ODEPrim.cs delete mode 100644 OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs delete mode 100644 OpenSim/Region/Physics/OdePlugin/OdePhysicsJoint.cs delete mode 100644 OpenSim/Region/Physics/OdePlugin/OdePlugin.cs delete mode 100644 OpenSim/Region/Physics/OdePlugin/OdeScene.cs delete mode 100644 OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs delete mode 100644 OpenSim/Region/Physics/OdePlugin/drawstuff.cs delete mode 100644 OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs delete mode 100644 OpenSim/Region/Physics/POSPlugin/POSCharacter.cs delete mode 100644 OpenSim/Region/Physics/POSPlugin/POSPlugin.cs delete mode 100644 OpenSim/Region/Physics/POSPlugin/POSPrim.cs delete mode 100644 OpenSim/Region/Physics/POSPlugin/POSScene.cs create mode 100644 OpenSim/Region/PhysicsModules/BasicPhysics/AssemblyInfo.cs create mode 100644 OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs create mode 100644 OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs create mode 100644 OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActors.cs create mode 100644 OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs create mode 100644 OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs create mode 100644 OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSParam.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs create mode 100644 OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs create mode 100644 OpenSim/Region/PhysicsModules/BulletS/BSScene.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt create mode 100755 OpenSim/Region/PhysicsModules/BulletS/ExtendedPhysics.cs create mode 100644 OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs create mode 100755 OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs create mode 100644 OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/CTri.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Concavity.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexBuilder.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexDecomposition.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexResult.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullClasses.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullTriangle.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/LICENSE.txt create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Plane.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/PlaneTri.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Quaternion.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/README.txt create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/SplitPlane.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/VertexLookup.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float2.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3x3.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4x4.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int3.cs create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int4.cs create mode 100644 OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/HelperTypes.cs create mode 100644 OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Mesh.cs create mode 100644 OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs create mode 100644 OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/PrimMesher.cs create mode 100644 OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMap.cs create mode 100644 OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMesh.cs create mode 100644 OpenSim/Region/PhysicsModules/Meshing/Properties/AssemblyInfo.cs create mode 100644 OpenSim/Region/PhysicsModules/Meshing/ZeroMesher.cs create mode 100644 OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs create mode 100644 OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs create mode 100644 OpenSim/Region/PhysicsModules/Ode/ODEDynamics.c_comments create mode 100644 OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs create mode 100644 OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs create mode 100644 OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs create mode 100644 OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs create mode 100644 OpenSim/Region/PhysicsModules/Ode/OdeScene.cs create mode 100644 OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs create mode 100644 OpenSim/Region/PhysicsModules/Ode/drawstuff.cs create mode 100644 OpenSim/Region/PhysicsModules/POS/AssemblyInfo.cs create mode 100644 OpenSim/Region/PhysicsModules/POS/POSCharacter.cs create mode 100644 OpenSim/Region/PhysicsModules/POS/POSPrim.cs create mode 100644 OpenSim/Region/PhysicsModules/POS/POSScene.cs create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/AssemblyInfo.cs create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/CollisionLocker.cs create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/IMesher.cs create mode 100755 OpenSim/Region/PhysicsModules/SharedBase/IPhysicsParameters.cs create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/NullPhysicsScene.cs create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/PhysicsJoint.cs create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/PhysicsScene.cs create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/PhysicsSensor.cs create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/PhysicsVector.cs create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/VehicleConstants.cs delete mode 100644 OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Region/RegionCombinerModule/RegionCombinerClientEventForwarder.cs delete mode 100644 OpenSim/Region/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs delete mode 100644 OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs delete mode 100644 OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs delete mode 100644 OpenSim/Region/RegionCombinerModule/RegionCombinerPermissionModule.cs delete mode 100644 OpenSim/Region/RegionCombinerModule/RegionConnections.cs delete mode 100644 OpenSim/Region/RegionCombinerModule/RegionCourseLocation.cs delete mode 100644 OpenSim/Region/RegionCombinerModule/RegionData.cs delete mode 100644 OpenSim/Region/RegionCombinerModule/Resources/RegionCombinerModule.addin.xml delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Atom.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/BagofAnswers.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/FindallAnswers.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor1.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor2.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor3.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/IndexedAnswers.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/ListPair.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Parser.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/PrologException.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/UndefinedPredicateException.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Variable.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YPCompiler.cs create mode 100644 OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/LSL_EventTests.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/CodeTools/YP2CSConverter.cs create mode 100644 OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs create mode 100644 OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiAvatarTests.cs create mode 100644 OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs create mode 100644 OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiNotecardTests.cs create mode 100644 OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiObjectTests.cs create mode 100644 OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiUserTests.cs create mode 100644 OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs delete mode 100644 OpenSim/Region/ScriptEngine/XEngine/Resources/XEngine.addin.xml create mode 100644 OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs create mode 100644 OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineCrossingTests.cs create mode 100644 OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs delete mode 100644 OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs mode change 100644 => 100755 OpenSim/Region/ScriptEngine/XEngine/XEngine.cs delete mode 100644 OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs delete mode 100644 OpenSim/Region/UserStatistics/Clients_report.cs delete mode 100644 OpenSim/Region/UserStatistics/Default_Report.cs delete mode 100644 OpenSim/Region/UserStatistics/HTMLUtil.cs delete mode 100644 OpenSim/Region/UserStatistics/IStatsReport.cs delete mode 100644 OpenSim/Region/UserStatistics/LogLinesAJAX.cs delete mode 100644 OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Region/UserStatistics/Prototype_distributor.cs delete mode 100644 OpenSim/Region/UserStatistics/Sessions_Report.cs delete mode 100644 OpenSim/Region/UserStatistics/SimStatsAJAX.cs delete mode 100644 OpenSim/Region/UserStatistics/Updater_distributor.cs delete mode 100644 OpenSim/Region/UserStatistics/WebStatsModule.cs create mode 100644 OpenSim/Server/Handlers/AgentPreferences/AgentPreferencesServerPostHandler.cs create mode 100644 OpenSim/Server/Handlers/AgentPreferences/AgentPreferencesServiceConnector.cs create mode 100644 OpenSim/Server/Handlers/Asset/AssetsExistHandler.cs create mode 100644 OpenSim/Server/Handlers/BakedTextures/XBakes.cs create mode 100644 OpenSim/Server/Handlers/BakedTextures/XBakesGetHandler.cs create mode 100644 OpenSim/Server/Handlers/BakedTextures/XBakesHandler.cs create mode 100644 OpenSim/Server/Handlers/BakedTextures/XBakesPostHandler.cs create mode 100644 OpenSim/Server/Handlers/Estate/EstateDataRobustConnector.cs create mode 100644 OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs create mode 100644 OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs create mode 100644 OpenSim/Services/Connectors/AgentPreferences/AgentPreferencesConnector.cs create mode 100644 OpenSim/Services/Connectors/BaseServiceConnector.cs create mode 100644 OpenSim/Services/Connectors/Estate/EstateDataConnector.cs create mode 100644 OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs delete mode 100644 OpenSim/Services/Connectors/Simulation/EstateDataService.cs delete mode 100644 OpenSim/Services/Connectors/Simulation/SimulationDataService.cs create mode 100644 OpenSim/Services/EstateService/EstateDataService.cs create mode 100644 OpenSim/Services/FSAssetService/FSAssetService.cs create mode 100644 OpenSim/Services/HypergridService/HGFSAssetService.cs create mode 100644 OpenSim/Services/HypergridService/UserAgentServiceBase.cs create mode 100644 OpenSim/Services/Interfaces/IAgentPreferencesService.cs create mode 100644 OpenSim/Services/Interfaces/IBakedTextureService.cs create mode 100644 OpenSim/Services/Interfaces/IBansService.cs create mode 100644 OpenSim/Services/Interfaces/IEstateDataService.cs create mode 100644 OpenSim/Services/Interfaces/IUserManagement.cs create mode 100644 OpenSim/Services/Interfaces/IUserProfilesService.cs create mode 100644 OpenSim/Services/Interfaces/OpenProfileClient.cs create mode 100644 OpenSim/Services/SimulationService/SimulationDataService.cs create mode 100644 OpenSim/Services/UserAccountService/AgentPreferencesService.cs create mode 100644 OpenSim/Services/UserAccountService/AgentPreferencesServiceBase.cs create mode 100644 OpenSim/Services/UserProfilesService/UserProfilesService.cs create mode 100644 OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs create mode 100644 OpenSim/Tests/Clients/Assets/AssetsClient.cs delete mode 100644 OpenSim/Tests/Clients/Grid/GridClient.cs delete mode 100644 OpenSim/Tests/Clients/Grid/GridForm.html delete mode 100644 OpenSim/Tests/Clients/InstantMessage/IMClient.cs delete mode 100644 OpenSim/Tests/Clients/Presence/OpenSim.Server.ini delete mode 100644 OpenSim/Tests/Clients/Presence/PresenceClient.cs delete mode 100644 OpenSim/Tests/Clients/UserAccounts/OpenSim.Server.ini delete mode 100644 OpenSim/Tests/Clients/UserAccounts/UserAccountsClient.cs create mode 100644 OpenSim/Tests/Common/Helpers/ClientStackHelpers.cs create mode 100644 OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs create mode 100644 OpenSim/Tests/Common/Mock/MockScriptEngine.cs create mode 100644 OpenSim/Tests/Common/Mock/TestEventQueueGetModule.cs create mode 100644 OpenSim/Tests/Common/Mock/TestHttpClientContext.cs create mode 100644 OpenSim/Tests/Common/Mock/TestHttpRequest.cs create mode 100644 OpenSim/Tests/Common/Mock/TestHttpResponse.cs create mode 100644 OpenSim/Tests/Common/Mock/TestLLUDPServer.cs create mode 100644 OpenSim/Tests/Robust/Clients/Grid/GridClient.cs create mode 100644 OpenSim/Tests/Robust/Clients/Grid/GridForm.html create mode 100644 OpenSim/Tests/Robust/Clients/InstantMessage/IMClient.cs create mode 100644 OpenSim/Tests/Robust/Clients/Inventory/InventoryClient.cs create mode 100644 OpenSim/Tests/Robust/Clients/Presence/PresenceClient.cs create mode 100644 OpenSim/Tests/Robust/Clients/UserAccounts/UserAccountsClient.cs create mode 100644 OpenSim/Tests/Robust/Server/DemonServer.cs delete mode 100644 OpenSim/Tools/OpenSim.32BitLaunch/OpenSim.32BitLaunch.csproj delete mode 100644 OpenSim/Tools/OpenSim.32BitLaunch/Program.cs delete mode 100644 OpenSim/Tools/OpenSim.32BitLaunch/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Tools/Robust.32BitLaunch/Program.cs delete mode 100644 OpenSim/Tools/Robust.32BitLaunch/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Tools/Robust.32BitLaunch/Robust.32BitLaunch.csproj delete mode 100644 OpenSim/Tools/Robust.32BitLaunch/Robust.32BitLaunch.sln create mode 100644 OpenSim/Tools/pCampBot/Behaviours/InventoryDownloadBehaviour.cs create mode 100644 OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs create mode 100644 OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour2.cs create mode 100644 OpenSim/Tools/pCampBot/Behaviours/TwitchyBehaviour.cs (limited to 'OpenSim') diff --git a/OpenSim/Addons/Groups/ForeignImporter.cs b/OpenSim/Addons/Groups/ForeignImporter.cs new file mode 100644 index 0000000..055f76c --- /dev/null +++ b/OpenSim/Addons/Groups/ForeignImporter.cs @@ -0,0 +1,78 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; + +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Groups +{ + public class ForeignImporter + { + IUserManagement m_UserManagement; + public ForeignImporter(IUserManagement uman) + { + m_UserManagement = uman; + } + + public GroupMembersData ConvertGroupMembersData(ExtendedGroupMembersData _m) + { + GroupMembersData m = new GroupMembersData(); + m.AcceptNotices = _m.AcceptNotices; + m.AgentPowers = _m.AgentPowers; + m.Contribution = _m.Contribution; + m.IsOwner = _m.IsOwner; + m.ListInProfile = _m.ListInProfile; + m.OnlineStatus = _m.OnlineStatus; + m.Title = _m.Title; + + string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty; + Util.ParseUniversalUserIdentifier(_m.AgentID, out m.AgentID, out url, out first, out last, out tmp); + if (url != string.Empty) + m_UserManagement.AddUser(m.AgentID, first, last, url); + + return m; + } + + public GroupRoleMembersData ConvertGroupRoleMembersData(ExtendedGroupRoleMembersData _rm) + { + GroupRoleMembersData rm = new GroupRoleMembersData(); + rm.RoleID = _rm.RoleID; + + string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty; + Util.ParseUniversalUserIdentifier(_rm.MemberID, out rm.MemberID, out url, out first, out last, out tmp); + if (url != string.Empty) + m_UserManagement.AddUser(rm.MemberID, first, last, url); + + return rm; + } + + } +} diff --git a/OpenSim/Addons/Groups/GroupsExtendedData.cs b/OpenSim/Addons/Groups/GroupsExtendedData.cs new file mode 100644 index 0000000..c783b9e --- /dev/null +++ b/OpenSim/Addons/Groups/GroupsExtendedData.cs @@ -0,0 +1,533 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; + +using OpenSim.Framework; +using OpenMetaverse; + +namespace OpenSim.Groups +{ + public class ExtendedGroupRecord : GroupRecord + { + public int MemberCount; + public int RoleCount; + public string ServiceLocation; + public string FounderUUI; + } + + public class ExtendedGroupMembershipData : GroupMembershipData + { + public string AccessToken; + } + + public class ExtendedGroupMembersData + { + // This is the only difference: this is a string + public string AgentID; + public int Contribution; + public string OnlineStatus; + public ulong AgentPowers; + public string Title; + public bool IsOwner; + public bool ListInProfile; + public bool AcceptNotices; + public string AccessToken; + } + + public class ExtendedGroupRoleMembersData + { + public UUID RoleID; + // This is the only difference: this is a string + public string MemberID; + + } + + public struct ExtendedGroupNoticeData + { + public UUID NoticeID; + public uint Timestamp; + public string FromName; + public string Subject; + public bool HasAttachment; + public byte AttachmentType; + public string AttachmentName; + public UUID AttachmentItemID; + public string AttachmentOwnerID; + + public GroupNoticeData ToGroupNoticeData() + { + GroupNoticeData n = new GroupNoticeData(); + n.FromName = this.FromName; + n.AssetType = this.AttachmentType; + n.HasAttachment = this.HasAttachment; + n.NoticeID = this.NoticeID; + n.Subject = this.Subject; + n.Timestamp = this.Timestamp; + + return n; + } + } + + public class GroupsDataUtils + { + public static string Sanitize(string s) + { + return s == null ? string.Empty : s; + } + + public static Dictionary GroupRecord(ExtendedGroupRecord grec) + { + Dictionary dict = new Dictionary(); + if (grec == null) + return dict; + + dict["AllowPublish"] = grec.AllowPublish.ToString(); + dict["Charter"] = Sanitize(grec.Charter); + dict["FounderID"] = grec.FounderID.ToString(); + dict["FounderUUI"] = Sanitize(grec.FounderUUI); + dict["GroupID"] = grec.GroupID.ToString(); + dict["GroupName"] = Sanitize(grec.GroupName); + dict["InsigniaID"] = grec.GroupPicture.ToString(); + dict["MaturePublish"] = grec.MaturePublish.ToString(); + dict["MembershipFee"] = grec.MembershipFee.ToString(); + dict["OpenEnrollment"] = grec.OpenEnrollment.ToString(); + dict["OwnerRoleID"] = grec.OwnerRoleID.ToString(); + dict["ServiceLocation"] = Sanitize(grec.ServiceLocation); + dict["ShownInList"] = grec.ShowInList.ToString(); + dict["MemberCount"] = grec.MemberCount.ToString(); + dict["RoleCount"] = grec.RoleCount.ToString(); + + return dict; + } + + public static ExtendedGroupRecord GroupRecord(Dictionary dict) + { + if (dict == null) + return null; + + ExtendedGroupRecord grec = new ExtendedGroupRecord(); + if (dict.ContainsKey("AllowPublish") && dict["AllowPublish"] != null) + grec.AllowPublish = bool.Parse(dict["AllowPublish"].ToString()); + + if (dict.ContainsKey("Charter") && dict["Charter"] != null) + grec.Charter = dict["Charter"].ToString(); + else + grec.Charter = string.Empty; + + if (dict.ContainsKey("FounderID") && dict["FounderID"] != null) + grec.FounderID = UUID.Parse(dict["FounderID"].ToString()); + + if (dict.ContainsKey("FounderUUI") && dict["FounderUUI"] != null) + grec.FounderUUI = dict["FounderUUI"].ToString(); + else + grec.FounderUUI = string.Empty; + + if (dict.ContainsKey("GroupID") && dict["GroupID"] != null) + grec.GroupID = UUID.Parse(dict["GroupID"].ToString()); + + if (dict.ContainsKey("GroupName") && dict["GroupName"] != null) + grec.GroupName = dict["GroupName"].ToString(); + else + grec.GroupName = string.Empty; + + if (dict.ContainsKey("InsigniaID") && dict["InsigniaID"] != null) + grec.GroupPicture = UUID.Parse(dict["InsigniaID"].ToString()); + + if (dict.ContainsKey("MaturePublish") && dict["MaturePublish"] != null) + grec.MaturePublish = bool.Parse(dict["MaturePublish"].ToString()); + + if (dict.ContainsKey("MembershipFee") && dict["MembershipFee"] != null) + grec.MembershipFee = Int32.Parse(dict["MembershipFee"].ToString()); + + if (dict.ContainsKey("OpenEnrollment") && dict["OpenEnrollment"] != null) + grec.OpenEnrollment = bool.Parse(dict["OpenEnrollment"].ToString()); + + if (dict.ContainsKey("OwnerRoleID") && dict["OwnerRoleID"] != null) + grec.OwnerRoleID = UUID.Parse(dict["OwnerRoleID"].ToString()); + + if (dict.ContainsKey("ServiceLocation") && dict["ServiceLocation"] != null) + grec.ServiceLocation = dict["ServiceLocation"].ToString(); + else + grec.ServiceLocation = string.Empty; + + if (dict.ContainsKey("ShownInList") && dict["ShownInList"] != null) + grec.ShowInList = bool.Parse(dict["ShownInList"].ToString()); + + if (dict.ContainsKey("MemberCount") && dict["MemberCount"] != null) + grec.MemberCount = Int32.Parse(dict["MemberCount"].ToString()); + + if (dict.ContainsKey("RoleCount") && dict["RoleCount"] != null) + grec.RoleCount = Int32.Parse(dict["RoleCount"].ToString()); + + return grec; + } + + public static Dictionary GroupMembershipData(ExtendedGroupMembershipData membership) + { + Dictionary dict = new Dictionary(); + if (membership == null) + return dict; + + dict["AcceptNotices"] = membership.AcceptNotices.ToString(); + dict["AccessToken"] = Sanitize(membership.AccessToken); + dict["Active"] = membership.Active.ToString(); + dict["ActiveRole"] = membership.ActiveRole.ToString(); + dict["AllowPublish"] = membership.AllowPublish.ToString(); + dict["Charter"] = Sanitize(membership.Charter); + dict["Contribution"] = membership.Contribution.ToString(); + dict["FounderID"] = membership.FounderID.ToString(); + dict["GroupID"] = membership.GroupID.ToString(); + dict["GroupName"] = Sanitize(membership.GroupName); + dict["GroupPicture"] = membership.GroupPicture.ToString(); + dict["GroupPowers"] = membership.GroupPowers.ToString(); + dict["GroupTitle"] = Sanitize(membership.GroupTitle); + dict["ListInProfile"] = membership.ListInProfile.ToString(); + dict["MaturePublish"] = membership.MaturePublish.ToString(); + dict["MembershipFee"] = membership.MembershipFee.ToString(); + dict["OpenEnrollment"] = membership.OpenEnrollment.ToString(); + dict["ShowInList"] = membership.ShowInList.ToString(); + + return dict; + } + + public static ExtendedGroupMembershipData GroupMembershipData(Dictionary dict) + { + if (dict == null) + return null; + + ExtendedGroupMembershipData membership = new ExtendedGroupMembershipData(); + + if (dict.ContainsKey("AcceptNotices") && dict["AcceptNotices"] != null) + membership.AcceptNotices = bool.Parse(dict["AcceptNotices"].ToString()); + + if (dict.ContainsKey("AccessToken") && dict["AccessToken"] != null) + membership.AccessToken = dict["AccessToken"].ToString(); + else + membership.AccessToken = string.Empty; + + if (dict.ContainsKey("Active") && dict["Active"] != null) + membership.Active = bool.Parse(dict["Active"].ToString()); + + if (dict.ContainsKey("ActiveRole") && dict["ActiveRole"] != null) + membership.ActiveRole = UUID.Parse(dict["ActiveRole"].ToString()); + + if (dict.ContainsKey("AllowPublish") && dict["AllowPublish"] != null) + membership.AllowPublish = bool.Parse(dict["AllowPublish"].ToString()); + + if (dict.ContainsKey("Charter") && dict["Charter"] != null) + membership.Charter = dict["Charter"].ToString(); + else + membership.Charter = string.Empty; + + if (dict.ContainsKey("Contribution") && dict["Contribution"] != null) + membership.Contribution = Int32.Parse(dict["Contribution"].ToString()); + + if (dict.ContainsKey("FounderID") && dict["FounderID"] != null) + membership.FounderID = UUID.Parse(dict["FounderID"].ToString()); + + if (dict.ContainsKey("GroupID") && dict["GroupID"] != null) + membership.GroupID = UUID.Parse(dict["GroupID"].ToString()); + + if (dict.ContainsKey("GroupName") && dict["GroupName"] != null) + membership.GroupName = dict["GroupName"].ToString(); + else + membership.GroupName = string.Empty; + + if (dict.ContainsKey("GroupPicture") && dict["GroupPicture"] != null) + membership.GroupPicture = UUID.Parse(dict["GroupPicture"].ToString()); + + if (dict.ContainsKey("GroupPowers") && dict["GroupPowers"] != null) + membership.GroupPowers = UInt64.Parse(dict["GroupPowers"].ToString()); + + if (dict.ContainsKey("GroupTitle") && dict["GroupTitle"] != null) + membership.GroupTitle = dict["GroupTitle"].ToString(); + else + membership.GroupTitle = string.Empty; + + if (dict.ContainsKey("ListInProfile") && dict["ListInProfile"] != null) + membership.ListInProfile = bool.Parse(dict["ListInProfile"].ToString()); + + if (dict.ContainsKey("MaturePublish") && dict["MaturePublish"] != null) + membership.MaturePublish = bool.Parse(dict["MaturePublish"].ToString()); + + if (dict.ContainsKey("MembershipFee") && dict["MembershipFee"] != null) + membership.MembershipFee = Int32.Parse(dict["MembershipFee"].ToString()); + + if (dict.ContainsKey("OpenEnrollment") && dict["OpenEnrollment"] != null) + membership.OpenEnrollment = bool.Parse(dict["OpenEnrollment"].ToString()); + + if (dict.ContainsKey("ShowInList") && dict["ShowInList"] != null) + membership.ShowInList = bool.Parse(dict["ShowInList"].ToString()); + + return membership; + } + + public static Dictionary GroupMembersData(ExtendedGroupMembersData member) + { + Dictionary dict = new Dictionary(); + + dict["AcceptNotices"] = member.AcceptNotices.ToString(); + dict["AccessToken"] = Sanitize(member.AccessToken); + dict["AgentID"] = Sanitize(member.AgentID); + dict["AgentPowers"] = member.AgentPowers.ToString(); + dict["Contribution"] = member.Contribution.ToString(); + dict["IsOwner"] = member.IsOwner.ToString(); + dict["ListInProfile"] = member.ListInProfile.ToString(); + dict["OnlineStatus"] = Sanitize(member.OnlineStatus); + dict["Title"] = Sanitize(member.Title); + + return dict; + } + + public static ExtendedGroupMembersData GroupMembersData(Dictionary dict) + { + ExtendedGroupMembersData member = new ExtendedGroupMembersData(); + + if (dict == null) + return member; + + if (dict.ContainsKey("AcceptNotices") && dict["AcceptNotices"] != null) + member.AcceptNotices = bool.Parse(dict["AcceptNotices"].ToString()); + + if (dict.ContainsKey("AccessToken") && dict["AccessToken"] != null) + member.AccessToken = Sanitize(dict["AccessToken"].ToString()); + else + member.AccessToken = string.Empty; + + if (dict.ContainsKey("AgentID") && dict["AgentID"] != null) + member.AgentID = Sanitize(dict["AgentID"].ToString()); + else + member.AgentID = UUID.Zero.ToString(); + + if (dict.ContainsKey("AgentPowers") && dict["AgentPowers"] != null) + member.AgentPowers = UInt64.Parse(dict["AgentPowers"].ToString()); + + if (dict.ContainsKey("Contribution") && dict["Contribution"] != null) + member.Contribution = Int32.Parse(dict["Contribution"].ToString()); + + if (dict.ContainsKey("IsOwner") && dict["IsOwner"] != null) + member.IsOwner = bool.Parse(dict["IsOwner"].ToString()); + + if (dict.ContainsKey("ListInProfile") && dict["ListInProfile"] != null) + member.ListInProfile = bool.Parse(dict["ListInProfile"].ToString()); + + if (dict.ContainsKey("OnlineStatus") && dict["OnlineStatus"] != null) + member.OnlineStatus = Sanitize(dict["OnlineStatus"].ToString()); + else + member.OnlineStatus = string.Empty; + + if (dict.ContainsKey("Title") && dict["Title"] != null) + member.Title = Sanitize(dict["Title"].ToString()); + else + member.Title = string.Empty; + + return member; + } + + public static Dictionary GroupRolesData(GroupRolesData role) + { + Dictionary dict = new Dictionary(); + + dict["Description"] = Sanitize(role.Description); + dict["Members"] = role.Members.ToString(); + dict["Name"] = Sanitize(role.Name); + dict["Powers"] = role.Powers.ToString(); + dict["RoleID"] = role.RoleID.ToString(); + dict["Title"] = Sanitize(role.Title); + + return dict; + } + + public static GroupRolesData GroupRolesData(Dictionary dict) + { + GroupRolesData role = new GroupRolesData(); + + if (dict == null) + return role; + + if (dict.ContainsKey("Description") && dict["Description"] != null) + role.Description = Sanitize(dict["Description"].ToString()); + else + role.Description = string.Empty; + + if (dict.ContainsKey("Members") && dict["Members"] != null) + role.Members = Int32.Parse(dict["Members"].ToString()); + + if (dict.ContainsKey("Name") && dict["Name"] != null) + role.Name = Sanitize(dict["Name"].ToString()); + else + role.Name = string.Empty; + + if (dict.ContainsKey("Powers") && dict["Powers"] != null) + role.Powers = UInt64.Parse(dict["Powers"].ToString()); + + if (dict.ContainsKey("Title") && dict["Title"] != null) + role.Title = Sanitize(dict["Title"].ToString()); + else + role.Title = string.Empty; + + if (dict.ContainsKey("RoleID") && dict["RoleID"] != null) + role.RoleID = UUID.Parse(dict["RoleID"].ToString()); + + return role; + } + + public static Dictionary GroupRoleMembersData(ExtendedGroupRoleMembersData rmember) + { + Dictionary dict = new Dictionary(); + + dict["RoleID"] = rmember.RoleID.ToString(); + dict["MemberID"] = rmember.MemberID; + return dict; + } + + public static ExtendedGroupRoleMembersData GroupRoleMembersData(Dictionary dict) + { + ExtendedGroupRoleMembersData rmember = new ExtendedGroupRoleMembersData(); + + if (dict.ContainsKey("RoleID") && dict["RoleID"] != null) + rmember.RoleID = new UUID(dict["RoleID"].ToString()); + + if (dict.ContainsKey("MemberID") && dict["MemberID"] != null) + rmember.MemberID = dict["MemberID"].ToString(); + + return rmember; + } + + public static Dictionary GroupInviteInfo(GroupInviteInfo invite) + { + Dictionary dict = new Dictionary(); + + dict["InviteID"] = invite.InviteID.ToString(); + dict["GroupID"] = invite.GroupID.ToString(); + dict["RoleID"] = invite.RoleID.ToString(); + dict["AgentID"] = invite.AgentID; + + return dict; + } + + public static GroupInviteInfo GroupInviteInfo(Dictionary dict) + { + if (dict == null) + return null; + + GroupInviteInfo invite = new GroupInviteInfo(); + + invite.InviteID = new UUID(dict["InviteID"].ToString()); + invite.GroupID = new UUID(dict["GroupID"].ToString()); + invite.RoleID = new UUID(dict["RoleID"].ToString()); + invite.AgentID = Sanitize(dict["AgentID"].ToString()); + + return invite; + } + + public static Dictionary GroupNoticeData(ExtendedGroupNoticeData notice) + { + Dictionary dict = new Dictionary(); + + dict["NoticeID"] = notice.NoticeID.ToString(); + dict["Timestamp"] = notice.Timestamp.ToString(); + dict["FromName"] = Sanitize(notice.FromName); + dict["Subject"] = Sanitize(notice.Subject); + dict["HasAttachment"] = notice.HasAttachment.ToString(); + dict["AttachmentItemID"] = notice.AttachmentItemID.ToString(); + dict["AttachmentName"] = Sanitize(notice.AttachmentName); + dict["AttachmentType"] = notice.AttachmentType.ToString(); + dict["AttachmentOwnerID"] = Sanitize(notice.AttachmentOwnerID); + + return dict; + } + + public static ExtendedGroupNoticeData GroupNoticeData(Dictionary dict) + { + ExtendedGroupNoticeData notice = new ExtendedGroupNoticeData(); + + if (dict == null) + return notice; + + notice.NoticeID = new UUID(dict["NoticeID"].ToString()); + notice.Timestamp = UInt32.Parse(dict["Timestamp"].ToString()); + notice.FromName = Sanitize(dict["FromName"].ToString()); + notice.Subject = Sanitize(dict["Subject"].ToString()); + notice.HasAttachment = bool.Parse(dict["HasAttachment"].ToString()); + notice.AttachmentItemID = new UUID(dict["AttachmentItemID"].ToString()); + notice.AttachmentName = dict["AttachmentName"].ToString(); + notice.AttachmentType = byte.Parse(dict["AttachmentType"].ToString()); + notice.AttachmentOwnerID = dict["AttachmentOwnerID"].ToString(); + + return notice; + } + + public static Dictionary GroupNoticeInfo(GroupNoticeInfo notice) + { + Dictionary dict = GroupNoticeData(notice.noticeData); + + dict["GroupID"] = notice.GroupID.ToString(); + dict["Message"] = Sanitize(notice.Message); + + return dict; + } + + public static GroupNoticeInfo GroupNoticeInfo(Dictionary dict) + { + GroupNoticeInfo notice = new GroupNoticeInfo(); + + notice.noticeData = GroupNoticeData(dict); + notice.GroupID = new UUID(dict["GroupID"].ToString()); + notice.Message = Sanitize(dict["Message"].ToString()); + + return notice; + } + + public static Dictionary DirGroupsReplyData(DirGroupsReplyData g) + { + Dictionary dict = new Dictionary(); + + dict["GroupID"] = g.groupID; + dict["Name"] = g.groupName; + dict["NMembers"] = g.members; + dict["SearchOrder"] = g.searchOrder; + + return dict; + } + + public static DirGroupsReplyData DirGroupsReplyData(Dictionary dict) + { + DirGroupsReplyData g; + + g.groupID = new UUID(dict["GroupID"].ToString()); + g.groupName = dict["Name"].ToString(); + Int32.TryParse(dict["NMembers"].ToString(), out g.members); + float.TryParse(dict["SearchOrder"].ToString(), out g.searchOrder); + + return g; + } + } + +} diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs new file mode 100644 index 0000000..e95db41 --- /dev/null +++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs @@ -0,0 +1,848 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; + +namespace OpenSim.Groups +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsMessagingModule")] + public class GroupsMessagingModule : ISharedRegionModule, IGroupsMessagingModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private List m_sceneList = new List(); + private IPresenceService m_presenceService; + + private IMessageTransferModule m_msgTransferModule = null; + private IUserManagement m_UserManagement = null; + private IGroupsServicesConnector m_groupData = null; + + // Config Options + private bool m_groupMessagingEnabled; + private bool m_debugEnabled; + + /// + /// If enabled, module only tries to send group IMs to online users by querying cached presence information. + /// + private bool m_messageOnlineAgentsOnly; + + /// + /// Cache for online users. + /// + /// + /// Group ID is key, presence information for online members is value. + /// Will only be non-null if m_messageOnlineAgentsOnly = true + /// We cache here so that group messages don't constantly have to re-request the online user list to avoid + /// attempted expensive sending of messages to offline users. + /// The tradeoff is that a user that comes online will not receive messages consistently from all other users + /// until caches have updated. + /// Therefore, we set the cache expiry to just 20 seconds. + /// + private ExpiringCache m_usersOnlineCache; + + private int m_usersOnlineCacheExpirySeconds = 20; + + private Dictionary> m_groupsAgentsDroppedFromChatSession = new Dictionary>(); + private Dictionary> m_groupsAgentsInvitedToChatSession = new Dictionary>(); + + #region Region Module interfaceBase Members + + public void Initialise(IConfigSource config) + { + IConfig groupsConfig = config.Configs["Groups"]; + + if (groupsConfig == null) + // Do not run this module by default. + return; + + // if groups aren't enabled, we're not needed. + // if we're not specified as the connector to use, then we're not wanted + if ((groupsConfig.GetBoolean("Enabled", false) == false) + || (groupsConfig.GetString("MessagingModule", "") != Name)) + { + m_groupMessagingEnabled = false; + return; + } + + m_groupMessagingEnabled = groupsConfig.GetBoolean("MessagingEnabled", true); + + if (!m_groupMessagingEnabled) + return; + + m_messageOnlineAgentsOnly = groupsConfig.GetBoolean("MessageOnlineUsersOnly", false); + + if (m_messageOnlineAgentsOnly) + { + m_usersOnlineCache = new ExpiringCache(); + } + else + { + m_log.Error("[Groups.Messaging]: GroupsMessagingModule V2 requires MessageOnlineUsersOnly = true"); + m_groupMessagingEnabled = false; + return; + } + + m_debugEnabled = groupsConfig.GetBoolean("MessagingDebugEnabled", m_debugEnabled); + + m_log.InfoFormat( + "[Groups.Messaging]: GroupsMessagingModule enabled with MessageOnlineOnly = {0}, DebugEnabled = {1}", + m_messageOnlineAgentsOnly, m_debugEnabled); + } + + public void AddRegion(Scene scene) + { + if (!m_groupMessagingEnabled) + return; + + scene.RegisterModuleInterface(this); + m_sceneList.Add(scene); + + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; + scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; + scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; + scene.EventManager.OnClientLogin += OnClientLogin; + + scene.AddCommand( + "Debug", + this, + "debug groups messaging verbose", + "debug groups messaging verbose ", + "This setting turns on very verbose groups messaging debugging", + HandleDebugGroupsMessagingVerbose); + } + + public void RegionLoaded(Scene scene) + { + if (!m_groupMessagingEnabled) + return; + + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + m_groupData = scene.RequestModuleInterface(); + + // No groups module, no groups messaging + if (m_groupData == null) + { + m_log.Error("[Groups.Messaging]: Could not get IGroupsServicesConnector, GroupsMessagingModule is now disabled."); + RemoveRegion(scene); + return; + } + + m_msgTransferModule = scene.RequestModuleInterface(); + + // No message transfer module, no groups messaging + if (m_msgTransferModule == null) + { + m_log.Error("[Groups.Messaging]: Could not get MessageTransferModule"); + RemoveRegion(scene); + return; + } + + m_UserManagement = scene.RequestModuleInterface(); + + // No groups module, no groups messaging + if (m_UserManagement == null) + { + m_log.Error("[Groups.Messaging]: Could not get IUserManagement, GroupsMessagingModule is now disabled."); + RemoveRegion(scene); + return; + } + + if (m_presenceService == null) + m_presenceService = scene.PresenceService; + } + + public void RemoveRegion(Scene scene) + { + if (!m_groupMessagingEnabled) + return; + + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + m_sceneList.Remove(scene); + scene.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; + scene.EventManager.OnClientLogin -= OnClientLogin; + scene.UnregisterModuleInterface(this); + } + + public void Close() + { + if (!m_groupMessagingEnabled) + return; + + if (m_debugEnabled) m_log.Debug("[Groups.Messaging]: Shutting down GroupsMessagingModule module."); + + m_sceneList.Clear(); + + m_groupData = null; + m_msgTransferModule = null; + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public string Name + { + get { return "Groups Messaging Module V2"; } + } + + public void PostInitialise() + { + // NoOp + } + + #endregion + + private void HandleDebugGroupsMessagingVerbose(object modules, string[] args) + { + if (args.Length < 5) + { + MainConsole.Instance.Output("Usage: debug groups messaging verbose "); + return; + } + + bool verbose = false; + if (!bool.TryParse(args[4], out verbose)) + { + MainConsole.Instance.Output("Usage: debug groups messaging verbose "); + return; + } + + m_debugEnabled = verbose; + + MainConsole.Instance.OutputFormat("{0} verbose logging set to {1}", Name, m_debugEnabled); + } + + /// + /// Not really needed, but does confirm that the group exists. + /// + public bool StartGroupChatSession(UUID agentID, UUID groupID) + { + if (m_debugEnabled) + m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + GroupRecord groupInfo = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null); + + if (groupInfo != null) + { + return true; + } + else + { + return false; + } + } + + public void SendMessageToGroup(GridInstantMessage im, UUID groupID) + { + SendMessageToGroup(im, groupID, UUID.Zero, null); + } + + public void SendMessageToGroup( + GridInstantMessage im, UUID groupID, UUID sendingAgentForGroupCalls, Func sendCondition) + { + int requestStartTick = Environment.TickCount; + + UUID fromAgentID = new UUID(im.fromAgentID); + + // Unlike current XmlRpcGroups, Groups V2 can accept UUID.Zero when a perms check for the requesting agent + // is not necessary. + List groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), groupID); + + int groupMembersCount = groupMembers.Count; + PresenceInfo[] onlineAgents = null; + + // In V2 we always only send to online members. + // Sending to offline members is not an option. + string[] t1 = groupMembers.ConvertAll(gmd => gmd.AgentID.ToString()).ToArray(); + + // We cache in order not to overwhelm the presence service on large grids with many groups. This does + // mean that members coming online will not see all group members until after m_usersOnlineCacheExpirySeconds has elapsed. + // (assuming this is the same across all grid simulators). + if (!m_usersOnlineCache.TryGetValue(groupID, out onlineAgents)) + { + onlineAgents = m_presenceService.GetAgents(t1); + m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds); + } + + HashSet onlineAgentsUuidSet = new HashSet(); + Array.ForEach(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID)); + + groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList(); + +// if (m_debugEnabled) +// m_log.DebugFormat( +// "[Groups.Messaging]: SendMessageToGroup called for group {0} with {1} visible members, {2} online", +// groupID, groupMembersCount, groupMembers.Count()); + + im.imSessionID = groupID.Guid; + im.fromGroup = true; + IClientAPI thisClient = GetActiveClient(fromAgentID); + if (thisClient != null) + { + im.RegionID = thisClient.Scene.RegionInfo.RegionID.Guid; + } + + if ((im.binaryBucket == null) || (im.binaryBucket.Length == 0) || ((im.binaryBucket.Length == 1 && im.binaryBucket[0] == 0))) + { + ExtendedGroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), groupID, null); + if (groupInfo != null) + im.binaryBucket = Util.StringToBytes256(groupInfo.GroupName); + } + + // Send to self first of all + im.toAgentID = im.fromAgentID; + im.fromGroup = true; + ProcessMessageFromGroupSession(im); + + List regions = new List(); + List clientsAlreadySent = new List(); + + // Then send to everybody else + foreach (GroupMembersData member in groupMembers) + { + if (member.AgentID.Guid == im.fromAgentID) + continue; + + if (clientsAlreadySent.Contains(member.AgentID)) + continue; + + clientsAlreadySent.Add(member.AgentID); + + if (sendCondition != null) + { + if (!sendCondition(member)) + { + if (m_debugEnabled) + m_log.DebugFormat( + "[Groups.Messaging]: Not sending to {0} as they do not fulfill send condition", + member.AgentID); + + continue; + } + } + else if (hasAgentDroppedGroupChatSession(member.AgentID.ToString(), groupID)) + { + // Don't deliver messages to people who have dropped this session + if (m_debugEnabled) + m_log.DebugFormat("[Groups.Messaging]: {0} has dropped session, not delivering to them", member.AgentID); + + continue; + } + + im.toAgentID = member.AgentID.Guid; + + IClientAPI client = GetActiveClient(member.AgentID); + if (client == null) + { + // If they're not local, forward across the grid + // BUT do it only once per region, please! Sim would be even better! + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} via Grid", member.AgentID); + + bool reallySend = true; + if (onlineAgents != null) + { + PresenceInfo presence = onlineAgents.First(p => p.UserID == member.AgentID.ToString()); + if (regions.Contains(presence.RegionID)) + reallySend = false; + else + regions.Add(presence.RegionID); + } + + if (reallySend) + { + // We have to create a new IM structure because the transfer module + // uses async send + GridInstantMessage msg = new GridInstantMessage(im, true); + m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { }); + } + } + else + { + // Deliver locally, directly + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", client.Name); + + ProcessMessageFromGroupSession(im); + } + + } + + if (m_debugEnabled) + m_log.DebugFormat( + "[Groups.Messaging]: SendMessageToGroup for group {0} with {1} visible members, {2} online took {3}ms", + groupID, groupMembersCount, groupMembers.Count(), Environment.TickCount - requestStartTick); + } + + #region SimGridEventHandlers + + void OnClientLogin(IClientAPI client) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name); + } + + private void OnNewClient(IClientAPI client) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name); + + ResetAgentGroupChatSessions(client.AgentId.ToString()); + } + + void OnMakeRootAgent(ScenePresence sp) + { + sp.ControllingClient.OnInstantMessage += OnInstantMessage; + } + + void OnMakeChildAgent(ScenePresence sp) + { + sp.ControllingClient.OnInstantMessage -= OnInstantMessage; + } + + + private void OnGridInstantMessage(GridInstantMessage msg) + { + // The instant message module will only deliver messages of dialog types: + // MessageFromAgent, StartTyping, StopTyping, MessageFromObject + // + // Any other message type will not be delivered to a client by the + // Instant Message Module + + UUID regionID = new UUID(msg.RegionID); + if (m_debugEnabled) + { + m_log.DebugFormat("[Groups.Messaging]: {0} called, IM from region {1}", + System.Reflection.MethodBase.GetCurrentMethod().Name, regionID); + + DebugGridInstantMessage(msg); + } + + // Incoming message from a group + if ((msg.fromGroup == true) && (msg.dialog == (byte)InstantMessageDialog.SessionSend)) + { + // We have to redistribute the message across all members of the group who are here + // on this sim + + UUID GroupID = new UUID(msg.imSessionID); + + Scene aScene = m_sceneList[0]; + GridRegion regionOfOrigin = aScene.GridService.GetRegionByUUID(aScene.RegionInfo.ScopeID, regionID); + + List groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), GroupID); + + //if (m_debugEnabled) + // foreach (GroupMembersData m in groupMembers) + // m_log.DebugFormat("[Groups.Messaging]: member {0}", m.AgentID); + + foreach (Scene s in m_sceneList) + { + s.ForEachScenePresence(sp => + { + // If we got this via grid messaging, it's because the caller thinks + // that the root agent is here. We should only send the IM to root agents. + if (sp.IsChildAgent) + return; + + GroupMembersData m = groupMembers.Find(gmd => + { + return gmd.AgentID == sp.UUID; + }); + if (m.AgentID == UUID.Zero) + { + if (m_debugEnabled) + m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because he is not a member of the group", sp.UUID); + return; + } + + // Check if the user has an agent in the region where + // the IM came from, and if so, skip it, because the IM + // was already sent via that agent + if (regionOfOrigin != null) + { + AgentCircuitData aCircuit = s.AuthenticateHandler.GetAgentCircuitData(sp.UUID); + if (aCircuit != null) + { + if (aCircuit.ChildrenCapSeeds.Keys.Contains(regionOfOrigin.RegionHandle)) + { + if (m_debugEnabled) + m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because he has an agent in region of origin", sp.UUID); + return; + } + else + { + if (m_debugEnabled) + m_log.DebugFormat("[Groups.Messaging]: not skipping agent {0}", sp.UUID); + } + } + } + + UUID AgentID = sp.UUID; + msg.toAgentID = AgentID.Guid; + + if (!hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID)) + { + if (!hasAgentBeenInvitedToGroupChatSession(AgentID.ToString(), GroupID)) + AddAgentToSession(AgentID, GroupID, msg); + else + { + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", sp.Name); + + ProcessMessageFromGroupSession(msg); + } + } + }); + + } + } + } + + private void ProcessMessageFromGroupSession(GridInstantMessage msg) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Session message from {0} going to agent {1}", msg.fromAgentName, msg.toAgentID); + + UUID AgentID = new UUID(msg.fromAgentID); + UUID GroupID = new UUID(msg.imSessionID); + UUID toAgentID = new UUID(msg.toAgentID); + + switch (msg.dialog) + { + case (byte)InstantMessageDialog.SessionAdd: + AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + break; + + case (byte)InstantMessageDialog.SessionDrop: + AgentDroppedFromGroupChatSession(AgentID.ToString(), GroupID); + break; + + case (byte)InstantMessageDialog.SessionSend: + // User hasn't dropped, so they're in the session, + // maybe we should deliver it. + IClientAPI client = GetActiveClient(new UUID(msg.toAgentID)); + if (client != null) + { + // Deliver locally, directly + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} locally", client.Name); + + if (!hasAgentDroppedGroupChatSession(toAgentID.ToString(), GroupID)) + { + if (!hasAgentBeenInvitedToGroupChatSession(toAgentID.ToString(), GroupID)) + // This actually sends the message too, so no need to resend it + // with client.SendInstantMessage + AddAgentToSession(toAgentID, GroupID, msg); + else + client.SendInstantMessage(msg); + } + } + else + { + m_log.WarnFormat("[Groups.Messaging]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID); + } + break; + + default: + m_log.WarnFormat("[Groups.Messaging]: I don't know how to proccess a {0} message.", ((InstantMessageDialog)msg.dialog).ToString()); + break; + } + } + + private void AddAgentToSession(UUID AgentID, UUID GroupID, GridInstantMessage msg) + { + // Agent not in session and hasn't dropped from session + // Add them to the session for now, and Invite them + AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + + IClientAPI activeClient = GetActiveClient(AgentID); + if (activeClient != null) + { + GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null); + if (groupInfo != null) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Sending chatterbox invite instant message"); + + // Force? open the group session dialog??? + // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg); + IEventQueue eq = activeClient.Scene.RequestModuleInterface(); + eq.ChatterboxInvitation( + GroupID + , groupInfo.GroupName + , new UUID(msg.fromAgentID) + , msg.message + , AgentID + , msg.fromAgentName + , msg.dialog + , msg.timestamp + , msg.offline == 1 + , (int)msg.ParentEstateID + , msg.Position + , 1 + , new UUID(msg.imSessionID) + , msg.fromGroup + , OpenMetaverse.Utils.StringToBytes(groupInfo.GroupName) + ); + + eq.ChatterBoxSessionAgentListUpdates( + new UUID(GroupID) + , AgentID + , new UUID(msg.toAgentID) + , false //canVoiceChat + , false //isModerator + , false //text mute + ); + } + } + } + + #endregion + + + #region ClientEvents + private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im) + { + if (m_debugEnabled) + { + m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + DebugGridInstantMessage(im); + } + + // Start group IM session + if ((im.dialog == (byte)InstantMessageDialog.SessionGroupStart)) + { + if (m_debugEnabled) m_log.InfoFormat("[Groups.Messaging]: imSessionID({0}) toAgentID({1})", im.imSessionID, im.toAgentID); + + UUID GroupID = new UUID(im.imSessionID); + UUID AgentID = new UUID(im.fromAgentID); + + GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null); + + if (groupInfo != null) + { + AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + + ChatterBoxSessionStartReplyViaCaps(remoteClient, groupInfo.GroupName, GroupID); + + IEventQueue queue = remoteClient.Scene.RequestModuleInterface(); + queue.ChatterBoxSessionAgentListUpdates( + GroupID + , AgentID + , new UUID(im.toAgentID) + , false //canVoiceChat + , false //isModerator + , false //text mute + ); + } + } + + // Send a message from locally connected client to a group + if ((im.dialog == (byte)InstantMessageDialog.SessionSend)) + { + UUID GroupID = new UUID(im.imSessionID); + UUID AgentID = new UUID(im.fromAgentID); + + if (m_debugEnabled) + m_log.DebugFormat("[Groups.Messaging]: Send message to session for group {0} with session ID {1}", GroupID, im.imSessionID.ToString()); + + //If this agent is sending a message, then they want to be in the session + AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + + SendMessageToGroup(im, GroupID); + } + } + + #endregion + + void ChatterBoxSessionStartReplyViaCaps(IClientAPI remoteClient, string groupName, UUID groupID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + OSDMap moderatedMap = new OSDMap(4); + moderatedMap.Add("voice", OSD.FromBoolean(false)); + + OSDMap sessionMap = new OSDMap(4); + sessionMap.Add("moderated_mode", moderatedMap); + sessionMap.Add("session_name", OSD.FromString(groupName)); + sessionMap.Add("type", OSD.FromInteger(0)); + sessionMap.Add("voice_enabled", OSD.FromBoolean(false)); + + OSDMap bodyMap = new OSDMap(4); + bodyMap.Add("session_id", OSD.FromUUID(groupID)); + bodyMap.Add("temp_session_id", OSD.FromUUID(groupID)); + bodyMap.Add("success", OSD.FromBoolean(true)); + bodyMap.Add("session_info", sessionMap); + + IEventQueue queue = remoteClient.Scene.RequestModuleInterface(); + + if (queue != null) + { + queue.Enqueue(queue.BuildEvent("ChatterBoxSessionStartReply", bodyMap), remoteClient.AgentId); + } + } + + private void DebugGridInstantMessage(GridInstantMessage im) + { + // Don't log any normal IMs (privacy!) + if (m_debugEnabled && im.dialog != (byte)InstantMessageDialog.MessageFromAgent) + { + m_log.WarnFormat("[Groups.Messaging]: IM: fromGroup({0})", im.fromGroup ? "True" : "False"); + m_log.WarnFormat("[Groups.Messaging]: IM: Dialog({0})", ((InstantMessageDialog)im.dialog).ToString()); + m_log.WarnFormat("[Groups.Messaging]: IM: fromAgentID({0})", im.fromAgentID.ToString()); + m_log.WarnFormat("[Groups.Messaging]: IM: fromAgentName({0})", im.fromAgentName.ToString()); + m_log.WarnFormat("[Groups.Messaging]: IM: imSessionID({0})", im.imSessionID.ToString()); + m_log.WarnFormat("[Groups.Messaging]: IM: message({0})", im.message.ToString()); + m_log.WarnFormat("[Groups.Messaging]: IM: offline({0})", im.offline.ToString()); + m_log.WarnFormat("[Groups.Messaging]: IM: toAgentID({0})", im.toAgentID.ToString()); + m_log.WarnFormat("[Groups.Messaging]: IM: binaryBucket({0})", OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, "BinaryBucket")); + } + } + + #region Client Tools + + /// + /// Try to find an active IClientAPI reference for agentID giving preference to root connections + /// + private IClientAPI GetActiveClient(UUID agentID) + { + if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Looking for local client {0}", agentID); + + IClientAPI child = null; + + // Try root avatar first + foreach (Scene scene in m_sceneList) + { + ScenePresence sp = scene.GetScenePresence(agentID); + if (sp != null) + { + if (!sp.IsChildAgent) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Found root agent for client : {0}", sp.ControllingClient.Name); + return sp.ControllingClient; + } + else + { + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Found child agent for client : {0}", sp.ControllingClient.Name); + child = sp.ControllingClient; + } + } + } + + // If we didn't find a root, then just return whichever child we found, or null if none + if (child == null) + { + if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Could not find local client for agent : {0}", agentID); + } + else + { + if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Returning child agent for client : {0}", child.Name); + } + return child; + } + + #endregion + + #region GroupSessionTracking + + public void ResetAgentGroupChatSessions(string agentID) + { + foreach (List agentList in m_groupsAgentsDroppedFromChatSession.Values) + agentList.Remove(agentID); + + foreach (List agentList in m_groupsAgentsInvitedToChatSession.Values) + agentList.Remove(agentID); + } + + public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID) + { + // If we're tracking this group, and we can find them in the tracking, then they've been invited + return m_groupsAgentsInvitedToChatSession.ContainsKey(groupID) + && m_groupsAgentsInvitedToChatSession[groupID].Contains(agentID); + } + + public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID) + { + // If we're tracking drops for this group, + // and we find them, well... then they've dropped + return m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID) + && m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID); + } + + public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID) + { + if (m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID)) + { + // If not in dropped list, add + if (!m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID)) + { + m_groupsAgentsDroppedFromChatSession[groupID].Add(agentID); + } + } + } + + public void AgentInvitedToGroupChatSession(string agentID, UUID groupID) + { + // Add Session Status if it doesn't exist for this session + CreateGroupChatSessionTracking(groupID); + + // If nessesary, remove from dropped list + if (m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID)) + { + m_groupsAgentsDroppedFromChatSession[groupID].Remove(agentID); + } + + // Add to invited + if (!m_groupsAgentsInvitedToChatSession[groupID].Contains(agentID)) + m_groupsAgentsInvitedToChatSession[groupID].Add(agentID); + } + + private void CreateGroupChatSessionTracking(UUID groupID) + { + if (!m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID)) + { + m_groupsAgentsDroppedFromChatSession.Add(groupID, new List()); + m_groupsAgentsInvitedToChatSession.Add(groupID, new List()); + } + + } + #endregion + + } +} diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs new file mode 100644 index 0000000..d121d1a --- /dev/null +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -0,0 +1,1467 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Timers; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags; + +namespace OpenSim.Groups +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsModule")] + public class GroupsModule : ISharedRegionModule, IGroupsModule + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private List m_sceneList = new List(); + + private IMessageTransferModule m_msgTransferModule = null; + + private IGroupsServicesConnector m_groupData = null; + private IUserManagement m_UserManagement; + + // Configuration settings + private bool m_groupsEnabled = false; + private bool m_groupNoticesEnabled = true; + private bool m_debugEnabled = false; + private int m_levelGroupCreate = 0; + + #region Region Module interfaceBase Members + + public void Initialise(IConfigSource config) + { + IConfig groupsConfig = config.Configs["Groups"]; + + if (groupsConfig == null) + { + // Do not run this module by default. + return; + } + else + { + m_groupsEnabled = groupsConfig.GetBoolean("Enabled", false); + if (!m_groupsEnabled) + { + return; + } + + if (groupsConfig.GetString("Module", "Default") != Name) + { + m_groupsEnabled = false; + + return; + } + + m_log.InfoFormat("[Groups]: Initializing {0}", this.Name); + + m_groupNoticesEnabled = groupsConfig.GetBoolean("NoticesEnabled", true); + m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", false); + m_levelGroupCreate = groupsConfig.GetInt("LevelGroupCreate", 0); + } + } + + public void AddRegion(Scene scene) + { + if (m_groupsEnabled) + { + scene.RegisterModuleInterface(this); + scene.AddCommand( + "Debug", + this, + "debug groups verbose", + "debug groups verbose ", + "This setting turns on very verbose groups debugging", + HandleDebugGroupsVerbose); + } + } + + private void HandleDebugGroupsVerbose(object modules, string[] args) + { + if (args.Length < 4) + { + MainConsole.Instance.Output("Usage: debug groups verbose "); + return; + } + + bool verbose = false; + if (!bool.TryParse(args[3], out verbose)) + { + MainConsole.Instance.Output("Usage: debug groups verbose "); + return; + } + + m_debugEnabled = verbose; + + MainConsole.Instance.OutputFormat("{0} verbose logging set to {1}", Name, m_debugEnabled); + } + + public void RegionLoaded(Scene scene) + { + if (!m_groupsEnabled) + return; + + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRoot; + scene.EventManager.OnMakeChildAgent += OnMakeChild; + scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; + // The InstantMessageModule itself doesn't do this, + // so lets see if things explode if we don't do it + // scene.EventManager.OnClientClosed += OnClientClosed; + + if (m_groupData == null) + { + m_groupData = scene.RequestModuleInterface(); + + // No Groups Service Connector, then nothing works... + if (m_groupData == null) + { + m_groupsEnabled = false; + m_log.Error("[Groups]: Could not get IGroupsServicesConnector"); + RemoveRegion(scene); + return; + } + } + + if (m_msgTransferModule == null) + { + m_msgTransferModule = scene.RequestModuleInterface(); + + // No message transfer module, no notices, group invites, rejects, ejects, etc + if (m_msgTransferModule == null) + { + m_log.Warn("[Groups]: Could not get MessageTransferModule"); + } + } + + if (m_UserManagement == null) + { + m_UserManagement = scene.RequestModuleInterface(); + if (m_UserManagement == null) + m_log.Warn("[Groups]: Could not get UserManagementModule"); + } + + lock (m_sceneList) + { + m_sceneList.Add(scene); + } + + + } + + public void RemoveRegion(Scene scene) + { + if (!m_groupsEnabled) + return; + + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + scene.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnMakeRootAgent -= OnMakeRoot; + scene.EventManager.OnMakeChildAgent -= OnMakeChild; + scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; + + lock (m_sceneList) + { + m_sceneList.Remove(scene); + } + } + + public void Close() + { + if (!m_groupsEnabled) + return; + + if (m_debugEnabled) m_log.Debug("[Groups]: Shutting down Groups module."); + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public string Name + { + get { return "Groups Module V2"; } + } + + public void PostInitialise() + { + // NoOp + } + + #endregion + + #region EventHandlers + private void OnNewClient(IClientAPI client) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest; + client.OnRequestAvatarProperties += OnRequestAvatarProperties; + } + + private void OnMakeRoot(ScenePresence sp) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + sp.ControllingClient.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest; + // Used for Notices and Group Invites/Accept/Reject + sp.ControllingClient.OnInstantMessage += OnInstantMessage; + + // Send client their groups information. + SendAgentGroupDataUpdate(sp.ControllingClient, sp.UUID); + } + + private void OnMakeChild(ScenePresence sp) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + sp.ControllingClient.OnUUIDGroupNameRequest -= HandleUUIDGroupNameRequest; + // Used for Notices and Group Invites/Accept/Reject + sp.ControllingClient.OnInstantMessage -= OnInstantMessage; + } + + private void OnRequestAvatarProperties(IClientAPI remoteClient, UUID avatarID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + //GroupMembershipData[] avatarGroups = m_groupData.GetAgentGroupMemberships(GetRequestingAgentID(remoteClient), avatarID).ToArray(); + GroupMembershipData[] avatarGroups = GetProfileListedGroupMemberships(remoteClient, avatarID); + remoteClient.SendAvatarGroupsReply(avatarID, avatarGroups); + } + + /* + * This becomes very problematic in a shared module. In a shared module you may have more then one + * reference to IClientAPI's, one for 0 or 1 root connections, and 0 or more child connections. + * The OnClientClosed event does not provide anything to indicate which one of those should be closed + * nor does it provide what scene it was from so that the specific reference can be looked up. + * The InstantMessageModule.cs does not currently worry about unregistering the handles, + * and it should be an issue, since it's the client that references us not the other way around + * , so as long as we don't keep a reference to the client laying around, the client can still be GC'ed + private void OnClientClosed(UUID AgentId) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + lock (m_ActiveClients) + { + if (m_ActiveClients.ContainsKey(AgentId)) + { + IClientAPI client = m_ActiveClients[AgentId]; + client.OnUUIDGroupNameRequest -= HandleUUIDGroupNameRequest; + client.OnAgentDataUpdateRequest -= OnAgentDataUpdateRequest; + client.OnDirFindQuery -= OnDirFindQuery; + client.OnInstantMessage -= OnInstantMessage; + + m_ActiveClients.Remove(AgentId); + } + else + { + if (m_debugEnabled) m_log.WarnFormat("[Groups]: Client closed that wasn't registered here."); + } + + + } + } + */ + + private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + UUID activeGroupID = UUID.Zero; + string activeGroupTitle = string.Empty; + string activeGroupName = string.Empty; + ulong activeGroupPowers = (ulong)GroupPowers.None; + + GroupMembershipData membership = m_groupData.GetAgentActiveMembership(GetRequestingAgentIDStr(remoteClient), dataForAgentID.ToString()); + if (membership != null) + { + activeGroupID = membership.GroupID; + activeGroupTitle = membership.GroupTitle; + activeGroupPowers = membership.GroupPowers; + } + + SendAgentDataUpdate(remoteClient, dataForAgentID, activeGroupID, activeGroupName, activeGroupPowers, activeGroupTitle); + + SendScenePresenceUpdate(dataForAgentID, activeGroupTitle); + } + + private void HandleUUIDGroupNameRequest(UUID GroupID, IClientAPI remoteClient) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + string GroupName; + + GroupRecord group = m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), GroupID, null); + if (group != null) + { + GroupName = group.GroupName; + } + else + { + GroupName = "Unknown"; + } + + remoteClient.SendGroupNameReply(GroupID, GroupName); + } + + private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + //m_log.DebugFormat("[Groups]: IM From {0} to {1} msg {2} type {3}", im.fromAgentID, im.toAgentID, im.message, (InstantMessageDialog)im.dialog); + // Group invitations + if ((im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) || (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline)) + { + UUID inviteID = new UUID(im.imSessionID); + GroupInviteInfo inviteInfo = m_groupData.GetAgentToGroupInvite(GetRequestingAgentIDStr(remoteClient), inviteID); + + if (inviteInfo == null) + { + if (m_debugEnabled) m_log.WarnFormat("[Groups]: Received an Invite IM for an invite that does not exist {0}.", inviteID); + return; + } + + //m_log.DebugFormat("[XXX]: Invite is for Agent {0} to Group {1}.", inviteInfo.AgentID, inviteInfo.GroupID); + + UUID fromAgentID = new UUID(im.fromAgentID); + UUID invitee = UUID.Zero; + string tmp = string.Empty; + Util.ParseUniversalUserIdentifier(inviteInfo.AgentID, out invitee, out tmp, out tmp, out tmp, out tmp); + if ((inviteInfo != null) && (fromAgentID == invitee)) + { + // Accept + if (im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) + { + //m_log.DebugFormat("[XXX]: Received an accept invite notice."); + + // and the sessionid is the role + string reason = string.Empty; + if (!m_groupData.AddAgentToGroup(GetRequestingAgentIDStr(remoteClient), invitee.ToString(), inviteInfo.GroupID, inviteInfo.RoleID, string.Empty, out reason)) + remoteClient.SendAgentAlertMessage("Unable to add you to the group: " + reason, false); + else + { + GridInstantMessage msg = new GridInstantMessage(); + msg.imSessionID = UUID.Zero.Guid; + msg.fromAgentID = UUID.Zero.Guid; + msg.toAgentID = invitee.Guid; + msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); + msg.fromAgentName = "Groups"; + msg.message = string.Format("You have been added to the group."); + msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.MessageBox; + msg.fromGroup = false; + msg.offline = (byte)0; + msg.ParentEstateID = 0; + msg.Position = Vector3.Zero; + msg.RegionID = UUID.Zero.Guid; + msg.binaryBucket = new byte[0]; + + OutgoingInstantMessage(msg, invitee); + + UpdateAllClientsWithGroupInfo(invitee); + } + + m_groupData.RemoveAgentToGroupInvite(GetRequestingAgentIDStr(remoteClient), inviteID); + + } + + // Reject + if (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: Received a reject invite notice."); + m_groupData.RemoveAgentToGroupInvite(GetRequestingAgentIDStr(remoteClient), inviteID); + + m_groupData.RemoveAgentFromGroup(GetRequestingAgentIDStr(remoteClient), inviteInfo.AgentID, inviteInfo.GroupID); + } + } + } + + // Group notices + if ((im.dialog == (byte)InstantMessageDialog.GroupNotice)) + { + if (!m_groupNoticesEnabled) + { + return; + } + + UUID GroupID = new UUID(im.toAgentID); + if (m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), GroupID, null) != null) + { + UUID NoticeID = UUID.Random(); + string Subject = im.message.Substring(0, im.message.IndexOf('|')); + string Message = im.message.Substring(Subject.Length + 1); + + InventoryItemBase item = null; + bool hasAttachment = false; + + if (im.binaryBucket.Length >= 1 && im.binaryBucket[0] > 0) + { + hasAttachment = true; + string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket); + binBucket = binBucket.Remove(0, 14).Trim(); + + OSD binBucketOSD = OSDParser.DeserializeLLSDXml(binBucket); + if (binBucketOSD is OSDMap) + { + OSDMap binBucketMap = (OSDMap)binBucketOSD; + + UUID itemID = binBucketMap["item_id"].AsUUID(); + UUID ownerID = binBucketMap["owner_id"].AsUUID(); + item = new InventoryItemBase(itemID, ownerID); + item = m_sceneList[0].InventoryService.GetItem(item); + } + else + m_log.DebugFormat("[Groups]: Received OSD with unexpected type: {0}", binBucketOSD.GetType()); + } + + if (m_groupData.AddGroupNotice(GetRequestingAgentIDStr(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message, + hasAttachment, + (byte)(item == null ? 0 : item.AssetType), + item == null ? null : item.Name, + item == null ? UUID.Zero : item.ID, + item == null ? UUID.Zero.ToString() : item.Owner.ToString())) + { + if (OnNewGroupNotice != null) + { + OnNewGroupNotice(GroupID, NoticeID); + } + + + // Send notice out to everyone that wants notices + foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), GroupID)) + { + if (member.AcceptNotices) + { + // Build notice IIM, one of reach, because the sending may be async + GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice); + msg.toAgentID = member.AgentID.Guid; + OutgoingInstantMessage(msg, member.AgentID); + } + } + } + } + } + + if (im.dialog == (byte)InstantMessageDialog.GroupNoticeInventoryAccepted) + { + if (im.binaryBucket.Length < 16) // Invalid + return; + + //// 16 bytes are the UUID. Maybe. +// UUID folderID = new UUID(im.binaryBucket, 0); + UUID noticeID = new UUID(im.imSessionID); + + GroupNoticeInfo notice = m_groupData.GetGroupNotice(remoteClient.AgentId.ToString(), noticeID); + if (notice != null) + { + UUID giver = new UUID(im.toAgentID); + string tmp = string.Empty; + Util.ParseUniversalUserIdentifier(notice.noticeData.AttachmentOwnerID, out giver, out tmp, out tmp, out tmp, out tmp); + + m_log.DebugFormat("[Groups]: Giving inventory from {0} to {1}", giver, remoteClient.AgentId); + string message; + InventoryItemBase itemCopy = ((Scene)(remoteClient.Scene)).GiveInventoryItem(remoteClient.AgentId, + giver, notice.noticeData.AttachmentItemID, out message); + + if (itemCopy == null) + { + remoteClient.SendAgentAlertMessage(message, false); + return; + } + + remoteClient.SendInventoryItemCreateUpdate(itemCopy, 0); + } + + } + + // Interop, received special 210 code for ejecting a group member + // this only works within the comms servers domain, and won't work hypergrid + // TODO:FIXME: Use a presense server of some kind to find out where the + // client actually is, and try contacting that region directly to notify them, + // or provide the notification via xmlrpc update queue + if ((im.dialog == 210)) + { + // This is sent from the region that the ejectee was ejected from + // if it's being delivered here, then the ejectee is here + // so we need to send local updates to the agent. + + UUID ejecteeID = new UUID(im.toAgentID); + + im.dialog = (byte)InstantMessageDialog.MessageFromAgent; + OutgoingInstantMessage(im, ejecteeID); + + IClientAPI ejectee = GetActiveClient(ejecteeID); + if (ejectee != null) + { + UUID groupID = new UUID(im.imSessionID); + ejectee.SendAgentDropGroup(groupID); + } + } + } + + private void OnGridInstantMessage(GridInstantMessage msg) + { + if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + // Trigger the above event handler + OnInstantMessage(null, msg); + + // If a message from a group arrives here, it may need to be forwarded to a local client + if (msg.fromGroup == true) + { + switch (msg.dialog) + { + case (byte)InstantMessageDialog.GroupInvitation: + case (byte)InstantMessageDialog.GroupNotice: + UUID toAgentID = new UUID(msg.toAgentID); + IClientAPI localClient = GetActiveClient(toAgentID); + if (localClient != null) + { + localClient.SendInstantMessage(msg); + } + break; + } + } + } + + #endregion + + #region IGroupsModule Members + + public event NewGroupNotice OnNewGroupNotice; + + public GroupRecord GetGroupRecord(UUID GroupID) + { + return m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null); + } + + public GroupRecord GetGroupRecord(string name) + { + return m_groupData.GetGroupRecord(UUID.Zero.ToString(), UUID.Zero, name); + } + + public void ActivateGroup(IClientAPI remoteClient, UUID groupID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + m_groupData.SetAgentActiveGroup(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID); + + // Changing active group changes title, active powers, all kinds of things + // anyone who is in any region that can see this client, should probably be + // updated with new group info. At a minimum, they should get ScenePresence + // updated with new title. + UpdateAllClientsWithGroupInfo(remoteClient.AgentId); + } + + /// + /// Get the Role Titles for an Agent, for a specific group + /// + public List GroupTitlesRequest(IClientAPI remoteClient, UUID groupID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + List agentRoles = m_groupData.GetAgentGroupRoles(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID); + GroupMembershipData agentMembership = m_groupData.GetAgentGroupMembership(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID); + + List titles = new List(); + foreach (GroupRolesData role in agentRoles) + { + GroupTitlesData title = new GroupTitlesData(); + title.Name = role.Name; + if (agentMembership != null) + { + title.Selected = agentMembership.ActiveRole == role.RoleID; + } + title.UUID = role.RoleID; + + titles.Add(title); + } + + return titles; + } + + public List GroupMembersRequest(IClientAPI remoteClient, UUID groupID) + { + if (m_debugEnabled) + m_log.DebugFormat( + "[Groups]: GroupMembersRequest called for {0} from client {1}", groupID, remoteClient.Name); + + List data = m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), groupID); + + if (m_debugEnabled) + { + foreach (GroupMembersData member in data) + { + m_log.DebugFormat("[Groups]: Member({0}) - IsOwner({1})", member.AgentID, member.IsOwner); + } + } + + return data; + + } + + public List GroupRoleDataRequest(IClientAPI remoteClient, UUID groupID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + List data = m_groupData.GetGroupRoles(GetRequestingAgentIDStr(remoteClient), groupID); + + return data; + } + + public List GroupRoleMembersRequest(IClientAPI remoteClient, UUID groupID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + List data = m_groupData.GetGroupRoleMembers(GetRequestingAgentIDStr(remoteClient), groupID); + + if (m_debugEnabled) + { + foreach (GroupRoleMembersData member in data) + { + m_log.DebugFormat("[Groups]: Member({0}) - Role({1})", member.MemberID, member.RoleID); + } + } + return data; + } + + public GroupProfileData GroupProfileRequest(IClientAPI remoteClient, UUID groupID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + GroupProfileData profile = new GroupProfileData(); + + // just to get the OwnerRole... + ExtendedGroupRecord groupInfo = m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), groupID, string.Empty); + GroupMembershipData memberInfo = m_groupData.GetAgentGroupMembership(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID); + if (groupInfo != null) + { + profile.AllowPublish = groupInfo.AllowPublish; + profile.Charter = groupInfo.Charter; + profile.FounderID = groupInfo.FounderID; + profile.GroupID = groupID; + profile.GroupMembershipCount = groupInfo.MemberCount; + profile.GroupRolesCount = groupInfo.RoleCount; + profile.InsigniaID = groupInfo.GroupPicture; + profile.MaturePublish = groupInfo.MaturePublish; + profile.MembershipFee = groupInfo.MembershipFee; + profile.Money = 0; + profile.Name = groupInfo.GroupName; + profile.OpenEnrollment = groupInfo.OpenEnrollment; + profile.OwnerRole = groupInfo.OwnerRoleID; + profile.ShowInList = groupInfo.ShowInList; + } + if (memberInfo != null) + { + profile.MemberTitle = memberInfo.GroupTitle; + profile.PowersMask = memberInfo.GroupPowers; + } + + return profile; + } + + public GroupMembershipData[] GetMembershipData(UUID agentID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + return m_groupData.GetAgentGroupMemberships(UUID.Zero.ToString(), agentID.ToString()).ToArray(); + } + + public GroupMembershipData GetMembershipData(UUID groupID, UUID agentID) + { + if (m_debugEnabled) + m_log.DebugFormat( + "[Groups]: {0} called with groupID={1}, agentID={2}", + System.Reflection.MethodBase.GetCurrentMethod().Name, groupID, agentID); + + return m_groupData.GetAgentGroupMembership(UUID.Zero.ToString(), agentID.ToString(), groupID); + } + + public void UpdateGroupInfo(IClientAPI remoteClient, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + // Note: Permissions checking for modification rights is handled by the Groups Server/Service + string reason = string.Empty; + if (!m_groupData.UpdateGroup(GetRequestingAgentIDStr(remoteClient), groupID, charter, showInList, insigniaID, membershipFee, + openEnrollment, allowPublish, maturePublish, out reason)) + remoteClient.SendAgentAlertMessage(reason, false); + } + + public void SetGroupAcceptNotices(IClientAPI remoteClient, UUID groupID, bool acceptNotices, bool listInProfile) + { + // Note: Permissions checking for modification rights is handled by the Groups Server/Service + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + m_groupData.UpdateMembership(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID, acceptNotices, listInProfile); + } + + public UUID CreateGroup(IClientAPI remoteClient, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called in {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, remoteClient.Scene.RegionInfo.RegionName); + + if (m_groupData.GetGroupRecord(GetRequestingAgentIDStr(remoteClient), UUID.Zero, name) != null) + { + remoteClient.SendCreateGroupReply(UUID.Zero, false, "A group with the same name already exists."); + return UUID.Zero; + } + + // check user level + ScenePresence avatar = null; + Scene scene = (Scene)remoteClient.Scene; + scene.TryGetScenePresence(remoteClient.AgentId, out avatar); + + if (avatar != null) + { + if (avatar.UserLevel < m_levelGroupCreate) + { + remoteClient.SendCreateGroupReply(UUID.Zero, false, String.Format("Insufficient permissions to create a group. Requires level {0}", m_levelGroupCreate)); + return UUID.Zero; + } + } + + // check funds + // is there is a money module present ? + IMoneyModule money = scene.RequestModuleInterface(); + if (money != null) + { + // do the transaction, that is if the agent has got sufficient funds + if (!money.AmountCovered(remoteClient.AgentId, money.GroupCreationCharge)) { + remoteClient.SendCreateGroupReply(UUID.Zero, false, "Insufficient funds to create a group."); + return UUID.Zero; + } + } + + string reason = string.Empty; + UUID groupID = m_groupData.CreateGroup(remoteClient.AgentId, name, charter, showInList, insigniaID, membershipFee, openEnrollment, + allowPublish, maturePublish, remoteClient.AgentId, out reason); + + if (groupID != UUID.Zero) + { + if (money != null) + money.ApplyCharge(remoteClient.AgentId, money.GroupCreationCharge, MoneyTransactionType.GroupCreate); + + remoteClient.SendCreateGroupReply(groupID, true, "Group created successfullly"); + + // Update the founder with new group information. + SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient)); + } + else + remoteClient.SendCreateGroupReply(groupID, false, reason); + + return groupID; + } + + public GroupNoticeData[] GroupNoticesListRequest(IClientAPI remoteClient, UUID groupID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + // ToDo: check if agent is a member of group and is allowed to see notices? + + List notices = m_groupData.GetGroupNotices(GetRequestingAgentIDStr(remoteClient), groupID); + List os_notices = new List(); + foreach (ExtendedGroupNoticeData n in notices) + { + GroupNoticeData osn = n.ToGroupNoticeData(); + os_notices.Add(osn); + } + + return os_notices.ToArray(); + } + + /// + /// Get the title of the agent's current role. + /// + public string GetGroupTitle(UUID avatarID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + GroupMembershipData membership = m_groupData.GetAgentActiveMembership(UUID.Zero.ToString(), avatarID.ToString()); + if (membership != null) + { + return membership.GroupTitle; + } + return string.Empty; + } + + /// + /// Change the current Active Group Role for Agent + /// + public void GroupTitleUpdate(IClientAPI remoteClient, UUID groupID, UUID titleRoleID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + m_groupData.SetAgentActiveGroupRole(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID, titleRoleID); + + // TODO: Not sure what all is needed here, but if the active group role change is for the group + // the client currently has set active, then we need to do a scene presence update too + // if (m_groupData.GetAgentActiveMembership(GetRequestingAgentID(remoteClient)).GroupID == GroupID) + + UpdateAllClientsWithGroupInfo(GetRequestingAgentID(remoteClient)); + } + + + public void GroupRoleUpdate(IClientAPI remoteClient, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, byte updateType) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + // Security Checks are handled in the Groups Service. + + switch ((OpenMetaverse.GroupRoleUpdate)updateType) + { + case OpenMetaverse.GroupRoleUpdate.Create: + string reason = string.Empty; + if (!m_groupData.AddGroupRole(GetRequestingAgentIDStr(remoteClient), groupID, UUID.Random(), name, description, title, powers, out reason)) + remoteClient.SendAgentAlertMessage("Unable to create role: " + reason, false); + break; + + case OpenMetaverse.GroupRoleUpdate.Delete: + m_groupData.RemoveGroupRole(GetRequestingAgentIDStr(remoteClient), groupID, roleID); + break; + + case OpenMetaverse.GroupRoleUpdate.UpdateAll: + case OpenMetaverse.GroupRoleUpdate.UpdateData: + case OpenMetaverse.GroupRoleUpdate.UpdatePowers: + if (m_debugEnabled) + { + GroupPowers gp = (GroupPowers)powers; + m_log.DebugFormat("[Groups]: Role ({0}) updated with Powers ({1}) ({2})", name, powers.ToString(), gp.ToString()); + } + m_groupData.UpdateGroupRole(GetRequestingAgentIDStr(remoteClient), groupID, roleID, name, description, title, powers); + break; + + case OpenMetaverse.GroupRoleUpdate.NoUpdate: + default: + // No Op + break; + + } + + // TODO: This update really should send out updates for everyone in the role that just got changed. + SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient)); + } + + public void GroupRoleChanges(IClientAPI remoteClient, UUID groupID, UUID roleID, UUID memberID, uint changes) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + // Todo: Security check + + switch (changes) + { + case 0: + // Add + m_groupData.AddAgentToGroupRole(GetRequestingAgentIDStr(remoteClient), memberID.ToString(), groupID, roleID); + + break; + case 1: + // Remove + m_groupData.RemoveAgentFromGroupRole(GetRequestingAgentIDStr(remoteClient), memberID.ToString(), groupID, roleID); + + break; + default: + m_log.ErrorFormat("[Groups]: {0} does not understand changes == {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, changes); + break; + } + + // TODO: This update really should send out updates for everyone in the role that just got changed. + SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient)); + } + + public void GroupNoticeRequest(IClientAPI remoteClient, UUID groupNoticeID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called for notice {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, groupNoticeID); + + GridInstantMessage msg = CreateGroupNoticeIM(remoteClient.AgentId, groupNoticeID, (byte)InstantMessageDialog.GroupNoticeRequested); + + OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient)); + } + + public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + GridInstantMessage msg = new GridInstantMessage(); + byte[] bucket; + + msg.imSessionID = groupNoticeID.Guid; + msg.toAgentID = agentID.Guid; + msg.dialog = dialog; + // msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNotice; + msg.fromGroup = true; + msg.offline = (byte)0; + msg.ParentEstateID = 0; + msg.Position = Vector3.Zero; + msg.RegionID = UUID.Zero.Guid; + + GroupNoticeInfo info = m_groupData.GetGroupNotice(agentID.ToString(), groupNoticeID); + if (info != null) + { + msg.fromAgentID = info.GroupID.Guid; + msg.timestamp = info.noticeData.Timestamp; + msg.fromAgentName = info.noticeData.FromName; + msg.message = info.noticeData.Subject + "|" + info.Message; + if (info.noticeData.HasAttachment) + { + byte[] name = System.Text.Encoding.UTF8.GetBytes(info.noticeData.AttachmentName); + bucket = new byte[19 + name.Length]; + bucket[0] = 1; // has attachment? + bucket[1] = info.noticeData.AttachmentType; // attachment type + name.CopyTo(bucket, 18); + } + else + { + bucket = new byte[19]; + bucket[0] = 0; // Has att? + bucket[1] = 0; // type + bucket[18] = 0; // null terminated + } + + info.GroupID.ToBytes(bucket, 2); + msg.binaryBucket = bucket; + } + else + { + m_log.DebugFormat("[Groups]: Group Notice {0} not found, composing empty message.", groupNoticeID); + msg.fromAgentID = UUID.Zero.Guid; + msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); ; + msg.fromAgentName = string.Empty; + msg.message = string.Empty; + msg.binaryBucket = new byte[0]; + } + + return msg; + } + + public void SendAgentGroupDataUpdate(IClientAPI remoteClient) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + // Send agent information about his groups + SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient)); + } + + public void JoinGroupRequest(IClientAPI remoteClient, UUID groupID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + string reason = string.Empty; + // Should check to see if OpenEnrollment, or if there's an outstanding invitation + if (m_groupData.AddAgentToGroup(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID, UUID.Zero, string.Empty, out reason)) + { + + remoteClient.SendJoinGroupReply(groupID, true); + + // Should this send updates to everyone in the group? + SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient)); + + if (reason != string.Empty) + // A warning + remoteClient.SendAlertMessage("Warning: " + reason); + } + else + remoteClient.SendJoinGroupReply(groupID, false); + } + + public void LeaveGroupRequest(IClientAPI remoteClient, UUID groupID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + m_groupData.RemoveAgentFromGroup(GetRequestingAgentIDStr(remoteClient), GetRequestingAgentIDStr(remoteClient), groupID); + + remoteClient.SendLeaveGroupReply(groupID, true); + + remoteClient.SendAgentDropGroup(groupID); + + // SL sends out notifcations to the group messaging session that the person has left + // Should this also update everyone who is in the group? + SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient)); + } + + public void EjectGroupMemberRequest(IClientAPI remoteClient, UUID groupID, UUID ejecteeID) + { + EjectGroupMember(remoteClient, GetRequestingAgentID(remoteClient), groupID, ejecteeID); + } + + public void EjectGroupMember(IClientAPI remoteClient, UUID agentID, UUID groupID, UUID ejecteeID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + // Todo: Security check? + m_groupData.RemoveAgentFromGroup(agentID.ToString(), ejecteeID.ToString(), groupID); + + string agentName; + RegionInfo regionInfo; + + // remoteClient provided or just agentID? + if (remoteClient != null) + { + agentName = remoteClient.Name; + regionInfo = remoteClient.Scene.RegionInfo; + remoteClient.SendEjectGroupMemberReply(agentID, groupID, true); + } + else + { + IClientAPI client = GetActiveClient(agentID); + + if (client != null) + { + agentName = client.Name; + regionInfo = client.Scene.RegionInfo; + client.SendEjectGroupMemberReply(agentID, groupID, true); + } + else + { + regionInfo = m_sceneList[0].RegionInfo; + UserAccount acc = m_sceneList[0].UserAccountService.GetUserAccount(regionInfo.ScopeID, agentID); + + if (acc != null) + { + agentName = acc.FirstName + " " + acc.LastName; + } + else + { + agentName = "Unknown member"; + } + } + } + + GroupRecord groupInfo = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null); + + UserAccount account = m_sceneList[0].UserAccountService.GetUserAccount(regionInfo.ScopeID, ejecteeID); + if ((groupInfo == null) || (account == null)) + { + return; + } + + // Send Message to Ejectee + GridInstantMessage msg = new GridInstantMessage(); + + msg.imSessionID = UUID.Zero.Guid; + msg.fromAgentID = agentID.Guid; + // msg.fromAgentID = info.GroupID; + msg.toAgentID = ejecteeID.Guid; + //msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); + msg.timestamp = 0; + msg.fromAgentName = agentName; + msg.message = string.Format("You have been ejected from '{1}' by {0}.", agentName, groupInfo.GroupName); + msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.MessageFromAgent; + msg.fromGroup = false; + msg.offline = (byte)0; + msg.ParentEstateID = 0; + msg.Position = Vector3.Zero; + msg.RegionID = regionInfo.RegionID.Guid; + msg.binaryBucket = new byte[0]; + OutgoingInstantMessage(msg, ejecteeID); + + // Message to ejector + // Interop, received special 210 code for ejecting a group member + // this only works within the comms servers domain, and won't work hypergrid + // TODO:FIXME: Use a presense server of some kind to find out where the + // client actually is, and try contacting that region directly to notify them, + // or provide the notification via xmlrpc update queue + + msg = new GridInstantMessage(); + msg.imSessionID = UUID.Zero.Guid; + msg.fromAgentID = agentID.Guid; + msg.toAgentID = agentID.Guid; + msg.timestamp = 0; + msg.fromAgentName = agentName; + if (account != null) + { + msg.message = string.Format("{2} has been ejected from '{1}' by {0}.", agentName, groupInfo.GroupName, account.FirstName + " " + account.LastName); + } + else + { + msg.message = string.Format("{2} has been ejected from '{1}' by {0}.", agentName, groupInfo.GroupName, "Unknown member"); + } + msg.dialog = (byte)210; //interop + msg.fromGroup = false; + msg.offline = (byte)0; + msg.ParentEstateID = 0; + msg.Position = Vector3.Zero; + msg.RegionID = regionInfo.RegionID.Guid; + msg.binaryBucket = new byte[0]; + OutgoingInstantMessage(msg, agentID); + + + // SL sends out messages to everyone in the group + // Who all should receive updates and what should they be updated with? + UpdateAllClientsWithGroupInfo(ejecteeID); + } + + public void InviteGroupRequest(IClientAPI remoteClient, UUID groupID, UUID invitedAgentID, UUID roleID) + { + InviteGroup(remoteClient, GetRequestingAgentID(remoteClient), groupID, invitedAgentID, roleID); + } + + public void InviteGroup(IClientAPI remoteClient, UUID agentID, UUID groupID, UUID invitedAgentID, UUID roleID) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + string agentName = m_UserManagement.GetUserName(agentID); + RegionInfo regionInfo = m_sceneList[0].RegionInfo; + + GroupRecord group = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null); + if (group == null) + { + m_log.DebugFormat("[Groups]: No such group {0}", groupID); + return; + } + + // Todo: Security check, probably also want to send some kind of notification + UUID InviteID = UUID.Random(); + + if (m_groupData.AddAgentToGroupInvite(agentID.ToString(), InviteID, groupID, roleID, invitedAgentID.ToString())) + { + if (m_msgTransferModule != null) + { + Guid inviteUUID = InviteID.Guid; + + GridInstantMessage msg = new GridInstantMessage(); + + msg.imSessionID = inviteUUID; + + // msg.fromAgentID = agentID.Guid; + msg.fromAgentID = groupID.Guid; + msg.toAgentID = invitedAgentID.Guid; + //msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); + msg.timestamp = 0; + msg.fromAgentName = agentName; + 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); + msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupInvitation; + msg.fromGroup = true; + msg.offline = (byte)0; + msg.ParentEstateID = 0; + msg.Position = Vector3.Zero; + msg.RegionID = regionInfo.RegionID.Guid; + msg.binaryBucket = new byte[20]; + + OutgoingInstantMessage(msg, invitedAgentID); + } + } + } + + public List FindGroups(IClientAPI remoteClient, string query) + { + return m_groupData.FindGroups(GetRequestingAgentIDStr(remoteClient), query); + } + + #endregion + + #region Client/Update Tools + + /// + /// Try to find an active IClientAPI reference for agentID giving preference to root connections + /// + private IClientAPI GetActiveClient(UUID agentID) + { + IClientAPI child = null; + + // Try root avatar first + foreach (Scene scene in m_sceneList) + { + ScenePresence sp = scene.GetScenePresence(agentID); + if (sp != null) + { + if (!sp.IsChildAgent) + { + return sp.ControllingClient; + } + else + { + child = sp.ControllingClient; + } + } + } + + // If we didn't find a root, then just return whichever child we found, or null if none + return child; + } + + /// + /// Send 'remoteClient' the group membership 'data' for agent 'dataForAgentID'. + /// + private void SendGroupMembershipInfoViaCaps(IClientAPI remoteClient, UUID dataForAgentID, GroupMembershipData[] data) + { + if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + // NPCs currently don't have a CAPs structure or event queues. There is a strong argument for conveying this information + // to them anyway since it makes writing server-side bots a lot easier, but for now we don't do anything. + if (remoteClient.SceneAgent.PresenceType == PresenceType.Npc) + return; + + OSDArray AgentData = new OSDArray(1); + OSDMap AgentDataMap = new OSDMap(1); + AgentDataMap.Add("AgentID", OSD.FromUUID(dataForAgentID)); + AgentData.Add(AgentDataMap); + + OSDArray GroupData = new OSDArray(data.Length); + OSDArray NewGroupData = new OSDArray(data.Length); + + foreach (GroupMembershipData membership in data) + { + if (GetRequestingAgentID(remoteClient) != dataForAgentID) + { + if (!membership.ListInProfile) + { + // If we're sending group info to remoteclient about another agent, + // filter out groups the other agent doesn't want to share. + continue; + } + } + + OSDMap GroupDataMap = new OSDMap(6); + OSDMap NewGroupDataMap = new OSDMap(1); + + GroupDataMap.Add("GroupID", OSD.FromUUID(membership.GroupID)); + GroupDataMap.Add("GroupPowers", OSD.FromULong(membership.GroupPowers)); + GroupDataMap.Add("AcceptNotices", OSD.FromBoolean(membership.AcceptNotices)); + GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(membership.GroupPicture)); + GroupDataMap.Add("Contribution", OSD.FromInteger(membership.Contribution)); + GroupDataMap.Add("GroupName", OSD.FromString(membership.GroupName)); + NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(membership.ListInProfile)); + + GroupData.Add(GroupDataMap); + NewGroupData.Add(NewGroupDataMap); + } + + OSDMap llDataStruct = new OSDMap(3); + llDataStruct.Add("AgentData", AgentData); + llDataStruct.Add("GroupData", GroupData); + llDataStruct.Add("NewGroupData", NewGroupData); + + if (m_debugEnabled) + { + m_log.InfoFormat("[Groups]: {0}", OSDParser.SerializeJsonString(llDataStruct)); + } + + IEventQueue queue = remoteClient.Scene.RequestModuleInterface(); + + if (queue != null) + { + queue.Enqueue(queue.BuildEvent("AgentGroupDataUpdate", llDataStruct), GetRequestingAgentID(remoteClient)); + } + } + + private void SendScenePresenceUpdate(UUID AgentID, string Title) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: Updating scene title for {0} with title: {1}", AgentID, Title); + + ScenePresence presence = null; + + foreach (Scene scene in m_sceneList) + { + presence = scene.GetScenePresence(AgentID); + if (presence != null) + { + if (presence.Grouptitle != Title) + { + presence.Grouptitle = Title; + + if (! presence.IsChildAgent) + presence.SendAvatarDataToAllClients(); + } + } + } + } + + /// + /// Send updates to all clients who might be interested in groups data for dataForClientID + /// + private void UpdateAllClientsWithGroupInfo(UUID dataForClientID) + { + if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + // TODO: Probably isn't nessesary to update every client in every scene. + // Need to examine client updates and do only what's nessesary. + lock (m_sceneList) + { + foreach (Scene scene in m_sceneList) + { + scene.ForEachClient(delegate(IClientAPI client) { SendAgentGroupDataUpdate(client, dataForClientID); }); + } + } + } + + /// + /// Update remoteClient with group information about dataForAgentID + /// + private void SendAgentGroupDataUpdate(IClientAPI remoteClient, UUID dataForAgentID) + { + if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called for {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, remoteClient.Name); + + // TODO: All the client update functions need to be reexamined because most do too much and send too much stuff + + OnAgentDataUpdateRequest(remoteClient, dataForAgentID, UUID.Zero); + + // Need to send a group membership update to the client + // UDP version doesn't seem to behave nicely. But we're going to send it out here + // with an empty group membership to hopefully remove groups being displayed due + // to the core Groups Stub + //remoteClient.SendGroupMembership(new GroupMembershipData[0]); + + GroupMembershipData[] membershipArray = GetProfileListedGroupMemberships(remoteClient, dataForAgentID); + SendGroupMembershipInfoViaCaps(remoteClient, dataForAgentID, membershipArray); + + //remoteClient.SendAvatarGroupsReply(dataForAgentID, membershipArray); + if (remoteClient.AgentId == dataForAgentID) + remoteClient.RefreshGroupMembership(); + } + + /// + /// Get a list of groups memberships for the agent that are marked "ListInProfile" + /// (unless that agent has a godLike aspect, in which case get all groups) + /// + /// + /// + private GroupMembershipData[] GetProfileListedGroupMemberships(IClientAPI requestingClient, UUID dataForAgentID) + { + List membershipData = m_groupData.GetAgentGroupMemberships(requestingClient.AgentId.ToString(), dataForAgentID.ToString()); + GroupMembershipData[] membershipArray; + + // cScene and property accessor 'isGod' are in support of the opertions to bypass 'hidden' group attributes for + // those with a GodLike aspect. + Scene cScene = (Scene)requestingClient.Scene; + bool isGod = cScene.Permissions.IsGod(requestingClient.AgentId); + + if (isGod) + { + membershipArray = membershipData.ToArray(); + } + else + { + if (requestingClient.AgentId != dataForAgentID) + { + Predicate showInProfile = delegate(GroupMembershipData membership) + { + return membership.ListInProfile; + }; + + membershipArray = membershipData.FindAll(showInProfile).ToArray(); + } + else + { + membershipArray = membershipData.ToArray(); + } + } + + if (m_debugEnabled) + { + m_log.InfoFormat("[Groups]: Get group membership information for {0} requested by {1}", dataForAgentID, requestingClient.AgentId); + foreach (GroupMembershipData membership in membershipArray) + { + m_log.InfoFormat("[Groups]: {0} :: {1} - {2} - {3}", dataForAgentID, membership.GroupName, membership.GroupTitle, membership.GroupPowers); + } + } + + return membershipArray; + } + + + private void SendAgentDataUpdate(IClientAPI remoteClient, UUID dataForAgentID, UUID activeGroupID, string activeGroupName, ulong activeGroupPowers, string activeGroupTitle) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + // TODO: All the client update functions need to be reexamined because most do too much and send too much stuff + string firstname = "Unknown", lastname = "Unknown"; + string name = m_UserManagement.GetUserName(dataForAgentID); + if (!string.IsNullOrEmpty(name)) + { + string[] parts = name.Split(new char[] { ' ' }); + if (parts.Length >= 2) + { + firstname = parts[0]; + lastname = parts[1]; + } + } + + remoteClient.SendAgentDataUpdate(dataForAgentID, activeGroupID, firstname, + lastname, activeGroupPowers, activeGroupName, + activeGroupTitle); + } + + #endregion + + #region IM Backed Processes + + private void OutgoingInstantMessage(GridInstantMessage msg, UUID msgTo) + { + if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + IClientAPI localClient = GetActiveClient(msgTo); + if (localClient != null) + { + if (m_debugEnabled) m_log.InfoFormat("[Groups]: MsgTo ({0}) is local, delivering directly", localClient.Name); + localClient.SendInstantMessage(msg); + } + else if (m_msgTransferModule != null) + { + if (m_debugEnabled) m_log.InfoFormat("[Groups]: MsgTo ({0}) is not local, delivering via TransferModule", msgTo); + m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { if (m_debugEnabled) m_log.DebugFormat("[Groups]: Message Sent: {0}", success?"Succeeded":"Failed"); }); + } + } + + public void NotifyChange(UUID groupID) + { + // Notify all group members of a chnge in group roles and/or + // permissions + // + } + + #endregion + + private string GetRequestingAgentIDStr(IClientAPI client) + { + return GetRequestingAgentID(client).ToString(); + } + + private UUID GetRequestingAgentID(IClientAPI client) + { + UUID requestingAgentID = UUID.Zero; + if (client != null) + { + requestingAgentID = client.AgentId; + } + return requestingAgentID; + } + + } + +} diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnector.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnector.cs new file mode 100644 index 0000000..653dbac --- /dev/null +++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnector.cs @@ -0,0 +1,289 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +using OpenSim.Framework; +using OpenSim.Server.Base; + +using OpenMetaverse; +using log4net; + +namespace OpenSim.Groups +{ + public class GroupsServiceHGConnector + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private string m_ServerURI; + private object m_Lock = new object(); + + public GroupsServiceHGConnector(string url) + { + m_ServerURI = url; + if (!m_ServerURI.EndsWith("/")) + m_ServerURI += "/"; + + m_log.DebugFormat("[Groups.HGConnector]: Groups server at {0}", m_ServerURI); + } + + public bool CreateProxy(string RequestingAgentID, string AgentID, string accessToken, UUID groupID, string url, string name, out string reason) + { + reason = string.Empty; + + Dictionary sendData = new Dictionary(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["AgentID"] = AgentID.ToString(); + sendData["AccessToken"] = accessToken; + sendData["GroupID"] = groupID.ToString(); + sendData["Location"] = url; + sendData["Name"] = name; + Dictionary ret = MakeRequest("POSTGROUP", sendData); + + if (ret == null) + return false; + + if (!ret.ContainsKey("RESULT")) + return false; + + if (ret["RESULT"].ToString().ToLower() != "true") + { + reason = ret["REASON"].ToString(); + return false; + } + + return true; + + } + + public void RemoveAgentFromGroup(string AgentID, UUID GroupID, string token) + { + Dictionary sendData = new Dictionary(); + sendData["AgentID"] = AgentID; + sendData["GroupID"] = GroupID.ToString(); + sendData["AccessToken"] = GroupsDataUtils.Sanitize(token); + MakeRequest("REMOVEAGENTFROMGROUP", sendData); + } + + public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName, string token) + { + if (GroupID == UUID.Zero && (GroupName == null || (GroupName != null && GroupName == string.Empty))) + return null; + + Dictionary sendData = new Dictionary(); + if (GroupID != UUID.Zero) + sendData["GroupID"] = GroupID.ToString(); + if (!string.IsNullOrEmpty(GroupName)) + sendData["Name"] = GroupsDataUtils.Sanitize(GroupName); + + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["AccessToken"] = GroupsDataUtils.Sanitize(token); + + Dictionary ret = MakeRequest("GETGROUP", sendData); + + if (ret == null) + return null; + + if (!ret.ContainsKey("RESULT")) + return null; + + if (ret["RESULT"].ToString() == "NULL") + return null; + + return GroupsDataUtils.GroupRecord((Dictionary)ret["RESULT"]); + } + + public List GetGroupMembers(string RequestingAgentID, UUID GroupID, string token) + { + List members = new List(); + + Dictionary sendData = new Dictionary(); + sendData["GroupID"] = GroupID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["AccessToken"] = GroupsDataUtils.Sanitize(token); + Dictionary ret = MakeRequest("GETGROUPMEMBERS", sendData); + + if (ret == null) + return members; + + if (!ret.ContainsKey("RESULT")) + return members; + + if (ret["RESULT"].ToString() == "NULL") + return members; + foreach (object v in ((Dictionary)ret["RESULT"]).Values) + { + ExtendedGroupMembersData m = GroupsDataUtils.GroupMembersData((Dictionary)v); + members.Add(m); + } + + return members; + } + + public List GetGroupRoles(string RequestingAgentID, UUID GroupID, string token) + { + List roles = new List(); + + Dictionary sendData = new Dictionary(); + sendData["GroupID"] = GroupID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["AccessToken"] = GroupsDataUtils.Sanitize(token); + Dictionary ret = MakeRequest("GETGROUPROLES", sendData); + + if (ret == null) + return roles; + + if (!ret.ContainsKey("RESULT")) + return roles; + + if (ret["RESULT"].ToString() == "NULL") + return roles; + foreach (object v in ((Dictionary)ret["RESULT"]).Values) + { + GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary)v); + roles.Add(m); + } + + return roles; + } + + public List GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, string token) + { + List rmembers = new List(); + + Dictionary sendData = new Dictionary(); + sendData["GroupID"] = GroupID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["AccessToken"] = GroupsDataUtils.Sanitize(token); + Dictionary ret = MakeRequest("GETROLEMEMBERS", sendData); + + if (ret == null) + return rmembers; + + if (!ret.ContainsKey("RESULT")) + return rmembers; + + if (ret["RESULT"].ToString() == "NULL") + return rmembers; + + foreach (object v in ((Dictionary)ret["RESULT"]).Values) + { + ExtendedGroupRoleMembersData m = GroupsDataUtils.GroupRoleMembersData((Dictionary)v); + rmembers.Add(m); + } + + return rmembers; + } + + public bool AddNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, + bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) + { + Dictionary sendData = new Dictionary(); + sendData["GroupID"] = groupID.ToString(); + sendData["NoticeID"] = noticeID.ToString(); + sendData["FromName"] = GroupsDataUtils.Sanitize(fromName); + sendData["Subject"] = GroupsDataUtils.Sanitize(subject); + sendData["Message"] = GroupsDataUtils.Sanitize(message); + sendData["HasAttachment"] = hasAttachment.ToString(); + if (hasAttachment) + { + sendData["AttachmentType"] = attType.ToString(); + sendData["AttachmentName"] = attName.ToString(); + sendData["AttachmentItemID"] = attItemID.ToString(); + sendData["AttachmentOwnerID"] = attOwnerID; + } + sendData["RequestingAgentID"] = RequestingAgentID; + + Dictionary ret = MakeRequest("ADDNOTICE", sendData); + + if (ret == null) + return false; + + if (!ret.ContainsKey("RESULT")) + return false; + + if (ret["RESULT"].ToString().ToLower() != "true") + return false; + + return true; + } + + public bool VerifyNotice(UUID noticeID, UUID groupID) + { + Dictionary sendData = new Dictionary(); + sendData["NoticeID"] = noticeID.ToString(); + sendData["GroupID"] = groupID.ToString(); + Dictionary ret = MakeRequest("VERIFYNOTICE", sendData); + + if (ret == null) + return false; + + if (!ret.ContainsKey("RESULT")) + return false; + + if (ret["RESULT"].ToString().ToLower() != "true") + return false; + + return true; + } + + // + // + // + // + // + + #region Make Request + + private Dictionary MakeRequest(string method, Dictionary sendData) + { + sendData["METHOD"] = method; + + string reply = string.Empty; + lock (m_Lock) + reply = SynchronousRestFormsRequester.MakeRequest("POST", + m_ServerURI + "hg-groups", + ServerUtils.BuildQueryString(sendData)); + + //m_log.DebugFormat("[XXX]: reply was {0}", reply); + + if (string.IsNullOrEmpty(reply)) + return null; + + Dictionary replyData = ServerUtils.ParseXmlResponse( + reply); + + return replyData; + } + #endregion + + } +} diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs new file mode 100644 index 0000000..7d57de1 --- /dev/null +++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs @@ -0,0 +1,707 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +using OpenSim.Framework; +using OpenSim.Framework.Monitoring; +using OpenSim.Framework.Servers; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Services.Interfaces; + +using OpenMetaverse; +using Mono.Addins; +using log4net; +using Nini.Config; + +namespace OpenSim.Groups +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceHGConnectorModule")] + public class GroupsServiceHGConnectorModule : ISharedRegionModule, IGroupsServicesConnector + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private bool m_Enabled = false; + private IGroupsServicesConnector m_LocalGroupsConnector; + private string m_LocalGroupsServiceLocation; + private IUserManagement m_UserManagement; + private IOfflineIMService m_OfflineIM; + private IMessageTransferModule m_Messaging; + private List m_Scenes; + private ForeignImporter m_ForeignImporter; + private string m_ServiceLocation; + private IConfigSource m_Config; + + private Dictionary m_NetworkConnectors = new Dictionary(); + private RemoteConnectorCacheWrapper m_CacheWrapper; // for caching info of external group services + + #region ISharedRegionModule + + public void Initialise(IConfigSource config) + { + IConfig groupsConfig = config.Configs["Groups"]; + if (groupsConfig == null) + return; + + if ((groupsConfig.GetBoolean("Enabled", false) == false) + || (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name)) + { + return; + } + + m_Config = config; + m_ServiceLocation = groupsConfig.GetString("LocalService", "local"); // local or remote + m_LocalGroupsServiceLocation = groupsConfig.GetString("GroupsExternalURI", "http://127.0.0.1"); + m_Scenes = new List(); + + m_Enabled = true; + + m_log.DebugFormat("[Groups]: Initializing {0} with LocalService {1}", this.Name, m_ServiceLocation); + } + + public string Name + { + get { return "Groups HG Service Connector"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName); + scene.RegisterModuleInterface(this); + m_Scenes.Add(scene); + + scene.EventManager.OnNewClient += OnNewClient; + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + + scene.UnregisterModuleInterface(this); + m_Scenes.Remove(scene); + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + + if (m_UserManagement == null) + { + m_UserManagement = scene.RequestModuleInterface(); + m_OfflineIM = scene.RequestModuleInterface(); + m_Messaging = scene.RequestModuleInterface(); + m_ForeignImporter = new ForeignImporter(m_UserManagement); + + if (m_ServiceLocation.Equals("local")) + { + m_LocalGroupsConnector = new GroupsServiceLocalConnectorModule(m_Config, m_UserManagement); + // Also, if local, create the endpoint for the HGGroupsService + new HGGroupsServiceRobustConnector(m_Config, MainServer.Instance, string.Empty, + scene.RequestModuleInterface(), scene.RequestModuleInterface()); + + } + else + m_LocalGroupsConnector = new GroupsServiceRemoteConnectorModule(m_Config, m_UserManagement); + + m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement); + } + + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + #endregion + + private void OnNewClient(IClientAPI client) + { + client.OnCompleteMovementToRegion += OnCompleteMovementToRegion; + } + + void OnCompleteMovementToRegion(IClientAPI client, bool arg2) + { + object sp = null; + if (client.Scene.TryGetScenePresence(client.AgentId, out sp)) + { + if (sp is ScenePresence && ((ScenePresence)sp).PresenceType != PresenceType.Npc) + { + AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId); + if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 && + m_OfflineIM != null && m_Messaging != null) + { + List ims = m_OfflineIM.GetMessages(aCircuit.AgentID); + if (ims != null && ims.Count > 0) + foreach (GridInstantMessage im in ims) + m_Messaging.SendInstantMessage(im, delegate(bool success) { }); + } + } + } + } + + #region IGroupsServicesConnector + + public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, + bool allowPublish, bool maturePublish, UUID founderID, out string reason) + { + reason = string.Empty; + if (m_UserManagement.IsLocalGridUser(RequestingAgentID)) + return m_LocalGroupsConnector.CreateGroup(RequestingAgentID, name, charter, showInList, insigniaID, + membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason); + else + { + reason = "Only local grid users are allowed to create a new group"; + return UUID.Zero; + } + } + + public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, + bool openEnrollment, bool allowPublish, bool maturePublish, out string reason) + { + reason = string.Empty; + string url = string.Empty; + string name = string.Empty; + if (IsLocal(groupID, out url, out name)) + return m_LocalGroupsConnector.UpdateGroup(AgentUUI(RequestingAgentID), groupID, charter, showInList, insigniaID, membershipFee, + openEnrollment, allowPublish, maturePublish, out reason); + else + { + reason = "Changes to remote group not allowed. Please go to the group's original world."; + return false; + } + } + + public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName) + { + string url = string.Empty; + string name = string.Empty; + if (IsLocal(GroupID, out url, out name)) + return m_LocalGroupsConnector.GetGroupRecord(AgentUUI(RequestingAgentID), GroupID, GroupName); + else if (url != string.Empty) + { + ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, GroupID); + string accessToken = string.Empty; + if (membership != null) + accessToken = membership.AccessToken; + else + return null; + + GroupsServiceHGConnector c = GetConnector(url); + if (c != null) + { + ExtendedGroupRecord grec = m_CacheWrapper.GetGroupRecord(RequestingAgentID, GroupID, GroupName, delegate + { + return c.GetGroupRecord(AgentUUIForOutside(RequestingAgentID), GroupID, GroupName, accessToken); + }); + + if (grec != null) + ImportForeigner(grec.FounderUUI); + return grec; + } + } + + return null; + } + + public List FindGroups(string RequestingAgentID, string search) + { + return m_LocalGroupsConnector.FindGroups(AgentUUI(RequestingAgentID), search); + } + + public List GetGroupMembers(string RequestingAgentID, UUID GroupID) + { + string url = string.Empty, gname = string.Empty; + if (IsLocal(GroupID, out url, out gname)) + { + string agentID = AgentUUI(RequestingAgentID); + return m_LocalGroupsConnector.GetGroupMembers(agentID, GroupID); + } + else if (!string.IsNullOrEmpty(url)) + { + ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, GroupID); + string accessToken = string.Empty; + if (membership != null) + accessToken = membership.AccessToken; + else + return null; + + GroupsServiceHGConnector c = GetConnector(url); + if (c != null) + { + return m_CacheWrapper.GetGroupMembers(RequestingAgentID, GroupID, delegate + { + return c.GetGroupMembers(AgentUUIForOutside(RequestingAgentID), GroupID, accessToken); + }); + + } + } + return new List(); + } + + public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason) + { + reason = string.Empty; + string url = string.Empty, gname = string.Empty; + + if (IsLocal(groupID, out url, out gname)) + return m_LocalGroupsConnector.AddGroupRole(AgentUUI(RequestingAgentID), groupID, roleID, name, description, title, powers, out reason); + else + { + reason = "Operation not allowed outside this group's origin world."; + return false; + } + } + + public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers) + { + string url = string.Empty, gname = string.Empty; + + if (IsLocal(groupID, out url, out gname)) + return m_LocalGroupsConnector.UpdateGroupRole(AgentUUI(RequestingAgentID), groupID, roleID, name, description, title, powers); + else + { + return false; + } + + } + + public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID) + { + string url = string.Empty, gname = string.Empty; + + if (IsLocal(groupID, out url, out gname)) + m_LocalGroupsConnector.RemoveGroupRole(AgentUUI(RequestingAgentID), groupID, roleID); + else + { + return; + } + } + + public List GetGroupRoles(string RequestingAgentID, UUID groupID) + { + string url = string.Empty, gname = string.Empty; + + if (IsLocal(groupID, out url, out gname)) + return m_LocalGroupsConnector.GetGroupRoles(AgentUUI(RequestingAgentID), groupID); + else if (!string.IsNullOrEmpty(url)) + { + ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, groupID); + string accessToken = string.Empty; + if (membership != null) + accessToken = membership.AccessToken; + else + return null; + + GroupsServiceHGConnector c = GetConnector(url); + if (c != null) + { + return m_CacheWrapper.GetGroupRoles(RequestingAgentID, groupID, delegate + { + return c.GetGroupRoles(AgentUUIForOutside(RequestingAgentID), groupID, accessToken); + }); + + } + } + + return new List(); + } + + public List GetGroupRoleMembers(string RequestingAgentID, UUID groupID) + { + string url = string.Empty, gname = string.Empty; + + if (IsLocal(groupID, out url, out gname)) + return m_LocalGroupsConnector.GetGroupRoleMembers(AgentUUI(RequestingAgentID), groupID); + else if (!string.IsNullOrEmpty(url)) + { + ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, groupID); + string accessToken = string.Empty; + if (membership != null) + accessToken = membership.AccessToken; + else + return null; + + GroupsServiceHGConnector c = GetConnector(url); + if (c != null) + { + return m_CacheWrapper.GetGroupRoleMembers(RequestingAgentID, groupID, delegate + { + return c.GetGroupRoleMembers(AgentUUIForOutside(RequestingAgentID), groupID, accessToken); + }); + + } + } + + return new List(); + } + + public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason) + { + string url = string.Empty; + string name = string.Empty; + reason = string.Empty; + + UUID uid = new UUID(AgentID); + if (IsLocal(GroupID, out url, out name)) + { + if (m_UserManagement.IsLocalGridUser(uid)) // local user + { + // normal case: local group, local user + return m_LocalGroupsConnector.AddAgentToGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID, token, out reason); + } + else // local group, foreign user + { + // the user is accepting the invitation, or joining, where the group resides + token = UUID.Random().ToString(); + bool success = m_LocalGroupsConnector.AddAgentToGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID, token, out reason); + + if (success) + { + // Here we always return true. The user has been added to the local group, + // independent of whether the remote operation succeeds or not + url = m_UserManagement.GetUserServerURL(uid, "GroupsServerURI"); + if (url == string.Empty) + { + reason = "You don't have an accessible groups server in your home world. You membership to this group in only within this grid."; + return true; + } + + GroupsServiceHGConnector c = GetConnector(url); + if (c != null) + c.CreateProxy(AgentUUI(RequestingAgentID), AgentID, token, GroupID, m_LocalGroupsServiceLocation, name, out reason); + return true; + } + return false; + } + } + else if (m_UserManagement.IsLocalGridUser(uid)) // local user + { + // foreign group, local user. She's been added already by the HG service. + // Let's just check + if (m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID) != null) + return true; + } + + reason = "Operation not allowed outside this group's origin world"; + return false; + } + + + public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) + { + string url = string.Empty, name = string.Empty; + if (!IsLocal(GroupID, out url, out name) && url != string.Empty) + { + ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID); + if (membership != null) + { + GroupsServiceHGConnector c = GetConnector(url); + if (c != null) + c.RemoveAgentFromGroup(AgentUUIForOutside(AgentID), GroupID, membership.AccessToken); + } + } + + // remove from local service + m_LocalGroupsConnector.RemoveAgentFromGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID); + } + + public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID) + { + string url = string.Empty, gname = string.Empty; + + if (IsLocal(groupID, out url, out gname)) + return m_LocalGroupsConnector.AddAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID, groupID, roleID, AgentUUI(agentID)); + else + return false; + } + + public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID) + { + return m_LocalGroupsConnector.GetAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID); ; + } + + public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID) + { + m_LocalGroupsConnector.RemoveAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID); + } + + public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + string url = string.Empty, gname = string.Empty; + + if (IsLocal(GroupID, out url, out gname)) + m_LocalGroupsConnector.AddAgentToGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID); + + } + + public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + string url = string.Empty, gname = string.Empty; + + if (IsLocal(GroupID, out url, out gname)) + m_LocalGroupsConnector.RemoveAgentFromGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID); + } + + public List GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID) + { + string url = string.Empty, gname = string.Empty; + + if (IsLocal(GroupID, out url, out gname)) + return m_LocalGroupsConnector.GetAgentGroupRoles(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID); + else + return new List(); + } + + public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID) + { + string url = string.Empty, gname = string.Empty; + + if (IsLocal(GroupID, out url, out gname)) + m_LocalGroupsConnector.SetAgentActiveGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID); + } + + public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID) + { + return m_LocalGroupsConnector.GetAgentActiveMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID)); + } + + public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + string url = string.Empty, gname = string.Empty; + + if (IsLocal(GroupID, out url, out gname)) + m_LocalGroupsConnector.SetAgentActiveGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID); + } + + public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile) + { + m_LocalGroupsConnector.UpdateMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, AcceptNotices, ListInProfile); + } + + public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID) + { + string url = string.Empty, gname = string.Empty; + + if (IsLocal(GroupID, out url, out gname)) + return m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID); + else + return null; + } + + public List GetAgentGroupMemberships(string RequestingAgentID, string AgentID) + { + return m_LocalGroupsConnector.GetAgentGroupMemberships(AgentUUI(RequestingAgentID), AgentUUI(AgentID)); + } + + public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, + bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) + { + string url = string.Empty, gname = string.Empty; + + if (IsLocal(groupID, out url, out gname)) + { + if (m_LocalGroupsConnector.AddGroupNotice(AgentUUI(RequestingAgentID), groupID, noticeID, fromName, subject, message, + hasAttachment, attType, attName, attItemID, AgentUUI(attOwnerID))) + { + // then send the notice to every grid for which there are members in this group + List members = m_LocalGroupsConnector.GetGroupMembers(AgentUUI(RequestingAgentID), groupID); + List urls = new List(); + foreach (GroupMembersData m in members) + { + if (!m_UserManagement.IsLocalGridUser(m.AgentID)) + { + string gURL = m_UserManagement.GetUserServerURL(m.AgentID, "GroupsServerURI"); + if (!urls.Contains(gURL)) + urls.Add(gURL); + } + } + + // so we have the list of urls to send the notice to + // this may take a long time... + WorkManager.RunInThread(delegate + { + foreach (string u in urls) + { + GroupsServiceHGConnector c = GetConnector(u); + if (c != null) + { + c.AddNotice(AgentUUIForOutside(RequestingAgentID), groupID, noticeID, fromName, subject, message, + hasAttachment, attType, attName, attItemID, AgentUUIForOutside(attOwnerID)); + } + } + }, null, string.Format("AddGroupNotice (agent {0}, group {1})", RequestingAgentID, groupID)); + + return true; + } + + return false; + } + else + return false; + } + + public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID) + { + GroupNoticeInfo notice = m_LocalGroupsConnector.GetGroupNotice(AgentUUI(RequestingAgentID), noticeID); + + if (notice != null && notice.noticeData.HasAttachment && notice.noticeData.AttachmentOwnerID != null) + ImportForeigner(notice.noticeData.AttachmentOwnerID); + + return notice; + } + + public List GetGroupNotices(string RequestingAgentID, UUID GroupID) + { + return m_LocalGroupsConnector.GetGroupNotices(AgentUUI(RequestingAgentID), GroupID); + } + + #endregion + + #region hypergrid groups + + private string AgentUUI(string AgentIDStr) + { + UUID AgentID = UUID.Zero; + try + { + AgentID = new UUID(AgentIDStr); + } + catch (FormatException) + { + return AgentID.ToString(); + } + + if (m_UserManagement.IsLocalGridUser(AgentID)) + return AgentID.ToString(); + + AgentCircuitData agent = null; + foreach (Scene scene in m_Scenes) + { + agent = scene.AuthenticateHandler.GetAgentCircuitData(AgentID); + if (agent != null) + break; + } + if (agent != null) + return Util.ProduceUserUniversalIdentifier(agent); + + // we don't know anything about this foreign user + // try asking the user management module, which may know more + return m_UserManagement.GetUserUUI(AgentID); + + } + + private string AgentUUIForOutside(string AgentIDStr) + { + UUID AgentID = UUID.Zero; + try + { + AgentID = new UUID(AgentIDStr); + } + catch (FormatException) + { + return AgentID.ToString(); + } + + AgentCircuitData agent = null; + foreach (Scene scene in m_Scenes) + { + agent = scene.AuthenticateHandler.GetAgentCircuitData(AgentID); + if (agent != null) + break; + } + if (agent == null) // oops + return AgentID.ToString(); + + return Util.ProduceUserUniversalIdentifier(agent); + } + + private UUID ImportForeigner(string uID) + { + UUID userID = UUID.Zero; + string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty; + if (Util.ParseUniversalUserIdentifier(uID, out userID, out url, out first, out last, out tmp)) + m_UserManagement.AddUser(userID, first, last, url); + + return userID; + } + + private bool IsLocal(UUID groupID, out string serviceLocation, out string name) + { + serviceLocation = string.Empty; + name = string.Empty; + if (groupID.Equals(UUID.Zero)) + return true; + + ExtendedGroupRecord group = m_LocalGroupsConnector.GetGroupRecord(UUID.Zero.ToString(), groupID, string.Empty); + if (group == null) + { + //m_log.DebugFormat("[XXX]: IsLocal? group {0} not found -- no.", groupID); + return false; + } + + serviceLocation = group.ServiceLocation; + name = group.GroupName; + bool isLocal = (group.ServiceLocation == string.Empty); + //m_log.DebugFormat("[XXX]: IsLocal? {0}", isLocal); + return isLocal; + } + + private GroupsServiceHGConnector GetConnector(string url) + { + lock (m_NetworkConnectors) + { + if (m_NetworkConnectors.ContainsKey(url)) + return m_NetworkConnectors[url]; + + GroupsServiceHGConnector c = new GroupsServiceHGConnector(url); + m_NetworkConnectors[url] = c; + } + + return m_NetworkConnectors[url]; + } + #endregion + } +} diff --git a/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs new file mode 100644 index 0000000..f60c1a5 --- /dev/null +++ b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs @@ -0,0 +1,444 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using System.Text; +using System.Xml; +using System.Collections.Generic; +using System.IO; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; +using log4net; +using OpenMetaverse; + +namespace OpenSim.Groups +{ + public class HGGroupsServiceRobustConnector : ServiceConnector + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private HGGroupsService m_GroupsService; + private string m_ConfigName = "Groups"; + + // Called by Robust shell + public HGGroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) : + this(config, server, configName, null, null) + { + } + + // Called by the sim-bound module + public HGGroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName, IOfflineIMService im, IUserAccountService users) : + base(config, server, configName) + { + if (configName != String.Empty) + m_ConfigName = configName; + + m_log.DebugFormat("[Groups.RobustHGConnector]: Starting with config name {0}", m_ConfigName); + + string homeURI = Util.GetConfigVarFromSections(config, "HomeURI", + new string[] { "Startup", "Hypergrid", m_ConfigName}, string.Empty); + if (homeURI == string.Empty) + throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide the HomeURI [Startup] or in section {0}", m_ConfigName)); + + IConfig cnf = config.Configs[m_ConfigName]; + if (cnf == null) + throw new Exception(String.Format("[Groups.RobustHGConnector]: {0} section does not exist", m_ConfigName)); + + if (im == null) + { + string imDll = cnf.GetString("OfflineIMService", string.Empty); + if (imDll == string.Empty) + throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide OfflineIMService in section {0}", m_ConfigName)); + + Object[] args = new Object[] { config }; + im = ServerUtils.LoadPlugin(imDll, args); + } + + if (users == null) + { + string usersDll = cnf.GetString("UserAccountService", string.Empty); + if (usersDll == string.Empty) + throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide UserAccountService in section {0}", m_ConfigName)); + + Object[] args = new Object[] { config }; + users = ServerUtils.LoadPlugin(usersDll, args); + } + + m_GroupsService = new HGGroupsService(config, im, users, homeURI); + + server.AddStreamHandler(new HGGroupsServicePostHandler(m_GroupsService)); + } + + } + + public class HGGroupsServicePostHandler : BaseStreamHandler + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private HGGroupsService m_GroupsService; + + public HGGroupsServicePostHandler(HGGroupsService service) : + base("POST", "/hg-groups") + { + m_GroupsService = service; + } + + protected override byte[] ProcessRequest(string path, Stream requestData, + IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + StreamReader sr = new StreamReader(requestData); + string body = sr.ReadToEnd(); + sr.Close(); + body = body.Trim(); + + //m_log.DebugFormat("[XXX]: query String: {0}", body); + + try + { + Dictionary request = + ServerUtils.ParseQueryString(body); + + if (!request.ContainsKey("METHOD")) + return FailureResult(); + + string method = request["METHOD"].ToString(); + request.Remove("METHOD"); + + m_log.DebugFormat("[Groups.RobustHGConnector]: {0}", method); + switch (method) + { + case "POSTGROUP": + return HandleAddGroupProxy(request); + case "REMOVEAGENTFROMGROUP": + return HandleRemoveAgentFromGroup(request); + case "GETGROUP": + return HandleGetGroup(request); + case "ADDNOTICE": + return HandleAddNotice(request); + case "VERIFYNOTICE": + return HandleVerifyNotice(request); + case "GETGROUPMEMBERS": + return HandleGetGroupMembers(request); + case "GETGROUPROLES": + return HandleGetGroupRoles(request); + case "GETROLEMEMBERS": + return HandleGetRoleMembers(request); + + } + m_log.DebugFormat("[Groups.RobustHGConnector]: unknown method request: {0}", method); + } + catch (Exception e) + { + m_log.Error(string.Format("[Groups.RobustHGConnector]: Exception {0} ", e.Message), e); + } + + return FailureResult(); + } + + byte[] HandleAddGroupProxy(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") + || !request.ContainsKey("AgentID") + || !request.ContainsKey("AccessToken") || !request.ContainsKey("Location")) + NullResult(result, "Bad network data"); + + else + { + string RequestingAgentID = request["RequestingAgentID"].ToString(); + string agentID = request["AgentID"].ToString(); + UUID groupID = new UUID(request["GroupID"].ToString()); + string accessToken = request["AccessToken"].ToString(); + string location = request["Location"].ToString(); + string name = string.Empty; + if (request.ContainsKey("Name")) + name = request["Name"].ToString(); + + string reason = string.Empty; + bool success = m_GroupsService.CreateGroupProxy(RequestingAgentID, agentID, accessToken, groupID, location, name, out reason); + result["REASON"] = reason; + result["RESULT"] = success.ToString(); + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleRemoveAgentFromGroup(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("AccessToken") || !request.ContainsKey("AgentID") || + !request.ContainsKey("GroupID")) + NullResult(result, "Bad network data"); + else + { + UUID groupID = new UUID(request["GroupID"].ToString()); + string agentID = request["AgentID"].ToString(); + string token = request["AccessToken"].ToString(); + + if (!m_GroupsService.RemoveAgentFromGroup(agentID, agentID, groupID, token)) + NullResult(result, "Internal error"); + else + result["RESULT"] = "true"; + } + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); + } + + byte[] HandleGetGroup(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AccessToken")) + NullResult(result, "Bad network data"); + else + { + string RequestingAgentID = request["RequestingAgentID"].ToString(); + string token = request["AccessToken"].ToString(); + + UUID groupID = UUID.Zero; + string groupName = string.Empty; + + if (request.ContainsKey("GroupID")) + groupID = new UUID(request["GroupID"].ToString()); + if (request.ContainsKey("Name")) + groupName = request["Name"].ToString(); + + ExtendedGroupRecord grec = m_GroupsService.GetGroupRecord(RequestingAgentID, groupID, groupName, token); + if (grec == null) + NullResult(result, "Group not found"); + else + result["RESULT"] = GroupsDataUtils.GroupRecord(grec); + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleGetGroupMembers(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken")) + NullResult(result, "Bad network data"); + else + { + UUID groupID = new UUID(request["GroupID"].ToString()); + string requestingAgentID = request["RequestingAgentID"].ToString(); + string token = request["AccessToken"].ToString(); + + List members = m_GroupsService.GetGroupMembers(requestingAgentID, groupID, token); + if (members == null || (members != null && members.Count == 0)) + { + NullResult(result, "No members"); + } + else + { + Dictionary dict = new Dictionary(); + int i = 0; + foreach (ExtendedGroupMembersData m in members) + { + dict["m-" + i++] = GroupsDataUtils.GroupMembersData(m); + } + + result["RESULT"] = dict; + } + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleGetGroupRoles(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken")) + NullResult(result, "Bad network data"); + else + { + UUID groupID = new UUID(request["GroupID"].ToString()); + string requestingAgentID = request["RequestingAgentID"].ToString(); + string token = request["AccessToken"].ToString(); + + List roles = m_GroupsService.GetGroupRoles(requestingAgentID, groupID, token); + if (roles == null || (roles != null && roles.Count == 0)) + { + NullResult(result, "No members"); + } + else + { + Dictionary dict = new Dictionary(); + int i = 0; + foreach (GroupRolesData r in roles) + dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r); + + result["RESULT"] = dict; + } + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleGetRoleMembers(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken")) + NullResult(result, "Bad network data"); + else + { + UUID groupID = new UUID(request["GroupID"].ToString()); + string requestingAgentID = request["RequestingAgentID"].ToString(); + string token = request["AccessToken"].ToString(); + + List rmembers = m_GroupsService.GetGroupRoleMembers(requestingAgentID, groupID, token); + if (rmembers == null || (rmembers != null && rmembers.Count == 0)) + { + NullResult(result, "No members"); + } + else + { + Dictionary dict = new Dictionary(); + int i = 0; + foreach (ExtendedGroupRoleMembersData rm in rmembers) + dict["rm-" + i++] = GroupsDataUtils.GroupRoleMembersData(rm); + + result["RESULT"] = dict; + } + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleAddNotice(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("NoticeID") || + !request.ContainsKey("FromName") || !request.ContainsKey("Subject") || !request.ContainsKey("Message") || + !request.ContainsKey("HasAttachment")) + NullResult(result, "Bad network data"); + + else + { + + bool hasAtt = bool.Parse(request["HasAttachment"].ToString()); + byte attType = 0; + string attName = string.Empty; + string attOwner = string.Empty; + UUID attItem = UUID.Zero; + if (request.ContainsKey("AttachmentType")) + attType = byte.Parse(request["AttachmentType"].ToString()); + if (request.ContainsKey("AttachmentName")) + attName = request["AttachmentType"].ToString(); + if (request.ContainsKey("AttachmentItemID")) + attItem = new UUID(request["AttachmentItemID"].ToString()); + if (request.ContainsKey("AttachmentOwnerID")) + attOwner = request["AttachmentOwnerID"].ToString(); + + bool success = m_GroupsService.AddNotice(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()), + new UUID(request["NoticeID"].ToString()), request["FromName"].ToString(), request["Subject"].ToString(), + request["Message"].ToString(), hasAtt, attType, attName, attItem, attOwner); + + result["RESULT"] = success.ToString(); + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleVerifyNotice(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("NoticeID") || !request.ContainsKey("GroupID")) + NullResult(result, "Bad network data"); + + else + { + UUID noticeID = new UUID(request["NoticeID"].ToString()); + UUID groupID = new UUID(request["GroupID"].ToString()); + + bool success = m_GroupsService.VerifyNotice(noticeID, groupID); + //m_log.DebugFormat("[XXX]: VerifyNotice returned {0}", success); + result["RESULT"] = success.ToString(); + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + // + // + // + // + // + + #region Helpers + + private void NullResult(Dictionary result, string reason) + { + result["RESULT"] = "NULL"; + result["REASON"] = reason; + } + + private byte[] FailureResult() + { + Dictionary result = new Dictionary(); + NullResult(result, "Unknown method"); + string xmlString = ServerUtils.BuildXmlResponse(result); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + #endregion + } +} diff --git a/OpenSim/Addons/Groups/IGroupsServicesConnector.cs b/OpenSim/Addons/Groups/IGroupsServicesConnector.cs new file mode 100644 index 0000000..a09b59e --- /dev/null +++ b/OpenSim/Addons/Groups/IGroupsServicesConnector.cs @@ -0,0 +1,112 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse; +using OpenSim.Framework; + +namespace OpenSim.Groups +{ + public interface IGroupsServicesConnector + { + UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, + bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID, out string reason); + bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, + bool openEnrollment, bool allowPublish, bool maturePublish, out string reason); + ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName); + List FindGroups(string RequestingAgentID, string search); + List GetGroupMembers(string RequestingAgentID, UUID GroupID); + + bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason); + bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers); + void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID); + List GetGroupRoles(string RequestingAgentID, UUID GroupID); + List GetGroupRoleMembers(string RequestingAgentID, UUID GroupID); + + bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason); + void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID); + + bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID); + GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID); + void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID); + + void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID); + void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID); + List GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID); + + void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID); + ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID); + + void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID); + void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile); + + /// + /// Get information about a specific group to which the user belongs. + /// + /// The agent requesting the information. + /// The agent requested. + /// The group requested. + /// + /// If the user is a member of the group then the data structure is returned. If not, then null is returned. + /// + ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID); + + /// + /// Get information about the groups to which a user belongs. + /// + /// The agent requesting the information. + /// The agent requested. + /// + /// Information about the groups to which the user belongs. If the user belongs to no groups then an empty + /// list is returned. + /// + List GetAgentGroupMemberships(string RequestingAgentID, string AgentID); + + bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, + bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID); + GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID); + List GetGroupNotices(string RequestingAgentID, UUID GroupID); + + } + + public class GroupInviteInfo + { + public UUID GroupID = UUID.Zero; + public UUID RoleID = UUID.Zero; + public string AgentID = string.Empty; + public UUID InviteID = UUID.Zero; + } + + public class GroupNoticeInfo + { + public ExtendedGroupNoticeData noticeData = new ExtendedGroupNoticeData(); + public UUID GroupID = UUID.Zero; + public string Message = string.Empty; + } + +} diff --git a/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs b/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs new file mode 100644 index 0000000..8e30df5 --- /dev/null +++ b/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs @@ -0,0 +1,326 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Services.Interfaces; + +using OpenMetaverse; +using Mono.Addins; +using log4net; +using Nini.Config; + +namespace OpenSim.Groups +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceLocalConnectorModule")] + public class GroupsServiceLocalConnectorModule : ISharedRegionModule, IGroupsServicesConnector + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private bool m_Enabled = false; + private GroupsService m_GroupsService; + private IUserManagement m_UserManagement; + private List m_Scenes; + private ForeignImporter m_ForeignImporter; + + #region constructors + public GroupsServiceLocalConnectorModule() + { + } + + public GroupsServiceLocalConnectorModule(IConfigSource config, IUserManagement uman) + { + Init(config); + m_UserManagement = uman; + m_ForeignImporter = new ForeignImporter(uman); + } + #endregion + + private void Init(IConfigSource config) + { + m_GroupsService = new GroupsService(config); + m_Scenes = new List(); + } + + #region ISharedRegionModule + + public void Initialise(IConfigSource config) + { + IConfig groupsConfig = config.Configs["Groups"]; + if (groupsConfig == null) + return; + + if ((groupsConfig.GetBoolean("Enabled", false) == false) + || (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name)) + { + return; + } + + Init(config); + m_Enabled = true; + + m_log.DebugFormat("[Groups]: Initializing {0}", this.Name); + } + + public string Name + { + get { return "Groups Local Service Connector"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName); + scene.RegisterModuleInterface(this); + m_Scenes.Add(scene); + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + + scene.UnregisterModuleInterface(this); + m_Scenes.Remove(scene); + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + + if (m_UserManagement == null) + { + m_UserManagement = scene.RequestModuleInterface(); + m_ForeignImporter = new ForeignImporter(m_UserManagement); + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + #endregion + + #region IGroupsServicesConnector + + public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, + bool allowPublish, bool maturePublish, UUID founderID, out string reason) + { + m_log.DebugFormat("[Groups]: Creating group {0}", name); + reason = string.Empty; + return m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID, + membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason); + } + + public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, + bool openEnrollment, bool allowPublish, bool maturePublish, out string reason) + { + reason = string.Empty; + m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish); + return true; + } + + public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName) + { + if (GroupID != UUID.Zero) + return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID); + else if (GroupName != null) + return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupName); + + return null; + } + + public List FindGroups(string RequestingAgentID, string search) + { + return m_GroupsService.FindGroups(RequestingAgentID, search); + } + + public List GetGroupMembers(string RequestingAgentID, UUID GroupID) + { + List _members = m_GroupsService.GetGroupMembers(RequestingAgentID, GroupID); + if (_members != null && _members.Count > 0) + { + List members = _members.ConvertAll(new Converter(m_ForeignImporter.ConvertGroupMembersData)); + return members; + } + + return new List(); + } + + public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason) + { + return m_GroupsService.AddGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, out reason); + } + + public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers) + { + return m_GroupsService.UpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers); + } + + public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID) + { + m_GroupsService.RemoveGroupRole(RequestingAgentID, groupID, roleID); + } + + public List GetGroupRoles(string RequestingAgentID, UUID GroupID) + { + return m_GroupsService.GetGroupRoles(RequestingAgentID, GroupID); + } + + public List GetGroupRoleMembers(string RequestingAgentID, UUID GroupID) + { + List _rm = m_GroupsService.GetGroupRoleMembers(RequestingAgentID, GroupID); + if (_rm != null && _rm.Count > 0) + { + List rm = _rm.ConvertAll(new Converter(m_ForeignImporter.ConvertGroupRoleMembersData)); + return rm; + } + + return new List(); + + } + + public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason) + { + return m_GroupsService.AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, token, out reason); + } + + public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) + { + m_GroupsService.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID); + } + + public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID) + { + return m_GroupsService.AddAgentToGroupInvite(RequestingAgentID, inviteID, groupID, roleID, agentID); + } + + public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID) + { + return m_GroupsService.GetAgentToGroupInvite(RequestingAgentID, inviteID); ; + } + + public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID) + { + m_GroupsService.RemoveAgentToGroupInvite(RequestingAgentID, inviteID); + } + + public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + m_GroupsService.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); + } + + public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + m_GroupsService.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); + } + + public List GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID) + { + return m_GroupsService.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID); + } + + public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID) + { + m_GroupsService.SetAgentActiveGroup(RequestingAgentID, AgentID, GroupID); + } + + public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID) + { + return m_GroupsService.GetAgentActiveMembership(RequestingAgentID, AgentID); + } + + public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + m_GroupsService.SetAgentActiveGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); + } + + public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile) + { + m_GroupsService.UpdateMembership(RequestingAgentID, AgentID, GroupID, AcceptNotices, ListInProfile); + } + + public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID) + { + return m_GroupsService.GetAgentGroupMembership(RequestingAgentID, AgentID, GroupID); ; + } + + public List GetAgentGroupMemberships(string RequestingAgentID, string AgentID) + { + return m_GroupsService.GetAgentGroupMemberships(RequestingAgentID, AgentID); + } + + public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, + bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) + { + return m_GroupsService.AddGroupNotice(RequestingAgentID, groupID, noticeID, fromName, subject, message, + hasAttachment, attType, attName, attItemID, attOwnerID); + } + + public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID) + { + GroupNoticeInfo notice = m_GroupsService.GetGroupNotice(RequestingAgentID, noticeID); + + //if (notice != null && notice.noticeData.HasAttachment && notice.noticeData.AttachmentOwnerID != null) + //{ + // UUID userID = UUID.Zero; + // string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty; + // Util.ParseUniversalUserIdentifier(notice.noticeData.AttachmentOwnerID, out userID, out url, out first, out last, out tmp); + // if (url != string.Empty) + // m_UserManagement.AddUser(userID, first, last, url); + //} + + return notice; + } + + public List GetGroupNotices(string RequestingAgentID, UUID GroupID) + { + return m_GroupsService.GetGroupNotices(RequestingAgentID, GroupID); + } + + #endregion + } +} diff --git a/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs b/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..cf0de1d --- /dev/null +++ b/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Mono.Addins; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.Addons.Groups")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("http://opensimulator.org")] +[assembly: AssemblyProduct("OpenSim.Addons.Groups")] +[assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("313d4865-d179-4735-9b5a-fe74885878b2")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("0.8.3.*")] + +[assembly: Addin("OpenSim.Groups", OpenSim.VersionInfo.VersionNumber)] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs new file mode 100644 index 0000000..7450c14 --- /dev/null +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs @@ -0,0 +1,696 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; +using OpenSim.Server.Base; + +using OpenMetaverse; +using log4net; +using Nini.Config; + +namespace OpenSim.Groups +{ + public class GroupsServiceRemoteConnector + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private string m_ServerURI; + private IServiceAuth m_Auth; + private object m_Lock = new object(); + + public GroupsServiceRemoteConnector(IConfigSource config) + { + IConfig groupsConfig = config.Configs["Groups"]; + string url = groupsConfig.GetString("GroupsServerURI", string.Empty); + if (!Uri.IsWellFormedUriString(url, UriKind.Absolute)) + throw new Exception(string.Format("[Groups.RemoteConnector]: Malformed groups server URL {0}. Fix it or disable the Groups feature.", url)); + + m_ServerURI = url; + if (!m_ServerURI.EndsWith("/")) + m_ServerURI += "/"; + + /// This is from BaseServiceConnector + string authType = Util.GetConfigVarFromSections(config, "AuthType", new string[] { "Network", "Groups" }, "None"); + + switch (authType) + { + case "BasicHttpAuthentication": + m_Auth = new BasicHttpAuthentication(config, "Groups"); + break; + } + /// + + m_log.DebugFormat("[Groups.RemoteConnector]: Groups server at {0}, authentication {1}", + m_ServerURI, (m_Auth == null ? "None" : m_Auth.GetType().ToString())); + } + + public ExtendedGroupRecord CreateGroup(string RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, + bool allowPublish, bool maturePublish, UUID founderID, out string reason) + { + reason = string.Empty; + + ExtendedGroupRecord rec = new ExtendedGroupRecord(); + rec.AllowPublish = allowPublish; + rec.Charter = charter; + rec.FounderID = founderID; + rec.GroupName = name; + rec.GroupPicture = insigniaID; + rec.MaturePublish = maturePublish; + rec.MembershipFee = membershipFee; + rec.OpenEnrollment = openEnrollment; + rec.ShowInList = showInList; + + Dictionary sendData = GroupsDataUtils.GroupRecord(rec); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["OP"] = "ADD"; + Dictionary ret = MakeRequest("PUTGROUP", sendData); + + if (ret == null) + return null; + + if (ret["RESULT"].ToString() == "NULL") + { + reason = ret["REASON"].ToString(); + return null; + } + + return GroupsDataUtils.GroupRecord((Dictionary)ret["RESULT"]); + + } + + public ExtendedGroupRecord UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish) + { + ExtendedGroupRecord rec = new ExtendedGroupRecord(); + rec.AllowPublish = allowPublish; + rec.Charter = charter; + rec.GroupPicture = insigniaID; + rec.MaturePublish = maturePublish; + rec.GroupID = groupID; + rec.MembershipFee = membershipFee; + rec.OpenEnrollment = openEnrollment; + rec.ShowInList = showInList; + + Dictionary sendData = GroupsDataUtils.GroupRecord(rec); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["OP"] = "UPDATE"; + Dictionary ret = MakeRequest("PUTGROUP", sendData); + + if (ret == null || (ret != null && (!ret.ContainsKey("RESULT") || ret["RESULT"].ToString() == "NULL"))) + return null; + + return GroupsDataUtils.GroupRecord((Dictionary)ret["RESULT"]); + } + + public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName) + { + if (GroupID == UUID.Zero && (GroupName == null || (GroupName != null && GroupName == string.Empty))) + return null; + + Dictionary sendData = new Dictionary(); + if (GroupID != UUID.Zero) + sendData["GroupID"] = GroupID.ToString(); + if (!string.IsNullOrEmpty(GroupName)) + sendData["Name"] = GroupsDataUtils.Sanitize(GroupName); + + sendData["RequestingAgentID"] = RequestingAgentID; + + Dictionary ret = MakeRequest("GETGROUP", sendData); + + if (ret == null || (ret != null && (!ret.ContainsKey("RESULT") || ret["RESULT"].ToString() == "NULL"))) + return null; + + return GroupsDataUtils.GroupRecord((Dictionary)ret["RESULT"]); + } + + public List FindGroups(string RequestingAgentID, string query) + { + List hits = new List(); + if (string.IsNullOrEmpty(query)) + return hits; + + Dictionary sendData = new Dictionary(); + sendData["Query"] = query; + sendData["RequestingAgentID"] = RequestingAgentID; + + Dictionary ret = MakeRequest("FINDGROUPS", sendData); + + if (ret == null) + return hits; + + if (!ret.ContainsKey("RESULT")) + return hits; + + if (ret["RESULT"].ToString() == "NULL") + return hits; + + foreach (object v in ((Dictionary)ret["RESULT"]).Values) + { + DirGroupsReplyData m = GroupsDataUtils.DirGroupsReplyData((Dictionary)v); + hits.Add(m); + } + + return hits; + } + + public GroupMembershipData AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason) + { + reason = string.Empty; + + Dictionary sendData = new Dictionary(); + sendData["AgentID"] = AgentID; + sendData["GroupID"] = GroupID.ToString(); + sendData["RoleID"] = RoleID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["AccessToken"] = token; + Dictionary ret = MakeRequest("ADDAGENTTOGROUP", sendData); + + if (ret == null) + return null; + + if (!ret.ContainsKey("RESULT")) + return null; + + if (ret["RESULT"].ToString() == "NULL") + { + reason = ret["REASON"].ToString(); + return null; + } + + return GroupsDataUtils.GroupMembershipData((Dictionary)ret["RESULT"]); + + } + + public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) + { + Dictionary sendData = new Dictionary(); + sendData["AgentID"] = AgentID; + sendData["GroupID"] = GroupID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + MakeRequest("REMOVEAGENTFROMGROUP", sendData); + } + + public ExtendedGroupMembershipData GetMembership(string RequestingAgentID, string AgentID, UUID GroupID) + { + Dictionary sendData = new Dictionary(); + sendData["AgentID"] = AgentID; + if (GroupID != UUID.Zero) + sendData["GroupID"] = GroupID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + Dictionary ret = MakeRequest("GETMEMBERSHIP", sendData); + + if (ret == null) + return null; + + if (!ret.ContainsKey("RESULT")) + return null; + + if (ret["RESULT"].ToString() == "NULL") + return null; + + return GroupsDataUtils.GroupMembershipData((Dictionary)ret["RESULT"]); + } + + public List GetMemberships(string RequestingAgentID, string AgentID) + { + List memberships = new List(); + + Dictionary sendData = new Dictionary(); + sendData["AgentID"] = AgentID; + sendData["ALL"] = "true"; + sendData["RequestingAgentID"] = RequestingAgentID; + Dictionary ret = MakeRequest("GETMEMBERSHIP", sendData); + + if (ret == null) + return memberships; + + if (!ret.ContainsKey("RESULT")) + return memberships; + + if (ret["RESULT"].ToString() == "NULL") + return memberships; + + foreach (object v in ((Dictionary)ret["RESULT"]).Values) + { + GroupMembershipData m = GroupsDataUtils.GroupMembershipData((Dictionary)v); + memberships.Add(m); + } + + return memberships; + } + + public List GetGroupMembers(string RequestingAgentID, UUID GroupID) + { + List members = new List(); + + Dictionary sendData = new Dictionary(); + sendData["GroupID"] = GroupID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + + Dictionary ret = MakeRequest("GETGROUPMEMBERS", sendData); + + if (ret == null) + return members; + + if (!ret.ContainsKey("RESULT")) + return members; + + if (ret["RESULT"].ToString() == "NULL") + return members; + + foreach (object v in ((Dictionary)ret["RESULT"]).Values) + { + ExtendedGroupMembersData m = GroupsDataUtils.GroupMembersData((Dictionary)v); + members.Add(m); + } + + return members; + } + + public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason) + { + reason = string.Empty; + + Dictionary sendData = new Dictionary(); + sendData["GroupID"] = groupID.ToString(); + sendData["RoleID"] = roleID.ToString(); + sendData["Name"] = GroupsDataUtils.Sanitize(name); + sendData["Description"] = GroupsDataUtils.Sanitize(description); + sendData["Title"] = GroupsDataUtils.Sanitize(title); + sendData["Powers"] = powers.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["OP"] = "ADD"; + Dictionary ret = MakeRequest("PUTROLE", sendData); + + if (ret == null) + return false; + + if (!ret.ContainsKey("RESULT")) + return false; + + if (ret["RESULT"].ToString().ToLower() != "true") + { + reason = ret["REASON"].ToString(); + return false; + } + + return true; + } + + public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers) + { + Dictionary sendData = new Dictionary(); + sendData["GroupID"] = groupID.ToString(); + sendData["RoleID"] = roleID.ToString(); + sendData["Name"] = GroupsDataUtils.Sanitize(name); + sendData["Description"] = GroupsDataUtils.Sanitize(description); + sendData["Title"] = GroupsDataUtils.Sanitize(title); + sendData["Powers"] = powers.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["OP"] = "UPDATE"; + Dictionary ret = MakeRequest("PUTROLE", sendData); + + if (ret == null) + return false; + + if (!ret.ContainsKey("RESULT")) + return false; + + if (ret["RESULT"].ToString().ToLower() != "true") + return false; + + return true; + } + + public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID) + { + Dictionary sendData = new Dictionary(); + sendData["GroupID"] = groupID.ToString(); + sendData["RoleID"] = roleID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + MakeRequest("REMOVEROLE", sendData); + } + + public List GetGroupRoles(string RequestingAgentID, UUID GroupID) + { + List roles = new List(); + + Dictionary sendData = new Dictionary(); + sendData["GroupID"] = GroupID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + Dictionary ret = MakeRequest("GETGROUPROLES", sendData); + + if (ret == null) + return roles; + + if (!ret.ContainsKey("RESULT")) + return roles; + + if (ret["RESULT"].ToString() == "NULL") + return roles; + + foreach (object v in ((Dictionary)ret["RESULT"]).Values) + { + GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary)v); + roles.Add(m); + } + + return roles; + } + + public List GetGroupRoleMembers(string RequestingAgentID, UUID GroupID) + { + List rmembers = new List(); + + Dictionary sendData = new Dictionary(); + sendData["GroupID"] = GroupID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + Dictionary ret = MakeRequest("GETROLEMEMBERS", sendData); + + if (ret == null) + return rmembers; + + if (!ret.ContainsKey("RESULT")) + return rmembers; + + if (ret["RESULT"].ToString() == "NULL") + return rmembers; + + foreach (object v in ((Dictionary)ret["RESULT"]).Values) + { + ExtendedGroupRoleMembersData m = GroupsDataUtils.GroupRoleMembersData((Dictionary)v); + rmembers.Add(m); + } + + return rmembers; + } + + public bool AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + Dictionary sendData = new Dictionary(); + sendData["AgentID"] = AgentID.ToString(); + sendData["GroupID"] = GroupID.ToString(); + sendData["RoleID"] = RoleID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["OP"] = "ADD"; + + Dictionary ret = MakeRequest("AGENTROLE", sendData); + + if (ret == null) + return false; + + if (!ret.ContainsKey("RESULT")) + return false; + + if (ret["RESULT"].ToString().ToLower() != "true") + return false; + + return true; + } + + public bool RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + Dictionary sendData = new Dictionary(); + sendData["AgentID"] = AgentID.ToString(); + sendData["GroupID"] = GroupID.ToString(); + sendData["RoleID"] = RoleID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["OP"] = "DELETE"; + + Dictionary ret = MakeRequest("AGENTROLE", sendData); + + if (ret == null) + return false; + + if (!ret.ContainsKey("RESULT")) + return false; + + if (ret["RESULT"].ToString().ToLower() != "true") + return false; + + return true; + } + + public List GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID) + { + List roles = new List(); + + Dictionary sendData = new Dictionary(); + sendData["AgentID"] = AgentID.ToString(); + sendData["GroupID"] = GroupID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + Dictionary ret = MakeRequest("GETAGENTROLES", sendData); + + if (ret == null) + return roles; + + if (!ret.ContainsKey("RESULT")) + return roles; + + if (ret["RESULT"].ToString() == "NULL") + return roles; + + foreach (object v in ((Dictionary)ret["RESULT"]).Values) + { + GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary)v); + roles.Add(m); + } + + return roles; + } + + public GroupMembershipData SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID) + { + Dictionary sendData = new Dictionary(); + sendData["AgentID"] = AgentID.ToString(); + sendData["GroupID"] = GroupID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["OP"] = "GROUP"; + + Dictionary ret = MakeRequest("SETACTIVE", sendData); + + if (ret == null) + return null; + + if (!ret.ContainsKey("RESULT")) + return null; + + if (ret["RESULT"].ToString() == "NULL") + return null; + + return GroupsDataUtils.GroupMembershipData((Dictionary)ret["RESULT"]); + } + + public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + Dictionary sendData = new Dictionary(); + sendData["AgentID"] = AgentID.ToString(); + sendData["GroupID"] = GroupID.ToString(); + sendData["RoleID"] = RoleID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["OP"] = "ROLE"; + + MakeRequest("SETACTIVE", sendData); + } + + public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile) + { + Dictionary sendData = new Dictionary(); + sendData["AgentID"] = AgentID.ToString(); + sendData["GroupID"] = GroupID.ToString(); + sendData["AcceptNotices"] = AcceptNotices.ToString(); + sendData["ListInProfile"] = ListInProfile.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + MakeRequest("UPDATEMEMBERSHIP", sendData); + } + + public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID) + { + Dictionary sendData = new Dictionary(); + sendData["InviteID"] = inviteID.ToString(); + sendData["GroupID"] = groupID.ToString(); + sendData["RoleID"] = roleID.ToString(); + sendData["AgentID"] = agentID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["OP"] = "ADD"; + + Dictionary ret = MakeRequest("INVITE", sendData); + + if (ret == null) + return false; + + if (!ret.ContainsKey("RESULT")) + return false; + + if (ret["RESULT"].ToString().ToLower() != "true") // it may return "NULL" + return false; + + return true; + } + + public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID) + { + Dictionary sendData = new Dictionary(); + sendData["InviteID"] = inviteID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["OP"] = "GET"; + + Dictionary ret = MakeRequest("INVITE", sendData); + + if (ret == null) + return null; + + if (!ret.ContainsKey("RESULT")) + return null; + + if (ret["RESULT"].ToString() == "NULL") + return null; + + return GroupsDataUtils.GroupInviteInfo((Dictionary)ret["RESULT"]); + } + + public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID) + { + Dictionary sendData = new Dictionary(); + sendData["InviteID"] = inviteID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + sendData["OP"] = "DELETE"; + + MakeRequest("INVITE", sendData); + } + + public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, + bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) + { + Dictionary sendData = new Dictionary(); + sendData["GroupID"] = groupID.ToString(); + sendData["NoticeID"] = noticeID.ToString(); + sendData["FromName"] = GroupsDataUtils.Sanitize(fromName); + sendData["Subject"] = GroupsDataUtils.Sanitize(subject); + sendData["Message"] = GroupsDataUtils.Sanitize(message); + sendData["HasAttachment"] = hasAttachment.ToString(); + if (hasAttachment) + { + sendData["AttachmentType"] = attType.ToString(); + sendData["AttachmentName"] = attName.ToString(); + sendData["AttachmentItemID"] = attItemID.ToString(); + sendData["AttachmentOwnerID"] = attOwnerID; + } + sendData["RequestingAgentID"] = RequestingAgentID; + + Dictionary ret = MakeRequest("ADDNOTICE", sendData); + + if (ret == null) + return false; + + if (!ret.ContainsKey("RESULT")) + return false; + + if (ret["RESULT"].ToString().ToLower() != "true") + return false; + + return true; + } + + public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID) + { + Dictionary sendData = new Dictionary(); + sendData["NoticeID"] = noticeID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + + Dictionary ret = MakeRequest("GETNOTICES", sendData); + + if (ret == null) + return null; + + if (!ret.ContainsKey("RESULT")) + return null; + + if (ret["RESULT"].ToString() == "NULL") + return null; + + return GroupsDataUtils.GroupNoticeInfo((Dictionary)ret["RESULT"]); + } + + public List GetGroupNotices(string RequestingAgentID, UUID GroupID) + { + List notices = new List(); + + Dictionary sendData = new Dictionary(); + sendData["GroupID"] = GroupID.ToString(); + sendData["RequestingAgentID"] = RequestingAgentID; + Dictionary ret = MakeRequest("GETNOTICES", sendData); + + if (ret == null) + return notices; + + if (!ret.ContainsKey("RESULT")) + return notices; + + if (ret["RESULT"].ToString() == "NULL") + return notices; + + foreach (object v in ((Dictionary)ret["RESULT"]).Values) + { + ExtendedGroupNoticeData m = GroupsDataUtils.GroupNoticeData((Dictionary)v); + notices.Add(m); + } + + return notices; + } + + #region Make Request + + private Dictionary MakeRequest(string method, Dictionary sendData) + { + sendData["METHOD"] = method; + + string reply = string.Empty; + lock (m_Lock) + reply = SynchronousRestFormsRequester.MakeRequest("POST", + m_ServerURI + "groups", + ServerUtils.BuildQueryString(sendData), + m_Auth); + + if (reply == string.Empty) + return null; + + Dictionary replyData = ServerUtils.ParseXmlResponse( + reply); + + return replyData; + } + + #endregion + } +} \ No newline at end of file diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs new file mode 100644 index 0000000..d4739c6 --- /dev/null +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs @@ -0,0 +1,408 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Text; + +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; + +using OpenMetaverse; +using Mono.Addins; +using log4net; +using Nini.Config; + +namespace OpenSim.Groups +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceRemoteConnectorModule")] + public class GroupsServiceRemoteConnectorModule : ISharedRegionModule, IGroupsServicesConnector + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private bool m_Enabled = false; + private GroupsServiceRemoteConnector m_GroupsService; + private IUserManagement m_UserManagement; + private List m_Scenes; + + private RemoteConnectorCacheWrapper m_CacheWrapper; + + #region constructors + public GroupsServiceRemoteConnectorModule() + { + } + + public GroupsServiceRemoteConnectorModule(IConfigSource config, IUserManagement uman) + { + Init(config); + m_UserManagement = uman; + m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement); + + } + #endregion + + private void Init(IConfigSource config) + { + m_GroupsService = new GroupsServiceRemoteConnector(config); + m_Scenes = new List(); + + } + + #region ISharedRegionModule + + public void Initialise(IConfigSource config) + { + IConfig groupsConfig = config.Configs["Groups"]; + if (groupsConfig == null) + return; + + if ((groupsConfig.GetBoolean("Enabled", false) == false) + || (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name)) + { + return; + } + + Init(config); + + m_Enabled = true; + m_log.DebugFormat("[Groups.RemoteConnector]: Initializing {0}", this.Name); + } + + public string Name + { + get { return "Groups Remote Service Connector"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + m_log.DebugFormat("[Groups.RemoteConnector]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName); + scene.RegisterModuleInterface(this); + m_Scenes.Add(scene); + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + + scene.UnregisterModuleInterface(this); + m_Scenes.Remove(scene); + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + + if (m_UserManagement == null) + { + m_UserManagement = scene.RequestModuleInterface(); + m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement); + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + #endregion + + #region IGroupsServicesConnector + + public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, + bool allowPublish, bool maturePublish, UUID founderID, out string reason) + { + m_log.DebugFormat("[Groups.RemoteConnector]: Creating group {0}", name); + string r = string.Empty; + + UUID groupID = m_CacheWrapper.CreateGroup(RequestingAgentID, delegate + { + return m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID, + membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out r); + }); + + reason = r; + return groupID; + } + + public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, + bool openEnrollment, bool allowPublish, bool maturePublish, out string reason) + { + string r = string.Empty; + + bool success = m_CacheWrapper.UpdateGroup(groupID, delegate + { + return m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish); + }); + + reason = r; + return success; + } + + public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName) + { + if (GroupID == UUID.Zero && (GroupName == null || GroupName != null && GroupName == string.Empty)) + return null; + + return m_CacheWrapper.GetGroupRecord(RequestingAgentID,GroupID,GroupName, delegate + { + return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID, GroupName); + }); + } + + public List FindGroups(string RequestingAgentID, string search) + { + // TODO! + return m_GroupsService.FindGroups(RequestingAgentID, search); + } + + public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason) + { + string agentFullID = AgentID; + m_log.DebugFormat("[Groups.RemoteConnector]: Add agent {0} to group {1}", agentFullID, GroupID); + string r = string.Empty; + + bool success = m_CacheWrapper.AddAgentToGroup(RequestingAgentID, AgentID, GroupID, delegate + { + return m_GroupsService.AddAgentToGroup(RequestingAgentID, agentFullID, GroupID, RoleID, token, out r); + }); + + reason = r; + return success; + } + + public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) + { + m_CacheWrapper.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID, delegate + { + m_GroupsService.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID); + }); + + } + + public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID) + { + m_CacheWrapper.SetAgentActiveGroup(AgentID, delegate + { + return m_GroupsService.SetAgentActiveGroup(RequestingAgentID, AgentID, GroupID); + }); + } + + public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID) + { + return m_CacheWrapper.GetAgentActiveMembership(AgentID, delegate + { + return m_GroupsService.GetMembership(RequestingAgentID, AgentID, UUID.Zero); + }); + } + + public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID) + { + return m_CacheWrapper.GetAgentGroupMembership(AgentID, GroupID, delegate + { + return m_GroupsService.GetMembership(RequestingAgentID, AgentID, GroupID); + }); + } + + public List GetAgentGroupMemberships(string RequestingAgentID, string AgentID) + { + return m_CacheWrapper.GetAgentGroupMemberships(AgentID, delegate + { + return m_GroupsService.GetMemberships(RequestingAgentID, AgentID); + }); + } + + + public List GetGroupMembers(string RequestingAgentID, UUID GroupID) + { + return m_CacheWrapper.GetGroupMembers(RequestingAgentID, GroupID, delegate + { + return m_GroupsService.GetGroupMembers(RequestingAgentID, GroupID); + }); + } + + public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason) + { + string r = string.Empty; + bool success = m_CacheWrapper.AddGroupRole(groupID, roleID, description, name, powers, title, delegate + { + return m_GroupsService.AddGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, out r); + }); + + reason = r; + return success; + } + + public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers) + { + return m_CacheWrapper.UpdateGroupRole(groupID, roleID, name, description, title, powers, delegate + { + return m_GroupsService.UpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers); + }); + } + + public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID) + { + m_CacheWrapper.RemoveGroupRole(RequestingAgentID, groupID, roleID, delegate + { + m_GroupsService.RemoveGroupRole(RequestingAgentID, groupID, roleID); + }); + } + + public List GetGroupRoles(string RequestingAgentID, UUID GroupID) + { + return m_CacheWrapper.GetGroupRoles(RequestingAgentID, GroupID, delegate + { + return m_GroupsService.GetGroupRoles(RequestingAgentID, GroupID); + }); + } + + public List GetGroupRoleMembers(string RequestingAgentID, UUID GroupID) + { + return m_CacheWrapper.GetGroupRoleMembers(RequestingAgentID, GroupID, delegate + { + return m_GroupsService.GetGroupRoleMembers(RequestingAgentID, GroupID); + }); + } + + public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + m_CacheWrapper.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID, delegate + { + return m_GroupsService.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); + }); + } + + public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + m_CacheWrapper.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID, delegate + { + return m_GroupsService.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); + }); + } + + public List GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID) + { + return m_CacheWrapper.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID, delegate + { + return m_GroupsService.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID); ; + }); + } + + public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + m_CacheWrapper.SetAgentActiveGroupRole(AgentID, GroupID, delegate + { + m_GroupsService.SetAgentActiveGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); + }); + } + + public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile) + { + m_CacheWrapper.UpdateMembership(AgentID, GroupID, AcceptNotices, ListInProfile, delegate + { + m_GroupsService.UpdateMembership(RequestingAgentID, AgentID, GroupID, AcceptNotices, ListInProfile); + }); + } + + public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID) + { + return m_GroupsService.AddAgentToGroupInvite(RequestingAgentID, inviteID, groupID, roleID, agentID); + } + + public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID) + { + return m_GroupsService.GetAgentToGroupInvite(RequestingAgentID, inviteID); + } + + public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID) + { + m_GroupsService.RemoveAgentToGroupInvite(RequestingAgentID, inviteID); + } + + public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, + bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) + { + GroupNoticeInfo notice = new GroupNoticeInfo(); + notice.GroupID = groupID; + notice.Message = message; + notice.noticeData = new ExtendedGroupNoticeData(); + notice.noticeData.AttachmentItemID = attItemID; + notice.noticeData.AttachmentName = attName; + notice.noticeData.AttachmentOwnerID = attOwnerID.ToString(); + notice.noticeData.AttachmentType = attType; + notice.noticeData.FromName = fromName; + notice.noticeData.HasAttachment = hasAttachment; + notice.noticeData.NoticeID = noticeID; + notice.noticeData.Subject = subject; + notice.noticeData.Timestamp = (uint)Util.UnixTimeSinceEpoch(); + + return m_CacheWrapper.AddGroupNotice(groupID, noticeID, notice, delegate + { + return m_GroupsService.AddGroupNotice(RequestingAgentID, groupID, noticeID, fromName, subject, message, + hasAttachment, attType, attName, attItemID, attOwnerID); + }); + } + + public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID) + { + return m_CacheWrapper.GetGroupNotice(noticeID, delegate + { + return m_GroupsService.GetGroupNotice(RequestingAgentID, noticeID); + }); + } + + public List GetGroupNotices(string RequestingAgentID, UUID GroupID) + { + return m_CacheWrapper.GetGroupNotices(GroupID, delegate + { + return m_GroupsService.GetGroupNotices(RequestingAgentID, GroupID); + }); + } + + #endregion + } + +} diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs new file mode 100644 index 0000000..26e844e --- /dev/null +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs @@ -0,0 +1,816 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using System.Text; +using System.Xml; +using System.Collections.Generic; +using System.IO; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework.ServiceAuth; +using OpenSim.Server.Handlers.Base; +using log4net; +using OpenMetaverse; + +namespace OpenSim.Groups +{ + public class GroupsServiceRobustConnector : ServiceConnector + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private GroupsService m_GroupsService; + private string m_ConfigName = "Groups"; + + public GroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + string key = string.Empty; + if (configName != String.Empty) + m_ConfigName = configName; + + m_log.DebugFormat("[Groups.RobustConnector]: Starting with config name {0}", m_ConfigName); + + IConfig groupsConfig = config.Configs[m_ConfigName]; + if (groupsConfig != null) + { + key = groupsConfig.GetString("SecretKey", string.Empty); + m_log.DebugFormat("[Groups.RobustConnector]: Starting with secret key {0}", key); + } +// else +// m_log.DebugFormat("[Groups.RobustConnector]: Unable to find {0} section in configuration", m_ConfigName); + + m_GroupsService = new GroupsService(config); + + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); + + server.AddStreamHandler(new GroupsServicePostHandler(m_GroupsService, auth)); + } + } + + public class GroupsServicePostHandler : BaseStreamHandler + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private GroupsService m_GroupsService; + + public GroupsServicePostHandler(GroupsService service, IServiceAuth auth) : + base("POST", "/groups", auth) + { + m_GroupsService = service; + } + + protected override byte[] ProcessRequest(string path, Stream requestData, + IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + StreamReader sr = new StreamReader(requestData); + string body = sr.ReadToEnd(); + sr.Close(); + body = body.Trim(); + + //m_log.DebugFormat("[XXX]: query String: {0}", body); + + try + { + Dictionary request = + ServerUtils.ParseQueryString(body); + + if (!request.ContainsKey("METHOD")) + return FailureResult(); + + string method = request["METHOD"].ToString(); + request.Remove("METHOD"); + +// m_log.DebugFormat("[Groups.Handler]: {0}", method); + switch (method) + { + case "PUTGROUP": + return HandleAddOrUpdateGroup(request); + case "GETGROUP": + return HandleGetGroup(request); + case "ADDAGENTTOGROUP": + return HandleAddAgentToGroup(request); + case "REMOVEAGENTFROMGROUP": + return HandleRemoveAgentFromGroup(request); + case "GETMEMBERSHIP": + return HandleGetMembership(request); + case "GETGROUPMEMBERS": + return HandleGetGroupMembers(request); + case "PUTROLE": + return HandlePutRole(request); + case "REMOVEROLE": + return HandleRemoveRole(request); + case "GETGROUPROLES": + return HandleGetGroupRoles(request); + case "GETROLEMEMBERS": + return HandleGetRoleMembers(request); + case "AGENTROLE": + return HandleAgentRole(request); + case "GETAGENTROLES": + return HandleGetAgentRoles(request); + case "SETACTIVE": + return HandleSetActive(request); + case "UPDATEMEMBERSHIP": + return HandleUpdateMembership(request); + case "INVITE": + return HandleInvite(request); + case "ADDNOTICE": + return HandleAddNotice(request); + case "GETNOTICES": + return HandleGetNotices(request); + case "FINDGROUPS": + return HandleFindGroups(request); + } + m_log.DebugFormat("[GROUPS HANDLER]: unknown method request: {0}", method); + } + catch (Exception e) + { + m_log.Error(string.Format("[GROUPS HANDLER]: Exception {0} ", e.Message), e); + } + + return FailureResult(); + } + + byte[] HandleAddOrUpdateGroup(Dictionary request) + { + Dictionary result = new Dictionary(); + + ExtendedGroupRecord grec = GroupsDataUtils.GroupRecord(request); + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("OP")) + NullResult(result, "Bad network data"); + + else + { + string RequestingAgentID = request["RequestingAgentID"].ToString(); + string reason = string.Empty; + string op = request["OP"].ToString(); + if (op == "ADD") + { + grec.GroupID = m_GroupsService.CreateGroup(RequestingAgentID, grec.GroupName, grec.Charter, grec.ShowInList, grec.GroupPicture, grec.MembershipFee, + grec.OpenEnrollment, grec.AllowPublish, grec.MaturePublish, grec.FounderID, out reason); + + } + else if (op == "UPDATE") + { + m_GroupsService.UpdateGroup(RequestingAgentID, grec.GroupID, grec.Charter, grec.ShowInList, grec.GroupPicture, grec.MembershipFee, + grec.OpenEnrollment, grec.AllowPublish, grec.MaturePublish); + + } + + if (grec.GroupID != UUID.Zero) + { + grec = m_GroupsService.GetGroupRecord(RequestingAgentID, grec.GroupID); + if (grec == null) + NullResult(result, "Internal Error"); + else + result["RESULT"] = GroupsDataUtils.GroupRecord(grec); + } + else + NullResult(result, reason); + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleGetGroup(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID")) + NullResult(result, "Bad network data"); + else + { + string RequestingAgentID = request["RequestingAgentID"].ToString(); + ExtendedGroupRecord grec = null; + if (request.ContainsKey("GroupID")) + { + UUID groupID = new UUID(request["GroupID"].ToString()); + grec = m_GroupsService.GetGroupRecord(RequestingAgentID, groupID); + } + else if (request.ContainsKey("Name")) + { + string name = request["Name"].ToString(); + grec = m_GroupsService.GetGroupRecord(RequestingAgentID, name); + } + + if (grec == null) + NullResult(result, "Group not found"); + else + result["RESULT"] = GroupsDataUtils.GroupRecord(grec); + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleAddAgentToGroup(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") || + !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID")) + NullResult(result, "Bad network data"); + else + { + UUID groupID = new UUID(request["GroupID"].ToString()); + UUID roleID = new UUID(request["RoleID"].ToString()); + string agentID = request["AgentID"].ToString(); + string requestingAgentID = request["RequestingAgentID"].ToString(); + string token = string.Empty; + string reason = string.Empty; + + if (request.ContainsKey("AccessToken")) + token = request["AccessToken"].ToString(); + + if (!m_GroupsService.AddAgentToGroup(requestingAgentID, agentID, groupID, roleID, token, out reason)) + NullResult(result, reason); + else + { + GroupMembershipData membership = m_GroupsService.GetAgentGroupMembership(requestingAgentID, agentID, groupID); + if (membership == null) + NullResult(result, "Internal error"); + else + result["RESULT"] = GroupsDataUtils.GroupMembershipData((ExtendedGroupMembershipData)membership); + } + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleRemoveAgentFromGroup(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") || !request.ContainsKey("GroupID")) + NullResult(result, "Bad network data"); + else + { + UUID groupID = new UUID(request["GroupID"].ToString()); + string agentID = request["AgentID"].ToString(); + string requestingAgentID = request["RequestingAgentID"].ToString(); + + if (!m_GroupsService.RemoveAgentFromGroup(requestingAgentID, agentID, groupID)) + NullResult(result, string.Format("Insufficient permissions.", agentID)); + else + result["RESULT"] = "true"; + } + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); + } + + byte[] HandleGetMembership(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID")) + NullResult(result, "Bad network data"); + else + { + string agentID = request["AgentID"].ToString(); + UUID groupID = UUID.Zero; + if (request.ContainsKey("GroupID")) + groupID = new UUID(request["GroupID"].ToString()); + string requestingAgentID = request["RequestingAgentID"].ToString(); + bool all = request.ContainsKey("ALL"); + + if (!all) + { + ExtendedGroupMembershipData membership = null; + if (groupID == UUID.Zero) + { + membership = m_GroupsService.GetAgentActiveMembership(requestingAgentID, agentID); + } + else + { + membership = m_GroupsService.GetAgentGroupMembership(requestingAgentID, agentID, groupID); + } + + if (membership == null) + NullResult(result, "No such membership"); + else + result["RESULT"] = GroupsDataUtils.GroupMembershipData(membership); + } + else + { + List memberships = m_GroupsService.GetAgentGroupMemberships(requestingAgentID, agentID); + if (memberships == null || (memberships != null && memberships.Count == 0)) + { + NullResult(result, "No memberships"); + } + else + { + Dictionary dict = new Dictionary(); + int i = 0; + foreach (GroupMembershipData m in memberships) + dict["m-" + i++] = GroupsDataUtils.GroupMembershipData((ExtendedGroupMembershipData)m); + + result["RESULT"] = dict; + } + } + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleGetGroupMembers(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID")) + NullResult(result, "Bad network data"); + else + { + UUID groupID = new UUID(request["GroupID"].ToString()); + string requestingAgentID = request["RequestingAgentID"].ToString(); + + List members = m_GroupsService.GetGroupMembers(requestingAgentID, groupID); + if (members == null || (members != null && members.Count == 0)) + { + NullResult(result, "No members"); + } + else + { + Dictionary dict = new Dictionary(); + int i = 0; + foreach (ExtendedGroupMembersData m in members) + { + dict["m-" + i++] = GroupsDataUtils.GroupMembersData(m); + } + + result["RESULT"] = dict; + } + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandlePutRole(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID") || + !request.ContainsKey("Name") || !request.ContainsKey("Description") || !request.ContainsKey("Title") || + !request.ContainsKey("Powers") || !request.ContainsKey("OP")) + NullResult(result, "Bad network data"); + + else + { + string op = request["OP"].ToString(); + string reason = string.Empty; + + bool success = false; + if (op == "ADD") + success = m_GroupsService.AddGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()), + new UUID(request["RoleID"].ToString()), request["Name"].ToString(), request["Description"].ToString(), + request["Title"].ToString(), UInt64.Parse(request["Powers"].ToString()), out reason); + + else if (op == "UPDATE") + success = m_GroupsService.UpdateGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()), + new UUID(request["RoleID"].ToString()), request["Name"].ToString(), request["Description"].ToString(), + request["Title"].ToString(), UInt64.Parse(request["Powers"].ToString())); + + result["RESULT"] = success.ToString(); + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleRemoveRole(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID")) + NullResult(result, "Bad network data"); + + else + { + m_GroupsService.RemoveGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()), + new UUID(request["RoleID"].ToString())); + result["RESULT"] = "true"; + } + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); + } + + byte[] HandleGetGroupRoles(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID")) + NullResult(result, "Bad network data"); + else + { + UUID groupID = new UUID(request["GroupID"].ToString()); + string requestingAgentID = request["RequestingAgentID"].ToString(); + + List roles = m_GroupsService.GetGroupRoles(requestingAgentID, groupID); + if (roles == null || (roles != null && roles.Count == 0)) + { + NullResult(result, "No members"); + } + else + { + Dictionary dict = new Dictionary(); + int i = 0; + foreach (GroupRolesData r in roles) + dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r); + + result["RESULT"] = dict; + } + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleGetRoleMembers(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID")) + NullResult(result, "Bad network data"); + else + { + UUID groupID = new UUID(request["GroupID"].ToString()); + string requestingAgentID = request["RequestingAgentID"].ToString(); + + List rmembers = m_GroupsService.GetGroupRoleMembers(requestingAgentID, groupID); + if (rmembers == null || (rmembers != null && rmembers.Count == 0)) + { + NullResult(result, "No members"); + } + else + { + Dictionary dict = new Dictionary(); + int i = 0; + foreach (ExtendedGroupRoleMembersData rm in rmembers) + dict["rm-" + i++] = GroupsDataUtils.GroupRoleMembersData(rm); + + result["RESULT"] = dict; + } + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleAgentRole(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID") || + !request.ContainsKey("AgentID") || !request.ContainsKey("OP")) + NullResult(result, "Bad network data"); + + else + { + string op = request["OP"].ToString(); + + bool success = false; + if (op == "ADD") + success = m_GroupsService.AddAgentToGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), + new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString())); + + else if (op == "DELETE") + success = m_GroupsService.RemoveAgentFromGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), + new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString())); + + result["RESULT"] = success.ToString(); + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleGetAgentRoles(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AgentID")) + NullResult(result, "Bad network data"); + else + { + UUID groupID = new UUID(request["GroupID"].ToString()); + string agentID = request["AgentID"].ToString(); + string requestingAgentID = request["RequestingAgentID"].ToString(); + + List roles = m_GroupsService.GetAgentGroupRoles(requestingAgentID, agentID, groupID); + if (roles == null || (roles != null && roles.Count == 0)) + { + NullResult(result, "No members"); + } + else + { + Dictionary dict = new Dictionary(); + int i = 0; + foreach (GroupRolesData r in roles) + dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r); + + result["RESULT"] = dict; + } + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleSetActive(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || + !request.ContainsKey("AgentID") || !request.ContainsKey("OP")) + { + NullResult(result, "Bad network data"); + string xmlString = ServerUtils.BuildXmlResponse(result); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + else + { + string op = request["OP"].ToString(); + + if (op == "GROUP") + { + ExtendedGroupMembershipData group = m_GroupsService.SetAgentActiveGroup(request["RequestingAgentID"].ToString(), + request["AgentID"].ToString(), new UUID(request["GroupID"].ToString())); + + if (group == null) + NullResult(result, "Internal error"); + else + result["RESULT"] = GroupsDataUtils.GroupMembershipData(group); + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + + } + else if (op == "ROLE" && request.ContainsKey("RoleID")) + { + m_GroupsService.SetAgentActiveGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), + new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString())); + result["RESULT"] = "true"; + } + + return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); + } + + } + + byte[] HandleUpdateMembership(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") || !request.ContainsKey("GroupID") || + !request.ContainsKey("AcceptNotices") || !request.ContainsKey("ListInProfile")) + NullResult(result, "Bad network data"); + + else + { + m_GroupsService.UpdateMembership(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), new UUID(request["GroupID"].ToString()), + bool.Parse(request["AcceptNotices"].ToString()), bool.Parse(request["ListInProfile"].ToString())); + + result["RESULT"] = "true"; + } + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); + } + + byte[] HandleInvite(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("InviteID")) + { + NullResult(result, "Bad network data"); + string xmlString = ServerUtils.BuildXmlResponse(result); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + else + { + string op = request["OP"].ToString(); + + if (op == "ADD" && request.ContainsKey("GroupID") && request.ContainsKey("RoleID") && request.ContainsKey("AgentID")) + { + bool success = m_GroupsService.AddAgentToGroupInvite(request["RequestingAgentID"].ToString(), + new UUID(request["InviteID"].ToString()), new UUID(request["GroupID"].ToString()), + new UUID(request["RoleID"].ToString()), request["AgentID"].ToString()); + + result["RESULT"] = success.ToString(); + return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); + + } + else if (op == "DELETE") + { + m_GroupsService.RemoveAgentToGroupInvite(request["RequestingAgentID"].ToString(), new UUID(request["InviteID"].ToString())); + result["RESULT"] = "true"; + return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); + } + else if (op == "GET") + { + GroupInviteInfo invite = m_GroupsService.GetAgentToGroupInvite(request["RequestingAgentID"].ToString(), + new UUID(request["InviteID"].ToString())); + + if (invite != null) + result["RESULT"] = GroupsDataUtils.GroupInviteInfo(invite); + else + result["RESULT"] = "NULL"; + + return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); + } + + NullResult(result, "Bad OP in request"); + return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); + } + + } + + byte[] HandleAddNotice(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("NoticeID") || + !request.ContainsKey("FromName") || !request.ContainsKey("Subject") || !request.ContainsKey("Message") || + !request.ContainsKey("HasAttachment")) + NullResult(result, "Bad network data"); + + else + { + + bool hasAtt = bool.Parse(request["HasAttachment"].ToString()); + byte attType = 0; + string attName = string.Empty; + string attOwner = string.Empty; + UUID attItem = UUID.Zero; + if (request.ContainsKey("AttachmentType")) + attType = byte.Parse(request["AttachmentType"].ToString()); + if (request.ContainsKey("AttachmentName")) + attName = request["AttachmentName"].ToString(); + if (request.ContainsKey("AttachmentItemID")) + attItem = new UUID(request["AttachmentItemID"].ToString()); + if (request.ContainsKey("AttachmentOwnerID")) + attOwner = request["AttachmentOwnerID"].ToString(); + + bool success = m_GroupsService.AddGroupNotice(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()), + new UUID(request["NoticeID"].ToString()), request["FromName"].ToString(), request["Subject"].ToString(), + request["Message"].ToString(), hasAtt, attType, attName, attItem, attOwner); + + result["RESULT"] = success.ToString(); + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleGetNotices(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID")) + NullResult(result, "Bad network data"); + + else if (request.ContainsKey("NoticeID")) // just one + { + GroupNoticeInfo notice = m_GroupsService.GetGroupNotice(request["RequestingAgentID"].ToString(), new UUID(request["NoticeID"].ToString())); + + if (notice == null) + NullResult(result, "NO such notice"); + else + result["RESULT"] = GroupsDataUtils.GroupNoticeInfo(notice); + + } + else if (request.ContainsKey("GroupID")) // all notices for group + { + List notices = m_GroupsService.GetGroupNotices(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString())); + + if (notices == null || (notices != null && notices.Count == 0)) + NullResult(result, "No notices"); + else + { + Dictionary dict = new Dictionary(); + int i = 0; + foreach (ExtendedGroupNoticeData n in notices) + dict["n-" + i++] = GroupsDataUtils.GroupNoticeData(n); + + result["RESULT"] = dict; + } + + } + else + NullResult(result, "Bad OP in request"); + + string xmlString = ServerUtils.BuildXmlResponse(result); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleFindGroups(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("Query")) + NullResult(result, "Bad network data"); + + List hits = m_GroupsService.FindGroups(request["RequestingAgentID"].ToString(), request["Query"].ToString()); + + if (hits == null || (hits != null && hits.Count == 0)) + NullResult(result, "No hits"); + else + { + Dictionary dict = new Dictionary(); + int i = 0; + foreach (DirGroupsReplyData n in hits) + dict["n-" + i++] = GroupsDataUtils.DirGroupsReplyData(n); + + result["RESULT"] = dict; + } + + + string xmlString = ServerUtils.BuildXmlResponse(result); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + + #region Helpers + + private void NullResult(Dictionary result, string reason) + { + result["RESULT"] = "NULL"; + result["REASON"] = reason; + } + + private byte[] FailureResult() + { + Dictionary result = new Dictionary(); + NullResult(result, "Unknown method"); + string xmlString = ServerUtils.BuildXmlResponse(result); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + private byte[] FailureResult(string reason) + { + Dictionary result = new Dictionary(); + NullResult(result, reason); + string xmlString = ServerUtils.BuildXmlResponse(result); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + #endregion + } +} diff --git a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs new file mode 100644 index 0000000..813f796 --- /dev/null +++ b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs @@ -0,0 +1,888 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; + +using OpenSim.Framework; +//using OpenSim.Region.Framework.Interfaces; +using OpenSim.Services.Interfaces; + +using OpenMetaverse; + +namespace OpenSim.Groups +{ + public delegate ExtendedGroupRecord GroupRecordDelegate(); + public delegate GroupMembershipData GroupMembershipDelegate(); + public delegate List GroupMembershipListDelegate(); + public delegate List GroupMembersListDelegate(); + public delegate List GroupRolesListDelegate(); + public delegate List RoleMembersListDelegate(); + public delegate GroupNoticeInfo NoticeDelegate(); + public delegate List NoticeListDelegate(); + public delegate void VoidDelegate(); + public delegate bool BooleanDelegate(); + + public class RemoteConnectorCacheWrapper + { + private ForeignImporter m_ForeignImporter; + + private Dictionary m_ActiveRequests = new Dictionary(); + private const int GROUPS_CACHE_TIMEOUT = 1 * 60; // 1 minutes + + // This all important cache cahces objects of different types: + // group- or group- => ExtendedGroupRecord + // active- => GroupMembershipData + // membership-- => GroupMembershipData + // memberships- => List + // members-- => List + // role- => GroupRolesData + // roles- => List ; all roles in the group + // roles-- => List ; roles that the agent has + // rolemembers-- => List + // notice- => GroupNoticeInfo + // notices- => List + private ExpiringCache m_Cache = new ExpiringCache(); + + public RemoteConnectorCacheWrapper(IUserManagement uman) + { + m_ForeignImporter = new ForeignImporter(uman); + } + + public UUID CreateGroup(UUID RequestingAgentID, GroupRecordDelegate d) + { + //m_log.DebugFormat("[Groups.RemoteConnector]: Creating group {0}", name); + //reason = string.Empty; + + //ExtendedGroupRecord group = m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID, + // membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason); + ExtendedGroupRecord group = d(); + + if (group == null) + return UUID.Zero; + + if (group.GroupID != UUID.Zero) + lock (m_Cache) + { + m_Cache.Add("group-" + group.GroupID.ToString(), group, GROUPS_CACHE_TIMEOUT); + if (m_Cache.Contains("memberships-" + RequestingAgentID.ToString())) + m_Cache.Remove("memberships-" + RequestingAgentID.ToString()); + } + + return group.GroupID; + } + + public bool UpdateGroup(UUID groupID, GroupRecordDelegate d) + { + //reason = string.Empty; + //ExtendedGroupRecord group = m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish); + ExtendedGroupRecord group = d(); + + if (group != null && group.GroupID != UUID.Zero) + lock (m_Cache) + m_Cache.AddOrUpdate("group-" + group.GroupID.ToString(), group, GROUPS_CACHE_TIMEOUT); + return true; + } + + public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName, GroupRecordDelegate d) + { + //if (GroupID == UUID.Zero && (GroupName == null || GroupName != null && GroupName == string.Empty)) + // return null; + + object group = null; + bool firstCall = false; + string cacheKey = "group-"; + if (GroupID != UUID.Zero) + cacheKey += GroupID.ToString(); + else + cacheKey += GroupName; + + //m_log.DebugFormat("[XXX]: GetGroupRecord {0}", cacheKey); + + while (true) + { + lock (m_Cache) + { + if (m_Cache.TryGetValue(cacheKey, out group)) + { + //m_log.DebugFormat("[XXX]: GetGroupRecord {0} cached!", cacheKey); + return (ExtendedGroupRecord)group; + } + + // not cached + if (!m_ActiveRequests.ContainsKey(cacheKey)) + { + m_ActiveRequests.Add(cacheKey, true); + firstCall = true; + } + } + + if (firstCall) + { + try + { + //group = m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID, GroupName); + group = d(); + + lock (m_Cache) + { + m_Cache.AddOrUpdate(cacheKey, group, GROUPS_CACHE_TIMEOUT); + return (ExtendedGroupRecord)group; + } + } + finally + { + m_ActiveRequests.Remove(cacheKey); + } + } + else + Thread.Sleep(50); + } + } + + public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, GroupMembershipDelegate d) + { + GroupMembershipData membership = d(); + if (membership == null) + return false; + + lock (m_Cache) + { + // first, remove everything! add a user is a heavy-duty op + m_Cache.Clear(); + + m_Cache.AddOrUpdate("active-" + AgentID.ToString(), membership, GROUPS_CACHE_TIMEOUT); + m_Cache.AddOrUpdate("membership-" + AgentID.ToString() + "-" + GroupID.ToString(), membership, GROUPS_CACHE_TIMEOUT); + } + + + return true; + } + + public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID, VoidDelegate d) + { + d(); + + lock (m_Cache) + { + string cacheKey = "active-" + AgentID.ToString(); + if (m_Cache.Contains(cacheKey)) + m_Cache.Remove(cacheKey); + + cacheKey = "memberships-" + AgentID.ToString(); + if (m_Cache.Contains(cacheKey)) + m_Cache.Remove(cacheKey); + + cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString(); + if (m_Cache.Contains(cacheKey)) + m_Cache.Remove(cacheKey); + + cacheKey = "members-" + RequestingAgentID.ToString() + "-" + GroupID.ToString(); + if (m_Cache.Contains(cacheKey)) + m_Cache.Remove(cacheKey); + + cacheKey = "roles-" + "-" + GroupID.ToString() + "-" + AgentID.ToString(); + if (m_Cache.Contains(cacheKey)) + m_Cache.Remove(cacheKey); + } + } + + public void SetAgentActiveGroup(string AgentID, GroupMembershipDelegate d) + { + GroupMembershipData activeGroup = d(); + string cacheKey = "active-" + AgentID.ToString(); + lock (m_Cache) + if (m_Cache.Contains(cacheKey)) + m_Cache.AddOrUpdate(cacheKey, activeGroup, GROUPS_CACHE_TIMEOUT); + } + + public ExtendedGroupMembershipData GetAgentActiveMembership(string AgentID, GroupMembershipDelegate d) + { + object membership = null; + bool firstCall = false; + string cacheKey = "active-" + AgentID.ToString(); + + //m_log.DebugFormat("[XXX]: GetAgentActiveMembership {0}", cacheKey); + + while (true) + { + lock (m_Cache) + { + if (m_Cache.TryGetValue(cacheKey, out membership)) + { + //m_log.DebugFormat("[XXX]: GetAgentActiveMembership {0} cached!", cacheKey); + return (ExtendedGroupMembershipData)membership; + } + + // not cached + if (!m_ActiveRequests.ContainsKey(cacheKey)) + { + m_ActiveRequests.Add(cacheKey, true); + firstCall = true; + } + } + + if (firstCall) + { + try + { + membership = d(); + + lock (m_Cache) + { + m_Cache.AddOrUpdate(cacheKey, membership, GROUPS_CACHE_TIMEOUT); + return (ExtendedGroupMembershipData)membership; + } + } + finally + { + m_ActiveRequests.Remove(cacheKey); + } + } + else + Thread.Sleep(50); + } + + } + + public ExtendedGroupMembershipData GetAgentGroupMembership(string AgentID, UUID GroupID, GroupMembershipDelegate d) + { + object membership = null; + bool firstCall = false; + string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString(); + + //m_log.DebugFormat("[XXX]: GetAgentGroupMembership {0}", cacheKey); + + while (true) + { + lock (m_Cache) + { + if (m_Cache.TryGetValue(cacheKey, out membership)) + { + //m_log.DebugFormat("[XXX]: GetAgentGroupMembership {0}", cacheKey); + return (ExtendedGroupMembershipData)membership; + } + + // not cached + if (!m_ActiveRequests.ContainsKey(cacheKey)) + { + m_ActiveRequests.Add(cacheKey, true); + firstCall = true; + } + } + + if (firstCall) + { + try + { + membership = d(); + lock (m_Cache) + { + m_Cache.AddOrUpdate(cacheKey, membership, GROUPS_CACHE_TIMEOUT); + return (ExtendedGroupMembershipData)membership; + } + } + finally + { + m_ActiveRequests.Remove(cacheKey); + } + } + else + Thread.Sleep(50); + } + } + + public List GetAgentGroupMemberships(string AgentID, GroupMembershipListDelegate d) + { + object memberships = null; + bool firstCall = false; + string cacheKey = "memberships-" + AgentID.ToString(); + + //m_log.DebugFormat("[XXX]: GetAgentGroupMemberships {0}", cacheKey); + + while (true) + { + lock (m_Cache) + { + if (m_Cache.TryGetValue(cacheKey, out memberships)) + { + //m_log.DebugFormat("[XXX]: GetAgentGroupMemberships {0} cached!", cacheKey); + return (List)memberships; + } + + // not cached + if (!m_ActiveRequests.ContainsKey(cacheKey)) + { + m_ActiveRequests.Add(cacheKey, true); + firstCall = true; + } + } + + if (firstCall) + { + try + { + memberships = d(); + lock (m_Cache) + { + m_Cache.AddOrUpdate(cacheKey, memberships, GROUPS_CACHE_TIMEOUT); + return (List)memberships; + } + } + finally + { + m_ActiveRequests.Remove(cacheKey); + } + } + else + Thread.Sleep(50); + } + } + + public List GetGroupMembers(string RequestingAgentID, UUID GroupID, GroupMembersListDelegate d) + { + object members = null; + bool firstCall = false; + // we need to key in also on the requester, because different ppl have different view privileges + string cacheKey = "members-" + RequestingAgentID.ToString() + "-" + GroupID.ToString(); + + //m_log.DebugFormat("[XXX]: GetGroupMembers {0}", cacheKey); + + while (true) + { + lock (m_Cache) + { + if (m_Cache.TryGetValue(cacheKey, out members)) + { + List xx = (List)members; + return xx.ConvertAll(new Converter(m_ForeignImporter.ConvertGroupMembersData)); + } + + // not cached + if (!m_ActiveRequests.ContainsKey(cacheKey)) + { + m_ActiveRequests.Add(cacheKey, true); + firstCall = true; + } + } + + if (firstCall) + { + try + { + List _members = d(); + + if (_members != null && _members.Count > 0) + members = _members.ConvertAll(new Converter(m_ForeignImporter.ConvertGroupMembersData)); + else + members = new List(); + + lock (m_Cache) + { + //m_Cache.AddOrUpdate(cacheKey, members, GROUPS_CACHE_TIMEOUT); + m_Cache.AddOrUpdate(cacheKey, _members, GROUPS_CACHE_TIMEOUT); + + return (List)members; + } + } + finally + { + m_ActiveRequests.Remove(cacheKey); + } + } + else + Thread.Sleep(50); + } + } + + public bool AddGroupRole(UUID groupID, UUID roleID, string description, string name, ulong powers, string title, BooleanDelegate d) + { + if (d()) + { + GroupRolesData role = new GroupRolesData(); + role.Description = description; + role.Members = 0; + role.Name = name; + role.Powers = powers; + role.RoleID = roleID; + role.Title = title; + + lock (m_Cache) + { + m_Cache.AddOrUpdate("role-" + roleID.ToString(), role, GROUPS_CACHE_TIMEOUT); + + // also remove this list + if (m_Cache.Contains("roles-" + groupID.ToString())) + m_Cache.Remove("roles-" + groupID.ToString()); + + } + + return true; + } + + return false; + } + + public bool UpdateGroupRole(UUID groupID, UUID roleID, string name, string description, string title, ulong powers, BooleanDelegate d) + { + if (d()) + { + object role; + lock (m_Cache) + if (m_Cache.TryGetValue("role-" + roleID.ToString(), out role)) + { + GroupRolesData r = (GroupRolesData)role; + r.Description = description; + r.Name = name; + r.Powers = powers; + r.Title = title; + + m_Cache.Update("role-" + roleID.ToString(), r, GROUPS_CACHE_TIMEOUT); + } + return true; + } + else + { + lock (m_Cache) + { + if (m_Cache.Contains("role-" + roleID.ToString())) + m_Cache.Remove("role-" + roleID.ToString()); + + // also remove these lists, because they will have an outdated role + if (m_Cache.Contains("roles-" + groupID.ToString())) + m_Cache.Remove("roles-" + groupID.ToString()); + + } + + return false; + } + } + + public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, VoidDelegate d) + { + d(); + + lock (m_Cache) + { + if (m_Cache.Contains("role-" + roleID.ToString())) + m_Cache.Remove("role-" + roleID.ToString()); + + // also remove the list, because it will have an removed role + if (m_Cache.Contains("roles-" + groupID.ToString())) + m_Cache.Remove("roles-" + groupID.ToString()); + + if (m_Cache.Contains("roles-" + groupID.ToString() + "-" + RequestingAgentID.ToString())) + m_Cache.Remove("roles-" + groupID.ToString() + "-" + RequestingAgentID.ToString()); + + if (m_Cache.Contains("rolemembers-" + RequestingAgentID.ToString() + "-" + groupID.ToString())) + m_Cache.Remove("rolemembers-" + RequestingAgentID.ToString() + "-" + groupID.ToString()); + } + } + + public List GetGroupRoles(string RequestingAgentID, UUID GroupID, GroupRolesListDelegate d) + { + object roles = null; + bool firstCall = false; + string cacheKey = "roles-" + GroupID.ToString(); + + while (true) + { + lock (m_Cache) + { + if (m_Cache.TryGetValue(cacheKey, out roles)) + return (List)roles; + + // not cached + if (!m_ActiveRequests.ContainsKey(cacheKey)) + { + m_ActiveRequests.Add(cacheKey, true); + firstCall = true; + } + } + + if (firstCall) + { + try + { + roles = d(); + if (roles != null) + { + lock (m_Cache) + { + m_Cache.AddOrUpdate(cacheKey, roles, GROUPS_CACHE_TIMEOUT); + return (List)roles; + } + } + } + finally + { + m_ActiveRequests.Remove(cacheKey); + } + } + else + Thread.Sleep(50); + } + } + + public List GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, RoleMembersListDelegate d) + { + object rmembers = null; + bool firstCall = false; + // we need to key in also on the requester, because different ppl have different view privileges + string cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString(); + + //m_log.DebugFormat("[XXX]: GetGroupRoleMembers {0}", cacheKey); + while (true) + { + lock (m_Cache) + { + if (m_Cache.TryGetValue(cacheKey, out rmembers)) + { + List xx = (List)rmembers; + return xx.ConvertAll(m_ForeignImporter.ConvertGroupRoleMembersData); + } + + // not cached + if (!m_ActiveRequests.ContainsKey(cacheKey)) + { + m_ActiveRequests.Add(cacheKey, true); + firstCall = true; + } + } + + if (firstCall) + { + try + { + List _rmembers = d(); + + if (_rmembers != null && _rmembers.Count > 0) + rmembers = _rmembers.ConvertAll(new Converter(m_ForeignImporter.ConvertGroupRoleMembersData)); + else + rmembers = new List(); + + lock (m_Cache) + { + // For some strange reason, when I cache the list of GroupRoleMembersData, + // it gets emptied out. The TryGet gets an empty list... + //m_Cache.AddOrUpdate(cacheKey, rmembers, GROUPS_CACHE_TIMEOUT); + // Caching the list of ExtendedGroupRoleMembersData doesn't show that issue + // I don't get it. + m_Cache.AddOrUpdate(cacheKey, _rmembers, GROUPS_CACHE_TIMEOUT); + return (List)rmembers; + } + } + finally + { + m_ActiveRequests.Remove(cacheKey); + } + } + else + Thread.Sleep(50); + } + } + + public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, BooleanDelegate d) + { + if (d()) + { + lock (m_Cache) + { + // update the cached role + string cacheKey = "role-" + RoleID.ToString(); + object obj; + if (m_Cache.TryGetValue(cacheKey, out obj)) + { + GroupRolesData r = (GroupRolesData)obj; + r.Members++; + } + + // add this agent to the list of role members + cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString(); + if (m_Cache.TryGetValue(cacheKey, out obj)) + { + try + { + // This may throw an exception, in which case the agentID is not a UUID but a full ID + // In that case, let's just remove the whoe things from the cache + UUID id = new UUID(AgentID); + List xx = (List)obj; + List rmlist = xx.ConvertAll(m_ForeignImporter.ConvertGroupRoleMembersData); + GroupRoleMembersData rm = new GroupRoleMembersData(); + rm.MemberID = id; + rm.RoleID = RoleID; + rmlist.Add(rm); + } + catch + { + m_Cache.Remove(cacheKey); + } + } + + // Remove the cached info about this agent's roles + // because we don't have enough local info about the new role + cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString(); + if (m_Cache.Contains(cacheKey)) + m_Cache.Remove(cacheKey); + + } + } + } + + public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, BooleanDelegate d) + { + if (d()) + { + lock (m_Cache) + { + // update the cached role + string cacheKey = "role-" + RoleID.ToString(); + object obj; + if (m_Cache.TryGetValue(cacheKey, out obj)) + { + GroupRolesData r = (GroupRolesData)obj; + r.Members--; + } + + cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString(); + if (m_Cache.Contains(cacheKey)) + m_Cache.Remove(cacheKey); + + cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString(); + if (m_Cache.Contains(cacheKey)) + m_Cache.Remove(cacheKey); + } + } + } + + public List GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID, GroupRolesListDelegate d) + { + object roles = null; + bool firstCall = false; + string cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString(); + + //m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0}", cacheKey); + + while (true) + { + lock (m_Cache) + { + if (m_Cache.TryGetValue(cacheKey, out roles)) + { + //m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0} cached!", cacheKey); + return (List)roles; + } + + // not cached + if (!m_ActiveRequests.ContainsKey(cacheKey)) + { + m_ActiveRequests.Add(cacheKey, true); + firstCall = true; + } + } + + if (firstCall) + { + try + { + roles = d(); + lock (m_Cache) + { + m_Cache.AddOrUpdate(cacheKey, roles, GROUPS_CACHE_TIMEOUT); + m_ActiveRequests.Remove(cacheKey); + return (List)roles; + } + } + finally + { + m_ActiveRequests.Remove(cacheKey); + } + } + else + Thread.Sleep(50); + } + } + + public void SetAgentActiveGroupRole(string AgentID, UUID GroupID, VoidDelegate d) + { + d(); + + lock (m_Cache) + { + // Invalidate cached info, because it has ActiveRoleID and Powers + string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString(); + if (m_Cache.Contains(cacheKey)) + m_Cache.Remove(cacheKey); + + cacheKey = "memberships-" + AgentID.ToString(); + if (m_Cache.Contains(cacheKey)) + m_Cache.Remove(cacheKey); + } + } + + public void UpdateMembership(string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile, VoidDelegate d) + { + d(); + + lock (m_Cache) + { + string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString(); + if (m_Cache.Contains(cacheKey)) + m_Cache.Remove(cacheKey); + + cacheKey = "memberships-" + AgentID.ToString(); + if (m_Cache.Contains(cacheKey)) + m_Cache.Remove(cacheKey); + + cacheKey = "active-" + AgentID.ToString(); + object m = null; + if (m_Cache.TryGetValue(cacheKey, out m)) + { + GroupMembershipData membership = (GroupMembershipData)m; + membership.ListInProfile = ListInProfile; + membership.AcceptNotices = AcceptNotices; + } + } + } + + public bool AddGroupNotice(UUID groupID, UUID noticeID, GroupNoticeInfo notice, BooleanDelegate d) + { + if (d()) + { + lock (m_Cache) + { + m_Cache.AddOrUpdate("notice-" + noticeID.ToString(), notice, GROUPS_CACHE_TIMEOUT); + string cacheKey = "notices-" + groupID.ToString(); + if (m_Cache.Contains(cacheKey)) + m_Cache.Remove(cacheKey); + + } + + return true; + } + + return false; + } + + public GroupNoticeInfo GetGroupNotice(UUID noticeID, NoticeDelegate d) + { + object notice = null; + bool firstCall = false; + string cacheKey = "notice-" + noticeID.ToString(); + + //m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0}", cacheKey); + + while (true) + { + lock (m_Cache) + { + if (m_Cache.TryGetValue(cacheKey, out notice)) + { + return (GroupNoticeInfo)notice; + } + + // not cached + if (!m_ActiveRequests.ContainsKey(cacheKey)) + { + m_ActiveRequests.Add(cacheKey, true); + firstCall = true; + } + } + + if (firstCall) + { + try + { + GroupNoticeInfo _notice = d(); + + lock (m_Cache) + { + m_Cache.AddOrUpdate(cacheKey, _notice, GROUPS_CACHE_TIMEOUT); + return _notice; + } + } + finally + { + m_ActiveRequests.Remove(cacheKey); + } + } + else + Thread.Sleep(50); + } + } + + public List GetGroupNotices(UUID GroupID, NoticeListDelegate d) + { + object notices = null; + bool firstCall = false; + string cacheKey = "notices-" + GroupID.ToString(); + + //m_log.DebugFormat("[XXX]: GetGroupNotices {0}", cacheKey); + + while (true) + { + lock (m_Cache) + { + if (m_Cache.TryGetValue(cacheKey, out notices)) + { + //m_log.DebugFormat("[XXX]: GetGroupNotices {0} cached!", cacheKey); + return (List)notices; + } + + // not cached + if (!m_ActiveRequests.ContainsKey(cacheKey)) + { + m_ActiveRequests.Add(cacheKey, true); + firstCall = true; + } + } + + if (firstCall) + { + try + { + notices = d(); + + lock (m_Cache) + { + m_Cache.AddOrUpdate(cacheKey, notices, GROUPS_CACHE_TIMEOUT); + return (List)notices; + } + } + finally + { + m_ActiveRequests.Remove(cacheKey); + } + } + else + Thread.Sleep(50); + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Addons/Groups/Service/GroupsService.cs b/OpenSim/Addons/Groups/Service/GroupsService.cs new file mode 100644 index 0000000..07641ef --- /dev/null +++ b/OpenSim/Addons/Groups/Service/GroupsService.cs @@ -0,0 +1,1060 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Timers; +using log4net; +using Nini.Config; + +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Groups +{ + public class GroupsService : GroupsServiceBase + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public const GroupPowers DefaultEveryonePowers = GroupPowers.AllowSetHome | + GroupPowers.Accountable | + GroupPowers.JoinChat | + GroupPowers.AllowVoiceChat | + GroupPowers.ReceiveNotices | + GroupPowers.StartProposal | + GroupPowers.VoteOnProposal; + + public const GroupPowers OwnerPowers = GroupPowers.Accountable | + GroupPowers.AllowEditLand | + GroupPowers.AllowFly | + GroupPowers.AllowLandmark | + GroupPowers.AllowRez | + GroupPowers.AllowSetHome | + GroupPowers.AllowVoiceChat | + GroupPowers.AssignMember | + GroupPowers.AssignMemberLimited | + GroupPowers.ChangeActions | + GroupPowers.ChangeIdentity | + GroupPowers.ChangeMedia | + GroupPowers.ChangeOptions | + GroupPowers.CreateRole | + GroupPowers.DeedObject | + GroupPowers.DeleteRole | + GroupPowers.Eject | + GroupPowers.FindPlaces | + GroupPowers.HostEvent | + GroupPowers.Invite | + GroupPowers.JoinChat | + GroupPowers.LandChangeIdentity | + GroupPowers.LandDeed | + GroupPowers.LandDivideJoin | + GroupPowers.LandEdit | + GroupPowers.LandEjectAndFreeze | + GroupPowers.LandGardening | + GroupPowers.LandManageAllowed | + GroupPowers.LandManageBanned | + GroupPowers.LandManagePasses | + GroupPowers.LandOptions | + GroupPowers.LandRelease | + GroupPowers.LandSetSale | + GroupPowers.ModerateChat | + GroupPowers.ObjectManipulate | + GroupPowers.ObjectSetForSale | + GroupPowers.ReceiveNotices | + GroupPowers.RemoveMember | + GroupPowers.ReturnGroupOwned | + GroupPowers.ReturnGroupSet | + GroupPowers.ReturnNonGroup | + GroupPowers.RoleProperties | + GroupPowers.SendNotices | + GroupPowers.SetLandingPoint | + GroupPowers.StartProposal | + GroupPowers.VoteOnProposal; + + #region Daily Cleanup + + private Timer m_CleanupTimer; + + public GroupsService(IConfigSource config, string configName) + : base(config, configName) + { + } + + public GroupsService(IConfigSource config) + : this(config, string.Empty) + { + // Once a day + m_CleanupTimer = new Timer(24 * 60 * 60 * 1000); + m_CleanupTimer.AutoReset = true; + m_CleanupTimer.Elapsed += new ElapsedEventHandler(m_CleanupTimer_Elapsed); + m_CleanupTimer.Enabled = true; + m_CleanupTimer.Start(); + } + + private void m_CleanupTimer_Elapsed(object sender, ElapsedEventArgs e) + { + m_Database.DeleteOldNotices(); + m_Database.DeleteOldInvites(); + } + + #endregion + + public UUID CreateGroup(string RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, + bool allowPublish, bool maturePublish, UUID founderID, out string reason) + { + reason = string.Empty; + + // Check if the group already exists + if (m_Database.RetrieveGroup(name) != null) + { + reason = "A group with that name already exists"; + return UUID.Zero; + } + + // Create the group + GroupData data = new GroupData(); + data.GroupID = UUID.Random(); + data.Data = new Dictionary(); + data.Data["Name"] = name; + data.Data["Charter"] = charter; + data.Data["InsigniaID"] = insigniaID.ToString(); + data.Data["FounderID"] = founderID.ToString(); + data.Data["MembershipFee"] = membershipFee.ToString(); + data.Data["OpenEnrollment"] = openEnrollment ? "1" : "0"; + data.Data["ShowInList"] = showInList ? "1" : "0"; + data.Data["AllowPublish"] = allowPublish ? "1" : "0"; + data.Data["MaturePublish"] = maturePublish ? "1" : "0"; + UUID roleID = UUID.Random(); + data.Data["OwnerRoleID"] = roleID.ToString(); + + if (!m_Database.StoreGroup(data)) + return UUID.Zero; + + // Create Everyone role + _AddOrUpdateGroupRole(RequestingAgentID, data.GroupID, UUID.Zero, "Everyone", "Everyone in the group", "Member of " + name, (ulong)DefaultEveryonePowers, true); + + // Create Owner role + _AddOrUpdateGroupRole(RequestingAgentID, data.GroupID, roleID, "Owners", "Owners of the group", "Owner of " + name, (ulong)OwnerPowers, true); + + // Add founder to group + _AddAgentToGroup(RequestingAgentID, founderID.ToString(), data.GroupID, roleID); + + return data.GroupID; + } + + public void UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish) + { + GroupData data = m_Database.RetrieveGroup(groupID); + if (data == null) + return; + + // Check perms + if (!HasPower(RequestingAgentID, groupID, GroupPowers.ChangeActions)) + { + m_log.DebugFormat("[Groups]: ({0}) Attempt at updating group {1} denied because of lack of permission", RequestingAgentID, groupID); + return; + } + + data.GroupID = groupID; + data.Data["Charter"] = charter; + data.Data["ShowInList"] = showInList ? "1" : "0"; + data.Data["InsigniaID"] = insigniaID.ToString(); + data.Data["MembershipFee"] = membershipFee.ToString(); + data.Data["OpenEnrollment"] = openEnrollment ? "1" : "0"; + data.Data["AllowPublish"] = allowPublish ? "1" : "0"; + data.Data["MaturePublish"] = maturePublish ? "1" : "0"; + + m_Database.StoreGroup(data); + + } + + public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID) + { + GroupData data = m_Database.RetrieveGroup(GroupID); + + return _GroupDataToRecord(data); + } + + public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, string GroupName) + { + GroupData data = m_Database.RetrieveGroup(GroupName); + + return _GroupDataToRecord(data); + } + + public List FindGroups(string RequestingAgentID, string search) + { + List groups = new List(); + + GroupData[] data = m_Database.RetrieveGroups(search); + + if (data != null && data.Length > 0) + { + foreach (GroupData d in data) + { + // Don't list group proxies + if (d.Data.ContainsKey("Location") && d.Data["Location"] != string.Empty) + continue; + + DirGroupsReplyData g = new DirGroupsReplyData(); + g.groupID = d.GroupID; + + if (d.Data.ContainsKey("Name")) + g.groupName = d.Data["Name"]; + else + m_log.DebugFormat("[Groups]: Key Name not found"); + + g.members = m_Database.MemberCount(d.GroupID); + + groups.Add(g); + } + } + + return groups; + } + + public List GetGroupMembers(string RequestingAgentID, UUID GroupID) + { + List members = new List(); + + GroupData group = m_Database.RetrieveGroup(GroupID); + if (group == null) + return members; + + // Unfortunately this doesn't quite work on legacy group data because of a bug + // that's also being fixed here on CreateGroup. The OwnerRoleID sent to the DB was wrong. + // See how to find the ownerRoleID a few lines below. + UUID ownerRoleID = new UUID(group.Data["OwnerRoleID"]); + + RoleData[] roles = m_Database.RetrieveRoles(GroupID); + if (roles == null) + // something wrong with this group + return members; + List rolesList = new List(roles); + + // Let's find the "real" ownerRoleID + RoleData ownerRole = rolesList.Find(r => r.Data["Powers"] == ((long)OwnerPowers).ToString()); + if (ownerRole != null) + ownerRoleID = ownerRole.RoleID; + + // Check visibility? + // When we don't want to check visibility, we pass it "all" as the requestingAgentID + bool checkVisibility = !RequestingAgentID.Equals(UUID.Zero.ToString()); + + if (checkVisibility) + { + // Is the requester a member of the group? + bool isInGroup = false; + if (m_Database.RetrieveMember(GroupID, RequestingAgentID) != null) + isInGroup = true; + + if (!isInGroup) // reduce the roles to the visible ones + rolesList = rolesList.FindAll(r => (UInt64.Parse(r.Data["Powers"]) & (ulong)GroupPowers.MemberVisible) != 0); + } + + MembershipData[] datas = m_Database.RetrieveMembers(GroupID); + if (datas == null || (datas != null && datas.Length == 0)) + return members; + + // OK, we have everything we need + + foreach (MembershipData d in datas) + { + RoleMembershipData[] rolememberships = m_Database.RetrieveMemberRoles(GroupID, d.PrincipalID); + List rolemembershipsList = new List(rolememberships); + + ExtendedGroupMembersData m = new ExtendedGroupMembersData(); + + // What's this person's current role in the group? + UUID selectedRole = new UUID(d.Data["SelectedRoleID"]); + RoleData selected = rolesList.Find(r => r.RoleID == selectedRole); + + if (selected != null) + { + m.Title = selected.Data["Title"]; + m.AgentPowers = UInt64.Parse(selected.Data["Powers"]); + } + + m.AgentID = d.PrincipalID; + m.AcceptNotices = d.Data["AcceptNotices"] == "1" ? true : false; + m.Contribution = Int32.Parse(d.Data["Contribution"]); + m.ListInProfile = d.Data["ListInProfile"] == "1" ? true : false; + + GridUserData gud = m_GridUserService.Get(d.PrincipalID); + if (gud != null) + { + if (bool.Parse(gud.Data["Online"])) + { + m.OnlineStatus = @"Online"; + } + else + { + int unixtime = int.Parse(gud.Data["Login"]); + // The viewer is very picky about how these strings are formed. Eg. it will crash on malformed dates! + m.OnlineStatus = (unixtime == 0) ? @"unknown" : Util.ToDateTime(unixtime).ToString("MM/dd/yyyy"); + } + } + + // Is this person an owner of the group? + m.IsOwner = (rolemembershipsList.Find(r => r.RoleID == ownerRoleID) != null) ? true : false; + + members.Add(m); + } + + return members; + } + + public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason) + { + reason = string.Empty; + // check that the requesting agent has permissions to add role + if (!HasPower(RequestingAgentID, groupID, GroupPowers.CreateRole)) + { + m_log.DebugFormat("[Groups]: ({0}) Attempt at creating role in group {1} denied because of lack of permission", RequestingAgentID, groupID); + reason = "Insufficient permission to create role"; + return false; + } + + return _AddOrUpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, true); + + } + + public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers) + { + // check perms + if (!HasPower(RequestingAgentID, groupID, GroupPowers.ChangeActions)) + { + m_log.DebugFormat("[Groups]: ({0}) Attempt at changing role in group {1} denied because of lack of permission", RequestingAgentID, groupID); + return false; + } + + return _AddOrUpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, false); + } + + public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID) + { + // check perms + if (!HasPower(RequestingAgentID, groupID, GroupPowers.DeleteRole)) + { + m_log.DebugFormat("[Groups]: ({0}) Attempt at deleting role from group {1} denied because of lack of permission", RequestingAgentID, groupID); + return; + } + + // Can't delete Everyone and Owners roles + if (roleID == UUID.Zero) + { + m_log.DebugFormat("[Groups]: Attempt at deleting Everyone role from group {0} denied", groupID); + return; + } + + GroupData group = m_Database.RetrieveGroup(groupID); + if (group == null) + { + m_log.DebugFormat("[Groups]: Attempt at deleting role from non-existing group {0}", groupID); + return; + } + + if (roleID == new UUID(group.Data["OwnerRoleID"])) + { + m_log.DebugFormat("[Groups]: Attempt at deleting Owners role from group {0} denied", groupID); + return; + } + + _RemoveGroupRole(groupID, roleID); + } + + public List GetGroupRoles(string RequestingAgentID, UUID GroupID) + { + // TODO: check perms + return _GetGroupRoles(GroupID); + } + + public List GetGroupRoleMembers(string RequestingAgentID, UUID GroupID) + { + // TODO: check perms + + // Is the requester a member of the group? + bool isInGroup = false; + if (m_Database.RetrieveMember(GroupID, RequestingAgentID) != null) + isInGroup = true; + + return _GetGroupRoleMembers(GroupID, isInGroup); + } + + public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason) + { + reason = string.Empty; + + _AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, token); + + return true; + } + + public bool RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) + { + // check perms + if (RequestingAgentID != AgentID && !HasPower(RequestingAgentID, GroupID, GroupPowers.Eject)) + return false; + + _RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID); + + return true; + } + + public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID) + { + // Check whether the invitee is already a member of the group + MembershipData m = m_Database.RetrieveMember(groupID, agentID); + if (m != null) + return false; + + // Check permission to invite + if (!HasPower(RequestingAgentID, groupID, GroupPowers.Invite)) + { + m_log.DebugFormat("[Groups]: ({0}) Attempt at inviting to group {1} denied because of lack of permission", RequestingAgentID, groupID); + return false; + } + + // Check whether there are pending invitations and delete them + InvitationData invite = m_Database.RetrieveInvitation(groupID, agentID); + if (invite != null) + m_Database.DeleteInvite(invite.InviteID); + + invite = new InvitationData(); + invite.InviteID = inviteID; + invite.PrincipalID = agentID; + invite.GroupID = groupID; + invite.RoleID = roleID; + invite.Data = new Dictionary(); + + return m_Database.StoreInvitation(invite); + } + + public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID) + { + InvitationData data = m_Database.RetrieveInvitation(inviteID); + + if (data == null) + return null; + + GroupInviteInfo inviteInfo = new GroupInviteInfo(); + inviteInfo.AgentID = data.PrincipalID; + inviteInfo.GroupID = data.GroupID; + inviteInfo.InviteID = data.InviteID; + inviteInfo.RoleID = data.RoleID; + + return inviteInfo; + } + + public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID) + { + m_Database.DeleteInvite(inviteID); + } + + public bool AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + //if (!m_Database.CheckOwnerRole(RequestingAgentID, GroupID, RoleID)) + // return; + + // check permissions + bool limited = HasPower(RequestingAgentID, GroupID, GroupPowers.AssignMemberLimited); + bool unlimited = HasPower(RequestingAgentID, GroupID, GroupPowers.AssignMember) | IsOwner(RequestingAgentID, GroupID); + if (!limited || !unlimited) + { + m_log.DebugFormat("[Groups]: ({0}) Attempt at assigning {1} to role {2} denied because of lack of permission", RequestingAgentID, AgentID, RoleID); + return false; + } + + // AssignMemberLimited means that the person can assign another person to the same roles that she has in the group + if (!unlimited && limited) + { + // check whether person's has this role + RoleMembershipData rolemembership = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID); + if (rolemembership == null) + { + m_log.DebugFormat("[Groups]: ({0}) Attempt at assigning {1} to role {2} denied because of limited permission", RequestingAgentID, AgentID, RoleID); + return false; + } + } + + _AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); + + return true; + } + + public bool RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + // Don't remove from Everyone role! + if (RoleID == UUID.Zero) + return false; + + // check permissions + bool unlimited = HasPower(RequestingAgentID, GroupID, GroupPowers.AssignMember) || IsOwner(RequestingAgentID, GroupID); + if (!unlimited) + { + m_log.DebugFormat("[Groups]: ({0}) Attempt at removing {1} from role {2} denied because of lack of permission", RequestingAgentID, AgentID, RoleID); + return false; + } + + RoleMembershipData rolemember = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID); + + if (rolemember == null) + return false; + + m_Database.DeleteRoleMember(rolemember); + + // Find another role for this person + UUID newRoleID = UUID.Zero; // Everyone + RoleMembershipData[] rdata = m_Database.RetrieveMemberRoles(GroupID, AgentID); + if (rdata != null) + foreach (RoleMembershipData r in rdata) + { + if (r.RoleID != UUID.Zero) + { + newRoleID = r.RoleID; + break; + } + } + + MembershipData member = m_Database.RetrieveMember(GroupID, AgentID); + if (member != null) + { + member.Data["SelectedRoleID"] = newRoleID.ToString(); + m_Database.StoreMember(member); + } + + return true; + } + + public List GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID) + { + List roles = new List(); + // TODO: check permissions + + RoleMembershipData[] data = m_Database.RetrieveMemberRoles(GroupID, AgentID); + if (data == null || (data != null && data.Length ==0)) + return roles; + + foreach (RoleMembershipData d in data) + { + RoleData rdata = m_Database.RetrieveRole(GroupID, d.RoleID); + if (rdata == null) // hippos + continue; + + GroupRolesData r = new GroupRolesData(); + r.Name = rdata.Data["Name"]; + r.Powers = UInt64.Parse(rdata.Data["Powers"]); + r.RoleID = rdata.RoleID; + r.Title = rdata.Data["Title"]; + + roles.Add(r); + } + + return roles; + } + + public ExtendedGroupMembershipData SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID) + { + // TODO: check perms + PrincipalData principal = new PrincipalData(); + principal.PrincipalID = AgentID; + principal.ActiveGroupID = GroupID; + m_Database.StorePrincipal(principal); + + return GetAgentGroupMembership(RequestingAgentID, AgentID, GroupID); + } + + public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID) + { + // 1. get the principal data for the active group + PrincipalData principal = m_Database.RetrievePrincipal(AgentID); + if (principal == null) + return null; + + return GetAgentGroupMembership(RequestingAgentID, AgentID, principal.ActiveGroupID); + } + + public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID) + { + return GetAgentGroupMembership(RequestingAgentID, AgentID, GroupID, null); + } + + private ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID, MembershipData membership) + { + // 2. get the active group + GroupData group = m_Database.RetrieveGroup(GroupID); + if (group == null) + return null; + + // 3. get the membership info if we don't have it already + if (membership == null) + { + membership = m_Database.RetrieveMember(group.GroupID, AgentID); + if (membership == null) + return null; + } + + // 4. get the active role + UUID activeRoleID = new UUID(membership.Data["SelectedRoleID"]); + RoleData role = m_Database.RetrieveRole(group.GroupID, activeRoleID); + + ExtendedGroupMembershipData data = new ExtendedGroupMembershipData(); + data.AcceptNotices = membership.Data["AcceptNotices"] == "1" ? true : false; + data.AccessToken = membership.Data["AccessToken"]; + data.Active = true; + data.ActiveRole = activeRoleID; + data.AllowPublish = group.Data["AllowPublish"] == "1" ? true : false; + data.Charter = group.Data["Charter"]; + data.Contribution = Int32.Parse(membership.Data["Contribution"]); + data.FounderID = new UUID(group.Data["FounderID"]); + data.GroupID = new UUID(group.GroupID); + data.GroupName = group.Data["Name"]; + data.GroupPicture = new UUID(group.Data["InsigniaID"]); + if (role != null) + { + data.GroupPowers = UInt64.Parse(role.Data["Powers"]); + data.GroupTitle = role.Data["Title"]; + } + data.ListInProfile = membership.Data["ListInProfile"] == "1" ? true : false; + data.MaturePublish = group.Data["MaturePublish"] == "1" ? true : false; + data.MembershipFee = Int32.Parse(group.Data["MembershipFee"]); + data.OpenEnrollment = group.Data["OpenEnrollment"] == "1" ? true : false; + data.ShowInList = group.Data["ShowInList"] == "1" ? true : false; + + return data; + } + + public List GetAgentGroupMemberships(string RequestingAgentID, string AgentID) + { + List memberships = new List(); + + // 1. Get all the groups that this person is a member of + MembershipData[] mdata = m_Database.RetrieveMemberships(AgentID); + + if (mdata == null || (mdata != null && mdata.Length == 0)) + return memberships; + + foreach (MembershipData d in mdata) + { + GroupMembershipData gmember = GetAgentGroupMembership(RequestingAgentID, AgentID, d.GroupID, d); + if (gmember != null) + { + memberships.Add(gmember); + //m_log.DebugFormat("[XXX]: Member of {0} as {1}", gmember.GroupName, gmember.GroupTitle); + //Util.PrintCallStack(); + } + } + + return memberships; + } + + public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + MembershipData data = m_Database.RetrieveMember(GroupID, AgentID); + if (data == null) + return; + + data.Data["SelectedRoleID"] = RoleID.ToString(); + m_Database.StoreMember(data); + } + + public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile) + { + // TODO: check perms + + MembershipData membership = m_Database.RetrieveMember(GroupID, AgentID); + if (membership == null) + return; + + membership.Data["AcceptNotices"] = AcceptNotices ? "1" : "0"; + membership.Data["ListInProfile"] = ListInProfile ? "1" : "0"; + + m_Database.StoreMember(membership); + } + + public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, + bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) + { + // Check perms + if (!HasPower(RequestingAgentID, groupID, GroupPowers.SendNotices)) + { + m_log.DebugFormat("[Groups]: ({0}) Attempt at sending notice to group {1} denied because of lack of permission", RequestingAgentID, groupID); + return false; + } + + return _AddNotice(groupID, noticeID, fromName, subject, message, hasAttachment, attType, attName, attItemID, attOwnerID); + } + + public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID) + { + NoticeData data = m_Database.RetrieveNotice(noticeID); + + if (data == null) + return null; + + return _NoticeDataToInfo(data); + } + + public List GetGroupNotices(string RequestingAgentID, UUID groupID) + { + NoticeData[] data = m_Database.RetrieveNotices(groupID); + List infos = new List(); + + if (data == null || (data != null && data.Length == 0)) + return infos; + + foreach (NoticeData d in data) + { + ExtendedGroupNoticeData info = _NoticeDataToData(d); + infos.Add(info); + } + + return infos; + } + + public void ResetAgentGroupChatSessions(string agentID) + { + } + + public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID) + { + return false; + } + + public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID) + { + return false; + } + + public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID) + { + } + + public void AgentInvitedToGroupChatSession(string agentID, UUID groupID) + { + } + + #region Actions without permission checks + + protected void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + _AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, string.Empty); + } + + protected void _RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) + { + // 1. Delete membership + m_Database.DeleteMember(GroupID, AgentID); + + // 2. Remove from rolememberships + m_Database.DeleteMemberAllRoles(GroupID, AgentID); + + // 3. if it was active group, inactivate it + PrincipalData principal = m_Database.RetrievePrincipal(AgentID); + if (principal != null && principal.ActiveGroupID == GroupID) + { + principal.ActiveGroupID = UUID.Zero; + m_Database.StorePrincipal(principal); + } + } + + protected void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string accessToken) + { + // Check if it's already there + MembershipData data = m_Database.RetrieveMember(GroupID, AgentID); + if (data != null) + return; + + // Add the membership + data = new MembershipData(); + data.PrincipalID = AgentID; + data.GroupID = GroupID; + data.Data = new Dictionary(); + data.Data["SelectedRoleID"] = RoleID.ToString(); + data.Data["Contribution"] = "0"; + data.Data["ListInProfile"] = "1"; + data.Data["AcceptNotices"] = "1"; + data.Data["AccessToken"] = accessToken; + + m_Database.StoreMember(data); + + // Add principal to everyone role + _AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, UUID.Zero); + + // Add principal to role, if different from everyone role + if (RoleID != UUID.Zero) + _AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); + + // Make thit this active group + PrincipalData pdata = new PrincipalData(); + pdata.PrincipalID = AgentID; + pdata.ActiveGroupID = GroupID; + m_Database.StorePrincipal(pdata); + + } + + protected bool _AddOrUpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, bool add) + { + RoleData data = m_Database.RetrieveRole(groupID, roleID); + + if (add && data != null) // it already exists, can't create + { + m_log.DebugFormat("[Groups]: Group {0} already exists. Can't create it again", groupID); + return false; + } + + if (!add && data == null) // it deosn't exist, can't update + { + m_log.DebugFormat("[Groups]: Group {0} doesn't exist. Can't update it", groupID); + return false; + } + + if (add) + data = new RoleData(); + + data.GroupID = groupID; + data.RoleID = roleID; + data.Data = new Dictionary(); + data.Data["Name"] = name; + data.Data["Description"] = description; + data.Data["Title"] = title; + data.Data["Powers"] = powers.ToString(); + + return m_Database.StoreRole(data); + } + + protected void _RemoveGroupRole(UUID groupID, UUID roleID) + { + m_Database.DeleteRole(groupID, roleID); + } + + protected void _AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + { + RoleMembershipData data = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID); + if (data != null) + return; + + data = new RoleMembershipData(); + data.GroupID = GroupID; + data.PrincipalID = AgentID; + data.RoleID = RoleID; + m_Database.StoreRoleMember(data); + + // Make it the SelectedRoleID + MembershipData membership = m_Database.RetrieveMember(GroupID, AgentID); + if (membership == null) + { + m_log.DebugFormat("[Groups]: ({0}) No such member {0} in group {1}", AgentID, GroupID); + return; + } + + membership.Data["SelectedRoleID"] = RoleID.ToString(); + m_Database.StoreMember(membership); + + } + + protected List _GetGroupRoles(UUID groupID) + { + List roles = new List(); + + RoleData[] data = m_Database.RetrieveRoles(groupID); + + if (data == null || (data != null && data.Length == 0)) + return roles; + + foreach (RoleData d in data) + { + GroupRolesData r = new GroupRolesData(); + r.Description = d.Data["Description"]; + r.Members = m_Database.RoleMemberCount(groupID, d.RoleID); + r.Name = d.Data["Name"]; + r.Powers = UInt64.Parse(d.Data["Powers"]); + r.RoleID = d.RoleID; + r.Title = d.Data["Title"]; + + roles.Add(r); + } + + return roles; + } + + protected List _GetGroupRoleMembers(UUID GroupID, bool isInGroup) + { + List rmembers = new List(); + + RoleData[] rdata = new RoleData[0]; + if (!isInGroup) + { + rdata = m_Database.RetrieveRoles(GroupID); + if (rdata == null || (rdata != null && rdata.Length == 0)) + return rmembers; + } + List rlist = new List(rdata); + if (!isInGroup) + rlist = rlist.FindAll(r => (UInt64.Parse(r.Data["Powers"]) & (ulong)GroupPowers.MemberVisible) != 0); + + RoleMembershipData[] data = m_Database.RetrieveRolesMembers(GroupID); + + if (data == null || (data != null && data.Length == 0)) + return rmembers; + + foreach (RoleMembershipData d in data) + { + if (!isInGroup) + { + RoleData rd = rlist.Find(_r => _r.RoleID == d.RoleID); // visible role + if (rd == null) + continue; + } + + ExtendedGroupRoleMembersData r = new ExtendedGroupRoleMembersData(); + r.MemberID = d.PrincipalID; + r.RoleID = d.RoleID; + + rmembers.Add(r); + } + + return rmembers; + } + + protected bool _AddNotice(UUID groupID, UUID noticeID, string fromName, string subject, string message, + bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) + { + NoticeData data = new NoticeData(); + data.GroupID = groupID; + data.NoticeID = noticeID; + data.Data = new Dictionary(); + data.Data["FromName"] = fromName; + data.Data["Subject"] = subject; + data.Data["Message"] = message; + data.Data["HasAttachment"] = hasAttachment ? "1" : "0"; + if (hasAttachment) + { + data.Data["AttachmentType"] = attType.ToString(); + data.Data["AttachmentName"] = attName; + data.Data["AttachmentItemID"] = attItemID.ToString(); + data.Data["AttachmentOwnerID"] = attOwnerID; + } + data.Data["TMStamp"] = ((uint)Util.UnixTimeSinceEpoch()).ToString(); + + return m_Database.StoreNotice(data); + } + + #endregion + + #region structure translations + ExtendedGroupRecord _GroupDataToRecord(GroupData data) + { + if (data == null) + return null; + + ExtendedGroupRecord rec = new ExtendedGroupRecord(); + rec.AllowPublish = data.Data["AllowPublish"] == "1" ? true : false; + rec.Charter = data.Data["Charter"]; + rec.FounderID = new UUID(data.Data["FounderID"]); + rec.GroupID = data.GroupID; + rec.GroupName = data.Data["Name"]; + rec.GroupPicture = new UUID(data.Data["InsigniaID"]); + rec.MaturePublish = data.Data["MaturePublish"] == "1" ? true : false; + rec.MembershipFee = Int32.Parse(data.Data["MembershipFee"]); + rec.OpenEnrollment = data.Data["OpenEnrollment"] == "1" ? true : false; + rec.OwnerRoleID = new UUID(data.Data["OwnerRoleID"]); + rec.ShowInList = data.Data["ShowInList"] == "1" ? true : false; + rec.ServiceLocation = data.Data["Location"]; + rec.MemberCount = m_Database.MemberCount(data.GroupID); + rec.RoleCount = m_Database.RoleCount(data.GroupID); + + return rec; + } + + GroupNoticeInfo _NoticeDataToInfo(NoticeData data) + { + GroupNoticeInfo notice = new GroupNoticeInfo(); + notice.GroupID = data.GroupID; + notice.Message = data.Data["Message"]; + notice.noticeData = _NoticeDataToData(data); + + return notice; + } + + ExtendedGroupNoticeData _NoticeDataToData(NoticeData data) + { + ExtendedGroupNoticeData notice = new ExtendedGroupNoticeData(); + notice.FromName = data.Data["FromName"]; + notice.NoticeID = data.NoticeID; + notice.Subject = data.Data["Subject"]; + notice.Timestamp = uint.Parse((string)data.Data["TMStamp"]); + notice.HasAttachment = data.Data["HasAttachment"] == "1" ? true : false; + if (notice.HasAttachment) + { + notice.AttachmentName = data.Data["AttachmentName"]; + notice.AttachmentItemID = new UUID(data.Data["AttachmentItemID"].ToString()); + notice.AttachmentType = byte.Parse(data.Data["AttachmentType"].ToString()); + notice.AttachmentOwnerID = data.Data["AttachmentOwnerID"].ToString(); + } + + + return notice; + } + + #endregion + + #region permissions + private bool HasPower(string agentID, UUID groupID, GroupPowers power) + { + RoleMembershipData[] rmembership = m_Database.RetrieveMemberRoles(groupID, agentID); + if (rmembership == null || (rmembership != null && rmembership.Length == 0)) + return false; + + foreach (RoleMembershipData rdata in rmembership) + { + RoleData role = m_Database.RetrieveRole(groupID, rdata.RoleID); + if ( (UInt64.Parse(role.Data["Powers"]) & (ulong)power) != 0 ) + return true; + } + return false; + } + + private bool IsOwner(string agentID, UUID groupID) + { + GroupData group = m_Database.RetrieveGroup(groupID); + if (group == null) + return false; + + RoleMembershipData rmembership = m_Database.RetrieveRoleMember(groupID, new UUID(group.Data["OwnerRoleID"]), agentID); + if (rmembership == null) + return false; + + return true; + } + #endregion + + } +} diff --git a/OpenSim/Addons/Groups/Service/GroupsServiceBase.cs b/OpenSim/Addons/Groups/Service/GroupsServiceBase.cs new file mode 100644 index 0000000..8e237aa --- /dev/null +++ b/OpenSim/Addons/Groups/Service/GroupsServiceBase.cs @@ -0,0 +1,101 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Data; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Base; + +namespace OpenSim.Groups +{ + public class GroupsServiceBase : ServiceBase + { + protected IGroupsData m_Database = null; + protected IGridUserData m_GridUserService = null; + + public GroupsServiceBase(IConfigSource config, string cName) + : base(config) + { + string dllName = String.Empty; + string connString = String.Empty; + string realm = "os_groups"; + string usersRealm = "GridUser"; + string configName = (cName == string.Empty) ? "Groups" : cName; + + // + // Try reading the [DatabaseService] section, if it exists + // + IConfig dbConfig = config.Configs["DatabaseService"]; + if (dbConfig != null) + { + if (dllName == String.Empty) + dllName = dbConfig.GetString("StorageProvider", String.Empty); + if (connString == String.Empty) + connString = dbConfig.GetString("ConnectionString", String.Empty); + } + + // + // [Groups] section overrides [DatabaseService], if it exists + // + IConfig groupsConfig = config.Configs[configName]; + if (groupsConfig != null) + { + dllName = groupsConfig.GetString("StorageProvider", dllName); + connString = groupsConfig.GetString("ConnectionString", connString); + realm = groupsConfig.GetString("Realm", realm); + } + + // + // We tried, but this doesn't exist. We can't proceed. + // + if (dllName.Equals(String.Empty)) + throw new Exception("No StorageProvider configured"); + + m_Database = LoadPlugin(dllName, new Object[] { connString, realm }); + if (m_Database == null) + throw new Exception("Could not find a storage interface in the given module " + dllName); + + // + // [GridUserService] section overrides [DatabaseService], if it exists + // + IConfig usersConfig = config.Configs["GridUserService"]; + if (usersConfig != null) + { + dllName = usersConfig.GetString("StorageProvider", dllName); + connString = usersConfig.GetString("ConnectionString", connString); + usersRealm = usersConfig.GetString("Realm", usersRealm); + } + + m_GridUserService = LoadPlugin(dllName, new Object[] { connString, usersRealm }); + if (m_GridUserService == null) + throw new Exception("Could not find a storage inferface for the given users module " + dllName); + } + } +} diff --git a/OpenSim/Addons/Groups/Service/HGGroupsService.cs b/OpenSim/Addons/Groups/Service/HGGroupsService.cs new file mode 100644 index 0000000..56e999b --- /dev/null +++ b/OpenSim/Addons/Groups/Service/HGGroupsService.cs @@ -0,0 +1,361 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Timers; +using log4net; +using Nini.Config; + +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Groups +{ + public class HGGroupsService : GroupsService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IOfflineIMService m_OfflineIM; + private IUserAccountService m_UserAccounts; + private string m_HomeURI; + + public HGGroupsService(IConfigSource config, IOfflineIMService im, IUserAccountService users, string homeURI) + : base(config, string.Empty) + { + m_OfflineIM = im; + m_UserAccounts = users; + m_HomeURI = homeURI; + if (!m_HomeURI.EndsWith("/")) + m_HomeURI += "/"; + } + + + #region HG specific operations + + public bool CreateGroupProxy(string RequestingAgentID, string agentID, string accessToken, UUID groupID, string serviceLocation, string name, out string reason) + { + reason = string.Empty; + Uri uri = null; + try + { + uri = new Uri(serviceLocation); + } + catch (UriFormatException) + { + reason = "Bad location for group proxy"; + return false; + } + + // Check if it already exists + GroupData grec = m_Database.RetrieveGroup(groupID); + if (grec == null || + (grec != null && grec.Data["Location"] != string.Empty && grec.Data["Location"].ToLower() != serviceLocation.ToLower())) + { + // Create the group + grec = new GroupData(); + grec.GroupID = groupID; + grec.Data = new Dictionary(); + grec.Data["Name"] = name + " @ " + uri.Authority; + grec.Data["Location"] = serviceLocation; + grec.Data["Charter"] = string.Empty; + grec.Data["InsigniaID"] = UUID.Zero.ToString(); + grec.Data["FounderID"] = UUID.Zero.ToString(); + grec.Data["MembershipFee"] = "0"; + grec.Data["OpenEnrollment"] = "0"; + grec.Data["ShowInList"] = "0"; + grec.Data["AllowPublish"] = "0"; + grec.Data["MaturePublish"] = "0"; + grec.Data["OwnerRoleID"] = UUID.Zero.ToString(); + + + if (!m_Database.StoreGroup(grec)) + return false; + } + + if (grec.Data["Location"] == string.Empty) + { + reason = "Cannot add proxy membership to non-proxy group"; + return false; + } + + UUID uid = UUID.Zero; + string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty; + Util.ParseUniversalUserIdentifier(RequestingAgentID, out uid, out url, out first, out last, out tmp); + string fromName = first + "." + last + "@" + url; + + // Invite to group again + InviteToGroup(fromName, groupID, new UUID(agentID), grec.Data["Name"]); + + // Stick the proxy membership in the DB already + // we'll delete it if the agent declines the invitation + MembershipData membership = new MembershipData(); + membership.PrincipalID = agentID; + membership.GroupID = groupID; + membership.Data = new Dictionary(); + membership.Data["SelectedRoleID"] = UUID.Zero.ToString(); + membership.Data["Contribution"] = "0"; + membership.Data["ListInProfile"] = "1"; + membership.Data["AcceptNotices"] = "1"; + membership.Data["AccessToken"] = accessToken; + + m_Database.StoreMember(membership); + + return true; + } + + public bool RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID, string token) + { + // check the token + MembershipData membership = m_Database.RetrieveMember(GroupID, AgentID); + if (membership != null) + { + if (token != string.Empty && token.Equals(membership.Data["AccessToken"])) + { + return RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID); + } + else + { + m_log.DebugFormat("[Groups.HGGroupsService]: access token {0} did not match stored one {1}", token, membership.Data["AccessToken"]); + return false; + } + } + else + { + m_log.DebugFormat("[Groups.HGGroupsService]: membership not found for {0}", AgentID); + return false; + } + } + + public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string groupName, string token) + { + // check the token + if (!VerifyToken(GroupID, RequestingAgentID, token)) + return null; + + ExtendedGroupRecord grec; + if (GroupID == UUID.Zero) + grec = GetGroupRecord(RequestingAgentID, groupName); + else + grec = GetGroupRecord(RequestingAgentID, GroupID); + + if (grec != null) + FillFounderUUI(grec); + + return grec; + } + + public List GetGroupMembers(string RequestingAgentID, UUID GroupID, string token) + { + if (!VerifyToken(GroupID, RequestingAgentID, token)) + return new List(); + + List members = GetGroupMembers(RequestingAgentID, GroupID); + + // convert UUIDs to UUIs + members.ForEach(delegate (ExtendedGroupMembersData m) + { + if (m.AgentID.ToString().Length == 36) // UUID + { + UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, new UUID(m.AgentID)); + if (account != null) + m.AgentID = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI); + } + }); + + return members; + } + + public List GetGroupRoles(string RequestingAgentID, UUID GroupID, string token) + { + if (!VerifyToken(GroupID, RequestingAgentID, token)) + return new List(); + + return GetGroupRoles(RequestingAgentID, GroupID); + } + + public List GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, string token) + { + if (!VerifyToken(GroupID, RequestingAgentID, token)) + return new List(); + + List rolemembers = GetGroupRoleMembers(RequestingAgentID, GroupID); + + // convert UUIDs to UUIs + rolemembers.ForEach(delegate(ExtendedGroupRoleMembersData m) + { + if (m.MemberID.ToString().Length == 36) // UUID + { + UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, new UUID(m.MemberID)); + if (account != null) + m.MemberID = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI); + } + }); + + return rolemembers; + } + + public bool AddNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, + bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) + { + // check that the group proxy exists + ExtendedGroupRecord grec = GetGroupRecord(RequestingAgentID, groupID); + if (grec == null) + { + m_log.DebugFormat("[Groups.HGGroupsService]: attempt at adding notice to non-existent group proxy"); + return false; + } + + // check that the group is remote + if (grec.ServiceLocation == string.Empty) + { + m_log.DebugFormat("[Groups.HGGroupsService]: attempt at adding notice to local (non-proxy) group"); + return false; + } + + // check that there isn't already a notice with the same ID + if (GetGroupNotice(RequestingAgentID, noticeID) != null) + { + m_log.DebugFormat("[Groups.HGGroupsService]: a notice with the same ID already exists", grec.ServiceLocation); + return false; + } + + // This has good intentions (security) but it will potentially DDS the origin... + // We'll need to send a proof along with the message. Maybe encrypt the message + // using key pairs + // + //// check that the notice actually exists in the origin + //GroupsServiceHGConnector c = new GroupsServiceHGConnector(grec.ServiceLocation); + //if (!c.VerifyNotice(noticeID, groupID)) + //{ + // m_log.DebugFormat("[Groups.HGGroupsService]: notice does not exist at origin {0}", grec.ServiceLocation); + // return false; + //} + + // ok, we're good! + return _AddNotice(groupID, noticeID, fromName, subject, message, hasAttachment, attType, attName, attItemID, attOwnerID); + } + + public bool VerifyNotice(UUID noticeID, UUID groupID) + { + GroupNoticeInfo notice = GetGroupNotice(string.Empty, noticeID); + + if (notice == null) + return false; + + if (notice.GroupID != groupID) + return false; + + return true; + } + + #endregion + + private void InviteToGroup(string fromName, UUID groupID, UUID invitedAgentID, string groupName) + { + // Todo: Security check, probably also want to send some kind of notification + UUID InviteID = UUID.Random(); + + if (AddAgentToGroupInvite(InviteID, groupID, invitedAgentID.ToString())) + { + Guid inviteUUID = InviteID.Guid; + + GridInstantMessage msg = new GridInstantMessage(); + + msg.imSessionID = inviteUUID; + + // msg.fromAgentID = agentID.Guid; + msg.fromAgentID = groupID.Guid; + msg.toAgentID = invitedAgentID.Guid; + //msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); + msg.timestamp = 0; + msg.fromAgentName = fromName; + msg.message = string.Format("Please confirm your acceptance to join group {0}.", groupName); + msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupInvitation; + msg.fromGroup = true; + msg.offline = (byte)0; + msg.ParentEstateID = 0; + msg.Position = Vector3.Zero; + msg.RegionID = UUID.Zero.Guid; + msg.binaryBucket = new byte[20]; + + string reason = string.Empty; + m_OfflineIM.StoreMessage(msg, out reason); + + } + } + + private bool AddAgentToGroupInvite(UUID inviteID, UUID groupID, string agentID) + { + // Check whether the invitee is already a member of the group + MembershipData m = m_Database.RetrieveMember(groupID, agentID); + if (m != null) + return false; + + // Check whether there are pending invitations and delete them + InvitationData invite = m_Database.RetrieveInvitation(groupID, agentID); + if (invite != null) + m_Database.DeleteInvite(invite.InviteID); + + invite = new InvitationData(); + invite.InviteID = inviteID; + invite.PrincipalID = agentID; + invite.GroupID = groupID; + invite.RoleID = UUID.Zero; + invite.Data = new Dictionary(); + + return m_Database.StoreInvitation(invite); + } + + private void FillFounderUUI(ExtendedGroupRecord grec) + { + UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, grec.FounderID); + if (account != null) + grec.FounderUUI = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI); + } + + private bool VerifyToken(UUID groupID, string agentID, string token) + { + // check the token + MembershipData membership = m_Database.RetrieveMember(groupID, agentID); + if (membership != null) + { + if (token != string.Empty && token.Equals(membership.Data["AccessToken"])) + return true; + else + m_log.DebugFormat("[Groups.HGGroupsService]: access token {0} did not match stored one {1}", token, membership.Data["AccessToken"]); + } + else + m_log.DebugFormat("[Groups.HGGroupsService]: membership not found for {0}", agentID); + + return false; + } + } +} diff --git a/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs b/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs new file mode 100644 index 0000000..5340bcd --- /dev/null +++ b/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs @@ -0,0 +1,268 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Reflection; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Client; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; + +namespace OpenSim.OfflineIM +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "OfflineIMConnectorModule")] + public class OfflineIMRegionModule : ISharedRegionModule, IOfflineIMService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private bool m_Enabled = false; + private List m_SceneList = new List(); + IMessageTransferModule m_TransferModule = null; + private bool m_ForwardOfflineGroupMessages = true; + + private IOfflineIMService m_OfflineIMService; + + public void Initialise(IConfigSource config) + { + IConfig cnf = config.Configs["Messaging"]; + if (cnf == null) + return; + if (cnf != null && cnf.GetString("OfflineMessageModule", string.Empty) != Name) + return; + + m_Enabled = true; + + string serviceLocation = cnf.GetString("OfflineMessageURL", string.Empty); + if (serviceLocation == string.Empty) + m_OfflineIMService = new OfflineIMService(config); + else + m_OfflineIMService = new OfflineIMServiceRemoteConnector(config); + + m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", m_ForwardOfflineGroupMessages); + m_log.DebugFormat("[OfflineIM.V2]: Offline messages enabled by {0}", Name); + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + scene.RegisterModuleInterface(this); + m_SceneList.Add(scene); + scene.EventManager.OnNewClient += OnNewClient; + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + + if (m_TransferModule == null) + { + m_TransferModule = scene.RequestModuleInterface(); + if (m_TransferModule == null) + { + scene.EventManager.OnNewClient -= OnNewClient; + + m_SceneList.Clear(); + + m_log.Error("[OfflineIM.V2]: No message transfer module is enabled. Disabling offline messages"); + } + m_TransferModule.OnUndeliveredMessage += UndeliveredMessage; + } + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + + m_SceneList.Remove(scene); + scene.EventManager.OnNewClient -= OnNewClient; + m_TransferModule.OnUndeliveredMessage -= UndeliveredMessage; + + scene.ForEachClient(delegate(IClientAPI client) + { + client.OnRetrieveInstantMessages -= RetrieveInstantMessages; + client.OnMuteListRequest -= OnMuteListRequest; + }); + } + + public void PostInitialise() + { + } + + public string Name + { + get { return "Offline Message Module V2"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Close() + { + m_SceneList.Clear(); + } + + private Scene FindScene(UUID agentID) + { + foreach (Scene s in m_SceneList) + { + ScenePresence presence = s.GetScenePresence(agentID); + if (presence != null && !presence.IsChildAgent) + return s; + } + return null; + } + + private IClientAPI FindClient(UUID agentID) + { + foreach (Scene s in m_SceneList) + { + ScenePresence presence = s.GetScenePresence(agentID); + if (presence != null && !presence.IsChildAgent) + return presence.ControllingClient; + } + return null; + } + + private void OnNewClient(IClientAPI client) + { + client.OnRetrieveInstantMessages += RetrieveInstantMessages; + client.OnMuteListRequest += OnMuteListRequest; + } + + private void RetrieveInstantMessages(IClientAPI client) + { + m_log.DebugFormat("[OfflineIM.V2]: Retrieving stored messages for {0}", client.AgentId); + + List msglist = m_OfflineIMService.GetMessages(client.AgentId); + + if (msglist == null) + m_log.DebugFormat("[OfflineIM.V2]: WARNING null message list."); + + foreach (GridInstantMessage im in msglist) + { + if (im.dialog == (byte)InstantMessageDialog.InventoryOffered) + // send it directly or else the item will be given twice + client.SendInstantMessage(im); + else + { + // Send through scene event manager so all modules get a chance + // to look at this message before it gets delivered. + // + // Needed for proper state management for stored group + // invitations + // + Scene s = FindScene(client.AgentId); + if (s != null) + s.EventManager.TriggerIncomingInstantMessage(im); + } + } + } + + // Apparently this is needed in order for the viewer to request the IMs. + private void OnMuteListRequest(IClientAPI client, uint crc) + { + m_log.DebugFormat("[OfflineIM.V2] Got mute list request for crc {0}", crc); + string filename = "mutes" + client.AgentId.ToString(); + + IXfer xfer = client.Scene.RequestModuleInterface(); + if (xfer != null) + { + xfer.AddNewFile(filename, new Byte[0]); + client.SendMuteListUpdate(filename); + } + } + + private void UndeliveredMessage(GridInstantMessage im) + { + if (im.dialog != (byte)InstantMessageDialog.MessageFromObject && + im.dialog != (byte)InstantMessageDialog.MessageFromAgent && + im.dialog != (byte)InstantMessageDialog.GroupNotice && + im.dialog != (byte)InstantMessageDialog.GroupInvitation && + im.dialog != (byte)InstantMessageDialog.InventoryOffered) + { + return; + } + + if (!m_ForwardOfflineGroupMessages) + { + if (im.dialog == (byte)InstantMessageDialog.GroupNotice || + im.dialog == (byte)InstantMessageDialog.GroupInvitation) + return; + } + + string reason = string.Empty; + bool success = m_OfflineIMService.StoreMessage(im, out reason); + + if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) + { + IClientAPI client = FindClient(new UUID(im.fromAgentID)); + if (client == null) + return; + + client.SendInstantMessage(new GridInstantMessage( + null, new UUID(im.toAgentID), + "System", new UUID(im.fromAgentID), + (byte)InstantMessageDialog.MessageFromAgent, + "User is not logged in. " + + (success ? "Message saved." : "Message not saved: " + reason), + false, new Vector3())); + } + } + + #region IOfflineIM + + public List GetMessages(UUID principalID) + { + return m_OfflineIMService.GetMessages(principalID); + } + + public bool StoreMessage(GridInstantMessage im, out string reason) + { + return m_OfflineIMService.StoreMessage(im, out reason); + } + + public void DeleteMessages(UUID userID) + { + m_OfflineIMService.DeleteMessages(userID); + } + + #endregion + } +} + diff --git a/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs b/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0699660 --- /dev/null +++ b/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Mono.Addins; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.Addons.OfflineIM")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("http://opensimulator.org")] +[assembly: AssemblyProduct("OpenSim.Addons.OfflineIM")] +[assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a16a9905-4393-4872-9fca-4c81bedbd9f2")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("0.8.3.*")] + +[assembly: Addin("OpenSim.OfflineIM", OpenSim.VersionInfo.VersionNumber)] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs new file mode 100644 index 0000000..047b8be --- /dev/null +++ b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs @@ -0,0 +1,171 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; + +using OpenMetaverse; +using log4net; +using Nini.Config; + +namespace OpenSim.OfflineIM +{ + public class OfflineIMServiceRemoteConnector : IOfflineIMService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private string m_ServerURI = string.Empty; + private IServiceAuth m_Auth; + private object m_Lock = new object(); + + public OfflineIMServiceRemoteConnector(string url) + { + m_ServerURI = url; + m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: Offline IM server at {0}", m_ServerURI); + } + + public OfflineIMServiceRemoteConnector(IConfigSource config) + { + IConfig cnf = config.Configs["Messaging"]; + if (cnf == null) + { + m_log.WarnFormat("[OfflineIM.V2.RemoteConnector]: Missing Messaging configuration"); + return; + } + + m_ServerURI = cnf.GetString("OfflineMessageURL", string.Empty); + + /// This is from BaseServiceConnector + string authType = Util.GetConfigVarFromSections(config, "AuthType", new string[] { "Network", "Messaging" }, "None"); + + switch (authType) + { + case "BasicHttpAuthentication": + m_Auth = new BasicHttpAuthentication(config, "Messaging"); + break; + } + /// + m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: Offline IM server at {0} with auth {1}", + m_ServerURI, (m_Auth == null ? "None" : m_Auth.GetType().ToString())); + } + + #region IOfflineIMService + public List GetMessages(UUID principalID) + { + List ims = new List(); + + Dictionary sendData = new Dictionary(); + sendData["PrincipalID"] = principalID; + Dictionary ret = MakeRequest("GET", sendData); + + if (ret == null) + return ims; + + if (!ret.ContainsKey("RESULT")) + return ims; + + string result = ret["RESULT"].ToString(); + if (result == "NULL" || result.ToLower() == "false") + { + string reason = ret.ContainsKey("REASON") ? ret["REASON"].ToString() : "Unknown error"; + m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: GetMessages for {0} failed: {1}", principalID, reason); + return ims; + } + + foreach (object v in ((Dictionary)ret["RESULT"]).Values) + { + GridInstantMessage m = OfflineIMDataUtils.GridInstantMessage((Dictionary)v); + ims.Add(m); + } + + return ims; + } + + public bool StoreMessage(GridInstantMessage im, out string reason) + { + reason = string.Empty; + Dictionary sendData = OfflineIMDataUtils.GridInstantMessage(im); + + Dictionary ret = MakeRequest("STORE", sendData); + + if (ret == null) + { + reason = "Bad response from server"; + return false; + } + + string result = ret["RESULT"].ToString(); + if (result == "NULL" || result.ToLower() == "false") + { + reason = ret.ContainsKey("REASON") ? ret["REASON"].ToString() : "Unknown error"; + return false; + } + + return true; + } + + public void DeleteMessages(UUID userID) + { + Dictionary sendData = new Dictionary(); + sendData["UserID"] = userID; + + MakeRequest("DELETE", sendData); + } + + #endregion + + + #region Make Request + + private Dictionary MakeRequest(string method, Dictionary sendData) + { + sendData["METHOD"] = method; + + string reply = string.Empty; + lock (m_Lock) + reply = SynchronousRestFormsRequester.MakeRequest("POST", + m_ServerURI + "/offlineim", + ServerUtils.BuildQueryString(sendData), + m_Auth); + + Dictionary replyData = ServerUtils.ParseXmlResponse( + reply); + + return replyData; + } + #endregion + + } +} diff --git a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs new file mode 100644 index 0000000..b3673da --- /dev/null +++ b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs @@ -0,0 +1,223 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using System.Text; +using System.Xml; +using System.Collections.Generic; +using System.IO; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework.ServiceAuth; +using OpenSim.Server.Handlers.Base; +using log4net; +using OpenMetaverse; + +namespace OpenSim.OfflineIM +{ + public class OfflineIMServiceRobustConnector : ServiceConnector + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IOfflineIMService m_OfflineIMService; + private string m_ConfigName = "Messaging"; + + public OfflineIMServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + if (configName != String.Empty) + m_ConfigName = configName; + + m_log.DebugFormat("[OfflineIM.V2.RobustConnector]: Starting with config name {0}", m_ConfigName); + + m_OfflineIMService = new OfflineIMService(config); + + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); + + server.AddStreamHandler(new OfflineIMServicePostHandler(m_OfflineIMService, auth)); + } + } + + public class OfflineIMServicePostHandler : BaseStreamHandler + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IOfflineIMService m_OfflineIMService; + + public OfflineIMServicePostHandler(IOfflineIMService service, IServiceAuth auth) : + base("POST", "/offlineim", auth) + { + m_OfflineIMService = service; + } + + protected override byte[] ProcessRequest(string path, Stream requestData, + IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + StreamReader sr = new StreamReader(requestData); + string body = sr.ReadToEnd(); + sr.Close(); + body = body.Trim(); + + //m_log.DebugFormat("[XXX]: query String: {0}", body); + + try + { + Dictionary request = + ServerUtils.ParseQueryString(body); + + if (!request.ContainsKey("METHOD")) + return FailureResult(); + + string method = request["METHOD"].ToString(); + request.Remove("METHOD"); + + switch (method) + { + case "GET": + return HandleGet(request); + case "STORE": + return HandleStore(request); + case "DELETE": + return HandleDelete(request); + } + m_log.DebugFormat("[OFFLINE IM HANDLER]: unknown method request: {0}", method); + } + catch (Exception e) + { + m_log.Error(string.Format("[OFFLINE IM HANDLER]: Exception {0} ", e.Message), e); + } + + return FailureResult(); + } + + byte[] HandleStore(Dictionary request) + { + Dictionary result = new Dictionary(); + + GridInstantMessage im = OfflineIMDataUtils.GridInstantMessage(request); + + string reason = string.Empty; + + bool success = m_OfflineIMService.StoreMessage(im, out reason); + + result["RESULT"] = success.ToString(); + if (!success) + result["REASON"] = reason; + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleGet(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("PrincipalID")) + NullResult(result, "Bad network data"); + else + { + UUID principalID = new UUID(request["PrincipalID"].ToString()); + List ims = m_OfflineIMService.GetMessages(principalID); + + Dictionary dict = new Dictionary(); + int i = 0; + foreach (GridInstantMessage m in ims) + dict["im-" + i++] = OfflineIMDataUtils.GridInstantMessage(m); + + result["RESULT"] = dict; + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleDelete(Dictionary request) + { + if (!request.ContainsKey("UserID")) + { + return FailureResult(); + } + else + { + UUID userID = new UUID(request["UserID"].ToString()); + m_OfflineIMService.DeleteMessages(userID); + + return SuccessResult(); + } + } + + #region Helpers + + private void NullResult(Dictionary result, string reason) + { + result["RESULT"] = "NULL"; + result["REASON"] = reason; + } + + private byte[] FailureResult() + { + return BoolResult(false); + } + + private byte[] SuccessResult() + { + return BoolResult(true); + } + + private byte[] BoolResult(bool value) + { + XmlDocument doc = new XmlDocument(); + + XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration, + "", ""); + + doc.AppendChild(xmlnode); + + XmlElement rootElement = doc.CreateElement("", "ServerResponse", + ""); + + doc.AppendChild(rootElement); + + XmlElement result = doc.CreateElement("", "RESULT", ""); + result.AppendChild(doc.CreateTextNode(value.ToString())); + + rootElement.AppendChild(result); + + return Util.DocToBytes(doc); + } + + #endregion + } +} diff --git a/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs new file mode 100644 index 0000000..02084ff --- /dev/null +++ b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs @@ -0,0 +1,135 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; +using System.Timers; +using System.Xml; +using System.Xml.Serialization; +using log4net; +using Nini.Config; + +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Services.Interfaces; + +namespace OpenSim.OfflineIM +{ + public class OfflineIMService : OfflineIMServiceBase, IOfflineIMService + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private const int MAX_IM = 25; + + private XmlSerializer m_serializer; + private static bool m_Initialized = false; + + public OfflineIMService(IConfigSource config) + : base(config) + { + m_serializer = new XmlSerializer(typeof(GridInstantMessage)); + if (!m_Initialized) + { + m_Database.DeleteOld(); + m_Initialized = true; + } + } + + public List GetMessages(UUID principalID) + { + List ims = new List(); + + OfflineIMData[] messages = m_Database.Get("PrincipalID", principalID.ToString()); + + if (messages == null || (messages != null && messages.Length == 0)) + return ims; + + foreach (OfflineIMData m in messages) + { + using (MemoryStream mstream = new MemoryStream(Encoding.UTF8.GetBytes(m.Data["Message"]))) + { + GridInstantMessage im = (GridInstantMessage)m_serializer.Deserialize(mstream); + ims.Add(im); + } + } + + // Then, delete them + m_Database.Delete("PrincipalID", principalID.ToString()); + + return ims; + } + + public bool StoreMessage(GridInstantMessage im, out string reason) + { + reason = string.Empty; + + // Check limits + UUID principalID = new UUID(im.toAgentID); + long count = m_Database.GetCount("PrincipalID", principalID.ToString()); + if (count >= MAX_IM) + { + reason = "Number of offline IMs has maxed out"; + return false; + } + + string imXml; + using (MemoryStream mstream = new MemoryStream()) + { + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Util.UTF8NoBomEncoding; + + using (XmlWriter writer = XmlWriter.Create(mstream, settings)) + { + m_serializer.Serialize(writer, im); + writer.Flush(); + } + + imXml = Util.UTF8NoBomEncoding.GetString(mstream.ToArray()); + } + + OfflineIMData data = new OfflineIMData(); + data.PrincipalID = principalID; + data.FromID = new UUID(im.fromAgentID); + data.Data = new Dictionary(); + data.Data["Message"] = imXml; + + return m_Database.Store(data); + + } + + public void DeleteMessages(UUID userID) + { + m_Database.Delete("PrincipalID", userID.ToString()); + m_Database.Delete("FromID", userID.ToString()); + } + + } +} 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 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Reflection; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Data; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Base; + +namespace OpenSim.OfflineIM +{ + public class OfflineIMServiceBase : ServiceBase + { + protected IOfflineIMData m_Database = null; + + public OfflineIMServiceBase(IConfigSource config) + : base(config) + { + string dllName = String.Empty; + string connString = String.Empty; + string realm = "im_offline"; + + // + // Try reading the [DatabaseService] section, if it exists + // + IConfig dbConfig = config.Configs["DatabaseService"]; + if (dbConfig != null) + { + if (dllName == String.Empty) + dllName = dbConfig.GetString("StorageProvider", String.Empty); + if (connString == String.Empty) + connString = dbConfig.GetString("ConnectionString", String.Empty); + } + + // + // [Messaging] section overrides [DatabaseService], if it exists + // + IConfig imConfig = config.Configs["Messaging"]; + if (imConfig != null) + { + dllName = imConfig.GetString("StorageProvider", dllName); + connString = imConfig.GetString("ConnectionString", connString); + realm = imConfig.GetString("Realm", realm); + } + + // + // We tried, but this doesn't exist. We can't proceed. + // + if (dllName.Equals(String.Empty)) + throw new Exception("No StorageProvider configured"); + + m_Database = LoadPlugin(dllName, new Object[] { connString, realm }); + if (m_Database == null) + throw new Exception("Could not find a storage interface in the given module " + dllName); + } + } +} diff --git a/OpenSim/ApplicationPlugins/LoadRegions/IRegionLoader.cs b/OpenSim/ApplicationPlugins/LoadRegions/IRegionLoader.cs new file mode 100644 index 0000000..2d1505d --- /dev/null +++ b/OpenSim/ApplicationPlugins/LoadRegions/IRegionLoader.cs @@ -0,0 +1,38 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using Nini.Config; +using OpenSim.Framework; + +namespace OpenSim.ApplicationPlugins.LoadRegions +{ + public interface IRegionLoader + { + void SetIniConfigSource(IConfigSource configSource); + RegionInfo[] LoadRegions(); + } +} \ No newline at end of file diff --git a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs index fcb6991..89224a6 100644 --- a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs +++ b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs @@ -32,16 +32,17 @@ using System.Threading; using log4net; using OpenMetaverse; using OpenSim.Framework; -using OpenSim.Framework.RegionLoader.Filesystem; -using OpenSim.Framework.RegionLoader.Web; using OpenSim.Region.CoreModules.Agent.AssetTransaction; using OpenSim.Region.CoreModules.Avatar.InstantMessage; using OpenSim.Region.CoreModules.Scripting.DynamicTexture; using OpenSim.Region.CoreModules.Scripting.LoadImageURL; using OpenSim.Region.CoreModules.Scripting.XMLRPC; +using OpenSim.Services.Interfaces; +using Mono.Addins; namespace OpenSim.ApplicationPlugins.LoadRegions { + [Extension(Path="/OpenSim/Startup", Id="LoadRegions", NodeName="Plugin")] public class LoadRegionsPlugin : IApplicationPlugin, IRegionCreator { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -115,6 +116,8 @@ namespace OpenSim.ApplicationPlugins.LoadRegions Environment.Exit(1); } + List createdScenes = new List(); + for (int i = 0; i < regionsToLoad.Length; i++) { IScene scene; @@ -123,17 +126,22 @@ namespace OpenSim.ApplicationPlugins.LoadRegions ")"); bool changed = m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]); + m_openSim.CreateRegion(regionsToLoad[i], true, out scene); + createdScenes.Add(scene); + if (changed) - regionsToLoad[i].EstateSettings.Save(); - - if (scene != null) + m_openSim.EstateDataService.StoreEstateSettings(regionsToLoad[i].EstateSettings); + } + + foreach (IScene scene in createdScenes) + { + scene.Start(); + + m_newRegionCreatedHandler = OnNewRegionCreated; + if (m_newRegionCreatedHandler != null) { - m_newRegionCreatedHandler = OnNewRegionCreated; - if (m_newRegionCreatedHandler != null) - { - m_newRegionCreatedHandler(scene); - } + m_newRegionCreatedHandler(scene); } } } diff --git a/OpenSim/ApplicationPlugins/LoadRegions/Properties/AssemblyInfo.cs b/OpenSim/ApplicationPlugins/LoadRegions/Properties/AssemblyInfo.cs index 57615ea..6c3c3e3 100644 --- a/OpenSim/ApplicationPlugins/LoadRegions/Properties/AssemblyInfo.cs +++ b/OpenSim/ApplicationPlugins/LoadRegions/Properties/AssemblyInfo.cs @@ -27,16 +27,17 @@ using System.Reflection; using System.Runtime.InteropServices; +using Mono.Addins; // General information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly : AssemblyTitle("OpenSim.Addin")] +[assembly : AssemblyTitle("OpenSim.ApplicationPlugins.LoadRegions")] [assembly : AssemblyDescription("")] [assembly : AssemblyConfiguration("")] [assembly : AssemblyCompany("http://opensimulator.org")] -[assembly : AssemblyProduct("OpenSim.Addin")] +[assembly : AssemblyProduct("OpenSim")] [assembly : AssemblyCopyright("Copyright © OpenSimulator.org Developers 2007-2009")] [assembly : AssemblyTrademark("")] [assembly : AssemblyCulture("")] @@ -60,7 +61,9 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -// [assembly: AssemblyVersion("0.7.5.*")] +// [assembly: AssemblyVersion("0.7.6.*")] -[assembly : AssemblyVersion("0.7.5.*")] -[assembly : AssemblyFileVersion("0.6.5.0")] \ No newline at end of file +[assembly : AssemblyVersion("0.8.2.*")] + +[assembly: Addin("OpenSim.ApplicationPlugins.LoadRegions", OpenSim.VersionInfo.VersionNumber)] +[assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderFileSystem.cs b/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderFileSystem.cs new file mode 100644 index 0000000..1873a06 --- /dev/null +++ b/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderFileSystem.cs @@ -0,0 +1,117 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using log4net; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using Nini.Config; +using OpenSim.Framework; + +namespace OpenSim.ApplicationPlugins.LoadRegions +{ + public class RegionLoaderFileSystem : IRegionLoader + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IConfigSource m_configSource; + + public void SetIniConfigSource(IConfigSource configSource) + { + m_configSource = configSource; + } + + public RegionInfo[] LoadRegions() + { + string regionConfigPath = Path.Combine(Util.configDir(), "Regions"); + bool allowRegionless = false; + + try + { + IConfig startupConfig = (IConfig)m_configSource.Configs["Startup"]; + regionConfigPath = startupConfig.GetString("regionload_regionsdir", regionConfigPath).Trim(); + allowRegionless = startupConfig.GetBoolean("allow_regionless", false); + } + catch (Exception) + { + // No INI setting recorded. + } + + if (!Directory.Exists(regionConfigPath)) + { + Directory.CreateDirectory(regionConfigPath); + } + + string[] configFiles = Directory.GetFiles(regionConfigPath, "*.xml"); + string[] iniFiles = Directory.GetFiles(regionConfigPath, "*.ini"); + + // Create an empty Regions.ini if there are no existing config files. + if (!allowRegionless && configFiles.Length == 0 && iniFiles.Length == 0) + { + new RegionInfo("DEFAULT REGION CONFIG", Path.Combine(regionConfigPath, "Regions.ini"), false, m_configSource); + iniFiles = Directory.GetFiles(regionConfigPath, "*.ini"); + } + + m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config files from {0}", regionConfigPath); + + List regionInfos = new List(); + + int i = 0; + foreach (string file in iniFiles) + { + m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config file {0}", file); + + IConfigSource source = new IniConfigSource(file); + + foreach (IConfig config in source.Configs) + { + RegionInfo regionInfo = new RegionInfo("REGION CONFIG #" + (i + 1), file, false, m_configSource, config.Name); + regionInfos.Add(regionInfo); + + m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loaded config for region {0}", regionInfo.RegionName); + + i++; + } + } + + foreach (string file in configFiles) + { + m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config file {0}", file); + + RegionInfo regionInfo = new RegionInfo("REGION CONFIG #" + (i + 1), file, false, m_configSource); + regionInfos.Add(regionInfo); + + m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loaded config for region {0}", regionInfo.RegionName); + + i++; + } + + return regionInfos.ToArray(); + } + } +} \ No newline at end of file diff --git a/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderWebServer.cs b/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderWebServer.cs new file mode 100644 index 0000000..850f3e0 --- /dev/null +++ b/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderWebServer.cs @@ -0,0 +1,148 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Net; +using System.Reflection; +using System.Xml; +using log4net; +using Nini.Config; +using OpenSim.Framework; + +namespace OpenSim.ApplicationPlugins.LoadRegions +{ + public class RegionLoaderWebServer : IRegionLoader + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IConfigSource m_configSource; + + public void SetIniConfigSource(IConfigSource configSource) + { + m_configSource = configSource; + } + + public RegionInfo[] LoadRegions() + { + if (m_configSource == null) + { + m_log.Error("[WEBLOADER]: Unable to load configuration source!"); + return null; + } + else + { + IConfig startupConfig = (IConfig) m_configSource.Configs["Startup"]; + string url = startupConfig.GetString("regionload_webserver_url", String.Empty).Trim(); + bool allowRegionless = startupConfig.GetBoolean("allow_regionless", false); + + if (url == String.Empty) + { + m_log.Error("[WEBLOADER]: Unable to load webserver URL - URL was empty."); + return null; + } + else + { + RegionInfo[] regionInfos = new RegionInfo[] {}; + int regionCount = 0; + HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create(url); + webRequest.Timeout = 30000; //30 Second Timeout + m_log.DebugFormat("[WEBLOADER]: Sending download request to {0}", url); + + try + { + string xmlSource = String.Empty; + + using (HttpWebResponse webResponse = (HttpWebResponse) webRequest.GetResponse()) + { + m_log.Debug("[WEBLOADER]: Downloading region information..."); + + using (Stream s = webResponse.GetResponseStream()) + { + using (StreamReader reader = new StreamReader(s)) + { + string tempStr = reader.ReadLine(); + while (tempStr != null) + { + xmlSource = xmlSource + tempStr; + tempStr = reader.ReadLine(); + } + } + } + } + + m_log.Debug("[WEBLOADER]: Done downloading region information from server. Total Bytes: " + + xmlSource.Length); + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(xmlSource); + if (xmlDoc.FirstChild.Name == "Nini") + { + regionCount = xmlDoc.FirstChild.ChildNodes.Count; + + if (regionCount > 0) + { + regionInfos = new RegionInfo[regionCount]; + int i; + for (i = 0; i < xmlDoc.FirstChild.ChildNodes.Count; i++) + { + m_log.Debug(xmlDoc.FirstChild.ChildNodes[i].OuterXml); + regionInfos[i] = + new RegionInfo("REGION CONFIG #" + (i + 1), xmlDoc.FirstChild.ChildNodes[i],false,m_configSource); + } + } + } + } + catch (WebException ex) + { + using (HttpWebResponse response = (HttpWebResponse)ex.Response) + { + if (response.StatusCode == HttpStatusCode.NotFound) + { + if (!allowRegionless) + throw ex; + } + else + { + throw ex; + } + } + } + + if (regionCount > 0 | allowRegionless) + { + return regionInfos; + } + else + { + m_log.Error("[WEBLOADER]: No region configs were available."); + return null; + } + } + } + } + } +} diff --git a/OpenSim/ApplicationPlugins/LoadRegions/Resources/LoadRegionsPlugin.addin.xml b/OpenSim/ApplicationPlugins/LoadRegions/Resources/LoadRegionsPlugin.addin.xml deleted file mode 100644 index 37222b7..0000000 --- a/OpenSim/ApplicationPlugins/LoadRegions/Resources/LoadRegionsPlugin.addin.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/OpenSim/ApplicationPlugins/RegionModulesController/Properties/AssemblyInfo.cs b/OpenSim/ApplicationPlugins/RegionModulesController/Properties/AssemblyInfo.cs index 14527d9..acbdc3a 100644 --- a/OpenSim/ApplicationPlugins/RegionModulesController/Properties/AssemblyInfo.cs +++ b/OpenSim/ApplicationPlugins/RegionModulesController/Properties/AssemblyInfo.cs @@ -1,6 +1,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using Mono.Addins; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -29,5 +30,7 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + +[assembly: Addin("OpenSim.ApplicationPlugins.RegionModulesController", OpenSim.VersionInfo.VersionNumber)] +[assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs b/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs index 633d005..8f38a29 100644 --- a/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs +++ b/OpenSim/ApplicationPlugins/RegionModulesController/RegionModulesControllerPlugin.cs @@ -32,11 +32,13 @@ using log4net; using Mono.Addins; using Nini.Config; using OpenSim; +using OpenSim.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; namespace OpenSim.ApplicationPlugins.RegionModulesController { + [Extension(Path = "/OpenSim/Startup", Id = "LoadRegions", NodeName = "Plugin")] public class RegionModulesControllerPlugin : IRegionModulesController, IApplicationPlugin { @@ -45,6 +47,12 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Controls whether we load modules from Mono.Addins. + /// + /// For debug purposes. Defaults to true. + public bool LoadModulesFromAddins { get; set; } + // Config access private OpenSimBase m_openSim; @@ -61,6 +69,11 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController private List m_sharedInstances = new List(); + public RegionModulesControllerPlugin() + { + LoadModulesFromAddins = true; + } + #region IApplicationPlugin implementation public void Initialise (OpenSimBase openSim) @@ -69,6 +82,9 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController m_openSim.ApplicationRegistry.RegisterInterface(this); m_log.DebugFormat("[REGIONMODULES]: Initializing..."); + if (!LoadModulesFromAddins) + return; + // Who we are string id = AddinManager.CurrentAddin.Id; @@ -85,30 +101,20 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController if (modulesConfig == null) modulesConfig = m_openSim.ConfigSource.Source.AddConfig("Modules"); + Dictionary> loadedModules = new Dictionary>(); + // Scan modules and load all that aren't disabled - foreach (TypeExtensionNode node in - AddinManager.GetExtensionNodes("/OpenSim/RegionModules")) + foreach (TypeExtensionNode node in AddinManager.GetExtensionNodes("/OpenSim/RegionModules")) + AddNode(node, modulesConfig, loadedModules); + + foreach (KeyValuePair> loadedModuleData in loadedModules) { - if (node.Type.GetInterface(typeof(ISharedRegionModule).ToString()) != null) - { - if (CheckModuleEnabled(node, modulesConfig)) - { - m_log.DebugFormat("[REGIONMODULES]: Found shared region module {0}, class {1}", node.Id, node.Type); - m_sharedModules.Add(node); - } - } - else if (node.Type.GetInterface(typeof(INonSharedRegionModule).ToString()) != null) - { - if (CheckModuleEnabled(node, modulesConfig)) - { - m_log.DebugFormat("[REGIONMODULES]: Found non-shared region module {0}, class {1}", node.Id, node.Type); - m_nonSharedModules.Add(node); - } - } - else - { - m_log.DebugFormat("[REGIONMODULES]: Found unknown type of module {0}, class {1}", node.Id, node.Type); - } + m_log.InfoFormat( + "[REGIONMODULES]: From plugin {0}, (version {1}), loaded {2} modules, {3} shared, {4} non-shared {5} unknown", + loadedModuleData.Key.Id, + loadedModuleData.Key.Version, + loadedModuleData.Value[0] + loadedModuleData.Value[1] + loadedModuleData.Value[2], + loadedModuleData.Value[0], loadedModuleData.Value[1], loadedModuleData.Value[2]); } // Load and init the module. We try a constructor with a port @@ -125,6 +131,9 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController // Read the config again string moduleString = modulesConfig.GetString("Setup_" + node.Id, String.Empty); + // Test to see if we want this module + if (moduleString == "disabled") + continue; // Get the port number, if there is one if (moduleString != String.Empty) @@ -172,6 +181,41 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController #region IPlugin implementation + private void AddNode( + TypeExtensionNode node, IConfig modulesConfig, Dictionary> loadedModules) + { + IList loadedModuleData; + + if (!loadedModules.ContainsKey(node.Addin)) + loadedModules.Add(node.Addin, new List { 0, 0, 0 }); + + loadedModuleData = loadedModules[node.Addin]; + + if (node.Type.GetInterface(typeof(ISharedRegionModule).ToString()) != null) + { + if (CheckModuleEnabled(node, modulesConfig)) + { + m_log.DebugFormat("[REGIONMODULES]: Found shared region module {0}, class {1}", node.Id, node.Type); + m_sharedModules.Add(node); + loadedModuleData[0]++; + } + } + else if (node.Type.GetInterface(typeof(INonSharedRegionModule).ToString()) != null) + { + if (CheckModuleEnabled(node, modulesConfig)) + { + m_log.DebugFormat("[REGIONMODULES]: Found non-shared region module {0}, class {1}", node.Id, node.Type); + m_nonSharedModules.Add(node); + loadedModuleData[1]++; + } + } + else + { + m_log.WarnFormat("[REGIONMODULES]: Found unknown type of module {0}, class {1}", node.Id, node.Type); + loadedModuleData[2]++; + } + } + // We don't do that here // public void Initialise () @@ -193,6 +237,7 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController m_sharedInstances[0].Close(); m_sharedInstances.RemoveAt(0); } + m_sharedModules.Clear(); m_nonSharedModules.Clear(); } @@ -323,6 +368,10 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController string moduleString = modulesConfig.GetString("Setup_" + node.Id, String.Empty); + // We may not want to load this at all + if (moduleString == "disabled") + continue; + // Get the port number, if there is one if (moduleString != String.Empty) { @@ -460,6 +509,8 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController { module.RegionLoaded(scene); } + + scene.AllModulesLoaded(); } public void RemoveRegionFromModules (Scene scene) diff --git a/OpenSim/ApplicationPlugins/RegionModulesController/Resources/RegionModulesControllerPlugin.addin.xml b/OpenSim/ApplicationPlugins/RegionModulesController/Resources/RegionModulesControllerPlugin.addin.xml deleted file mode 100644 index a92713b..0000000 --- a/OpenSim/ApplicationPlugins/RegionModulesController/Resources/RegionModulesControllerPlugin.addin.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/OpenSim/ApplicationPlugins/RemoteController/Properties/AssemblyInfo.cs b/OpenSim/ApplicationPlugins/RemoteController/Properties/AssemblyInfo.cs index 8ad948c..ce87400 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/Properties/AssemblyInfo.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/Properties/AssemblyInfo.cs @@ -1,6 +1,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using Mono.Addins; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -29,5 +30,7 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + +[assembly: Addin("OpenSim.ApplicationPlugins.RemoteController", OpenSim.VersionInfo.VersionNumber)] +[assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index a75d10d..808d9e4 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -28,6 +28,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Xml; using System.Net; @@ -38,9 +39,9 @@ using log4net; using Nini.Config; using Nwc.XmlRpc; using OpenMetaverse; +using Mono.Addins; using OpenSim; using OpenSim.Framework; -using OpenSim.Framework.Communications; using OpenSim.Framework.Console; using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; @@ -50,9 +51,12 @@ using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; using GridRegion = OpenSim.Services.Interfaces.GridRegion; +using PermissionMask = OpenSim.Framework.PermissionMask; +using RegionInfo = OpenSim.Framework.RegionInfo; namespace OpenSim.ApplicationPlugins.RemoteController { + [Extension(Path = "/OpenSim/Startup", Id = "LoadRegions", NodeName = "Plugin")] public class RemoteAdminPlugin : IApplicationPlugin { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -136,6 +140,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController availableMethods["admin_save_heightmap"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcSaveHeightmapMethod); // Agent management + availableMethods["admin_get_agents"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcGetAgentsMethod); availableMethods["admin_teleport_agent"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcTeleportAgentMethod); // User management @@ -143,6 +148,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController availableMethods["admin_create_user_email"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcCreateUserMethod); availableMethods["admin_exists_user"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcUserExistsMethod); availableMethods["admin_update_user"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcUpdateUserAccountMethod); + availableMethods["admin_authenticate_user"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAuthenticateUserMethod); // Region state management availableMethods["admin_load_xml"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcLoadXMLMethod); @@ -155,6 +161,10 @@ namespace OpenSim.ApplicationPlugins.RemoteController availableMethods["admin_acl_add"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListAdd); availableMethods["admin_acl_remove"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListRemove); availableMethods["admin_acl_list"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListList); + availableMethods["admin_estate_reload"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcEstateReload); + + // Land management + availableMethods["admin_reset_land"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcResetLand); // Either enable full remote functionality or just selected features string enabledMethods = m_config.GetString("enabled_methods", "all"); @@ -324,18 +334,26 @@ namespace OpenSim.ApplicationPlugins.RemoteController // k, (string)requestData[k], ((string)requestData[k]).Length); // } - CheckStringParameters(requestData, responseData, new string[] {"filename", "regionid"}); + CheckStringParameters(requestData, responseData, new string[] { "filename" }); CheckRegionParams(requestData, responseData); Scene scene = null; GetSceneFromRegionParams(requestData, responseData, out scene); - string file = (string)requestData["filename"]; - responseData["accepted"] = true; + if (scene != null) + { + string file = (string)requestData["filename"]; - LoadHeightmap(file, scene.RegionInfo.RegionID); + responseData["accepted"] = true; - responseData["success"] = true; + LoadHeightmap(file, scene.RegionInfo.RegionID); + + responseData["success"] = true; + } + else + { + responseData["success"] = false; + } m_log.Info("[RADMIN]: Load height maps request complete"); } @@ -349,23 +367,30 @@ namespace OpenSim.ApplicationPlugins.RemoteController // m_log.DebugFormat("[RADMIN]: Save Terrain: XmlRpc {0}", request.ToString()); - CheckStringParameters(requestData, responseData, new string[] { "filename", "regionid" }); + CheckStringParameters(requestData, responseData, new string[] { "filename" }); CheckRegionParams(requestData, responseData); - Scene region = null; - GetSceneFromRegionParams(requestData, responseData, out region); + Scene scene = null; + GetSceneFromRegionParams(requestData, responseData, out scene); - string file = (string)requestData["filename"]; - m_log.InfoFormat("[RADMIN]: Terrain Saving: {0}", file); + if (scene != null) + { + string file = (string)requestData["filename"]; + m_log.InfoFormat("[RADMIN]: Terrain Saving: {0}", file); - responseData["accepted"] = true; + responseData["accepted"] = true; - ITerrainModule terrainModule = region.RequestModuleInterface(); - if (null == terrainModule) throw new Exception("terrain module not available"); + ITerrainModule terrainModule = scene.RequestModuleInterface(); + if (null == terrainModule) throw new Exception("terrain module not available"); - terrainModule.SaveToFile(file); + terrainModule.SaveToFile(file); - responseData["success"] = true; + responseData["success"] = true; + } + else + { + responseData["success"] = false; + } m_log.Info("[RADMIN]: Save height maps request complete"); } @@ -673,7 +698,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController region.EstateSettings.EstateName = (string) requestData["estate_name"]; region.EstateSettings.EstateOwner = userID; // Persistence does not seem to effect the need to save a new estate - region.EstateSettings.Save(); + m_application.EstateDataService.StoreEstateSettings(region.EstateSettings); if (!m_application.EstateDataService.LinkRegion(region.RegionID, (int) region.EstateSettings.EstateID)) throw new Exception("Failed to join estate."); @@ -698,11 +723,12 @@ namespace OpenSim.ApplicationPlugins.RemoteController IScene newScene; m_application.CreateRegion(region, out newScene); + newScene.Start(); // If an access specification was provided, use it. // Otherwise accept the default. newScene.RegionInfo.EstateSettings.PublicAccess = GetBoolean(requestData, "public", m_publicAccess); - newScene.RegionInfo.EstateSettings.Save(); + m_application.EstateDataService.StoreEstateSettings(newScene.RegionInfo.EstateSettings); // enable voice on newly created region if // requested by either the XmlRpc request or the @@ -888,7 +914,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController scene.RegionInfo.EstateSettings.PublicAccess = GetBoolean(requestData,"public", scene.RegionInfo.EstateSettings.PublicAccess); if (scene.RegionInfo.Persistent) - scene.RegionInfo.EstateSettings.Save(); + m_application.EstateDataService.StoreEstateSettings(scene.RegionInfo.EstateSettings); if (requestData.ContainsKey("enable_voice")) { @@ -1000,7 +1026,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController // Set home position GridRegion home = scene.GridService.GetRegionByPosition(scopeID, - (int)(regionXLocation * Constants.RegionSize), (int)(regionYLocation * Constants.RegionSize)); + (int)Util.RegionToWorldLoc(regionXLocation), (int)Util.RegionToWorldLoc(regionYLocation)); if (null == home) { m_log.WarnFormat("[RADMIN]: Unable to set home region for newly created user account {0} {1}", firstName, lastName); @@ -1092,7 +1118,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController { GridUserInfo userInfo = m_application.SceneManager.CurrentOrFirstScene.GridUserService.GetGridUserInfo(account.PrincipalID.ToString()); if (userInfo != null) - responseData["lastlogin"] = userInfo.Login; + responseData["lastlogin"] = Util.ToUnixTime(userInfo.Login); else responseData["lastlogin"] = 0; @@ -1230,7 +1256,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController if ((null != regionXLocation) && (null != regionYLocation)) { GridRegion home = scene.GridService.GetRegionByPosition(scopeID, - (int)(regionXLocation * Constants.RegionSize), (int)(regionYLocation * Constants.RegionSize)); + (int)Util.RegionToWorldLoc((uint)regionXLocation), (int)Util.RegionToWorldLoc((uint)regionYLocation)); if (null == home) { m_log.WarnFormat("[RADMIN]: Unable to set home region for updated user account {0} {1}", firstName, lastName); } else { @@ -1262,6 +1288,139 @@ namespace OpenSim.ApplicationPlugins.RemoteController } /// + /// Authenticate an user. + /// + /// incoming XML RPC request + /// + /// XmlRpcAuthenticateUserMethod takes the following XMLRPC + /// parameters + /// + /// parameter namedescription + /// password + /// admin password as set in OpenSim.ini + /// user_firstname + /// avatar's first name + /// user_lastname + /// avatar's last name + /// user_password + /// MD5 hash of avatar's password + /// token_lifetime + /// the lifetime of the returned token (upper bounded to 30s) + /// + /// + /// XmlRpcAuthenticateUserMethod returns + /// + /// namedescription + /// success + /// true or false + /// token + /// the authentication token sent by OpenSim + /// error + /// error message if success is false + /// + /// + private void XmlRpcAuthenticateUserMethod(XmlRpcRequest request, XmlRpcResponse response, + IPEndPoint remoteClient) + { + m_log.Info("[RADMIN]: AuthenticateUser: new request"); + + var responseData = (Hashtable)response.Value; + var requestData = (Hashtable)request.Params[0]; + + lock (m_requestLock) + { + try + { + CheckStringParameters(requestData, responseData, new[] + { + "user_firstname", + "user_lastname", + "user_password", + "token_lifetime" + }); + + var firstName = (string)requestData["user_firstname"]; + var lastName = (string)requestData["user_lastname"]; + var password = (string)requestData["user_password"]; + + var scene = m_application.SceneManager.CurrentOrFirstScene; + + if (scene.Equals(null)) + { + m_log.Debug("scene does not exist"); + throw new Exception("Scene does not exist."); + } + + var scopeID = scene.RegionInfo.ScopeID; + var account = scene.UserAccountService.GetUserAccount(scopeID, firstName, lastName); + + if (account.Equals(null) || account.PrincipalID.Equals(UUID.Zero)) + { + m_log.DebugFormat("avatar {0} {1} does not exist", firstName, lastName); + throw new Exception(String.Format("avatar {0} {1} does not exist", firstName, lastName)); + } + + if (String.IsNullOrEmpty(password)) + { + m_log.DebugFormat("[RADMIN]: AuthenticateUser: no password provided for {0} {1}", firstName, + lastName); + throw new Exception(String.Format("no password provided for {0} {1}", firstName, + lastName)); + } + + int lifetime; + if (int.TryParse((string)requestData["token_lifetime"], NumberStyles.Integer, CultureInfo.InvariantCulture, out lifetime) == false) + { + m_log.DebugFormat("[RADMIN]: AuthenticateUser: no token lifetime provided for {0} {1}", firstName, + lastName); + throw new Exception(String.Format("no token lifetime provided for {0} {1}", firstName, + lastName)); + } + + // Upper bound on lifetime set to 30s. + if (lifetime > 30) + { + m_log.DebugFormat("[RADMIN]: AuthenticateUser: token lifetime longer than 30s for {0} {1}", firstName, + lastName); + throw new Exception(String.Format("token lifetime longer than 30s for {0} {1}", firstName, + lastName)); + } + + var authModule = scene.RequestModuleInterface(); + if (authModule == null) + { + m_log.Debug("[RADMIN]: AuthenticateUser: no authentication module loded"); + throw new Exception("no authentication module loaded"); + } + + var token = authModule.Authenticate(account.PrincipalID, password, lifetime); + if (String.IsNullOrEmpty(token)) + { + m_log.DebugFormat("[RADMIN]: AuthenticateUser: authentication failed for {0} {1}", firstName, + lastName); + throw new Exception(String.Format("authentication failed for {0} {1}", firstName, + lastName)); + } + + m_log.DebugFormat("[RADMIN]: AuthenticateUser: account for user {0} {1} identified with token {2}", + firstName, lastName, token); + + responseData["token"] = token; + responseData["success"] = true; + + } + catch (Exception e) + { + responseData["success"] = false; + responseData["error"] = e.Message; + throw e; + } + + m_log.Info("[RADMIN]: AuthenticateUser: request complete"); + } + } + + /// /// Load an OAR file into a region.. /// /// incoming XML RPC request @@ -1329,8 +1488,11 @@ namespace OpenSim.ApplicationPlugins.RemoteController } IRegionArchiverModule archiver = scene.RequestModuleInterface(); + Dictionary archiveOptions = new Dictionary(); + if (mergeOar) archiveOptions.Add("merge", null); + if (skipAssets) archiveOptions.Add("skipAssets", null); if (archiver != null) - archiver.DearchiveRegion(filename, mergeOar, skipAssets, Guid.Empty); + archiver.DearchiveRegion(filename, Guid.Empty, archiveOptions); else throw new Exception("Archiver module not present for scene"); @@ -1389,7 +1551,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController /// private void XmlRpcSaveOARMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient) { - m_log.Info("[RADMIN]: Received Save OAR Administrator Request"); + m_log.Info("[RADMIN]: Received Save OAR Request"); Hashtable responseData = (Hashtable)response.Value; Hashtable requestData = (Hashtable)request.Params[0]; @@ -1435,8 +1597,14 @@ namespace OpenSim.ApplicationPlugins.RemoteController if (archiver != null) { + Guid requestId = Guid.NewGuid(); scene.EventManager.OnOarFileSaved += RemoteAdminOarSaveCompleted; - archiver.ArchiveRegion(filename, options); + + m_log.InfoFormat( + "[RADMIN]: Submitting save OAR request for {0} to file {1}, request ID {2}", + scene.Name, filename, requestId); + + archiver.ArchiveRegion(filename, requestId, options); lock (m_saveOarLock) Monitor.Wait(m_saveOarLock,5000); @@ -1457,12 +1625,16 @@ namespace OpenSim.ApplicationPlugins.RemoteController throw e; } - m_log.Info("[RADMIN]: Save OAR Administrator Request complete"); + m_log.Info("[RADMIN]: Save OAR Request complete"); } private void RemoteAdminOarSaveCompleted(Guid uuid, string name) { - m_log.DebugFormat("[RADMIN]: File processing complete for {0}", name); + if (name != "") + m_log.ErrorFormat("[RADMIN]: Saving of OAR file with request ID {0} failed with message {1}", uuid, name); + else + m_log.DebugFormat("[RADMIN]: Saved OAR file for request {0}", uuid); + lock (m_saveOarLock) Monitor.Pulse(m_saveOarLock); } @@ -1624,7 +1796,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController scene.RegionInfo.EstateSettings.EstateAccess = new UUID[]{}; if (scene.RegionInfo.Persistent) - scene.RegionInfo.EstateSettings.Save(); + m_application.EstateDataService.StoreEstateSettings(scene.RegionInfo.EstateSettings); m_log.Info("[RADMIN]: Access List Clear Request complete"); } @@ -1670,7 +1842,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } scene.RegionInfo.EstateSettings.EstateAccess = accessControlList.ToArray(); if (scene.RegionInfo.Persistent) - scene.RegionInfo.EstateSettings.Save(); + m_application.EstateDataService.StoreEstateSettings(scene.RegionInfo.EstateSettings); } responseData["added"] = addedUsers; @@ -1719,7 +1891,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController } scene.RegionInfo.EstateSettings.EstateAccess = accessControlList.ToArray(); if (scene.RegionInfo.Persistent) - scene.RegionInfo.EstateSettings.Save(); + m_application.EstateDataService.StoreEstateSettings(scene.RegionInfo.EstateSettings); } responseData["removed"] = removedUsers; @@ -1759,6 +1931,87 @@ namespace OpenSim.ApplicationPlugins.RemoteController m_log.Info("[RADMIN]: Access List List Request complete"); } + private void XmlRpcEstateReload(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient) + { + m_log.Info("[RADMIN]: Received Estate Reload Request"); + + Hashtable responseData = (Hashtable)response.Value; +// Hashtable requestData = (Hashtable)request.Params[0]; + + m_application.SceneManager.ForEachScene(s => + s.RegionInfo.EstateSettings = m_application.EstateDataService.LoadEstateSettings(s.RegionInfo.RegionID, false) + ); + + responseData["success"] = true; + + m_log.Info("[RADMIN]: Estate Reload Request complete"); + } + + private void XmlRpcGetAgentsMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient) + { + Hashtable responseData = (Hashtable)response.Value; + Hashtable requestData = (Hashtable)request.Params[0]; + + bool includeChildren = false; + + if (requestData.Contains("include_children")) + bool.TryParse((string)requestData["include_children"], out includeChildren); + + Scene scene; + GetSceneFromRegionParams(requestData, responseData, out scene); + + ArrayList xmlRpcRegions = new ArrayList(); + responseData["regions"] = xmlRpcRegions; + + Hashtable xmlRpcRegion = new Hashtable(); + xmlRpcRegions.Add(xmlRpcRegion); + + xmlRpcRegion["name"] = scene.Name; + xmlRpcRegion["id"] = scene.RegionInfo.RegionID.ToString(); + + List agents = scene.GetScenePresences(); + ArrayList xmlrpcAgents = new ArrayList(); + + foreach (ScenePresence agent in agents) + { + if (agent.IsChildAgent && !includeChildren) + continue; + + Hashtable xmlRpcAgent = new Hashtable(); + xmlRpcAgent.Add("name", agent.Name); + xmlRpcAgent.Add("id", agent.UUID.ToString()); + xmlRpcAgent.Add("type", agent.PresenceType.ToString()); + xmlRpcAgent.Add("current_parcel_id", agent.currentParcelUUID.ToString()); + + Vector3 pos = agent.AbsolutePosition; + xmlRpcAgent.Add("pos_x", pos.X.ToString()); + xmlRpcAgent.Add("pos_y", pos.Y.ToString()); + xmlRpcAgent.Add("pos_z", pos.Z.ToString()); + + Vector3 lookAt = agent.Lookat; + xmlRpcAgent.Add("lookat_x", lookAt.X.ToString()); + xmlRpcAgent.Add("lookat_y", lookAt.Y.ToString()); + xmlRpcAgent.Add("lookat_z", lookAt.Z.ToString()); + + Vector3 vel = agent.Velocity; + xmlRpcAgent.Add("vel_x", vel.X.ToString()); + xmlRpcAgent.Add("vel_y", vel.Y.ToString()); + xmlRpcAgent.Add("vel_z", vel.Z.ToString()); + + xmlRpcAgent.Add("is_flying", agent.Flying.ToString()); + xmlRpcAgent.Add("is_sat_on_ground", agent.SitGround.ToString()); + xmlRpcAgent.Add("is_sat_on_object", agent.IsSatOnObject.ToString()); + + xmlrpcAgents.Add(xmlRpcAgent); + } + + m_log.DebugFormat( + "[REMOTE ADMIN]: XmlRpcGetAgents found {0} agents in {1}", xmlrpcAgents.Count, scene.Name); + + xmlRpcRegion["agents"] = xmlrpcAgents; + responseData["success"] = true; + } + private void XmlRpcTeleportAgentMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient) { Hashtable responseData = (Hashtable)response.Value; @@ -1814,6 +2067,56 @@ namespace OpenSim.ApplicationPlugins.RemoteController responseData["success"] = true; } + private void XmlRpcResetLand(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient) + { + Hashtable requestData = (Hashtable)request.Params[0]; + Hashtable responseData = (Hashtable)response.Value; + + string musicURL = string.Empty; + UUID groupID = UUID.Zero; + uint flags = 0; + bool set_group = false, set_music = false, set_flags = false; + + if (requestData.Contains("group") && requestData["group"] != null) + set_group = UUID.TryParse(requestData["group"].ToString(), out groupID); + if (requestData.Contains("music") && requestData["music"] != null) + { + musicURL = requestData["music"].ToString(); + set_music = true; + } + if (requestData.Contains("flags") && requestData["flags"] != null) + set_flags = UInt32.TryParse(requestData["flags"].ToString(), out flags); + + m_log.InfoFormat("[RADMIN]: Received Reset Land Request group={0} musicURL={1} flags={2}", + (set_group ? groupID.ToString() : "unchanged"), + (set_music ? musicURL : "unchanged"), + (set_flags ? flags.ToString() : "unchanged")); + + m_application.SceneManager.ForEachScene(delegate(Scene s) + { + List parcels = s.LandChannel.AllParcels(); + foreach (ILandObject p in parcels) + { + if (set_music) + p.LandData.MusicURL = musicURL; + + if (set_group) + p.LandData.GroupID = groupID; + + if (set_flags) + p.LandData.Flags = flags; + + s.LandChannel.UpdateLandObject(p.LandData.LocalID, p.LandData); + } + } + ); + + responseData["success"] = true; + + m_log.Info("[RADMIN]: Reset Land Request complete"); + } + + /// /// Parse a float with the given parameter name from a request data hash table. /// @@ -1989,7 +2292,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController { account.ServiceURLs = new Dictionary(); account.ServiceURLs["HomeURI"] = string.Empty; - account.ServiceURLs["GatekeeperURI"] = string.Empty; account.ServiceURLs["InventoryServerURI"] = string.Empty; account.ServiceURLs["AssetServerURI"] = string.Empty; } @@ -2236,8 +2538,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController try { Dictionary inventoryMap = new Dictionary(); - CopyInventoryFolders(destination, source, AssetType.Clothing, inventoryMap, avatarAppearance); - CopyInventoryFolders(destination, source, AssetType.Bodypart, inventoryMap, avatarAppearance); + CopyInventoryFolders(destination, source, FolderType.Clothing, inventoryMap, avatarAppearance); + CopyInventoryFolders(destination, source, FolderType.BodyPart, inventoryMap, avatarAppearance); AvatarWearable[] wearables = avatarAppearance.Wearables; @@ -2273,20 +2575,20 @@ namespace OpenSim.ApplicationPlugins.RemoteController IInventoryService inventoryService = m_application.SceneManager.CurrentOrFirstScene.InventoryService; // Get Clothing folder of receiver - InventoryFolderBase destinationFolder = inventoryService.GetFolderForType(destination, AssetType.Clothing); + InventoryFolderBase destinationFolder = inventoryService.GetFolderForType(destination, FolderType.Clothing); if (destinationFolder == null) throw new Exception("Cannot locate folder(s)"); // Missing destination folder? This should *never* be the case - if (destinationFolder.Type != (short)AssetType.Clothing) + if (destinationFolder.Type != (short)FolderType.Clothing) { destinationFolder = new InventoryFolderBase(); destinationFolder.ID = UUID.Random(); destinationFolder.Name = "Clothing"; destinationFolder.Owner = destination; - destinationFolder.Type = (short)AssetType.Clothing; + destinationFolder.Type = (short)FolderType.Clothing; destinationFolder.ParentID = inventoryService.GetRootFolder(destination).ID; destinationFolder.Version = 1; inventoryService.AddFolder(destinationFolder); // store base record @@ -2404,7 +2706,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController /// This method is called by establishAppearance to copy inventory folders to make /// copies of Clothing and Bodyparts inventory folders and attaches worn attachments /// - private void CopyInventoryFolders(UUID destination, UUID source, AssetType assetType, Dictionary inventoryMap, + private void CopyInventoryFolders(UUID destination, UUID source, FolderType assetType, Dictionary inventoryMap, AvatarAppearance avatarAppearance) { IInventoryService inventoryService = m_application.SceneManager.CurrentOrFirstScene.InventoryService; @@ -2420,9 +2722,12 @@ namespace OpenSim.ApplicationPlugins.RemoteController { sourceFolder = new InventoryFolderBase(); sourceFolder.ID = UUID.Random(); - if (assetType == AssetType.Clothing) { + if (assetType == FolderType.Clothing) + { sourceFolder.Name = "Clothing"; - } else { + } + else + { sourceFolder.Name = "Body Parts"; } sourceFolder.Owner = source; @@ -2438,7 +2743,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController { destinationFolder = new InventoryFolderBase(); destinationFolder.ID = UUID.Random(); - if (assetType == AssetType.Clothing) + if (assetType == FolderType.Clothing) { destinationFolder.Name = "Clothing"; } @@ -2517,15 +2822,13 @@ namespace OpenSim.ApplicationPlugins.RemoteController /// private void ApplyNextOwnerPermissions(InventoryItemBase item) { - if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0) + if (item.InvType == (int)InventoryType.Object) { - if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0) - item.CurrentPermissions &= ~(uint)PermissionMask.Copy; - if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0) - item.CurrentPermissions &= ~(uint)PermissionMask.Transfer; - if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0) - item.CurrentPermissions &= ~(uint)PermissionMask.Modify; + uint perms = item.CurrentPermissions; + PermissionsUtil.ApplyFoldedPermissions(item.CurrentPermissions, ref perms); + item.CurrentPermissions = perms; } + item.CurrentPermissions &= item.NextPermissions; item.BasePermissions &= item.NextPermissions; item.EveryOnePermissions &= item.NextPermissions; @@ -2637,7 +2940,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController // Set home position GridRegion home = scene.GridService.GetRegionByPosition(scopeID, - (int)(regionXLocation * Constants.RegionSize), (int)(regionYLocation * Constants.RegionSize)); + (int)Util.RegionToWorldLoc(regionXLocation), (int)Util.RegionToWorldLoc(regionYLocation)); if (null == home) { m_log.WarnFormat("[RADMIN]: Unable to set home region for newly created user account {0} {1}", names[0], names[1]); } else { @@ -2679,16 +2982,16 @@ namespace OpenSim.ApplicationPlugins.RemoteController // m_log.DebugFormat("[RADMIN] {0} folders, {1} items in inventory", // uic.folders.Count, uic.items.Count); - InventoryFolderBase clothingFolder = inventoryService.GetFolderForType(ID, AssetType.Clothing); + InventoryFolderBase clothingFolder = inventoryService.GetFolderForType(ID, FolderType.Clothing); // This should *never* be the case - if (clothingFolder == null || clothingFolder.Type != (short)AssetType.Clothing) + if (clothingFolder == null || clothingFolder.Type != (short)FolderType.Clothing) { clothingFolder = new InventoryFolderBase(); clothingFolder.ID = UUID.Random(); clothingFolder.Name = "Clothing"; clothingFolder.Owner = ID; - clothingFolder.Type = (short)AssetType.Clothing; + clothingFolder.Type = (short)FolderType.Clothing; clothingFolder.ParentID = inventoryService.GetRootFolder(ID).ID; clothingFolder.Version = 1; inventoryService.AddFolder(clothingFolder); // store base record @@ -2734,7 +3037,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController extraFolder.ID = UUID.Random(); extraFolder.Name = outfitName; extraFolder.Owner = ID; - extraFolder.Type = (short)AssetType.Clothing; + extraFolder.Type = (short)FolderType.Clothing; extraFolder.Version = 1; extraFolder.ParentID = clothingFolder.ID; inventoryService.AddFolder(extraFolder); diff --git a/OpenSim/ApplicationPlugins/RemoteController/Resources/RemoteAdminPlugin.addin.xml b/OpenSim/ApplicationPlugins/RemoteController/Resources/RemoteAdminPlugin.addin.xml deleted file mode 100644 index d68f2e4..0000000 --- a/OpenSim/ApplicationPlugins/RemoteController/Resources/RemoteAdminPlugin.addin.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs deleted file mode 100644 index 8b43d42..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - /// - /// This interface represents the boundary between the general purpose - /// REST plugin handling, and the functionally specific handlers. The - /// handler knows only to initialize and terminate all such handlers - /// that it finds. Implementing this interface identifies the class as - /// a REST handler implementation. - /// - - internal interface IRest - { - void Initialize(); - void Close(); - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs deleted file mode 100644 index a88fe88..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using OpenSim.Framework.Servers.HttpServer; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - - /// - /// The handler delegates are not noteworthy. The allocator allows - /// a given handler to optionally subclass the base RequestData - /// structure to carry any locally required per-request state - /// needed. - /// - - public delegate void RestMethodHandler(RequestData rdata); - public delegate RequestData RestMethodAllocator(OSHttpRequest request, OSHttpResponse response, string path); - - /// - /// This interface exports the generic plugin-handling services - /// available to each loaded REST services module (IRest implementation) - /// - - internal interface IRestHandler - { - - string MsgId { get; } - string RequestId { get; } - - void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ma); - void AddStreamHandler(string httpMethod, string path, RestMethod method); - - } - -} 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; -using System.Xml; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Services.Interfaces; - -using OpenMetaverse; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - - /// - /// This class represents the current REST request. It - /// encapsulates the request/response state and takes care - /// of response generation without exposing the REST handler - /// to the actual mechanisms involved. - /// - /// This structure is created on entry to the Handler - /// method and is disposed of upon return. It is part of - /// the plug-in infrastructure, rather than the functionally - /// specific REST handler, and fundamental changes to - /// this should be reflected in the Rest HandlerVersion. The - /// object is instantiated, and may be extended by, any - /// given handler. See the inventory handler for an example - /// of this. - /// - /// If possible, the underlying request/response state is not - /// changed until the handler explicitly issues a Respond call. - /// This ensures that the request/response pair can be safely - /// processed by subsequent, unrelated, handlers even id the - /// agent handler had completed much of its processing. Think - /// of it as a transactional req/resp capability. - /// - - public class RequestData - { - - // HTTP Server interface data (Received values) - - internal OSHttpRequest request = null; - internal OSHttpResponse response = null; - internal string qprefix = null; - - // Request lifetime values - // buffer is global because it is referenced by the handler - // in supported of streamed requests. - // If a service provider wants to construct the message - // body explicitly it can use body to do this. The value - // in body is used if the buffer is still null when a response - // is generated. - // Storing information in body will suppress the return of - // statusBody which is only intended to report status on - // requests which do not themselves ordinarily generate - // an informational response. All of this is handled in - // Respond(). - - internal byte[] buffer = null; - internal string body = null; - internal string bodyType = "text/html"; - - // The encoding in effect is set to a server default. It may - // subsequently be overridden by a Content header. This - // value is established during construction and is used - // wherever encoding services are needed. - - internal Encoding encoding = Rest.Encoding; - - // These values are derived from the supplied URL. They - // are initialized during construction. - - internal string path = null; - internal string method = null; - internal Uri uri = null; - internal string query = null; - internal string hostname = "localhost"; - internal int port = 80; - - // The path part of the URI is decomposed. pathNodes - // is an array of every element in the URI. Parameters - // is an array that contains only those nodes that - // are not a part of the authority prefix - - private string[] pathNodes = null; - private string[] parameters = null; - private static readonly string[] EmptyPath = { String.Empty }; - - // The status code gets set during the course of processing - // and is the HTTP completion code. The status body is - // initialized during construction, is appended to during the - // course of execution, and is finalized during Respond - // processing. - // - // Fail processing marks the request as failed and this is - // then used to inhibit processing during Response processing. - - internal int statusCode = 0; - internal string statusBody = String.Empty; - internal bool fail = false; - - // This carries the URL to which the client should be redirected. - // It is set by the service provider using the Redirect call. - - internal string redirectLocation = null; - - // These values influence response processing. They can be set by - // service providers according to need. The defaults are generally - // good. - - internal bool keepAlive = false; - internal bool chunked = false; - - // XML related state - - internal XmlWriter writer = null; - internal XmlReader reader = null; - - // Internal working state - - private StringBuilder sbuilder = new StringBuilder(1024); - private MemoryStream xmldata = null; - - // This is used to make the response mechanism idempotent. - - internal bool handled = false; - - // Authentication related state - // - // Two supported authentication mechanisms are: - // scheme = Rest.AS_BASIC; - // scheme = Rest.AS_DIGEST; - // Presented in that order (as required by spec) - // A service provider can set the scheme variable to - // force selection of a particular authentication model - // (choosing from amongst those supported of course) - // - - internal bool authenticated = false; - internal string scheme = Rest.Scheme; - internal string realm = Rest.Realm; - internal string domain = null; - internal string nonce = null; - internal string cnonce = null; - internal string qop = Rest.Qop_Auth; - internal string opaque = null; - internal string stale = null; - internal string algorithm = Rest.Digest_MD5; - internal string authParms = null; - internal string authPrefix = null; - internal string userName = String.Empty; - internal string userPass = String.Empty; - - // Session related tables. These are only needed if QOP is set to "auth-sess" - // and for now at least, it is not. Session related authentication is of - // questionable merit in the context of REST anyway, but it is, arguably, more - // secure. - - private static Dictionary cntable = new Dictionary(); - private static Dictionary sktable = new Dictionary(); - - // This dictionary is used to keep track fo all of the parameters discovered - // when the authorisation header is anaylsed. - - private Dictionary authparms = new Dictionary(); - - // These regular expressions are used to decipher the various header entries. - - private static Regex schema = new Regex("^\\s*(?\\w+)\\s*.*", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - - private static Regex basicParms = new Regex("^\\s*(?:\\w+)\\s+(?\\S+)\\s*", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - - private static Regex digestParm1 = new Regex("\\s*(?\\w+)\\s*=\\s*\"(?[^\"]+)\"", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - - private static Regex digestParm2 = new Regex("\\s*(?\\w+)\\s*=\\s*(?[^\\p{P}\\s]+)", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - - private static Regex reuserPass = new Regex("(?[^:]+):(?[\\S\\s]*)", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - - // For efficiency, we create static instances of these objects - - private static MD5 md5hash = MD5.Create(); - - private static StringComparer sc = StringComparer.OrdinalIgnoreCase; - -#region properties - - // Just for convenience... - - internal string MsgId - { - get { return Rest.MsgId; } - } - - /// - /// Return a boolean indication of whether or no an authenticated user is - /// associated with this request. This could be wholly integrated, but - /// that would make authentication mandatory. - /// - - internal bool IsAuthenticated - { - get - { - if (Rest.Authenticate) - { - if (!authenticated) - { - authenticate(); - } - - return authenticated; - } - else return true; - } - } - - /// - /// Access to all 'nodes' in the supplied URI as an - /// array of strings. - /// - - internal string[] PathNodes - { - get - { - return pathNodes; - } - } - - /// - /// Access to all non-prefix 'nodes' in the supplied URI as an - /// array of strings. These identify a specific resource that - /// is managed by the authority (the prefix). - /// - - internal string[] Parameters - { - get - { - return parameters; - } - } - -#endregion properties - -#region constructors - - // Constructor - - internal RequestData(OSHttpRequest p_request, OSHttpResponse p_response, string p_qprefix) - { - - request = p_request; - response = p_response; - qprefix = p_qprefix; - - sbuilder.Length = 0; - - encoding = request.ContentEncoding; - - if (encoding == null) - { - encoding = Rest.Encoding; - } - - method = request.HttpMethod.ToLower(); - initUrl(); - - initParameters(p_qprefix.Length); - - } - -#endregion constructors - -#region authentication_common - - /// - /// The REST handler has requested authentication. Authentication - /// is considered to be with respect to the current values for - /// Realm, domain, etc. - /// - /// This method checks to see if the current request is already - /// authenticated for this domain. If it is, then it returns - /// true. If it is not, then it issues a challenge to the client - /// and responds negatively to the request. - /// - /// As soon as authentication failure is detected the method calls - /// DoChallenge() which terminates the request with REST exception - /// for unauthroized access. - /// - - private void authenticate() - { - - string authdata = request.Headers.Get("Authorization"); - string reqscheme = String.Empty; - - // If we don't have an authorization header, then this - // user is certainly not authorized. This is the typical - // pivot for the 1st request by a client. - - if (authdata == null) - { - Rest.Log.DebugFormat("{0} Challenge reason: No authorization data", MsgId); - DoChallenge(); - } - - // So, we have authentication data, now we have to check to - // see what we got and whether or not it is valid for the - // current domain. To do this we need to interpret the data - // provided in the Authorization header. First we need to - // identify the scheme being used and route accordingly. - - MatchCollection matches = schema.Matches(authdata); - - foreach (Match m in matches) - { - Rest.Log.DebugFormat("{0} Scheme matched : {1}", MsgId, m.Groups["scheme"].Value); - reqscheme = m.Groups["scheme"].Value.ToLower(); - } - - // If we want a specific authentication mechanism, make sure - // we get it. null indicates we don't care. non-null indicates - // a specific scheme requirement. - - if (scheme != null && scheme.ToLower() != reqscheme) - { - Rest.Log.DebugFormat("{0} Challenge reason: Requested scheme not acceptable", MsgId); - DoChallenge(); - } - - // In the future, these could be made into plug-ins... - // But for now at least we have no reason to use anything other - // then MD5. TLS/SSL are taken care of elsewhere. - - switch (reqscheme) - { - case "digest" : - Rest.Log.DebugFormat("{0} Digest authentication offered", MsgId); - DoDigest(authdata); - break; - - case "basic" : - Rest.Log.DebugFormat("{0} Basic authentication offered", MsgId); - DoBasic(authdata); - break; - } - - // If the current header is invalid, then a challenge is still needed. - - if (!authenticated) - { - Rest.Log.DebugFormat("{0} Challenge reason: Authentication failed", MsgId); - DoChallenge(); - } - - } - - /// - /// Construct the necessary WWW-Authenticate headers and fail the request - /// with a NOT AUTHORIZED response. The parameters are the union of values - /// required by the supported schemes. - /// - - private void DoChallenge() - { - Flush(); - nonce = Rest.NonceGenerator(); // should be unique per 401 (and it is) - Challenge(scheme, realm, domain, nonce, opaque, stale, algorithm, qop, authParms); - Fail(Rest.HttpStatusCodeNotAuthorized); - } - - /// - /// The Flush() call is here to support a problem encountered with the - /// client where an authentication rejection was lost because the rejection - /// may flow before the clienthas finished sending us the inbound data stream, - /// in which case the client responds to the socket error on out put, and - /// never sees the authentication challenge. The client should be fixed, - /// because this solution leaves the server prone to DOS attacks. A message - /// will be issued whenever flushing occurs. It can be enabled/disabled from - /// the configuration file. - /// - - private void Flush() - { - if (Rest.FlushEnabled) - { - byte[] dbuffer = new byte[8192]; - Rest.Log.WarnFormat("{0} REST server is flushing the inbound data stream", MsgId); - while (request.InputStream.Read(dbuffer,0,dbuffer.Length) != 0); - } - return; - } - - // Indicate that authentication is required - - private void Challenge(string scheme, string realm, string domain, string nonce, - string opaque, string stale, string alg, - string qop, string auth) - { - - sbuilder.Length = 0; - - // The service provider can force a particular scheme by - // assigning a value to scheme. - - // Basic authentication is pretty simple. - // Just specify the realm in question. - - if (scheme == null || scheme == Rest.AS_BASIC) - { - - sbuilder.Append(Rest.AS_BASIC); - - if (realm != null) - { - sbuilder.Append(" realm="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(realm); - sbuilder.Append(Rest.CS_DQUOTE); - } - AddHeader(Rest.HttpHeaderWWWAuthenticate,sbuilder.ToString()); - } - - sbuilder.Length = 0; - - // Digest authentication takes somewhat more - // to express. - - if (scheme == null || scheme == Rest.AS_DIGEST) - { - - sbuilder.Append(Rest.AS_DIGEST); - sbuilder.Append(" "); - - // Specify the effective realm. This should - // never be null if we are uthenticating, as it is required for all - // authentication schemes. It defines, in conjunction with the - // absolute URI information, the domain to which the authentication - // applies. It is an arbitrary string. I *believe* this allows an - // authentication to apply to disjoint resources within the same - // server. - - if (realm != null) - { - sbuilder.Append("realm="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(realm); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(Rest.CS_COMMA); - } - - // Share our nonce. This is *uniquely* generated each time a 401 is - // returned. We do not generate a very sophisticated nonce at the - // moment (it's simply a base64 encoded UUID). - - if (nonce != null) - { - sbuilder.Append("nonce="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(nonce); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(Rest.CS_COMMA); - } - - // The opaque string should be returned by the client unchanged in all - // subsequent requests. - - if (opaque != null) - { - sbuilder.Append("opaque="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(opaque); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(Rest.CS_COMMA); - } - - // This flag indicates that the authentication was rejected because the - // included nonce was stale. The server might use timestamp information - // in the nonce to determine this. We do not. - - if (stale != null) - { - sbuilder.Append("stale="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(stale); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(Rest.CS_COMMA); - } - - // Identifies the algorithm used to produce the digest and checksum. - // The default is MD5. - - if (alg != null) - { - sbuilder.Append("algorithm="); - sbuilder.Append(alg); - sbuilder.Append(Rest.CS_COMMA); - } - - // Theoretically QOP is optional, but it is required by a compliant - // with current versions of the scheme. In fact IE requires that QOP - // be specified and will refuse to authenticate otherwise. - - if (qop != String.Empty) - { - sbuilder.Append("qop="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(qop); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(Rest.CS_COMMA); - } - - // This parameter allows for arbitrary extensions to the protocol. - // Unrecognized values should be simply ignored. - - if (auth != null) - { - sbuilder.Append(auth); - sbuilder.Append(Rest.CS_COMMA); - } - - // We don't know the userid that will be used - // so we cannot make any authentication domain - // assumptions. So the prefix will determine - // this. - - sbuilder.Append("domain="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(qprefix); - sbuilder.Append(Rest.CS_DQUOTE); - - // Generate the authenticate header and we're basically - // done. - - AddHeader(Rest.HttpHeaderWWWAuthenticate,sbuilder.ToString()); - - } - - } - -#endregion authentication_common - -#region authentication_basic - - /// - /// Interpret a BASIC authorization claim. Some clients can only - /// understand this and also expect it to be the first one - /// offered. So we do. - /// OpenSim also needs this, as it is the only scheme that allows - /// authentication using the hashed passwords stored in the - /// user database. - /// - - private void DoBasic(string authdata) - { - - string response = null; - - MatchCollection matches = basicParms.Matches(authdata); - - // In the case of basic authentication there is - // only expected to be a single argument. - - foreach (Match m in matches) - { - authparms.Add("response",m.Groups["pval"].Value); - Rest.Log.DebugFormat("{0} Parameter matched : {1} = {2}", - MsgId, "response", m.Groups["pval"].Value); - } - - // Did we get a valid response? - - if (authparms.TryGetValue("response", out response)) - { - // Decode - response = Rest.Base64ToString(response); - Rest.Log.DebugFormat("{0} Auth response is: <{1}>", MsgId, response); - - // Extract user & password - Match m = reuserPass.Match(response); - userName = m.Groups["user"].Value; - userPass = m.Groups["pass"].Value; - - // Validate against user database - authenticated = Validate(userName,userPass); - } - - } - - /// - /// This method provides validation in support of the BASIC - /// authentication method. This is not normaly expected to be - /// used, but is included for completeness (and because I tried - /// it first). - /// - - private bool Validate(string user, string pass) - { - - Rest.Log.DebugFormat("{0} Simple User Validation", MsgId); - - // Both values are required - - if (user == null || pass == null) - return false; - - // Eliminate any leading or trailing spaces - user = user.Trim(); - - return vetPassword(user, pass); - - } - - /// - /// This is used by the BASIC authentication scheme to calculate - /// the double hash used by OpenSim to encode user's passwords. - /// It returns true, if the supplied password is actually correct. - /// If the specified user-id is not recognized, but the password - /// matches the God password, then this is accepted as an admin - /// session. - /// - - private bool vetPassword(string user, string pass) - { - - int x; - string first; - string last; - - // Distinguish the parts, if necessary - - if ((x=user.IndexOf(Rest.C_SPACE)) != -1) - { - first = user.Substring(0,x); - last = user.Substring(x+1); - } - else - { - first = user; - last = String.Empty; - } - - UserAccount account = Rest.UserServices.GetUserAccount(UUID.Zero, first, last); - - // If we don't recognize the user id, perhaps it is god? - if (account == null) - return pass == Rest.GodKey; - - return (Rest.AuthServices.Authenticate(account.PrincipalID, pass, 1) != string.Empty); - - } - -#endregion authentication_basic - -#region authentication_digest - - /// - /// This is an RFC2617 compliant HTTP MD5 Digest authentication - /// implementation. It has been tested with Firefox, Java HTTP client, - /// and Microsoft's Internet Explorer V7. - /// - - private void DoDigest(string authdata) - { - - string response = null; - - // Find all of the values of the for x = "y" - - MatchCollection matches = digestParm1.Matches(authdata); - - foreach (Match m in matches) - { - authparms.Add(m.Groups["parm"].Value,m.Groups["pval"].Value); - Rest.Log.DebugFormat("{0} String Parameter matched : {1} = {2}", - MsgId, m.Groups["parm"].Value,m.Groups["pval"].Value); - } - - // Find all of the values of the for x = y - - matches = digestParm2.Matches(authdata); - - foreach (Match m in matches) - { - authparms.Add(m.Groups["parm"].Value,m.Groups["pval"].Value); - Rest.Log.DebugFormat("{0} Tokenized Parameter matched : {1} = {2}", - MsgId, m.Groups["parm"].Value,m.Groups["pval"].Value); - } - - // A response string MUST be returned, otherwise we are - // NOT authenticated. - - Rest.Log.DebugFormat("{0} Validating authorization parameters", MsgId); - - if (authparms.TryGetValue("response", out response)) - { - - string temp = null; - - do - { - - string nck = null; - string ncl = null; - - // The userid is sent in clear text. Needed for the - // verification. - - authparms.TryGetValue("username", out userName); - - // All URI's of which this is a prefix are - // optimistically considered to be authenticated by the - // client. This is also needed to verify the response. - - authparms.TryGetValue("uri", out authPrefix); - - // There MUST be a nonce string present. We're not preserving any server - // side state and we can't validate the MD5 unless the client returns it - // to us, as it should. - - if (!authparms.TryGetValue("nonce", out nonce) || nonce == null) - { - Rest.Log.WarnFormat("{0} Authentication failed: nonce missing", MsgId); - break; - } - - // If there is an opaque string present, it had better - // match what we sent. - - if (authparms.TryGetValue("opaque", out temp)) - { - if (temp != opaque) - { - Rest.Log.WarnFormat("{0} Authentication failed: bad opaque value", MsgId); - break; - } - } - - // If an algorithm string is present, it had better - // match what we sent. - - if (authparms.TryGetValue("algorithm", out temp)) - { - if (temp != algorithm) - { - Rest.Log.WarnFormat("{0} Authentication failed: bad algorithm value", MsgId); - break; - } - } - - // Quality of protection considerations... - - if (authparms.TryGetValue("qop", out temp)) - { - - qop = temp.ToLower(); // replace with actual value used - - // if QOP was specified then - // these MUST be present. - - if (!authparms.ContainsKey("cnonce")) - { - Rest.Log.WarnFormat("{0} Authentication failed: cnonce missing", MsgId); - Fail(Rest.HttpStatusCodeBadRequest); - break; - } - - cnonce = authparms["cnonce"]; - - if (!authparms.TryGetValue("nc", out nck) || nck == null) - { - Rest.Log.WarnFormat("{0} Authentication failed: cnonce counter missing", MsgId); - Fail(Rest.HttpStatusCodeBadRequest); - break; - } - - Rest.Log.DebugFormat("{0} Comparing nonce indices", MsgId); - - if (cntable.TryGetValue(nonce, out ncl)) - { - Rest.Log.DebugFormat("{0} nonce values: Verify that request({1}) > Reference({2})", MsgId, nck, ncl); - - if (Rest.Hex2Int(ncl) >= Rest.Hex2Int(nck)) - { - Rest.Log.WarnFormat("{0} Authentication failed: bad cnonce counter", MsgId); - Fail(Rest.HttpStatusCodeBadRequest); - break; - } - cntable[nonce] = nck; - } - else - { - lock (cntable) cntable.Add(nonce, nck); - } - - } - else - { - - qop = String.Empty; - - // if QOP was not specified then - // these MUST NOT be present. - if (authparms.ContainsKey("cnonce")) - { - Rest.Log.WarnFormat("{0} Authentication failed: invalid cnonce", MsgId); - Fail(Rest.HttpStatusCodeBadRequest); - break; - } - if (authparms.ContainsKey("nc")) - { - Rest.Log.WarnFormat("{0} Authentication failed: invalid cnonce counter[2]", MsgId); - Fail(Rest.HttpStatusCodeBadRequest); - break; - } - } - - // Validate the supplied userid/password info - - authenticated = ValidateDigest(userName, nonce, cnonce, nck, authPrefix, response); - - } - while (false); - - } - else - Fail(Rest.HttpStatusCodeBadRequest); - - } - - /// - /// This mechanism is used by the digest authentication mechanism - /// to return the user's password. In fact, because the OpenSim - /// user's passwords are already hashed, and the HTTP mechanism - /// does not supply an open password, the hashed passwords cannot - /// be used unless the client has used the same salting mechanism - /// to has the password before using it in the authentication - /// algorithn. This is not inconceivable... - /// - - private string getPassword(string user) - { - - int x; - string first; - string last; - - // Distinguish the parts, if necessary - - if ((x=user.IndexOf(Rest.C_SPACE)) != -1) - { - first = user.Substring(0,x); - last = user.Substring(x+1); - } - else - { - first = user; - last = String.Empty; - } - - UserAccount account = Rest.UserServices.GetUserAccount(UUID.Zero, first, last); - // If we don;t recognize the user id, perhaps it is god? - - if (account == null) - { - Rest.Log.DebugFormat("{0} Administrator", MsgId); - return Rest.GodKey; - } - else - { - Rest.Log.DebugFormat("{0} Normal User {1}", MsgId, user); - - // !!! REFACTORING PROBLEM - // This is what it was. It doesn't work in 0.7 - // Nothing retrieves the password from the authentication service, there's only authentication. - //return udata.PasswordHash; - return string.Empty; - } - - } - - // Validate the request-digest - - private bool ValidateDigest(string user, string nonce, string cnonce, string nck, string uri, string response) - { - - string patt = null; - string payl = String.Empty; - string KDS = null; - string HA1 = null; - string HA2 = null; - string pass = getPassword(user); - - // Generate H(A1) - - if (algorithm == Rest.Digest_MD5Sess) - { - if (!sktable.ContainsKey(cnonce)) - { - patt = String.Format("{0}:{1}:{2}:{3}:{4}", user, realm, pass, nonce, cnonce); - HA1 = HashToString(patt); - sktable.Add(cnonce, HA1); - } - else - { - HA1 = sktable[cnonce]; - } - } - else - { - patt = String.Format("{0}:{1}:{2}", user, realm, pass); - HA1 = HashToString(patt); - } - - // Generate H(A2) - - if (qop == "auth-int") - { - patt = String.Format("{0}:{1}:{2}", request.HttpMethod, uri, HashToString(payl)); - } - else - { - patt = String.Format("{0}:{1}", request.HttpMethod, uri); - } - - HA2 = HashToString(patt); - - // Generate Digest - - if (qop != String.Empty) - { - patt = String.Format("{0}:{1}:{2}:{3}:{4}:{5}", HA1, nonce, nck, cnonce, qop, HA2); - } - else - { - patt = String.Format("{0}:{1}:{2}", HA1, nonce, HA2); - } - - KDS = HashToString(patt); - - // Compare the generated sequence with the original - - return (0 == sc.Compare(KDS, response)); - - } - - private string HashToString(string pattern) - { - - Rest.Log.DebugFormat("{0} Generate <{1}>", MsgId, pattern); - - byte[] hash = md5hash.ComputeHash(encoding.GetBytes(pattern)); - - sbuilder.Length = 0; - - for (int i = 0; i < hash.Length; i++) - { - sbuilder.Append(hash[i].ToString("x2")); - } - - Rest.Log.DebugFormat("{0} Hash = <{1}>", MsgId, sbuilder.ToString()); - - return sbuilder.ToString(); - - } - -#endregion authentication_digest - -#region service_interface - - /// - /// Conditionally set a normal completion code. This allows a normal - /// execution path to default. - /// - - internal void Complete() - { - if (statusCode == 0) - { - statusCode = Rest.HttpStatusCodeOK; - } - } - - /// - /// Indicate a functionally-dependent conclusion to the - /// request. See Rest.cs for a list of possible values. - /// - - internal void Complete(int code) - { - statusCode = code; - } - - /// - /// Indicate that a request should be redirected, using - /// the HTTP completion codes. Permanent and temporary - /// redirections may be indicated. The supplied URL is - /// the new location of the resource. - /// - - internal void Redirect(string Url, bool temp) - { - - redirectLocation = Url; - - if (temp) - { - statusCode = Rest.HttpStatusCodeTemporaryRedirect; - } - else - { - statusCode = Rest.HttpStatusCodePermanentRedirect; - } - - Fail(statusCode, String.Empty, true); - - } - - /// - /// Fail for an arbitrary reason. Just a failure with - /// headers. The supplied message will be returned in the - /// message body. - /// - - internal void Fail(int code) - { - Fail(code, String.Empty, false); - } - - /// - /// For the more adventurous. This failure also includes a - /// specified entity to be appended to the code-related - /// status string. - /// - - internal void Fail(int code, string addendum) - { - Fail(code, addendum, false); - } - - internal void Fail(int code, string addendum, bool reset) - { - - statusCode = code; - appendStatus(String.Format("({0}) : {1}", code, Rest.HttpStatusDesc[code])); - - // Add any final addendum to the status information - - if (addendum != String.Empty) - { - appendStatus(String.Format(addendum)); - } - - // Help us understand why the request is being rejected - - if (Rest.DEBUG) - { - Rest.Log.DebugFormat("{0} Request Failure State Dump", MsgId); - Rest.Log.DebugFormat("{0} Scheme = {1}", MsgId, scheme); - Rest.Log.DebugFormat("{0} Realm = {1}", MsgId, realm); - Rest.Log.DebugFormat("{0} Domain = {1}", MsgId, domain); - Rest.Log.DebugFormat("{0} Nonce = {1}", MsgId, nonce); - Rest.Log.DebugFormat("{0} CNonce = {1}", MsgId, cnonce); - Rest.Log.DebugFormat("{0} Opaque = {1}", MsgId, opaque); - Rest.Log.DebugFormat("{0} Stale = {1}", MsgId, stale); - Rest.Log.DebugFormat("{0} Algorithm = {1}", MsgId, algorithm); - Rest.Log.DebugFormat("{0} QOP = {1}", MsgId, qop); - Rest.Log.DebugFormat("{0} AuthPrefix = {1}", MsgId, authPrefix); - Rest.Log.DebugFormat("{0} UserName = {1}", MsgId, userName); - Rest.Log.DebugFormat("{0} UserPass = {1}", MsgId, userPass); - } - - fail = true; - - // Respond to the client's request, tag the response (for the - // benefit of trace) to indicate the reason. - - Respond(String.Format("Failure response: ({0}) : {1} ", - code, Rest.HttpStatusDesc[code])); - - // Finally initialize and the throw a RestException. All of the - // handler's infrastructure knows that this is a "normal" - // completion from a code point-of-view. - - RestException re = new RestException(Rest.HttpStatusDesc[code]+" <"+code+">"); - - re.statusCode = code; - re.statusDesc = Rest.HttpStatusDesc[code]; - re.httpmethod = method; - re.httppath = path; - - throw re; - - } - - // Reject this request - - internal void Reject() - { - Fail(Rest.HttpStatusCodeNotImplemented, "request rejected (not implemented)"); - } - - // This MUST be called by an agent handler before it returns - // control to Handle, otherwise the request will be ignored. - // This is called implciitly for the REST stream handlers and - // is harmless if it is called twice. - - internal virtual bool Respond(string reason) - { - - - Rest.Log.DebugFormat("{0} Respond ENTRY, handled = {1}, reason = {2}", MsgId, handled, reason); - - // We do this to try and make multiple Respond requests harmless, - // as it is sometimes convenient to isse a response without - // certain knowledge that it has not previously been done. - - if (!handled) - { - - Rest.Log.DebugFormat("{0} Generating Response", MsgId); - Rest.Log.DebugFormat("{0} Method is {1}", MsgId, method); - - // A Head request can NOT have a body! So don't waste time on - // formatting if we're going to reject it anyway! - - if (method != Rest.HEAD) - { - - Rest.Log.DebugFormat("{0} Response is not abbreviated", MsgId); - - // If the writer is non-null then we know that an XML - // data component exists. Flush and close the writer and - // then convert the result to the expected buffer format - // unless the request has already been failed for some - // reason. - - if (writer != null) - { - Rest.Log.DebugFormat("{0} XML Response handler extension ENTRY", MsgId); - Rest.Log.DebugFormat("{0} XML Response exists", MsgId); - writer.Flush(); - writer.Close(); - if (!fail) - { - buffer = xmldata.ToArray(); - AddHeader("Content-Type","application/xml"); - } - xmldata.Close(); - Rest.Log.DebugFormat("{0} XML Response encoded", MsgId); - Rest.Log.DebugFormat("{0} XML Response handler extension EXIT", MsgId); - } - - if (buffer == null && body != null) - { - buffer = encoding.GetBytes(body); - AddHeader("Content-Type",bodyType); - } - - // OK, if the buffer contains something, regardless of how - // it got there, set various response headers accordingly. - - if (buffer != null) - { - Rest.Log.DebugFormat("{0} Buffer-based entity", MsgId); - } - else - { - if (statusBody != String.Empty) - { - statusBody += Rest.statusTail; - buffer = encoding.GetBytes(statusBody); - AddHeader("Content-Type","text/html"); - } - else - { - statusBody = Rest.statusHead; - appendStatus(String.Format(": ({0}) {1}", - statusCode, Rest.HttpStatusDesc[statusCode])); - statusBody += Rest.statusTail; - buffer = encoding.GetBytes(statusBody); - AddHeader("Content-Type","text/html"); - } - } - - response.ContentLength64 = buffer.Length; - - if (response.ContentEncoding == null) - response.ContentEncoding = encoding; - - response.SendChunked = chunked; - response.KeepAlive = keepAlive; - - } - - // Set the status code & description. If nothing has been stored, - // we consider that a success. - - if (statusCode == 0) - { - Complete(); - } - - // Set the response code in the actual carrier - - response.StatusCode = statusCode; - - // For a redirect we need to set the relocation header accordingly - - if (response.StatusCode == (int) Rest.HttpStatusCodeTemporaryRedirect || - response.StatusCode == (int) Rest.HttpStatusCodePermanentRedirect) - { - Rest.Log.DebugFormat("{0} Re-direct location is {1}", MsgId, redirectLocation); - response.RedirectLocation = redirectLocation; - } - - // And include the status description if provided. - - response.StatusDescription = Rest.HttpStatusDesc[response.StatusCode]; - - // Finally we send back our response. - - // We've left the setting of handled' until the - // last minute because the header settings included - // above are pretty harmless. But everything from - // here on down probably leaves the response - // element unusable by anyone else. - - handled = true; - - // DumpHeaders(); - - // if (request.InputStream != null) - // { - // Rest.Log.DebugFormat("{0} Closing input stream", MsgId); - // request.InputStream.Close(); - // } - - if (buffer != null && buffer.Length != 0) - { - Rest.Log.DebugFormat("{0} Entity buffer, length = {1}", MsgId, buffer.Length); - // Rest.Log.DebugFormat("{0} Entity buffer, length = {1} : <{2}>", - // MsgId, buffer.Length, encoding.GetString(buffer)); - response.OutputStream.Write(buffer, 0, buffer.Length); - } - - // Closing the outputstream should complete the transmission process - - Rest.Log.DebugFormat("{0} Sending response", MsgId); - // response.OutputStream.Close(); - response.Send(); - - } - - Rest.Log.DebugFormat("{0} Respond EXIT, handled = {1}, reason = {2}", MsgId, handled, reason); - - return handled; - - } - - /// - /// These methods allow a service provider to manipulate the - /// request/response headers. The DumpHeaders method is intended - /// for problem diagnosis. - /// - - internal void AddHeader(string hdr, string data) - { - if (Rest.DEBUG) Rest.Log.DebugFormat("{0} Adding header: <{1}: {2}>", MsgId, hdr, data); - response.AddHeader(hdr, data); - } - - // internal void RemoveHeader(string hdr) - // { - // if (Rest.DEBUG) - // { - // Rest.Log.DebugFormat("{0} Removing header: <{1}>", MsgId, hdr); - // if (response.Headers.Get(hdr) == null) - // { - // Rest.Log.DebugFormat("{0} No such header existed", - // MsgId, hdr); - // } - // } - // response.Headers.Remove(hdr); - // } - - // internal void DumpHeaders() - // { - // if (Rest.DEBUG) - // { - // for (int i=0;i - /// Helper methods for deconstructing and reconstructing - /// URI path data. - /// - - private void initUrl() - { - - uri = request.Url; - - if (query == null) - { - query = uri.Query; - } - - // If the path has not been previously initialized, - // do so now. - - if (path == null) - { - path = uri.AbsolutePath; - if (path.EndsWith(Rest.UrlPathSeparator)) - path = path.Substring(0,path.Length-1); - } - - // If we succeeded in getting a path, perform any - // additional pre-processing required. - - if (path != null) - { - if (Rest.ExtendedEscape) - { - // Handle "+". Not a standard substitution, but - // common enough... - path = path.Replace(Rest.C_PLUS,Rest.C_SPACE); - } - pathNodes = path.Split(Rest.CA_PATHSEP); - } - else - { - pathNodes = EmptyPath; - } - - // Elimiate any %-escaped values. This is left until here - // so that escaped "+' are not mistakenly replaced. - - path = Uri.UnescapeDataString(path); - - // Request server context info - - hostname = uri.Host; - port = uri.Port; - - } - - private int initParameters(int prfxlen) - { - - if (prfxlen < path.Length-1) - { - parameters = path.Substring(prfxlen+1).Split(Rest.CA_PATHSEP); - } - else - { - parameters = new string[0]; - } - - // Generate a debug list of the decoded parameters - - if (Rest.DEBUG && prfxlen < path.Length-1) - { - Rest.Log.DebugFormat("{0} URI: Parameters: {1}", MsgId, path.Substring(prfxlen)); - for (int i = 0; i < parameters.Length; i++) - { - Rest.Log.DebugFormat("{0} Parameter[{1}]: {2}", MsgId, i, parameters[i]); - } - } - - return parameters.Length; - - } - -#endregion internal_methods - - } -} 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 @@ - - - - - - - - - - - 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Text; -using log4net; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Framework.Communications; -using OpenSim.Services.Interfaces; -using IAvatarService = OpenSim.Services.Interfaces.IAvatarService; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - public class Rest - { - internal static readonly ILog Log = - LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - internal static bool DEBUG = Log.IsDebugEnabled; - - /// - /// Supported authentication schemes - /// - - public const string AS_BASIC = "Basic"; // simple user/password verification - public const string AS_DIGEST = "Digest"; // password safe authentication - - /// Supported Digest algorithms - - public const string Digest_MD5 = "MD5"; // assumed default if omitted - public const string Digest_MD5Sess = "MD5-sess"; // session-span - not good for REST? - - public const string Qop_Auth = "auth"; // authentication only - public const string Qop_Int = "auth-int"; // TODO - - /// - /// These values have a single value for the whole - /// domain and lifetime of the plugin handler. We - /// make them static for ease of reference within - /// the assembly. These are initialized by the - /// RestHandler class during start-up. - /// - - internal static IRestHandler Plugin = null; - internal static OpenSimBase main = null; - internal static string Prefix = null; - internal static IConfig Config = null; - internal static string GodKey = null; - internal static bool Authenticate = true; - internal static bool Secure = true; - internal static bool ExtendedEscape = true; - internal static bool DumpAsset = false; - internal static bool Fill = true; - internal static bool FlushEnabled = true; - internal static string Realm = "OpenSim REST"; - internal static string Scheme = AS_BASIC; - internal static int DumpLineSize = 32; // Should be a multiple of 16 or (possibly) 4 - - /// - /// These are all dependent upon the Comms manager - /// being initialized. So they have to be properties - /// because the comms manager is now a module and is - /// not guaranteed to be there when the rest handler - /// initializes. - /// - - internal static IInventoryService InventoryServices - { - get { return main.SceneManager.CurrentOrFirstScene.InventoryService; } - } - - internal static IUserAccountService UserServices - { - get { return main.SceneManager.CurrentOrFirstScene.UserAccountService; } - } - - internal static IAuthenticationService AuthServices - { - get { return main.SceneManager.CurrentOrFirstScene.AuthenticationService; } - } - - internal static IAvatarService AvatarServices - { - get { return main.SceneManager.CurrentOrFirstScene.AvatarService; } - } - - internal static IAssetService AssetServices - { - get { return main.SceneManager.CurrentOrFirstScene.AssetService; } - } - - /// - /// HTTP requires that status information be generated for PUT - /// and POST opertaions. This is in support of that. The - /// operation verb gets substituted into the first string, - /// and the completion code is inserted into the tail. The - /// strings are put here to encourage consistency. - /// - - internal static string statusHead = "{0} status"; - internal static string statusTail = ""; - - internal static Dictionary HttpStatusDesc; - - static Rest() - { - HttpStatusDesc = new Dictionary(); - if (HttpStatusCodeArray.Length != HttpStatusDescArray.Length) - { - Log.ErrorFormat("{0} HTTP Status Code and Description arrays do not match"); - throw new Exception("HTTP Status array discrepancy"); - } - - // Repackage the data into something more tractable. The sparse - // nature of HTTP return codes makes an array a bad choice. - - for (int i=0; i - /// Version control for REST implementation. This - /// refers to the overall infrastructure represented - /// by the following classes - /// RequestData - /// RequestInventoryPlugin - /// Rest - /// It does no describe implementation classes such as - /// RestInventoryServices, which may morph much more - /// often. Such classes ARE dependent upon this however - /// and should check it in their Initialize method. - /// - - public static readonly float Version = 1.0F; - public const string Name = "REST 1.0"; - - /// - /// Currently defined HTTP methods. - /// Only GET and HEAD are required to be - /// supported by all servers. See Respond - /// to see how these are handled. - /// - - // REST AGENT 1.0 interpretations - public const string GET = "get"; // information retrieval - server state unchanged - public const string HEAD = "head"; // same as get except only the headers are returned. - public const string POST = "post"; // Replace the URI designated resource with the entity. - public const string PUT = "put"; // Add the entity to the context represented by the URI - public const string DELETE = "delete"; // Remove the URI designated resource from the server. - - public const string OPTIONS = "options"; // - public const string TRACE = "trace"; // - public const string CONNECT = "connect"; // - - // Define this in one place... - - public const string UrlPathSeparator = "/"; - public const string UrlMethodSeparator = ":"; - - // Redirection qualifications - - public const bool PERMANENT = false; - public const bool TEMPORARY = true; - - // Constant arrays used by String.Split - - public static readonly char C_SPACE = ' '; - public static readonly char C_SLASH = '/'; - public static readonly char C_PATHSEP = '/'; - public static readonly char C_COLON = ':'; - public static readonly char C_PLUS = '+'; - public static readonly char C_PERIOD = '.'; - public static readonly char C_COMMA = ','; - public static readonly char C_DQUOTE = '"'; - - public static readonly string CS_SPACE = " "; - public static readonly string CS_SLASH = "/"; - public static readonly string CS_PATHSEP = "/"; - public static readonly string CS_COLON = ":"; - public static readonly string CS_PLUS = "+"; - public static readonly string CS_PERIOD = "."; - public static readonly string CS_COMMA = ","; - public static readonly string CS_DQUOTE = "\""; - - public static readonly char[] CA_SPACE = { C_SPACE }; - public static readonly char[] CA_SLASH = { C_SLASH }; - public static readonly char[] CA_PATHSEP = { C_PATHSEP }; - public static readonly char[] CA_COLON = { C_COLON }; - public static readonly char[] CA_PERIOD = { C_PERIOD }; - public static readonly char[] CA_PLUS = { C_PLUS }; - public static readonly char[] CA_COMMA = { C_COMMA }; - public static readonly char[] CA_DQUOTE = { C_DQUOTE }; - - // HTTP Code Values (in value order) - - public const int HttpStatusCodeContinue = 100; - public const int HttpStatusCodeSwitchingProtocols = 101; - - public const int HttpStatusCodeOK = 200; - public const int HttpStatusCodeCreated = 201; - public const int HttpStatusCodeAccepted = 202; - public const int HttpStatusCodeNonAuthoritative = 203; - public const int HttpStatusCodeNoContent = 204; - public const int HttpStatusCodeResetContent = 205; - public const int HttpStatusCodePartialContent = 206; - - public const int HttpStatusCodeMultipleChoices = 300; - public const int HttpStatusCodePermanentRedirect = 301; - public const int HttpStatusCodeFound = 302; - public const int HttpStatusCodeSeeOther = 303; - public const int HttpStatusCodeNotModified = 304; - public const int HttpStatusCodeUseProxy = 305; - public const int HttpStatusCodeReserved306 = 306; - public const int HttpStatusCodeTemporaryRedirect = 307; - - public const int HttpStatusCodeBadRequest = 400; - public const int HttpStatusCodeNotAuthorized = 401; - public const int HttpStatusCodePaymentRequired = 402; - public const int HttpStatusCodeForbidden = 403; - public const int HttpStatusCodeNotFound = 404; - public const int HttpStatusCodeMethodNotAllowed = 405; - public const int HttpStatusCodeNotAcceptable = 406; - public const int HttpStatusCodeProxyAuthenticate = 407; - public const int HttpStatusCodeTimeOut = 408; - public const int HttpStatusCodeConflict = 409; - public const int HttpStatusCodeGone = 410; - public const int HttpStatusCodeLengthRequired = 411; - public const int HttpStatusCodePreconditionFailed = 412; - public const int HttpStatusCodeEntityTooLarge = 413; - public const int HttpStatusCodeUriTooLarge = 414; - public const int HttpStatusCodeUnsupportedMedia = 415; - public const int HttpStatusCodeRangeNotSatsified = 416; - public const int HttpStatusCodeExpectationFailed = 417; - - public const int HttpStatusCodeServerError = 500; - public const int HttpStatusCodeNotImplemented = 501; - public const int HttpStatusCodeBadGateway = 502; - public const int HttpStatusCodeServiceUnavailable = 503; - public const int HttpStatusCodeGatewayTimeout = 504; - public const int HttpStatusCodeHttpVersionError = 505; - - public static readonly int[] HttpStatusCodeArray = { - HttpStatusCodeContinue, - HttpStatusCodeSwitchingProtocols, - HttpStatusCodeOK, - HttpStatusCodeCreated, - HttpStatusCodeAccepted, - HttpStatusCodeNonAuthoritative, - HttpStatusCodeNoContent, - HttpStatusCodeResetContent, - HttpStatusCodePartialContent, - HttpStatusCodeMultipleChoices, - HttpStatusCodePermanentRedirect, - HttpStatusCodeFound, - HttpStatusCodeSeeOther, - HttpStatusCodeNotModified, - HttpStatusCodeUseProxy, - HttpStatusCodeReserved306, - HttpStatusCodeTemporaryRedirect, - HttpStatusCodeBadRequest, - HttpStatusCodeNotAuthorized, - HttpStatusCodePaymentRequired, - HttpStatusCodeForbidden, - HttpStatusCodeNotFound, - HttpStatusCodeMethodNotAllowed, - HttpStatusCodeNotAcceptable, - HttpStatusCodeProxyAuthenticate, - HttpStatusCodeTimeOut, - HttpStatusCodeConflict, - HttpStatusCodeGone, - HttpStatusCodeLengthRequired, - HttpStatusCodePreconditionFailed, - HttpStatusCodeEntityTooLarge, - HttpStatusCodeUriTooLarge, - HttpStatusCodeUnsupportedMedia, - HttpStatusCodeRangeNotSatsified, - HttpStatusCodeExpectationFailed, - HttpStatusCodeServerError, - HttpStatusCodeNotImplemented, - HttpStatusCodeBadGateway, - HttpStatusCodeServiceUnavailable, - HttpStatusCodeGatewayTimeout, - HttpStatusCodeHttpVersionError - }; - - // HTTP Status Descriptions (in status code order) - // This array must be kept strictly consistent with respect - // to the status code array above. - - public static readonly string[] HttpStatusDescArray = { - "Continue Request", - "Switching Protocols", - "OK", - "CREATED", - "ACCEPTED", - "NON-AUTHORITATIVE INFORMATION", - "NO CONTENT", - "RESET CONTENT", - "PARTIAL CONTENT", - "MULTIPLE CHOICES", - "PERMANENT REDIRECT", - "FOUND", - "SEE OTHER", - "NOT MODIFIED", - "USE PROXY", - "RESERVED CODE 306", - "TEMPORARY REDIRECT", - "BAD REQUEST", - "NOT AUTHORIZED", - "PAYMENT REQUIRED", - "FORBIDDEN", - "NOT FOUND", - "METHOD NOT ALLOWED", - "NOT ACCEPTABLE", - "PROXY AUTHENTICATION REQUIRED", - "TIMEOUT", - "CONFLICT", - "GONE", - "LENGTH REQUIRED", - "PRECONDITION FAILED", - "ENTITY TOO LARGE", - "URI TOO LARGE", - "UNSUPPORTED MEDIA", - "RANGE NOT SATISFIED", - "EXPECTATION FAILED", - "SERVER ERROR", - "NOT IMPLEMENTED", - "BAD GATEWAY", - "SERVICE UNAVAILABLE", - "GATEWAY TIMEOUT", - "HTTP VERSION NOT SUPPORTED" - }; - - // HTTP Headers - - public const string HttpHeaderAccept = "Accept"; - public const string HttpHeaderAcceptCharset = "Accept-Charset"; - public const string HttpHeaderAcceptEncoding = "Accept-Encoding"; - public const string HttpHeaderAcceptLanguage = "Accept-Language"; - public const string HttpHeaderAcceptRanges = "Accept-Ranges"; - public const string HttpHeaderAge = "Age"; - public const string HttpHeaderAllow = "Allow"; - public const string HttpHeaderAuthorization = "Authorization"; - public const string HttpHeaderCacheControl = "Cache-Control"; - public const string HttpHeaderConnection = "Connection"; - public const string HttpHeaderContentEncoding = "Content-Encoding"; - public const string HttpHeaderContentLanguage = "Content-Language"; - public const string HttpHeaderContentLength = "Content-Length"; - public const string HttpHeaderContentLocation = "Content-Location"; - public const string HttpHeaderContentMD5 = "Content-MD5"; - public const string HttpHeaderContentRange = "Content-Range"; - public const string HttpHeaderContentType = "Content-Type"; - public const string HttpHeaderDate = "Date"; - public const string HttpHeaderETag = "ETag"; - public const string HttpHeaderExpect = "Expect"; - public const string HttpHeaderExpires = "Expires"; - public const string HttpHeaderFrom = "From"; - public const string HttpHeaderHost = "Host"; - public const string HttpHeaderIfMatch = "If-Match"; - public const string HttpHeaderIfModifiedSince = "If-Modified-Since"; - public const string HttpHeaderIfNoneMatch = "If-None-Match"; - public const string HttpHeaderIfRange = "If-Range"; - public const string HttpHeaderIfUnmodifiedSince = "If-Unmodified-Since"; - public const string HttpHeaderLastModified = "Last-Modified"; - public const string HttpHeaderLocation = "Location"; - public const string HttpHeaderMaxForwards = "Max-Forwards"; - public const string HttpHeaderPragma = "Pragma"; - public const string HttpHeaderProxyAuthenticate = "Proxy-Authenticate"; - public const string HttpHeaderProxyAuthorization = "Proxy-Authorization"; - public const string HttpHeaderRange = "Range"; - public const string HttpHeaderReferer = "Referer"; - public const string HttpHeaderRetryAfter = "Retry-After"; - public const string HttpHeaderServer = "Server"; - public const string HttpHeaderTE = "TE"; - public const string HttpHeaderTrailer = "Trailer"; - public const string HttpHeaderTransferEncoding = "Transfer-Encoding"; - public const string HttpHeaderUpgrade = "Upgrade"; - public const string HttpHeaderUserAgent = "User-Agent"; - public const string HttpHeaderVary = "Vary"; - public const string HttpHeaderVia = "Via"; - public const string HttpHeaderWarning = "Warning"; - public const string HttpHeaderWWWAuthenticate = "WWW-Authenticate"; - - /// Utility routines - - public static string StringToBase64(string str) - { - try - { - byte[] encData_byte = new byte[str.Length]; - encData_byte = Util.UTF8.GetBytes(str); - return Convert.ToBase64String(encData_byte); - } - catch - { - return String.Empty; - } - } - - public static string Base64ToString(string str) - { - try - { - return Util.Base64ToString(str); - } - catch - { - return String.Empty; - } - } - - private const string hvals = "0123456789abcdef"; - - public static int Hex2Int(string hex) - { - int val = 0; - int sum = 0; - string tmp = null; - - if (hex != null) - { - tmp = hex.ToLower(); - for (int i = 0; i < tmp.Length; i++) - { - val = hvals.IndexOf(tmp[i]); - if (val == -1) - break; - sum *= 16; - sum += val; - } - } - - return sum; - } - - // Nonce management - - public static string NonceGenerator() - { - return StringToBase64(CreationDate + Guid.NewGuid().ToString()); - } - - // Dump the specified data stream - - public static void Dump(byte[] data) - { - char[] buffer = new char[DumpLineSize]; - int cc = 0; - - for (int i = 0; i < data.Length; i++) - { - if (i % DumpLineSize == 0) Console.Write("\n{0}: ",i.ToString("d8")); - - if (i % 4 == 0) Console.Write(" "); - - Console.Write("{0}",data[i].ToString("x2")); - - if (data[i] < 127 && data[i] > 31) - buffer[i % DumpLineSize] = (char) data[i]; - else - buffer[i % DumpLineSize] = '.'; - - cc++; - - if (i != 0 && (i + 1) % DumpLineSize == 0) - { - Console.Write(" |"+(new String(buffer))+"|"); - cc = 0; - } - } - - // Finish off any incomplete line - - if (cc != 0) - { - for (int i = cc ; i < DumpLineSize; i++) - { - if (i % 4 == 0) Console.Write(" "); - Console.Write(" "); - buffer[i % DumpLineSize] = ' '; - } - Console.WriteLine(" |"+(new String(buffer))+"|"); - } - else - { - Console.Write("\n"); - } - } - } - - // Local exception type - - public class RestException : Exception - { - internal int statusCode; - internal string statusDesc; - internal string httpmethod; - internal string httppath; - - public RestException(string msg) : base(msg) - { - } - } -} 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Xml; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Services.Interfaces; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - - public class RestAppearanceServices : IRest - { -// private static readonly int PARM_USERID = 0; - - // private static readonly int PARM_PATH = 1; - -// private bool enabled = false; - private string qPrefix = "appearance"; - - /// - /// The constructor makes sure that the service prefix is absolute - /// and the registers the service handler and the allocator. - /// - - public RestAppearanceServices() - { - Rest.Log.InfoFormat("{0} User appearance services initializing", MsgId); - Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); - - // If a relative path was specified for the handler's domain, - // add the standard prefix to make it absolute, e.g. /admin - - if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) - { - Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId); - qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); - qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); - Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix); - } - - // Register interface using the absolute URI. - - Rest.Plugin.AddPathHandler(DoAppearance,qPrefix,Allocate); - - // Activate if everything went OK - -// enabled = true; - - Rest.Log.InfoFormat("{0} User appearance services initialization complete", MsgId); - } - - /// - /// Post-construction, pre-enabled initialization opportunity - /// Not currently exploited. - /// - - public void Initialize() - { - } - - /// - /// Called by the plug-in to halt service processing. Local processing is - /// disabled. - /// - - public void Close() - { -// enabled = false; - Rest.Log.InfoFormat("{0} User appearance services closing down", MsgId); - } - - /// - /// This property is declared locally because it is used a lot and - /// brevity is nice. - /// - - internal string MsgId - { - get { return Rest.MsgId; } - } - - #region Interface - - /// - /// The plugin (RestHandler) calls this method to allocate the request - /// state carrier for a new request. It is destroyed when the request - /// completes. All request-instance specific state is kept here. This - /// is registered when this service provider is registered. - /// - /// Inbound HTTP request information - /// Outbound HTTP request information - /// REST service domain prefix - /// A RequestData instance suitable for this service - - private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) - { - return (RequestData) new AppearanceRequestData(request, response, prefix); - } - - /// - /// This method is registered with the handler when this service provider - /// is initialized. It is called whenever the plug-in identifies this service - /// provider as the best match for a given request. - /// It handles all aspects of inventory REST processing, i.e. /admin/inventory - /// - /// A consolidated HTTP request work area - - private void DoAppearance(RequestData hdata) - { - // !!! REFACTORIMG PROBLEM. This needs rewriting for 0.7 - - //AppearanceRequestData rdata = (AppearanceRequestData) hdata; - - //Rest.Log.DebugFormat("{0} DoAppearance ENTRY", MsgId); - - //// If we're disabled, do nothing. - - //if (!enabled) - //{ - // return; - //} - - //// Now that we know this is a serious attempt to - //// access inventory data, we should find out who - //// is asking, and make sure they are authorized - //// to do so. We need to validate the caller's - //// identity before revealing anything about the - //// status quo. Authenticate throws an exception - //// via Fail if no identity information is present. - //// - //// With the present HTTP server we can't use the - //// builtin authentication mechanisms because they - //// would be enforced for all in-bound requests. - //// Instead we look at the headers ourselves and - //// handle authentication directly. - - //try - //{ - // if (!rdata.IsAuthenticated) - // { - // rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName)); - // } - //} - //catch (RestException e) - //{ - // if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) - // { - // Rest.Log.WarnFormat("{0} User not authenticated", MsgId); - // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); - // } - // else - // { - // Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); - // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); - // } - // throw (e); - //} - - //Rest.Log.DebugFormat("{0} Authenticated {1}", MsgId, rdata.userName); - - //// We can only get here if we are authorized - //// - //// The requestor may have specified an UUID or - //// a conjoined FirstName LastName string. We'll - //// try both. If we fail with the first, UUID, - //// attempt, we try the other. As an example, the - //// URI for a valid inventory request might be: - //// - //// http://:/admin/inventory/Arthur Dent - //// - //// Indicating that this is an inventory request for - //// an avatar named Arthur Dent. This is ALL that is - //// required to designate a GET for an entire - //// inventory. - //// - - //// Do we have at least a user agent name? - - //if (rdata.Parameters.Length < 1) - //{ - // Rest.Log.WarnFormat("{0} Appearance: No user agent identifier specified", MsgId); - // rdata.Fail(Rest.HttpStatusCodeBadRequest, "no user identity specified"); - //} - - //// The first parameter MUST be the agent identification, either an UUID - //// or a space-separated First-name Last-Name specification. We check for - //// an UUID first, if anyone names their character using a valid UUID - //// that identifies another existing avatar will cause this a problem... - - //try - //{ - // rdata.uuid = new UUID(rdata.Parameters[PARM_USERID]); - // Rest.Log.DebugFormat("{0} UUID supplied", MsgId); - // rdata.userProfile = Rest.UserServices.GetUserProfile(rdata.uuid); - //} - //catch - //{ - // string[] names = rdata.Parameters[PARM_USERID].Split(Rest.CA_SPACE); - // if (names.Length == 2) - // { - // Rest.Log.DebugFormat("{0} Agent Name supplied [2]", MsgId); - // rdata.userProfile = Rest.UserServices.GetUserProfile(names[0],names[1]); - // } - // else - // { - // Rest.Log.WarnFormat("{0} A Valid UUID or both first and last names must be specified", MsgId); - // rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid user identity"); - // } - //} - - //// If the user profile is null then either the server is broken, or the - //// user is not known. We always assume the latter case. - - //if (rdata.userProfile != null) - //{ - // Rest.Log.DebugFormat("{0} User profile obtained for agent {1} {2}", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - //} - //else - //{ - // Rest.Log.WarnFormat("{0} No user profile for {1}", MsgId, rdata.path); - // rdata.Fail(Rest.HttpStatusCodeNotFound, "unrecognized user identity"); - //} - - //// If we get to here, then we have effectively validated the user's - - //switch (rdata.method) - //{ - // case Rest.HEAD : // Do the processing, set the status code, suppress entity - // DoGet(rdata); - // rdata.buffer = null; - // break; - - // case Rest.GET : // Do the processing, set the status code, return entity - // DoGet(rdata); - // break; - - // case Rest.PUT : // Update named element - // DoUpdate(rdata); - // break; - - // case Rest.POST : // Add new information to identified context. - // DoExtend(rdata); - // break; - - // case Rest.DELETE : // Delete information - // DoDelete(rdata); - // break; - - // default : - // Rest.Log.WarnFormat("{0} Method {1} not supported for {2}", - // MsgId, rdata.method, rdata.path); - // rdata.Fail(Rest.HttpStatusCodeMethodNotAllowed, - // String.Format("{0} not supported", rdata.method)); - // break; - //} - } - - #endregion Interface - - #region method-specific processing - - /// - /// This method implements GET processing for user's appearance. - /// - /// HTTP service request work area - -// private void DoGet(AppearanceRequestData rdata) -// { -// AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID); -// -// if (adata == null) -// { -// rdata.Fail(Rest.HttpStatusCodeNoContent, -// String.Format("appearance data not found for user {0} {1}", -// rdata.userProfile.FirstName, rdata.userProfile.SurName)); -// } -// rdata.userAppearance = adata.ToAvatarAppearance(rdata.userProfile.ID); -// -// rdata.initXmlWriter(); -// -// FormatUserAppearance(rdata); -// -// // Indicate a successful request -// -// rdata.Complete(); -// -// // Send the response to the user. The body will be implicitly -// // constructed from the result of the XML writer. -// -// rdata.Respond(String.Format("Appearance {0} Normal completion", rdata.method)); -// } - - /// - /// POST adds NEW information to the user profile database. - /// This effectively resets the appearance before applying those - /// characteristics supplied in the request. - /// - -// private void DoExtend(AppearanceRequestData rdata) -// { -// -// bool created = false; -// bool modified = false; -// string newnode = String.Empty; -// -// Rest.Log.DebugFormat("{0} POST ENTRY", MsgId); -// -// //AvatarAppearance old = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID); -// -// rdata.userAppearance = new AvatarAppearance(); -// -// // Although the following behavior is admitted by HTTP I am becoming -// // increasingly doubtful that it is appropriate for REST. If I attempt to -// // add a new record, and it already exists, then it seems to me that the -// // attempt should fail, rather than update the existing record. -// AvatarData adata = null; -// if (GetUserAppearance(rdata)) -// { -// modified = rdata.userAppearance != null; -// created = !modified; -// adata = new AvatarData(rdata.userAppearance); -// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata); -// // Rest.UserServices.UpdateUserProfile(rdata.userProfile); -// } -// else -// { -// created = true; -// adata = new AvatarData(rdata.userAppearance); -// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata); -// // Rest.UserServices.UpdateUserProfile(rdata.userProfile); -// } -// -// if (created) -// { -// newnode = String.Format("{0} {1}", rdata.userProfile.FirstName, -// rdata.userProfile.SurName); -// // Must include a location header with a URI that identifies the new resource. -// -// rdata.AddHeader(Rest.HttpHeaderLocation,String.Format("http://{0}{1}:{2}{3}{4}", -// rdata.hostname,rdata.port,rdata.path,Rest.UrlPathSeparator, newnode)); -// rdata.Complete(Rest.HttpStatusCodeCreated); -// -// } -// else -// { -// if (modified) -// { -// rdata.Complete(Rest.HttpStatusCodeOK); -// } -// else -// { -// rdata.Complete(Rest.HttpStatusCodeNoContent); -// } -// } -// -// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method)); -// -// } - - /// - /// This updates the user's appearance. not all aspects need to be provided, - /// only those supplied will be changed. - /// - -// private void DoUpdate(AppearanceRequestData rdata) -// { -// -// // REFACTORING PROBLEM This was commented out. It doesn't work for 0.7 -// -// //bool created = false; -// //bool modified = false; -// -// -// //rdata.userAppearance = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID); -// -// //// If the user exists then this is considered a modification regardless -// //// of what may, or may not be, specified in the payload. -// -// //if (rdata.userAppearance != null) -// //{ -// // modified = true; -// // Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance); -// // Rest.UserServices.UpdateUserProfile(rdata.userProfile); -// //} -// -// //if (created) -// //{ -// // rdata.Complete(Rest.HttpStatusCodeCreated); -// //} -// //else -// //{ -// // if (modified) -// // { -// // rdata.Complete(Rest.HttpStatusCodeOK); -// // } -// // else -// // { -// // rdata.Complete(Rest.HttpStatusCodeNoContent); -// // } -// //} -// -// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method)); -// -// } - - /// - /// Delete the specified user's appearance. This actually performs a reset - /// to the default avatar appearance, if the info is already there. - /// Existing ownership is preserved. All prior updates are lost and can not - /// be recovered. - /// -// private void DoDelete(AppearanceRequestData rdata) -// { -// AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID); -// -// if (adata != null) -// { -// AvatarAppearance old = adata.ToAvatarAppearance(rdata.userProfile.ID); -// rdata.userAppearance = new AvatarAppearance(); -// rdata.userAppearance.Owner = old.Owner; -// adata = new AvatarData(rdata.userAppearance); -// -// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata); -// -// rdata.Complete(); -// } -// else -// { -// -// rdata.Complete(Rest.HttpStatusCodeNoContent); -// } -// -// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method)); -// } - -#endregion method-specific processing - - private bool GetUserAppearance(AppearanceRequestData rdata) - { - - XmlReader xml; - bool indata = false; - - rdata.initXmlReader(); - xml = rdata.reader; - - while (xml.Read()) - { - switch (xml.NodeType) - { - case XmlNodeType.Element : - switch (xml.Name) - { - case "Appearance" : - if (xml.MoveToAttribute("Height")) - { - rdata.userAppearance.AvatarHeight = (float) Convert.ToDouble(xml.Value); - indata = true; - } -// if (xml.MoveToAttribute("Owner")) -// { -// rdata.userAppearance.Owner = (UUID)xml.Value; -// indata = true; -// } - if (xml.MoveToAttribute("Serial")) - { - rdata.userAppearance.Serial = Convert.ToInt32(xml.Value); - indata = true; - } - break; -/* - case "Body" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.BodyItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.BodyAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Skin" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.SkinItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.SkinAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Hair" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.HairItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.HairAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Eyes" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.EyesItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.EyesAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Shirt" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.ShirtItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.ShirtAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Pants" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.PantsItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.PantsAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Shoes" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.ShoesItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.ShoesAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Socks" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.SocksItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.SocksAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Jacket" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.JacketItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.JacketAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Gloves" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.GlovesItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.GlovesAsset = (UUID)xml.Value; - indata = true; - } - break; - case "UnderShirt" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.UnderShirtItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.UnderShirtAsset = (UUID)xml.Value; - indata = true; - } - break; - case "UnderPants" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.UnderPantsItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.UnderPantsAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Skirt" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.SkirtItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.SkirtAsset = (UUID)xml.Value; - indata = true; - } - break; -*/ - case "Attachment" : - { - - int ap; - UUID asset; - UUID item; - - if (xml.MoveToAttribute("AtPoint")) - { - ap = Convert.ToInt32(xml.Value); - if (xml.MoveToAttribute("Asset")) - { - asset = new UUID(xml.Value); - if (xml.MoveToAttribute("Asset")) - { - item = new UUID(xml.Value); - rdata.userAppearance.SetAttachment(ap, item, asset); - indata = true; - } - } - } - } - break; - case "Texture" : - if (xml.MoveToAttribute("Default")) - { - rdata.userAppearance.Texture = new Primitive.TextureEntry(new UUID(xml.Value)); - indata = true; - } - break; - case "Face" : - { - uint index; - if (xml.MoveToAttribute("Index")) - { - index = Convert.ToUInt32(xml.Value); - if (xml.MoveToAttribute("Id")) - { - rdata.userAppearance.Texture.CreateFace(index).TextureID = new UUID(xml.Value); - indata = true; - } - } - } - break; - case "VisualParameters" : - { - xml.ReadContentAsBase64(rdata.userAppearance.VisualParams, - 0, rdata.userAppearance.VisualParams.Length); - indata = true; - } - break; - } - break; - } - } - - return indata; - - } - - private void FormatPart(AppearanceRequestData rdata, string part, UUID item, UUID asset) - { - if (item != UUID.Zero || asset != UUID.Zero) - { - rdata.writer.WriteStartElement(part); - if (item != UUID.Zero) - { - rdata.writer.WriteAttributeString("Item",item.ToString()); - } - - if (asset != UUID.Zero) - { - rdata.writer.WriteAttributeString("Asset",asset.ToString()); - } - rdata.writer.WriteEndElement(); - } - } - - private void FormatUserAppearance(AppearanceRequestData rdata) - { - - Rest.Log.DebugFormat("{0} FormatUserAppearance", MsgId); - - if (rdata.userAppearance != null) - { - - Rest.Log.DebugFormat("{0} FormatUserAppearance: appearance object exists", MsgId); - rdata.writer.WriteStartElement("Appearance"); - - rdata.writer.WriteAttributeString("Height", rdata.userAppearance.AvatarHeight.ToString()); -// if (rdata.userAppearance.Owner != UUID.Zero) -// rdata.writer.WriteAttributeString("Owner", rdata.userAppearance.Owner.ToString()); - rdata.writer.WriteAttributeString("Serial", rdata.userAppearance.Serial.ToString()); - -/* - FormatPart(rdata, "Body", rdata.userAppearance.BodyItem, rdata.userAppearance.BodyAsset); - FormatPart(rdata, "Skin", rdata.userAppearance.SkinItem, rdata.userAppearance.SkinAsset); - FormatPart(rdata, "Hair", rdata.userAppearance.HairItem, rdata.userAppearance.HairAsset); - FormatPart(rdata, "Eyes", rdata.userAppearance.EyesItem, rdata.userAppearance.EyesAsset); - - FormatPart(rdata, "Shirt", rdata.userAppearance.ShirtItem, rdata.userAppearance.ShirtAsset); - FormatPart(rdata, "Pants", rdata.userAppearance.PantsItem, rdata.userAppearance.PantsAsset); - FormatPart(rdata, "Skirt", rdata.userAppearance.SkirtItem, rdata.userAppearance.SkirtAsset); - FormatPart(rdata, "Shoes", rdata.userAppearance.ShoesItem, rdata.userAppearance.ShoesAsset); - FormatPart(rdata, "Socks", rdata.userAppearance.SocksItem, rdata.userAppearance.SocksAsset); - - FormatPart(rdata, "Jacket", rdata.userAppearance.JacketItem, rdata.userAppearance.JacketAsset); - FormatPart(rdata, "Gloves", rdata.userAppearance.GlovesItem, rdata.userAppearance.GlovesAsset); - - FormatPart(rdata, "UnderShirt", rdata.userAppearance.UnderShirtItem, rdata.userAppearance.UnderShirtAsset); - FormatPart(rdata, "UnderPants", rdata.userAppearance.UnderPantsItem, rdata.userAppearance.UnderPantsAsset); -*/ - Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting attachments", MsgId); - - rdata.writer.WriteStartElement("Attachments"); - List attachments = rdata.userAppearance.GetAttachments(); - foreach (AvatarAttachment attach in attachments) - { - rdata.writer.WriteStartElement("Attachment"); - rdata.writer.WriteAttributeString("AtPoint", attach.AttachPoint.ToString()); - rdata.writer.WriteAttributeString("Item", attach.ItemID.ToString()); - rdata.writer.WriteAttributeString("Asset", attach.AssetID.ToString()); - rdata.writer.WriteEndElement(); - } - rdata.writer.WriteEndElement(); - - Primitive.TextureEntry texture = rdata.userAppearance.Texture; - - if (texture != null && (texture.DefaultTexture != null || texture.FaceTextures != null)) - { - Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting textures", MsgId); - - rdata.writer.WriteStartElement("Texture"); - - if (texture.DefaultTexture != null) - { - Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting default texture", MsgId); - rdata.writer.WriteAttributeString("Default", - texture.DefaultTexture.TextureID.ToString()); - } - - if (texture.FaceTextures != null) - { - - Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting face textures", MsgId); - - for (int i=0; i - /// These are the inventory specific request/response state - /// extensions. - /// - - internal UUID uuid = UUID.Zero; - internal UserProfileData userProfile = null; - internal AvatarAppearance userAppearance = null; - - internal AppearanceRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) - : base(request, response, prefix) - { - } - - } - - #endregion Appearance RequestData extension - - } -} 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Xml; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - public class RestAssetServices : IRest - { - private bool enabled = false; - private string qPrefix = "assets"; - - // A simple constructor is used to handle any once-only - // initialization of working classes. - - public RestAssetServices() - { - Rest.Log.InfoFormat("{0} Asset services initializing", MsgId); - Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); - - // If the handler specifies a relative path for its domain - // then we must add the standard absolute prefix, e.g. /admin - - if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) - { - Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix); - qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); - Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix); - } - - // Register interface using the fully-qualified prefix - - Rest.Plugin.AddPathHandler(DoAsset, qPrefix, Allocate); - - // Activate if all went OK - - enabled = true; - - Rest.Log.InfoFormat("{0} Asset services initialization complete", MsgId); - } - - // Post-construction, pre-enabled initialization opportunity - // Not currently exploited. - - public void Initialize() - { - } - - // Called by the plug-in to halt REST processing. Local processing is - // disabled, and control blocks until all current processing has - // completed. No new processing will be started - - public void Close() - { - enabled = false; - Rest.Log.InfoFormat("{0} Asset services ({1}) closing down", MsgId, qPrefix); - } - - // Properties - - internal string MsgId - { - get { return Rest.MsgId; } - } - - #region Interface - - private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) - { - return (RequestData) new AssetRequestData(request, response, prefix); - } - - // Asset Handler - - private void DoAsset(RequestData rparm) - { - if (!enabled) return; - - AssetRequestData rdata = (AssetRequestData) rparm; - - Rest.Log.DebugFormat("{0} REST Asset handler ({1}) ENTRY", MsgId, qPrefix); - - // Now that we know this is a serious attempt to - // access inventory data, we should find out who - // is asking, and make sure they are authorized - // to do so. We need to validate the caller's - // identity before revealing anything about the - // status quo. Authenticate throws an exception - // via Fail if no identity information is present. - // - // With the present HTTP server we can't use the - // builtin authentication mechanisms because they - // would be enforced for all in-bound requests. - // Instead we look at the headers ourselves and - // handle authentication directly. - - try - { - if (!rdata.IsAuthenticated) - { - rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated")); - } - } - catch (RestException e) - { - if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) - { - Rest.Log.WarnFormat("{0} User not authenticated", MsgId); - Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, - rdata.request.Headers.Get("Authorization")); - } - else - { - Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); - Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, - rdata.request.Headers.Get("Authorization")); - } - throw (e); - } - - // Remove the prefix and what's left are the parameters. If we don't have - // the parameters we need, fail the request. Parameters do NOT include - // any supplied query values. - - if (rdata.Parameters.Length > 0) - { - switch (rdata.method) - { - case "get" : - DoGet(rdata); - break; - case "put" : - DoPut(rdata); - break; - case "post" : - DoPost(rdata); - break; - case "delete" : - default : - Rest.Log.WarnFormat("{0} Asset: Method not supported: {1}", - MsgId, rdata.method); - rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method)); - break; - } - } - else - { - Rest.Log.WarnFormat("{0} Asset: No agent information provided", MsgId); - rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided"); - } - - Rest.Log.DebugFormat("{0} REST Asset handler EXIT", MsgId); - } - - #endregion Interface - - /// - /// The only parameter we recognize is a UUID.If an asset with this identification is - /// found, it's content, base-64 encoded, is returned to the client. - /// - - private void DoGet(AssetRequestData rdata) - { - Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length == 1) - { - UUID uuid = new UUID(rdata.Parameters[0]); - AssetBase asset = Rest.AssetServices.Get(uuid.ToString()); - - if (asset != null) - { - Rest.Log.DebugFormat("{0} Asset located <{1}>", MsgId, rdata.Parameters[0]); - - rdata.initXmlWriter(); - - rdata.writer.WriteStartElement(String.Empty,"Asset",String.Empty); - - rdata.writer.WriteAttributeString("id", asset.ID); - rdata.writer.WriteAttributeString("name", asset.Name); - rdata.writer.WriteAttributeString("desc", asset.Description); - rdata.writer.WriteAttributeString("type", asset.Type.ToString()); - rdata.writer.WriteAttributeString("local", asset.Local.ToString()); - rdata.writer.WriteAttributeString("temporary", asset.Temporary.ToString()); - - rdata.writer.WriteBase64(asset.Data,0,asset.Data.Length); - - rdata.writer.WriteFullEndElement(); - - } - else - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); - } - } - - rdata.Complete(); - rdata.Respond(String.Format("Asset <{0}> : Normal completion", rdata.method)); - - } - - /// - /// UPDATE existing item, if it exists. URI identifies the item in question. - /// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded) - /// is decoded and stored in the database, identified by the supplied UUID. - /// - private void DoPut(AssetRequestData rdata) - { - bool modified = false; - bool created = false; - - AssetBase asset = null; - - Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length == 1) - { - - rdata.initXmlReader(); - XmlReader xml = rdata.reader; - - if (!xml.ReadToFollowing("Asset")) - { - Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); - } - - UUID uuid = new UUID(rdata.Parameters[0]); - asset = Rest.AssetServices.Get(uuid.ToString()); - - modified = (asset != null); - created = !modified; - - asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString()); - asset.Description = xml.GetAttribute("desc"); - asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0; - asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0; - asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", "")); - - if (asset.ID != rdata.Parameters[0]) - { - Rest.Log.WarnFormat("{0} URI and payload disagree on UUID U:{1} vs P:{2}", - MsgId, rdata.Parameters[0], asset.ID); - } - - Rest.AssetServices.Store(asset); - - } - else - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); - } - - if (created) - { - rdata.appendStatus(String.Format("

Created asset {0}, UUID {1}

", asset.Name, asset.FullID)); - rdata.Complete(Rest.HttpStatusCodeCreated); - } - else - { - if (modified) - { - rdata.appendStatus(String.Format("

Modified asset {0}, UUID {1}

", asset.Name, asset.FullID)); - rdata.Complete(Rest.HttpStatusCodeOK); - } - else - { - rdata.Complete(Rest.HttpStatusCodeNoContent); - } - } - - rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method)); - - } - - ///

- /// CREATE new item, replace if it exists. URI identifies the context for the item in question. - /// No parameters are required for POST, just thepayload. - /// - - private void DoPost(AssetRequestData rdata) - { - - bool modified = false; - bool created = false; - - Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length != 0) - { - Rest.Log.WarnFormat("{0} Parameters ignored <{1}>", MsgId, rdata.path); - Rest.Log.InfoFormat("{0} POST of an asset has no parameters", MsgId, rdata.path); - } - - rdata.initXmlReader(); - XmlReader xml = rdata.reader; - - if (!xml.ReadToFollowing("Asset")) - { - Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); - } - - UUID uuid = new UUID(xml.GetAttribute("id")); - AssetBase asset = Rest.AssetServices.Get(uuid.ToString()); - - modified = (asset != null); - created = !modified; - - asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString()); - asset.Description = xml.GetAttribute("desc"); - asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0; - asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0; - asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", "")); - - Rest.AssetServices.Store(asset); - - if (created) - { - rdata.appendStatus(String.Format("

Created asset {0}, UUID {1}

", asset.Name, asset.FullID)); - rdata.Complete(Rest.HttpStatusCodeCreated); - } - else - { - if (modified) - { - rdata.appendStatus(String.Format("

Modified asset {0}, UUID {1}

", asset.Name, asset.FullID)); - rdata.Complete(Rest.HttpStatusCodeOK); - } - else - { - rdata.Complete(Rest.HttpStatusCodeNoContent); - } - } - - rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method)); - - } - - ///

- /// Asset processing has no special data area requirements. - /// - - internal class AssetRequestData : RequestData - { - internal AssetRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) - : base(request, response, prefix) - { - } - } - } -} 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Xml; -using System.IO; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - public class RestFileServices : IRest - { - private bool enabled = false; - private string qPrefix = "files"; - - // A simple constructor is used to handle any once-only - // initialization of working classes. - - public RestFileServices() - { - Rest.Log.InfoFormat("{0} File services initializing", MsgId); - Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); - - // If the handler specifies a relative path for its domain - // then we must add the standard absolute prefix, e.g. /admin - - if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) - { - Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix); - qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); - Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix); - } - - // Register interface using the fully-qualified prefix - - Rest.Plugin.AddPathHandler(DoFile, qPrefix, Allocate); - - // Activate if all went OK - - enabled = true; - - Rest.Log.InfoFormat("{0} File services initialization complete", MsgId); - } - - // Post-construction, pre-enabled initialization opportunity - // Not currently exploited. - - public void Initialize() - { - } - - // Called by the plug-in to halt REST processing. Local processing is - // disabled, and control blocks until all current processing has - // completed. No new processing will be started - - public void Close() - { - enabled = false; - Rest.Log.InfoFormat("{0} File services ({1}) closing down", MsgId, qPrefix); - } - - // Properties - - internal string MsgId - { - get { return Rest.MsgId; } - } - - #region Interface - - private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) - { - return (RequestData) new FileRequestData(request, response, prefix); - } - - // Asset Handler - - private void DoFile(RequestData rparm) - { - if (!enabled) return; - - FileRequestData rdata = (FileRequestData) rparm; - - Rest.Log.DebugFormat("{0} REST File handler ({1}) ENTRY", MsgId, qPrefix); - - // Now that we know this is a serious attempt to - // access file data, we should find out who - // is asking, and make sure they are authorized - // to do so. We need to validate the caller's - // identity before revealing anything about the - // status quo. Authenticate throws an exception - // via Fail if no identity information is present. - // - // With the present HTTP server we can't use the - // builtin authentication mechanisms because they - // would be enforced for all in-bound requests. - // Instead we look at the headers ourselves and - // handle authentication directly. - - try - { - if (!rdata.IsAuthenticated) - { - rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated")); - } - } - catch (RestException e) - { - if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) - { - Rest.Log.WarnFormat("{0} User not authenticated", MsgId); - Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, - rdata.request.Headers.Get("Authorization")); - } - else - { - Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); - Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, - rdata.request.Headers.Get("Authorization")); - } - throw (e); - } - - // Remove the prefix and what's left are the parameters. If we don't have - // the parameters we need, fail the request. Parameters do NOT include - // any supplied query values. - - if (rdata.Parameters.Length > 0) - { - switch (rdata.method) - { - case "get" : - DoGet(rdata); - break; - case "put" : - DoPut(rdata); - break; - case "post" : - DoPost(rdata); - break; - case "delete" : - DoDelete(rdata); - break; - default : - Rest.Log.WarnFormat("{0} File: Method not supported: {1}", - MsgId, rdata.method); - rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method)); - break; - } - } - else - { - Rest.Log.WarnFormat("{0} File: No agent information provided", MsgId); - rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided"); - } - - Rest.Log.DebugFormat("{0} REST File handler EXIT", MsgId); - - } - - #endregion Interface - - /// - /// The only parameter we recognize is a UUID.If an asset with this identification is - /// found, it's content, base-64 encoded, is returned to the client. - /// - - private void DoGet(FileRequestData rdata) - { - - string path = String.Empty; - - Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length > 1) - { - try - { - path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2); - if (File.Exists(path)) - { - Rest.Log.DebugFormat("{0} File located <{1}>", MsgId, path); - Byte[] data = File.ReadAllBytes(path); - rdata.initXmlWriter(); - rdata.writer.WriteStartElement(String.Empty,"File",String.Empty); - rdata.writer.WriteAttributeString("name", path); - rdata.writer.WriteBase64(data,0,data.Length); - rdata.writer.WriteFullEndElement(); - } - else - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, path); - rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0}", path)); - } - } - catch (Exception e) - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, e.Message); - rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}", - path, e.Message)); - } - } - - rdata.Complete(); - rdata.Respond(String.Format("File <{0}> : Normal completion", rdata.method)); - - } - - /// - /// UPDATE existing item, if it exists. URI identifies the item in question. - /// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded) - /// is decoded and stored in the database, identified by the supplied UUID. - /// - private void DoPut(FileRequestData rdata) - { - bool modified = false; - bool created = false; - string path = String.Empty; - - Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length > 1) - { - try - { - path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2); - bool maymod = File.Exists(path); - - rdata.initXmlReader(); - XmlReader xml = rdata.reader; - - if (!xml.ReadToFollowing("File")) - { - Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); - } - - Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", "")); - - File.WriteAllBytes(path,data); - modified = maymod; - created = ! maymod; - } - catch (Exception e) - { - Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId, - e.Message); - } - } - else - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); - } - - if (created) - { - rdata.appendStatus(String.Format("

Created file {0}

", path)); - rdata.Complete(Rest.HttpStatusCodeCreated); - } - else - { - if (modified) - { - rdata.appendStatus(String.Format("

Modified file {0}

", path)); - rdata.Complete(Rest.HttpStatusCodeOK); - } - else - { - rdata.Complete(Rest.HttpStatusCodeNoContent); - } - } - - rdata.Respond(String.Format("File {0} : Normal completion", rdata.method)); - - } - - ///

- /// CREATE new item, replace if it exists. URI identifies the context for the item in question. - /// No parameters are required for POST, just thepayload. - /// - - private void DoPost(FileRequestData rdata) - { - - bool modified = false; - bool created = false; - string path = String.Empty; - - Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length > 1) - { - try - { - path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2); - bool maymod = File.Exists(path); - - rdata.initXmlReader(); - XmlReader xml = rdata.reader; - - if (!xml.ReadToFollowing("File")) - { - Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); - } - - Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", "")); - - File.WriteAllBytes(path,data); - modified = maymod; - created = ! maymod; - } - catch (Exception e) - { - Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId, - e.Message); - } - } - else - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); - } - - if (created) - { - rdata.appendStatus(String.Format("

Created file {0}

", path)); - rdata.Complete(Rest.HttpStatusCodeCreated); - } - else - { - if (modified) - { - rdata.appendStatus(String.Format("

Modified file {0}

", path)); - rdata.Complete(Rest.HttpStatusCodeOK); - } - else - { - rdata.Complete(Rest.HttpStatusCodeNoContent); - } - } - - rdata.Respond(String.Format("File {0} : Normal completion", rdata.method)); - - } - - ///

- /// CREATE new item, replace if it exists. URI identifies the context for the item in question. - /// No parameters are required for POST, just thepayload. - /// - - private void DoDelete(FileRequestData rdata) - { - - bool modified = false; - bool created = false; - string path = String.Empty; - - Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length > 1) - { - try - { - path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2); - - if (File.Exists(path)) - { - File.Delete(path); - } - } - catch (Exception e) - { - Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId, - e.Message); - rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}", - path, e.Message)); - } - } - else - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); - } - - if (created) - { - rdata.appendStatus(String.Format("

Created file {0}

", path)); - rdata.Complete(Rest.HttpStatusCodeCreated); - } - else - { - if (modified) - { - rdata.appendStatus(String.Format("

Modified file {0}

", path)); - rdata.Complete(Rest.HttpStatusCodeOK); - } - else - { - rdata.Complete(Rest.HttpStatusCodeNoContent); - } - } - - rdata.Respond(String.Format("File {0} : Normal completion", rdata.method)); - - } - - ///

- /// File processing has no special data area requirements. - /// - - internal class FileRequestData : RequestData - { - internal FileRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) - : base(request, response, prefix) - { - } - } - } -} 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - /// - /// The class signature reveals the roles that RestHandler plays. - /// - /// [1] It is a sub-class of RestPlugin. It inherits and extends - /// the functionality of this class, constraining it to the - /// specific needs of this REST implementation. This relates - /// to the plug-in mechanism supported by OpenSim, the specifics - /// of which are mostly hidden by RestPlugin. - /// [2] IRestHandler describes the interface that this class - /// exports to service implementations. This is the services - /// management interface. - /// [3] IHttpAgentHandler describes the interface that is exported - /// to the BaseHttpServer in support of this particular HTTP - /// processing model. This is the request interface of the - /// handler. - /// - - public class RestHandler : RestPlugin, IRestHandler, IHttpAgentHandler - { - // Handler tables: both stream and REST are supported. The path handlers and their - // respective allocators are stored in separate tables. - - internal Dictionary pathHandlers = new Dictionary(); - internal Dictionary pathAllocators = new Dictionary(); - internal Dictionary streamHandlers = new Dictionary(); - - #region local static state - - private static bool handlersLoaded = false; - private static List classes = new List(); - private static List handlers = new List(); - private static Type[] parms = new Type[0]; - private static Object[] args = new Object[0]; - - /// - /// This static initializer scans the ASSEMBLY for classes that - /// export the IRest interface and builds a list of them. These - /// are later activated by the handler. To add a new handler it - /// is only necessary to create a new services class that implements - /// the IRest interface, and recompile the handler. This gives - /// all of the build-time flexibility of a modular approach - /// while not introducing yet-another module loader. Note that - /// multiple assembles can still be built, each with its own set - /// of handlers. Examples of services classes are RestInventoryServices - /// and RestSkeleton. - /// - - static RestHandler() - { - Module[] mods = Assembly.GetExecutingAssembly().GetModules(); - - foreach (Module m in mods) - { - Type[] types = m.GetTypes(); - foreach (Type t in types) - { - try - { - if (t.GetInterface("IRest") != null) - { - classes.Add(t); - } - } - catch (Exception) - { - Rest.Log.WarnFormat("[STATIC-HANDLER]: #0 Error scanning {1}", t); - Rest.Log.InfoFormat("[STATIC-HANDLER]: #0 {1} is not included", t); - } - } - } - } - - #endregion local static state - - #region local instance state - - /// - /// This routine loads all of the handlers discovered during - /// instance initialization. - /// A table of all loaded and successfully constructed handlers - /// is built, and this table is then used by the constructor to - /// initialize each of the handlers in turn. - /// NOTE: The loading process does not automatically imply that - /// the handler has registered any kind of an interface, that - /// may be (optionally) done by the handler either during - /// construction, or during initialization. - /// - /// I was not able to make this code work within a constructor - /// so it is isolated within this method. - /// - - private void LoadHandlers() - { - lock (handlers) - { - if (!handlersLoaded) - { - ConstructorInfo ci; - Object ht; - - foreach (Type t in classes) - { - try - { - ci = t.GetConstructor(parms); - ht = ci.Invoke(args); - handlers.Add((IRest)ht); - } - catch (Exception e) - { - Rest.Log.WarnFormat("{0} Unable to load {1} : {2}", MsgId, t, e.Message); - } - } - handlersLoaded = true; - } - } - } - - #endregion local instance state - - #region overriding properties - - // These properties override definitions - // in the base class. - - // Name is used to differentiate the message header. - - public override string Name - { - get { return "HANDLER"; } - } - - // Used to partition the .ini configuration space. - - public override string ConfigName - { - get { return "RestHandler"; } - } - - // We have to rename these because we want - // to be able to share the values with other - // classes in our assembly and the base - // names are protected. - - public string MsgId - { - get { return base.MsgID; } - } - - public string RequestId - { - get { return base.RequestID; } - } - - #endregion overriding properties - - #region overriding methods - - /// - /// This method is called by OpenSimMain immediately after loading the - /// plugin and after basic server setup, but before running any server commands. - /// - /// - /// Note that entries MUST be added to the active configuration files before - /// the plugin can be enabled. - /// - - public override void Initialise(OpenSimBase openSim) - { - try - { - // This plugin will only be enabled if the broader - // REST plugin mechanism is enabled. - - //Rest.Log.InfoFormat("{0} Plugin is initializing", MsgId); - - base.Initialise(openSim); - - // IsEnabled is implemented by the base class and - // reflects an overall RestPlugin status - - if (!IsEnabled) - { - //Rest.Log.WarnFormat("{0} Plugins are disabled", MsgId); - return; - } - - Rest.Log.InfoFormat("{0} Rest <{1}> plugin will be enabled", MsgId, Name); - Rest.Log.InfoFormat("{0} Configuration parameters read from <{1}>", MsgId, ConfigName); - - // These are stored in static variables to make - // them easy to reach from anywhere in the assembly. - - Rest.main = openSim; - if (Rest.main == null) - throw new Exception("OpenSim base pointer is null"); - - Rest.Plugin = this; - Rest.Config = Config; - Rest.Prefix = Prefix; - Rest.GodKey = GodKey; - Rest.Authenticate = Rest.Config.GetBoolean("authenticate", Rest.Authenticate); - Rest.Scheme = Rest.Config.GetString("auth-scheme", Rest.Scheme); - Rest.Secure = Rest.Config.GetBoolean("secured", Rest.Secure); - Rest.ExtendedEscape = Rest.Config.GetBoolean("extended-escape", Rest.ExtendedEscape); - Rest.Realm = Rest.Config.GetString("realm", Rest.Realm); - Rest.DumpAsset = Rest.Config.GetBoolean("dump-asset", Rest.DumpAsset); - Rest.Fill = Rest.Config.GetBoolean("path-fill", Rest.Fill); - Rest.DumpLineSize = Rest.Config.GetInt("dump-line-size", Rest.DumpLineSize); - Rest.FlushEnabled = Rest.Config.GetBoolean("flush-on-error", Rest.FlushEnabled); - - // Note: Odd spacing is required in the following strings - - Rest.Log.InfoFormat("{0} Authentication is {1}required", MsgId, - (Rest.Authenticate ? "" : "not ")); - - Rest.Log.InfoFormat("{0} Security is {1}enabled", MsgId, - (Rest.Secure ? "" : "not ")); - - Rest.Log.InfoFormat("{0} Extended URI escape processing is {1}enabled", MsgId, - (Rest.ExtendedEscape ? "" : "not ")); - - Rest.Log.InfoFormat("{0} Dumping of asset data is {1}enabled", MsgId, - (Rest.DumpAsset ? "" : "not ")); - - // The supplied prefix MUST be absolute - - if (Rest.Prefix.Substring(0,1) != Rest.UrlPathSeparator) - { - Rest.Log.WarnFormat("{0} Prefix <{1}> is not absolute and must be", MsgId, Rest.Prefix); - Rest.Log.InfoFormat("{0} Prefix changed to ", MsgId, Rest.Prefix); - Rest.Prefix = String.Format("{0}{1}", Rest.UrlPathSeparator, Rest.Prefix); - } - - // If data dumping is requested, report on the chosen line - // length. - - if (Rest.DumpAsset) - { - Rest.Log.InfoFormat("{0} Dump {1} bytes per line", MsgId, Rest.DumpLineSize); - } - - // Load all of the handlers present in the - // assembly - - // In principle, as we're an application plug-in, - // most of what needs to be done could be done using - // static resources, however the Open Sim plug-in - // model makes this an instance, so that's what we - // need to be. - // There is only one Communications manager per - // server, and by inference, only one each of the - // user, asset, and inventory servers. So we can cache - // those using a static initializer. - // We move all of this processing off to another - // services class to minimize overlap between function - // and infrastructure. - - LoadHandlers(); - - // The intention of a post construction initializer - // is to allow for setup that is dependent upon other - // activities outside of the agency. - - foreach (IRest handler in handlers) - { - try - { - handler.Initialize(); - } - catch (Exception e) - { - Rest.Log.ErrorFormat("{0} initialization error: {1}", MsgId, e.Message); - } - } - - // Now that everything is setup we can proceed to - // add THIS agent to the HTTP server's handler list - - // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will - // have to be handled through the AddHttpHandler interface. -// if (!AddAgentHandler(Rest.Name,this)) -// { -// Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId); -// foreach (IRest handler in handlers) -// { -// handler.Close(); -// } -// } - - } - catch (Exception e) - { - Rest.Log.ErrorFormat("{0} Plugin initialization has failed: {1}", MsgId, e.Message); - } - } - - /// - /// In the interests of efficiency, and because we cannot determine whether - /// or not this instance will actually be harvested, we clobber the only - /// anchoring reference to the working state for this plug-in. What the - /// call to close does is irrelevant to this class beyond knowing that it - /// can nullify the reference when it returns. - /// To make sure everything is copacetic we make sure the primary interface - /// is disabled by deleting the handler from the HTTP server tables. - /// - - public override void Close() - { - Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId); - - // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will - // have to be handled through the AddHttpHandler interface. -// try -// { -// RemoveAgentHandler(Rest.Name, this); -// } -// catch (KeyNotFoundException){} - - foreach (IRest handler in handlers) - { - handler.Close(); - } - } - - #endregion overriding methods - - #region interface methods - - /// - /// This method is called by the HTTP server to match an incoming - /// request. It scans all of the strings registered by the - /// underlying handlers and looks for the best match. It returns - /// true if a match is found. - /// The matching process could be made arbitrarily complex. - /// Note: The match is case-insensitive. - /// - - public bool Match(OSHttpRequest request, OSHttpResponse response) - { - - string path = request.RawUrl.ToLower(); - - // Rest.Log.DebugFormat("{0} Match ENTRY", MsgId); - - try - { - foreach (string key in pathHandlers.Keys) - { - // Rest.Log.DebugFormat("{0} Match testing {1} against agent prefix <{2}>", MsgId, path, key); - - // Note that Match will not necessarily find the handler that will - // actually be used - it does no test for the "closest" fit. It - // simply reflects that at least one possible handler exists. - - if (path.StartsWith(key)) - { - // Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key); - - // This apparently odd evaluation is needed to prevent a match - // on anything other than a URI token boundary. Otherwise we - // may match on URL's that were not intended for this handler. - - return (path.Length == key.Length || - path.Substring(key.Length, 1) == Rest.UrlPathSeparator); - } - } - - path = String.Format("{0}{1}{2}", request.HttpMethod, Rest.UrlMethodSeparator, path); - - foreach (string key in streamHandlers.Keys) - { - // Rest.Log.DebugFormat("{0} Match testing {1} against stream prefix <{2}>", MsgId, path, key); - - // Note that Match will not necessarily find the handler that will - // actually be used - it does no test for the "closest" fit. It - // simply reflects that at least one possible handler exists. - - if (path.StartsWith(key)) - { - // Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key); - - // This apparently odd evaluation is needed to prevent a match - // on anything other than a URI token boundary. Otherwise we - // may match on URL's that were not intended for this handler. - - return (path.Length == key.Length || - path.Substring(key.Length, 1) == Rest.UrlPathSeparator); - } - } - } - catch (Exception e) - { - Rest.Log.ErrorFormat("{0} matching exception for path <{1}> : {2}", MsgId, path, e.Message); - } - - return false; - } - - /// - /// This is called by the HTTP server once the handler has indicated - /// that it is able to handle the request. - /// Preconditions: - /// [1] request != null and is a valid request object - /// [2] response != null and is a valid response object - /// Behavior is undefined if preconditions are not satisfied. - /// - - public bool Handle(OSHttpRequest request, OSHttpResponse response) - { - bool handled; - base.MsgID = base.RequestID; - - // Debug only - - if (Rest.DEBUG) - { - Rest.Log.DebugFormat("{0} ENTRY", MsgId); - Rest.Log.DebugFormat("{0} Agent: {1}", MsgId, request.UserAgent); - Rest.Log.DebugFormat("{0} Method: {1}", MsgId, request.HttpMethod); - - for (int i = 0; i < request.Headers.Count; i++) - { - Rest.Log.DebugFormat("{0} Header [{1}] : <{2}> = <{3}>", - MsgId, i, request.Headers.GetKey(i), request.Headers.Get(i)); - } - Rest.Log.DebugFormat("{0} URI: {1}", MsgId, request.RawUrl); - } - - // If a path handler worked we're done, otherwise try any - // available stream handlers too. - - try - { - handled = (FindPathHandler(request, response) || - FindStreamHandler(request, response)); - } - catch (Exception e) - { - // A raw exception indicates that something we weren't expecting has - // happened. This should always reflect a shortcoming in the plugin, - // or a failure to satisfy the preconditions. It should not reflect - // an error in the request itself. Under such circumstances the state - // of the request cannot be determined and we are obliged to mark it - // as 'handled'. - - Rest.Log.ErrorFormat("{0} Plugin error: {1}", MsgId, e.Message); - handled = true; - } - - Rest.Log.DebugFormat("{0} EXIT", MsgId); - - return handled; - } - - #endregion interface methods - - /// - /// If there is a stream handler registered that can handle the - /// request, then fine. If the request is not matched, do - /// nothing. - /// Note: The selection is case-insensitive - /// - - private bool FindStreamHandler(OSHttpRequest request, OSHttpResponse response) - { - RequestData rdata = new RequestData(request, response, String.Empty); - - string bestMatch = String.Empty; - string path = String.Format("{0}:{1}", rdata.method, rdata.path).ToLower(); - - Rest.Log.DebugFormat("{0} Checking for stream handler for <{1}>", MsgId, path); - - if (!IsEnabled) - { - return false; - } - - foreach (string pattern in streamHandlers.Keys) - { - if (path.StartsWith(pattern)) - { - if (pattern.Length > bestMatch.Length) - { - bestMatch = pattern; - } - } - } - - // Handle using the best match available - - if (bestMatch.Length > 0) - { - Rest.Log.DebugFormat("{0} Stream-based handler matched with <{1}>", MsgId, bestMatch); - RestStreamHandler handler = streamHandlers[bestMatch]; - rdata.buffer = handler.Handle(rdata.path, rdata.request.InputStream, rdata.request, rdata.response); - rdata.AddHeader(rdata.response.ContentType,handler.ContentType); - rdata.Respond("FindStreamHandler Completion"); - } - - return rdata.handled; - } - - /// - /// Add a stream handler for the designated HTTP method and path prefix. - /// If the handler is not enabled, the request is ignored. If the path - /// does not start with the REST prefix, it is added. If method-qualified - /// path has not already been registered, the method is added to the active - /// handler table. - /// - public void AddStreamHandler(string httpMethod, string path, RestMethod method) - { - if (!IsEnabled) - { - return; - } - - if (!path.StartsWith(Rest.Prefix)) - { - path = String.Format("{0}{1}", Rest.Prefix, path); - } - - path = String.Format("{0}{1}{2}", httpMethod, Rest.UrlMethodSeparator, path); - - // Conditionally add to the list - - if (!streamHandlers.ContainsKey(path)) - { - streamHandlers.Add(path, new RestStreamHandler(httpMethod, path, method)); - Rest.Log.DebugFormat("{0} Added handler for {1}", MsgId, path); - } - else - { - Rest.Log.WarnFormat("{0} Ignoring duplicate handler for {1}", MsgId, path); - } - } - - /// - /// Given the supplied request/response, if the handler is enabled, the inbound - /// information is used to match an entry in the active path handler tables, using - /// the method-qualified path information. If a match is found, then the handler is - /// invoked. The result is the boolean result of the handler, or false if no - /// handler was located. The boolean indicates whether or not the request has been - /// handled, not whether or not the request was successful - that information is in - /// the response. - /// Note: The selection process is case-insensitive - /// - - internal bool FindPathHandler(OSHttpRequest request, OSHttpResponse response) - { - RequestData rdata = null; - string bestMatch = null; - - if (!IsEnabled) - { - return false; - } - - // Conditionally add to the list - - Rest.Log.DebugFormat("{0} Checking for path handler for <{1}>", MsgId, request.RawUrl); - - foreach (string pattern in pathHandlers.Keys) - { - if (request.RawUrl.ToLower().StartsWith(pattern)) - { - if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) - { - bestMatch = pattern; - } - } - } - - if (!String.IsNullOrEmpty(bestMatch)) - { - rdata = pathAllocators[bestMatch](request, response, bestMatch); - - Rest.Log.DebugFormat("{0} Path based REST handler matched with <{1}>", MsgId, bestMatch); - - try - { - pathHandlers[bestMatch](rdata); - } - - // A plugin generated error indicates a request-related error - // that has been handled by the plugin. - - catch (RestException r) - { - Rest.Log.WarnFormat("{0} Request failed: {1}", MsgId, r.Message); - } - } - - return (rdata == null) ? false : rdata.handled; - } - - /// - /// A method handler and a request allocator are stored using the designated - /// path as a key. If an entry already exists, it is replaced by the new one. - /// - - public void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ra) - { - if (!IsEnabled) - { - return; - } - - if (pathHandlers.ContainsKey(path)) - { - Rest.Log.DebugFormat("{0} Replacing handler for <${1}>", MsgId, path); - pathHandlers.Remove(path); - } - - if (pathAllocators.ContainsKey(path)) - { - Rest.Log.DebugFormat("{0} Replacing allocator for <${1}>", MsgId, path); - pathAllocators.Remove(path); - } - - Rest.Log.DebugFormat("{0} Adding path handler for {1}", MsgId, path); - - pathHandlers.Add(path, mh); - pathAllocators.Add(path, ra); - } - } -} 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Globalization; -using System.IO; -using System.Threading; -using System.Timers; -using System.Xml; -using OpenMetaverse; -using OpenMetaverse.Imaging; -using OpenSim.Framework; - -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using Timer=System.Timers.Timer; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - public class RestInventoryServices : IRest - { -// private static readonly int PARM_USERID = 0; -// private static readonly int PARM_PATH = 1; - -// private bool enabled = false; - private string qPrefix = "inventory"; - -// private static readonly string PRIVATE_ROOT_NAME = "My Inventory"; - - /// - /// The constructor makes sure that the service prefix is absolute - /// and the registers the service handler and the allocator. - /// - - public RestInventoryServices() - { - Rest.Log.InfoFormat("{0} Inventory services initializing", MsgId); - Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); - - // If a relative path was specified for the handler's domain, - // add the standard prefix to make it absolute, e.g. /admin - - if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) - { - Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId); - qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); - Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix); - } - - // Register interface using the absolute URI. - - Rest.Plugin.AddPathHandler(DoInventory,qPrefix,Allocate); - - // Activate if everything went OK - -// enabled = true; - - Rest.Log.InfoFormat("{0} Inventory services initialization complete", MsgId); - } - - /// - /// Post-construction, pre-enabled initialization opportunity - /// Not currently exploited. - /// - - public void Initialize() - { - } - - /// - /// Called by the plug-in to halt service processing. Local processing is - /// disabled. - /// - - public void Close() - { -// enabled = false; - Rest.Log.InfoFormat("{0} Inventory services closing down", MsgId); - } - - /// - /// This property is declared locally because it is used a lot and - /// brevity is nice. - /// - internal string MsgId - { - get { return Rest.MsgId; } - } - - #region Interface - - /// - /// The plugin (RestHandler) calls this method to allocate the request - /// state carrier for a new request. It is destroyed when the request - /// completes. All request-instance specific state is kept here. This - /// is registered when this service provider is registered. - /// - /// Inbound HTTP request information - /// Outbound HTTP request information - /// REST service domain prefix - /// A RequestData instance suitable for this service - private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) - { - return (RequestData) new InventoryRequestData(request, response, prefix); - } - - /// - /// This method is registered with the handler when this service provider - /// is initialized. It is called whenever the plug-in identifies this service - /// provider as the best match for a given request. - /// It handles all aspects of inventory REST processing, i.e. /admin/inventory - /// - /// A consolidated HTTP request work area - private void DoInventory(RequestData hdata) - { -// InventoryRequestData rdata = (InventoryRequestData) hdata; - - Rest.Log.DebugFormat("{0} DoInventory ENTRY", MsgId); - - // !!! REFACTORING PROBLEM - - //// If we're disabled, do nothing. - - //if (!enabled) - //{ - // return; - //} - - //// Now that we know this is a serious attempt to - //// access inventory data, we should find out who - //// is asking, and make sure they are authorized - //// to do so. We need to validate the caller's - //// identity before revealing anything about the - //// status quo. Authenticate throws an exception - //// via Fail if no identity information is present. - //// - //// With the present HTTP server we can't use the - //// builtin authentication mechanisms because they - //// would be enforced for all in-bound requests. - //// Instead we look at the headers ourselves and - //// handle authentication directly. - - //try - //{ - // if (!rdata.IsAuthenticated) - // { - // rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName)); - // } - //} - //catch (RestException e) - //{ - // if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) - // { - // Rest.Log.WarnFormat("{0} User not authenticated", MsgId); - // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); - // } - // else - // { - // Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); - // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); - // } - // throw (e); - //} - - //Rest.Log.DebugFormat("{0} Authenticated {1}", MsgId, rdata.userName); - - //// We can only get here if we are authorized - //// - //// The requestor may have specified an UUID or - //// a conjoined FirstName LastName string. We'll - //// try both. If we fail with the first, UUID, - //// attempt, we try the other. As an example, the - //// URI for a valid inventory request might be: - //// - //// http://:/admin/inventory/Arthur Dent - //// - //// Indicating that this is an inventory request for - //// an avatar named Arthur Dent. This is ALL that is - //// required to designate a GET for an entire - //// inventory. - //// - - - //// Do we have at least a user agent name? - - //if (rdata.Parameters.Length < 1) - //{ - // Rest.Log.WarnFormat("{0} Inventory: No user agent identifier specified", MsgId); - // rdata.Fail(Rest.HttpStatusCodeBadRequest, "no user identity specified"); - //} - - //// The first parameter MUST be the agent identification, either an UUID - //// or a space-separated First-name Last-Name specification. We check for - //// an UUID first, if anyone names their character using a valid UUID - //// that identifies another existing avatar will cause this a problem... - - //try - //{ - // rdata.uuid = new UUID(rdata.Parameters[PARM_USERID]); - // Rest.Log.DebugFormat("{0} UUID supplied", MsgId); - // rdata.userProfile = Rest.UserServices.GetUserProfile(rdata.uuid); - //} - //catch - //{ - // string[] names = rdata.Parameters[PARM_USERID].Split(Rest.CA_SPACE); - // if (names.Length == 2) - // { - // Rest.Log.DebugFormat("{0} Agent Name supplied [2]", MsgId); - // rdata.userProfile = Rest.UserServices.GetUserProfile(names[0],names[1]); - // } - // else - // { - // Rest.Log.WarnFormat("{0} A Valid UUID or both first and last names must be specified", MsgId); - // rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid user identity"); - // } - //} - - //// If the user profile is null then either the server is broken, or the - //// user is not known. We always assume the latter case. - - //if (rdata.userProfile != null) - //{ - // Rest.Log.DebugFormat("{0} Profile obtained for agent {1} {2}", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - //} - //else - //{ - // Rest.Log.WarnFormat("{0} No profile for {1}", MsgId, rdata.path); - // rdata.Fail(Rest.HttpStatusCodeNotFound, "unrecognized user identity"); - //} - - //// If we get to here, then we have effectively validated the user's - //// identity. Now we need to get the inventory. If the server does not - //// have the inventory, we reject the request with an appropriate explanation. - //// - //// Note that inventory retrieval is an asynchronous event, we use the rdata - //// class instance as the basis for our synchronization. - //// - - //rdata.uuid = rdata.userProfile.ID; - - //if (Rest.InventoryServices.HasInventoryForUser(rdata.uuid)) - //{ - // rdata.root = Rest.InventoryServices.GetRootFolder(rdata.uuid); - - // Rest.Log.DebugFormat("{0} Inventory Root retrieved for {1} {2}", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - - // Rest.InventoryServices.GetUserInventory(rdata.uuid, rdata.GetUserInventory); - - // Rest.Log.DebugFormat("{0} Inventory catalog requested for {1} {2}", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - - // lock (rdata) - // { - // if (!rdata.HaveInventory) - // { - // rdata.startWD(1000); - // rdata.timeout = false; - // Monitor.Wait(rdata); - // } - // } - - // if (rdata.timeout) - // { - // Rest.Log.WarnFormat("{0} Inventory not available for {1} {2}. No response from service.", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - // rdata.Fail(Rest.HttpStatusCodeServerError, "inventory server not responding"); - // } - - // if (rdata.root == null) - // { - // Rest.Log.WarnFormat("{0} Inventory is not available [1] for agent {1} {2}", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - // rdata.Fail(Rest.HttpStatusCodeServerError, "inventory retrieval failed"); - // } - - //} - //else - //{ - // Rest.Log.WarnFormat("{0} Inventory is not locally available for agent {1} {2}", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - // rdata.Fail(Rest.HttpStatusCodeNotFound, "no local inventory for user"); - //} - - //// If we get here, then we have successfully retrieved the user's information - //// and inventory information is now available locally. - - //switch (rdata.method) - //{ - // case Rest.HEAD : // Do the processing, set the status code, suppress entity - // DoGet(rdata); - // rdata.buffer = null; - // break; - - // case Rest.GET : // Do the processing, set the status code, return entity - // DoGet(rdata); - // break; - - // case Rest.PUT : // Update named element - // DoUpdate(rdata); - // break; - - // case Rest.POST : // Add new information to identified context. - // DoExtend(rdata); - // break; - - // case Rest.DELETE : // Delete information - // DoDelete(rdata); - // break; - - // default : - // Rest.Log.WarnFormat("{0} Method {1} not supported for {2}", - // MsgId, rdata.method, rdata.path); - // rdata.Fail(Rest.HttpStatusCodeMethodNotAllowed, - // String.Format("{0} not supported", rdata.method)); - // break; - //} - } - - #endregion Interface - - #region method-specific processing - - /// - /// This method implements GET processing for inventory. - /// Any remaining parameters are used to locate the - /// corresponding subtree based upon node name. - /// - /// HTTP service request work area -// private void DoGet(InventoryRequestData rdata) -// { -// rdata.initXmlWriter(); -// -// rdata.writer.WriteStartElement(String.Empty,"Inventory",String.Empty); -// -// // If there are additional parameters, then these represent -// // a path relative to the root of the inventory. This path -// // must be traversed before we format the sub-tree thus -// // identified. -// -// traverse(rdata, rdata.root, PARM_PATH); -// -// // Close all open elements -// -// rdata.writer.WriteFullEndElement(); -// -// // Indicate a successful request -// -// rdata.Complete(); -// -// // Send the response to the user. The body will be implicitly -// // constructed from the result of the XML writer. -// -// rdata.Respond(String.Format("Inventory {0} Normal completion", rdata.method)); -// } - - /// - /// In the case of the inventory, and probably in general, - /// the distinction between PUT and POST is not always - /// easy to discern. The standard is badly worded in places, - /// and adding a node to a hierarchy can be viewed as - /// an addition, or as a modification to the inventory as - /// a whole. This is exacerbated by an unjustified lack of - /// consistency across different implementations. - /// - /// For OpenSim PUT is an update and POST is an addition. This - /// is the behavior required by the HTTP specification and - /// therefore as required by REST. - /// - /// The best way to explain the distinction is to - /// consider the relationship between the URI and the - /// enclosed entity. For PUT, the URI identifies the - /// actual entity to be modified or replaced, i.e. the - /// enclosed entity. - /// - /// If the operation is POST,then the URI describes the - /// context into which the new entity will be added. - /// - /// As an example, suppose the URI contains: - /// /admin/inventory/Clothing - /// - /// A PUT request will normally result in some modification of - /// the folder or item named "Clothing". Whereas a POST - /// request will normally add some new information into the - /// content identified by Clothing. It follows from this - /// that for POST, the element identified by the URI MUST - /// be a folder. - /// - - /// - /// POST adds new information to the inventory in the - /// context identified by the URI. - /// - /// HTTP service request work area -// private void DoExtend(InventoryRequestData rdata) -// { -// bool created = false; -// bool modified = false; -// string newnode = String.Empty; -// -// // Resolve the context node specified in the URI. Entity -// // data will be ADDED beneath this node. rdata already contains -// // information about the current content of the user's -// // inventory. -// -// Object InventoryNode = getInventoryNode(rdata, rdata.root, PARM_PATH, Rest.Fill); -// -// // Processing depends upon the type of inventory node -// // identified in the URI. This is the CONTEXT for the -// // change. We either got a context or we threw an -// // exception. -// -// // It follows that we can only add information if the URI -// // has identified a folder. So only a type of folder is supported -// // in this case. -// -// if (typeof(InventoryFolderBase) == InventoryNode.GetType() || -// typeof(InventoryFolderImpl) == InventoryNode.GetType()) -// { -// // Cast the context node appropriately. -// -// InventoryFolderBase context = (InventoryFolderBase) InventoryNode; -// -// Rest.Log.DebugFormat("{0} {1}: Resource(s) will be added to folder {2}", -// MsgId, rdata.method, rdata.path); -// -// // Reconstitute the inventory sub-tree from the XML supplied in the entity. -// // The result is a stand-alone inventory subtree, not yet integrated into the -// // existing tree. An inventory collection consists of three components: -// // [1] A (possibly empty) set of folders. -// // [2] A (possibly empty) set of items. -// // [3] A (possibly empty) set of assets. -// // If all of these are empty, then the POST is a harmless no-operation. -// -// XmlInventoryCollection entity = ReconstituteEntity(rdata); -// -// // Inlined assets can be included in entity. These must be incorporated into -// // the asset database before we attempt to update the inventory. If anything -// // fails, return a failure to requestor. -// -// if (entity.Assets.Count > 0) -// { -// Rest.Log.DebugFormat("{0} Adding {1} assets to server", -// MsgId, entity.Assets.Count); -// -// foreach (AssetBase asset in entity.Assets) -// { -// Rest.Log.DebugFormat("{0} Rest asset: {1} {2} {3}", -// MsgId, asset.ID, asset.Type, asset.Name); -// Rest.AssetServices.Store(asset); -// -// created = true; -// rdata.appendStatus(String.Format("

Created asset {0}, UUID {1}

", -// asset.Name, asset.ID)); -// -// if (Rest.DEBUG && Rest.DumpAsset) -// { -// Rest.Dump(asset.Data); -// } -// } -// } -// -// // Modify the context using the collection of folders and items -// // returned in the XmlInventoryCollection. -// -// foreach (InventoryFolderBase folder in entity.Folders) -// { -// InventoryFolderBase found; -// -// // If the parentID is zero, then this folder is going -// // into the root folder identified by the URI. The requestor -// // may have already set the parent ID explicitly, in which -// // case we don't have to do it here. -// -// if (folder.ParentID == UUID.Zero || folder.ParentID == context.ID) -// { -// if (newnode != String.Empty) -// { -// Rest.Log.DebugFormat("{0} Too many resources", MsgId); -// rdata.Fail(Rest.HttpStatusCodeBadRequest, "only one root entity is allowed"); -// } -// folder.ParentID = context.ID; -// newnode = folder.Name; -// } -// -// // Search the existing inventory for an existing entry. If -// // we have one, we need to decide if it has really changed. -// // It could just be present as (unnecessary) context, and we -// // don't want to waste time updating the database in that -// // case, OR, it could be being moved from another location -// // in which case an update is most certainly necessary. -// -// found = null; -// -// foreach (InventoryFolderBase xf in rdata.folders) -// { -// // Compare identifying attribute -// if (xf.ID == folder.ID) -// { -// found = xf; -// break; -// } -// } -// -// if (found != null && FolderHasChanged(folder,found)) -// { -// Rest.Log.DebugFormat("{0} Updating existing folder", MsgId); -// Rest.InventoryServices.MoveFolder(folder); -// -// modified = true; -// rdata.appendStatus(String.Format("

Created folder {0}, UUID {1}

", -// folder.Name, folder.ID)); -// } -// else -// { -// Rest.Log.DebugFormat("{0} Adding new folder", MsgId); -// Rest.InventoryServices.AddFolder(folder); -// -// created = true; -// rdata.appendStatus(String.Format("

Modified folder {0}, UUID {1}

", -// folder.Name, folder.ID)); -// } -// } -// -// // Now we repeat a similar process for the items included -// // in the entity. -// -// foreach (InventoryItemBase item in entity.Items) -// { -// InventoryItemBase found = null; -// -// // If the parentID is zero, then this is going -// // directly into the root identified by the URI. -// -// if (item.Folder == UUID.Zero) -// { -// item.Folder = context.ID; -// } -// -// // Determine whether this is a new item or a -// // replacement definition. -// -// foreach (InventoryItemBase xi in rdata.items) -// { -// // Compare identifying attribute -// if (xi.ID == item.ID) -// { -// found = xi; -// break; -// } -// } -// -// if (found != null && ItemHasChanged(item, found)) -// { -// Rest.Log.DebugFormat("{0} Updating item {1} {2} {3} {4} {5}", -// MsgId, item.ID, item.AssetID, item.InvType, item.AssetType, item.Name); -// Rest.InventoryServices.UpdateItem(item); -// modified = true; -// rdata.appendStatus(String.Format("

Modified item {0}, UUID {1}

", item.Name, item.ID)); -// } -// else -// { -// Rest.Log.DebugFormat("{0} Adding item {1} {2} {3} {4} {5}", -// MsgId, item.ID, item.AssetID, item.InvType, item.AssetType, item.Name); -// Rest.InventoryServices.AddItem(item); -// created = true; -// rdata.appendStatus(String.Format("

Created item {0}, UUID {1}

", item.Name, item.ID)); -// } -// } -// -// if (created) -// { -// // Must include a location header with a URI that identifies the new resource. -// rdata.AddHeader(Rest.HttpHeaderLocation,String.Format("http://{0}{1}:{2}/{3}", -// rdata.hostname, rdata.port,rdata.path,newnode)); -// rdata.Complete(Rest.HttpStatusCodeCreated); -// } -// else -// { -// if (modified) -// { -// rdata.Complete(Rest.HttpStatusCodeOK); -// } -// else -// { -// rdata.Complete(Rest.HttpStatusCodeNoContent); -// } -// } -// -// rdata.Respond(String.Format("Profile {0} : Normal completion", rdata.method)); -// } -// else -// { -// Rest.Log.DebugFormat("{0} {1}: Resource {2} is not a valid context: {3}", -// MsgId, rdata.method, rdata.path, InventoryNode.GetType()); -// rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid resource context"); -// } -// } - - ///

- /// PUT updates the URI-identified element in the inventory. This - /// is actually far more flexible than it might at first sound. For - /// PUT the URI serves two purposes: - /// [1] It identifies the user whose inventory is to be - /// processed. - /// [2] It optionally specifies a subtree of the inventory - /// that is to be used to resolve any relative subtree - /// specifications in the entity. If nothing is specified - /// then the whole of the private inventory is implied. - /// Please note that the subtree specified by the URI is only relevant - /// to an entity containing a URI relative specification, i.e. one or - /// more elements do not specify parent folder information. These - /// elements will be implicitly referenced within the context identified - /// by the URI. - /// If an element in the entity specifies an explicit parent folder, then - /// that parent is effective, regardless of any value specified in the - /// URI. If the parent does not exist, then the element, and any dependent - /// elements, are ignored. This case is actually detected and handled - /// during the reconstitution process. - /// - /// HTTP service request work area -// private void DoUpdate(InventoryRequestData rdata) -// { -// int count = 0; -// bool created = false; -// bool modified = false; -// -// // Resolve the inventory node that is to be modified. -// // rdata already contains information about the current -// // content of the user's inventory. -// -// Object InventoryNode = getInventoryNode(rdata, rdata.root, PARM_PATH, Rest.Fill); -// -// // As long as we have a node, then we have something -// // meaningful to do, unlike POST. So we reconstitute the -// // subtree before doing anything else. Note that we -// // etiher got a valid node or we threw an exception. -// -// XmlInventoryCollection entity = ReconstituteEntity(rdata); -// -// // Incorporate any inlined assets first. Any failures -// // will terminate the request. -// -// if (entity.Assets.Count > 0) -// { -// Rest.Log.DebugFormat("{0} Adding {1} assets to server", -// MsgId, entity.Assets.Count); -// -// foreach (AssetBase asset in entity.Assets) -// { -// Rest.Log.DebugFormat("{0} Rest asset: {1} {2} {3}", -// MsgId, asset.ID, asset.Type, asset.Name); -// -// // The asset was validated during the collection process -// -// Rest.AssetServices.Store(asset); -// -// created = true; -// rdata.appendStatus(String.Format("

Created asset {0}, UUID {1}

", asset.Name, asset.ID)); -// -// if (Rest.DEBUG && Rest.DumpAsset) -// { -// Rest.Dump(asset.Data); -// } -// } -// } -// -// // The URI specifies either a folder or an item to be updated. -// // -// // The root node in the entity will replace the node identified -// // by the URI. This means the parent will remain the same, but -// // any or all attributes associated with the named element -// // will change. -// // -// // If the inventory collection contains an element with a zero -// // parent ID, then this is taken to be the replacement for the -// // named node. The collection MAY also specify an explicit -// // parent ID, in this case it MAY identify the same parent as -// // the current node, or it MAY specify a different parent, -// // indicating that the folder is being moved in addition to any -// // other modifications being made. -// -// if (typeof(InventoryFolderBase) == InventoryNode.GetType() || -// typeof(InventoryFolderImpl) == InventoryNode.GetType()) -// { -// bool rfound = false; -// InventoryFolderBase uri = (InventoryFolderBase) InventoryNode; -// InventoryFolderBase xml = null; -// -// // If the entity to be replaced resolved to be the root -// // directory itself (My Inventory), then make sure that -// // the supplied data include as appropriately typed and -// // named folder. Note that we can;t rule out the possibility -// // of a sub-directory being called "My Inventory", so that -// // is anticipated. -// -// if (uri == rdata.root) -// { -// foreach (InventoryFolderBase folder in entity.Folders) -// { -// if ((rfound = (folder.Name == PRIVATE_ROOT_NAME))) -// { -// if ((rfound = (folder.ParentID == UUID.Zero))) -// break; -// } -// } -// -// if (!rfound) -// { -// Rest.Log.DebugFormat("{0} {1}: Path <{2}> will result in loss of inventory", -// MsgId, rdata.method, rdata.path); -// rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid inventory structure"); -// } -// } -// -// // Scan the set of folders in the entity collection for an -// // entry that matches the context folder. It is assumed that -// // the only reliable indicator of this is a zero UUID (using -// // implicit context), or the parent's UUID matches that of the -// // URI designated node (explicit context). We don't allow -// // ambiguity in this case because this is POST and we are -// // supposed to be modifying a specific node. -// // We assign any element IDs required as an economy; we don't -// // want to iterate over the fodler set again if it can be -// // helped. -// -// foreach (InventoryFolderBase folder in entity.Folders) -// { -// if (folder.ParentID == uri.ParentID || -// folder.ParentID == UUID.Zero) -// { -// folder.ParentID = uri.ParentID; -// xml = folder; -// count++; -// } -// } -// -// // More than one entry is ambiguous. Other folders should be -// // added using the POST verb. -// -// if (count > 1) -// { -// Rest.Log.DebugFormat("{0} {1}: Request for <{2}> is ambiguous", -// MsgId, rdata.method, rdata.path); -// rdata.Fail(Rest.HttpStatusCodeConflict, "context is ambiguous"); -// } -// -// // Exactly one entry means we ARE replacing the node -// // identified by the URI. So we delete the old folder -// // by moving it to the trash and then purging it. -// // We then add all of the folders and items we -// // included in the entity. The subtree has been -// // modified. -// -// if (count == 1) -// { -// InventoryFolderBase TrashCan = GetTrashCan(rdata); -// -// // All went well, so we generate a UUID is one is -// // needed. -// -// if (xml.ID == UUID.Zero) -// { -// xml.ID = UUID.Random(); -// } -// -// uri.ParentID = TrashCan.ID; -// Rest.InventoryServices.MoveFolder(uri); -// Rest.InventoryServices.PurgeFolder(TrashCan); -// modified = true; -// } -// -// // Now, regardelss of what they represent, we -// // integrate all of the elements in the entity. -// -// foreach (InventoryFolderBase f in entity.Folders) -// { -// rdata.appendStatus(String.Format("

Moving folder {0} UUID {1}

", f.Name, f.ID)); -// Rest.InventoryServices.MoveFolder(f); -// } -// -// foreach (InventoryItemBase it in entity.Items) -// { -// rdata.appendStatus(String.Format("

Storing item {0} UUID {1}

", it.Name, it.ID)); -// Rest.InventoryServices.AddItem(it); -// } -// } -// -// ///

-// /// URI specifies an item to be updated -// /// -// /// -// /// The entity must contain a single item node to be -// /// updated. ID and Folder ID must be correct. -// /// -// -// else -// { -// InventoryItemBase uri = (InventoryItemBase) InventoryNode; -// InventoryItemBase xml = null; -// -// if (entity.Folders.Count != 0) -// { -// Rest.Log.DebugFormat("{0} {1}: Request should not contain any folders <{2}>", -// MsgId, rdata.method, rdata.path); -// rdata.Fail(Rest.HttpStatusCodeBadRequest, "folder is not allowed"); -// } -// -// if (entity.Items.Count > 1) -// { -// Rest.Log.DebugFormat("{0} {1}: Entity contains too many items <{2}>", -// MsgId, rdata.method, rdata.path); -// rdata.Fail(Rest.HttpStatusCodeBadRequest, "too may items"); -// } -// -// xml = entity.Items[0]; -// -// if (xml.ID == UUID.Zero) -// { -// xml.ID = UUID.Random(); -// } -// -// // If the folder reference has changed, then this item is -// // being moved. Otherwise we'll just delete the old, and -// // add in the new. -// -// // Delete the old item -// -// List uuids = new List(); -// uuids.Add(uri.ID); -// Rest.InventoryServices.DeleteItems(uri.Owner, uuids); -// -// // Add the new item to the inventory -// -// Rest.InventoryServices.AddItem(xml); -// -// rdata.appendStatus(String.Format("

Storing item {0} UUID {1}

", xml.Name, xml.ID)); -// } -// -// if (created) -// { -// rdata.Complete(Rest.HttpStatusCodeCreated); -// } -// else -// { -// if (modified) -// { -// rdata.Complete(Rest.HttpStatusCodeOK); -// } -// else -// { -// rdata.Complete(Rest.HttpStatusCodeNoContent); -// } -// } -// -// rdata.Respond(String.Format("Profile {0} : Normal completion", rdata.method)); -// } - - ///

- /// Arguably the most damaging REST interface. It deletes the inventory - /// item or folder identified by the URI. - /// - /// We only process if the URI identified node appears to exist - /// We do not test for success because we either get a context, - /// or an exception is thrown. - /// - /// Folders are deleted by moving them to another folder and then - /// purging that folder. We'll do that by creating a temporary - /// sub-folder in the TrashCan and purging that folder's - /// contents. If we can't can it, we don't delete it... - /// So, if no trashcan is available, the request does nothing. - /// Items are summarily deleted. - /// - /// In the interests of safety, a delete request should normally - /// be performed using UUID, as a name might identify several - /// elements. - /// - /// HTTP service request work area -// private void DoDelete(InventoryRequestData rdata) -// { -// Object InventoryNode = getInventoryNode(rdata, rdata.root, PARM_PATH, false); -// -// if (typeof(InventoryFolderBase) == InventoryNode.GetType() || -// typeof(InventoryFolderImpl) == InventoryNode.GetType()) -// { -// InventoryFolderBase TrashCan = GetTrashCan(rdata); -// -// InventoryFolderBase folder = (InventoryFolderBase) InventoryNode; -// Rest.Log.DebugFormat("{0} {1}: Folder {2} will be deleted", -// MsgId, rdata.method, rdata.path); -// folder.ParentID = TrashCan.ID; -// Rest.InventoryServices.MoveFolder(folder); -// Rest.InventoryServices.PurgeFolder(TrashCan); -// -// rdata.appendStatus(String.Format("

Deleted folder {0} UUID {1}

", folder.Name, folder.ID)); -// } -// -// // Deleting items is much more straight forward. -// -// else -// { -// InventoryItemBase item = (InventoryItemBase) InventoryNode; -// Rest.Log.DebugFormat("{0} {1}: Item {2} will be deleted", -// MsgId, rdata.method, rdata.path); -// List uuids = new List(); -// uuids.Add(item.ID); -// Rest.InventoryServices.DeleteItems(item.Owner, uuids); -// rdata.appendStatus(String.Format("

Deleted item {0} UUID {1}

", item.Name, item.ID)); -// } -// -// rdata.Complete(); -// rdata.Respond(String.Format("Profile {0} : Normal completion", rdata.method)); -// } - -#endregion method-specific processing - - ///

- /// This method is called to obtain the OpenSim inventory object identified - /// by the supplied URI. This may be either an Item or a Folder, so a suitably - /// ambiguous return type is employed (Object). This method recurses as - /// necessary to process the designated hierarchy. - /// - /// If we reach the end of the URI then we return the contextual folder to - /// our caller. - /// - /// If we are not yet at the end of the URI we attempt to find a child folder - /// and if we succeed we recurse. - /// - /// If this is the last node, then we look to see if this is an item. If it is, - /// we return that item. - /// - /// If we reach the end of an inventory path and the URI si not yet exhausted, - /// then if 'fill' is specified, we create the intermediate nodes. - /// - /// Otherwise we fail the request on the ground of an invalid URI. - /// - /// An ambiguous request causes the request to fail. - /// - /// - /// HTTP service request work area - /// The folder to be searched (parent) - /// URI parameter index - /// Should missing path members be created? - - private Object getInventoryNode(InventoryRequestData rdata, - InventoryFolderBase folder, - int pi, bool fill) - { - InventoryFolderBase foundf = null; - int fk = 0; - - Rest.Log.DebugFormat("{0} Searching folder {1} {2} [{3}]", MsgId, folder.ID, folder.Name, pi); - - // We have just run off the end of the parameter sequence - - if (pi >= rdata.Parameters.Length) - { - return folder; - } - - // There are more names in the parameter sequence, - // look for the folder named by param[pi] as a - // child of the folder supplied as an argument. - // Note that a UUID may have been supplied as the - // identifier (it is the ONLY guaranteed unambiguous - // option. - - if (rdata.folders != null) - { - foreach (InventoryFolderBase f in rdata.folders) - { - // Look for the present node in the directory list - if (f.ParentID == folder.ID && - (f.Name == rdata.Parameters[pi] || - f.ID.ToString() == rdata.Parameters[pi])) - { - foundf = f; - fk++; - } - } - } - - // If more than one node matched, then the path, as specified - // is ambiguous. - - if (fk > 1) - { - Rest.Log.DebugFormat("{0} {1}: Request for {2} is ambiguous", - MsgId, rdata.method, rdata.path); - rdata.Fail(Rest.HttpStatusCodeConflict, "request is ambiguous"); - } - - // If we find a match, then the method - // increment the parameter index, and calls itself - // passing the found folder as the new context. - - if (foundf != null) - { - return getInventoryNode(rdata, foundf, pi+1, fill); - } - - // No folders that match. Perhaps this parameter identifies an item? If - // it does, then it MUST also be the last name in the sequence. - - if (pi == rdata.Parameters.Length-1) - { - if (rdata.items != null) - { - int k = 0; - InventoryItemBase li = null; - foreach (InventoryItemBase i in rdata.items) - { - if (i.Folder == folder.ID && - (i.Name == rdata.Parameters[pi] || - i.ID.ToString() == rdata.Parameters[pi])) - { - li = i; - k++; - } - } - if (k == 1) - { - return li; - } - else if (k > 1) - { - Rest.Log.DebugFormat("{0} {1}: Request for {2} is ambiguous", - MsgId, rdata.method, rdata.path); - rdata.Fail(Rest.HttpStatusCodeConflict, "request is ambiguous"); - } - } - } - - // If fill is enabled, then we must create the missing intermediate nodes. - // And of course, even this is not straightforward. All intermediate nodes - // are obviously folders, but the last node may be a folder or an item. - - if (fill) - { - } - - // No fill, so abandon the request - - Rest.Log.DebugFormat("{0} {1}: Resource {2} not found", - MsgId, rdata.method, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound, - String.Format("resource {0}:{1} not found", rdata.method, rdata.path)); - - return null; /* Never reached */ - } - - /// - /// This routine traverse the inventory's structure until the end-point identified - /// in the URI is reached, the remainder of the inventory (if any) is then formatted - /// and returned to the requestor. - /// - /// Note that this method is only interested in those folder that match elements of - /// the URI supplied by the requestor, so once a match is fund, the processing does - /// not need to consider any further elements. - /// - /// Only the last element in the URI should identify an item. - /// - /// HTTP service request work area - /// The folder to be searched (parent) - /// URI parameter index - - private void traverse(InventoryRequestData rdata, InventoryFolderBase folder, int pi) - { - Rest.Log.DebugFormat("{0} Traverse[initial] : {1} {2} [{3}]", MsgId, folder.ID, folder.Name, pi); - - if (rdata.folders != null) - { - // If there was only one parameter (avatar name), then the entire - // inventory is being requested. - - if (rdata.Parameters.Length == 1) - { - formatInventory(rdata, rdata.root, String.Empty); - } - - // Has the client specified the root directory name explicitly? - // if yes, then we just absorb the reference, because the folder - // we start looking in for a match *is* the root directory. If there - // are more parameters remaining we tarverse, otehrwise it's time - // to format. Otherwise,we consider the "My Inventory" to be implied - // and we just traverse normally. - - else if (folder.ID.ToString() == rdata.Parameters[pi] || - folder.Name == rdata.Parameters[pi]) - { - // Length is -1 because the avatar name is a parameter - if (pi<(rdata.Parameters.Length-1)) - { - traverseInventory(rdata, folder, pi+1); - } - else - { - formatInventory(rdata, folder, String.Empty); - } - } - else - { - traverseInventory(rdata, folder, pi); - } - - return; - } - } - - /// - /// This is the recursive method. I've separated them in this way so that - /// we do not have to waste cycles on any first-case-only processing. - /// - - private void traverseInventory(InventoryRequestData rdata, InventoryFolderBase folder, int pi) - { - int fk = 0; - InventoryFolderBase ffound = null; - InventoryItemBase ifound = null; - - Rest.Log.DebugFormat("{0} Traverse Folder : {1} {2} [{3}]", MsgId, folder.ID, folder.Name, pi); - - foreach (InventoryFolderBase f in rdata.folders) - { - if (f.ParentID == folder.ID && - (f.Name == rdata.Parameters[pi] || - f.ID.ToString() == rdata.Parameters[pi])) - { - fk++; - ffound = f; - } - } - - // If this is the last element in the parameter sequence, then - // it is reasonable to check for an item. All intermediate nodes - // MUST be folders. - - if (pi == rdata.Parameters.Length-1) - { - // Only if there are any items, and there pretty much always are. - - if (rdata.items != null) - { - foreach (InventoryItemBase i in rdata.items) - { - if (i.Folder == folder.ID && - (i.Name == rdata.Parameters[pi] || - i.ID.ToString() == rdata.Parameters[pi])) - { - fk++; - ifound = i; - } - } - } - } - - if (fk == 1) - { - if (ffound != null) - { - if (pi < rdata.Parameters.Length-1) - { - traverseInventory(rdata, ffound, pi+1); - } - else - { - formatInventory(rdata, ffound, String.Empty); - } - return; - } - else - { - // Fetching an Item has a special significance. In this - // case we also want to fetch the associated asset. - // To make it interesting, we'll do this via redirection. - string asseturl = String.Format("http://{0}:{1}/{2}{3}{4}", rdata.hostname, rdata.port, - "admin/assets",Rest.UrlPathSeparator,ifound.AssetID.ToString()); - rdata.Redirect(asseturl,Rest.PERMANENT); - Rest.Log.DebugFormat("{0} Never Reached", MsgId); - } - } - else if (fk > 1) - { - rdata.Fail(Rest.HttpStatusCodeConflict, - String.Format("ambiguous element ({0}) in path specified: <{1}>", - pi, rdata.path)); - } - - Rest.Log.DebugFormat("{0} Inventory does not contain item/folder: <{1}>", - MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound,String.Format("no such item/folder : {0}", - rdata.Parameters[pi])); - - } - - /// - /// This method generates XML that describes an instance of InventoryFolderBase. - /// It recurses as necessary to reflect a folder hierarchy, and calls formatItem - /// to generate XML for any items encountered along the way. - /// The indentation parameter is solely for the benefit of trace record - /// formatting. - /// - /// HTTP service request work area - /// The folder to be searched (parent) - /// pretty print indentation - private void formatInventory(InventoryRequestData rdata, InventoryFolderBase folder, string indent) - { - if (Rest.DEBUG) - { - Rest.Log.DebugFormat("{0} Folder : {1} {2} {3} type = {4}", - MsgId, folder.ID, indent, folder.Name, folder.Type); - indent += "\t"; - } - - // Start folder item - - rdata.writer.WriteStartElement(String.Empty,"Folder",String.Empty); - rdata.writer.WriteAttributeString("name",String.Empty,folder.Name); - rdata.writer.WriteAttributeString("uuid",String.Empty,folder.ID.ToString()); - rdata.writer.WriteAttributeString("parent",String.Empty,folder.ParentID.ToString()); - rdata.writer.WriteAttributeString("owner",String.Empty,folder.Owner.ToString()); - rdata.writer.WriteAttributeString("type",String.Empty,folder.Type.ToString()); - rdata.writer.WriteAttributeString("version",String.Empty,folder.Version.ToString()); - - if (rdata.folders != null) - { - foreach (InventoryFolderBase f in rdata.folders) - { - if (f.ParentID == folder.ID) - { - formatInventory(rdata, f, indent); - } - } - } - - if (rdata.items != null) - { - foreach (InventoryItemBase i in rdata.items) - { - if (i.Folder == folder.ID) - { - formatItem(rdata, i, indent); - } - } - } - - // End folder item - - rdata.writer.WriteEndElement(); - } - - /// - /// This method generates XML that describes an instance of InventoryItemBase. - /// - /// HTTP service request work area - /// The item to be formatted - /// Pretty print indentation - private void formatItem(InventoryRequestData rdata, InventoryItemBase i, string indent) - { - Rest.Log.DebugFormat("{0} Item : {1} {2} {3} Type = {4}, AssetType = {5}", - MsgId, i.ID, indent, i.Name, i.InvType, i.AssetType); - - rdata.writer.WriteStartElement(String.Empty, "Item", String.Empty); - - rdata.writer.WriteAttributeString("name", String.Empty, i.Name); - rdata.writer.WriteAttributeString("desc", String.Empty, i.Description); - rdata.writer.WriteAttributeString("uuid", String.Empty, i.ID.ToString()); - rdata.writer.WriteAttributeString("folder", String.Empty, i.Folder.ToString()); - rdata.writer.WriteAttributeString("owner", String.Empty, i.Owner.ToString()); - rdata.writer.WriteAttributeString("creator", String.Empty, i.CreatorId); - rdata.writer.WriteAttributeString("creatordata", String.Empty, i.CreatorData); - rdata.writer.WriteAttributeString("creationdate", String.Empty, i.CreationDate.ToString()); - rdata.writer.WriteAttributeString("invtype", String.Empty, i.InvType.ToString()); - rdata.writer.WriteAttributeString("assettype", String.Empty, i.AssetType.ToString()); - rdata.writer.WriteAttributeString("groupowned", String.Empty, i.GroupOwned.ToString()); - rdata.writer.WriteAttributeString("groupid", String.Empty, i.GroupID.ToString()); - rdata.writer.WriteAttributeString("saletype", String.Empty, i.SaleType.ToString()); - rdata.writer.WriteAttributeString("saleprice", String.Empty, i.SalePrice.ToString()); - rdata.writer.WriteAttributeString("flags", String.Empty, i.Flags.ToString()); - - rdata.writer.WriteStartElement(String.Empty, "Permissions", String.Empty); - rdata.writer.WriteAttributeString("current", String.Empty, i.CurrentPermissions.ToString("X")); - rdata.writer.WriteAttributeString("next", String.Empty, i.NextPermissions.ToString("X")); - rdata.writer.WriteAttributeString("group", String.Empty, i.GroupPermissions.ToString("X")); - rdata.writer.WriteAttributeString("everyone", String.Empty, i.EveryOnePermissions.ToString("X")); - rdata.writer.WriteAttributeString("base", String.Empty, i.BasePermissions.ToString("X")); - rdata.writer.WriteEndElement(); - - rdata.writer.WriteElementString("Asset", i.AssetID.ToString()); - - rdata.writer.WriteEndElement(); - } - - /// - /// This method creates a "trashcan" folder to support folder and item - /// deletions by this interface. The xisting trash folder is found and - /// this folder is created within it. It is called "tmp" to indicate to - /// the client that it is OK to delete this folder. The REST interface - /// will recreate the folder on an as-required basis. - /// If the trash can cannot be created, then by implication the request - /// that required it cannot be completed, and it fails accordingly. - /// - /// HTTP service request work area - private InventoryFolderBase GetTrashCan(InventoryRequestData rdata) - { - InventoryFolderBase TrashCan = null; - - foreach (InventoryFolderBase f in rdata.folders) - { - if (f.Name == "Trash") - { - foreach (InventoryFolderBase t in rdata.folders) - { - if (t.Name == "tmp") - { - TrashCan = t; - } - } - if (TrashCan == null) - { - TrashCan = new InventoryFolderBase(); - TrashCan.Name = "tmp"; - TrashCan.ID = UUID.Random(); - TrashCan.Version = 1; - TrashCan.Type = (short) AssetType.TrashFolder; - TrashCan.ParentID = f.ID; - TrashCan.Owner = f.Owner; - Rest.InventoryServices.AddFolder(TrashCan); - } - } - } - - if (TrashCan == null) - { - Rest.Log.DebugFormat("{0} No Trash Can available", MsgId); - rdata.Fail(Rest.HttpStatusCodeServerError, "unable to create trash can"); - } - - return TrashCan; - } - - /// - /// Make sure that an unchanged folder is not unnecessarily - /// processed. - /// - /// Folder obtained from enclosed entity - /// Folder obtained from the user's inventory - private bool FolderHasChanged(InventoryFolderBase newf, InventoryFolderBase oldf) - { - return (newf.Name != oldf.Name - || newf.ParentID != oldf.ParentID - || newf.Owner != oldf.Owner - || newf.Type != oldf.Type - || newf.Version != oldf.Version - ); - } - - /// - /// Make sure that an unchanged item is not unnecessarily - /// processed. - /// - /// Item obtained from enclosed entity - /// Item obtained from the user's inventory - private bool ItemHasChanged(InventoryItemBase newf, InventoryItemBase oldf) - { - return (newf.Name != oldf.Name - || newf.Folder != oldf.Folder - || newf.Description != oldf.Description - || newf.Owner != oldf.Owner - || newf.CreatorId != oldf.CreatorId - || newf.AssetID != oldf.AssetID - || newf.GroupID != oldf.GroupID - || newf.GroupOwned != oldf.GroupOwned - || newf.InvType != oldf.InvType - || newf.AssetType != oldf.AssetType - ); - } - - /// - /// This method is called by PUT and POST to create an XmlInventoryCollection - /// instance that reflects the content of the entity supplied on the request. - /// Any elements in the completed collection whose UUID is zero, are - /// considered to be located relative to the end-point identified int he - /// URI. In this way, an entire sub-tree can be conveyed in a single REST - /// PUT or POST request. - /// - /// A new instance of XmlInventoryCollection is created and, if the request - /// has an entity, it is more completely initialized. thus, if no entity was - /// provided the collection is valid, but empty. - /// - /// The entity is then scanned and each tag is processed to produce the - /// appropriate inventory elements. At the end f the scan, teh XmlInventoryCollection - /// will reflect the subtree described by the entity. - /// - /// This is a very flexible mechanism, the entity may contain arbitrary, - /// discontiguous tree fragments, or may contain single element. The caller is - /// responsible for integrating this collection (and ensuring that any - /// missing parent IDs are resolved). - /// - /// HTTP service request work area - internal XmlInventoryCollection ReconstituteEntity(InventoryRequestData rdata) - { - Rest.Log.DebugFormat("{0} Reconstituting entity", MsgId); - - XmlInventoryCollection ic = new XmlInventoryCollection(); - - if (rdata.request.HasEntityBody) - { - Rest.Log.DebugFormat("{0} Entity present", MsgId); - - ic.init(rdata); - - try - { - while (ic.xml.Read()) - { - switch (ic.xml.NodeType) - { - case XmlNodeType.Element: - Rest.Log.DebugFormat("{0} StartElement: <{1}>", - MsgId, ic.xml.Name); - - switch (ic.xml.Name) - { - case "Folder": - Rest.Log.DebugFormat("{0} Processing {1} element", - MsgId, ic.xml.Name); - CollectFolder(ic); - break; - case "Item": - Rest.Log.DebugFormat("{0} Processing {1} element", - MsgId, ic.xml.Name); - CollectItem(ic); - break; - case "Asset": - Rest.Log.DebugFormat("{0} Processing {1} element", - MsgId, ic.xml.Name); - CollectAsset(ic); - break; - case "Permissions": - Rest.Log.DebugFormat("{0} Processing {1} element", - MsgId, ic.xml.Name); - CollectPermissions(ic); - break; - default: - Rest.Log.DebugFormat("{0} Ignoring {1} element", - MsgId, ic.xml.Name); - break; - } - - // This stinks, but the ReadElement call above not only reads - // the imbedded data, but also consumes the end tag for Asset - // and moves the element pointer on to the containing Item's - // element-end, however, if there was a permissions element - // following, it would get us to the start of that.. - if (ic.xml.NodeType == XmlNodeType.EndElement && - ic.xml.Name == "Item") - { - Validate(ic); - } - break; - - case XmlNodeType.EndElement : - switch (ic.xml.Name) - { - case "Folder": - Rest.Log.DebugFormat("{0} Completing {1} element", - MsgId, ic.xml.Name); - ic.Pop(); - break; - case "Item": - Rest.Log.DebugFormat("{0} Completing {1} element", - MsgId, ic.xml.Name); - Validate(ic); - break; - case "Asset": - Rest.Log.DebugFormat("{0} Completing {1} element", - MsgId, ic.xml.Name); - break; - case "Permissions": - Rest.Log.DebugFormat("{0} Completing {1} element", - MsgId, ic.xml.Name); - break; - default: - Rest.Log.DebugFormat("{0} Ignoring {1} element", - MsgId, ic.xml.Name); - break; - } - break; - - default: - Rest.Log.DebugFormat("{0} Ignoring: <{1}>:<{2}>", - MsgId, ic.xml.NodeType, ic.xml.Value); - break; - } - } - } - catch (XmlException e) - { - Rest.Log.WarnFormat("{0} XML parsing error: {1}", MsgId, e.Message); - throw e; - } - catch (Exception e) - { - Rest.Log.WarnFormat("{0} Unexpected XML parsing error: {1}", MsgId, e.Message); - throw e; - } - } - else - { - Rest.Log.DebugFormat("{0} Entity absent", MsgId); - } - - if (Rest.DEBUG) - { - Rest.Log.DebugFormat("{0} Reconstituted entity", MsgId); - Rest.Log.DebugFormat("{0} {1} assets", MsgId, ic.Assets.Count); - Rest.Log.DebugFormat("{0} {1} folder", MsgId, ic.Folders.Count); - Rest.Log.DebugFormat("{0} {1} items", MsgId, ic.Items.Count); - } - - return ic; - } - - /// - /// This method creates an inventory Folder from the - /// information supplied in the request's entity. - /// A folder instance is created and initialized to reflect - /// default values. These values are then overridden - /// by information supplied in the entity. - /// If context was not explicitly provided, then the - /// appropriate ID values are determined. - /// - - private void CollectFolder(XmlInventoryCollection ic) - { - Rest.Log.DebugFormat("{0} Interpret folder element", MsgId); - - InventoryFolderBase result = new InventoryFolderBase(); - - // Default values - - result.Name = String.Empty; - result.ID = UUID.Zero; - result.Owner = ic.UserID; - result.ParentID = UUID.Zero; // Context - result.Type = (short) AssetType.Folder; - result.Version = 1; - - if (ic.xml.HasAttributes) - { - for (int i = 0; i < ic.xml.AttributeCount; i++) - { - ic.xml.MoveToAttribute(i); - switch (ic.xml.Name) - { - case "name": - result.Name = ic.xml.Value; - break; - case "uuid": - result.ID = new UUID(ic.xml.Value); - break; - case "parent": - result.ParentID = new UUID(ic.xml.Value); - break; - case "owner": - result.Owner = new UUID(ic.xml.Value); - break; - case "type": - result.Type = Int16.Parse(ic.xml.Value); - break; - case "version": - result.Version = UInt16.Parse(ic.xml.Value); - break; - default: - Rest.Log.DebugFormat("{0} Folder: unrecognized attribute: {1}:{2}", - MsgId, ic.xml.Name, ic.xml.Value); - ic.Fail(Rest.HttpStatusCodeBadRequest, String.Format("unrecognized attribute <{0}>", - ic.xml.Name)); - break; - } - } - } - - ic.xml.MoveToElement(); - - // The client is relying upon the reconstitution process - // to determine the parent's UUID based upon context. This - // is necessary where a new folder may have been - // introduced. - - if (result.ParentID == UUID.Zero) - { - result.ParentID = ic.Parent(); - } - else - { - bool found = false; - - foreach (InventoryFolderBase parent in ic.rdata.folders) - { - if (parent.ID == result.ParentID) - { - found = true; - break; - } - } - - if (!found) - { - Rest.Log.ErrorFormat("{0} Invalid parent ID ({1}) in folder {2}", - MsgId, ic.Item.Folder, result.ID); - ic.Fail(Rest.HttpStatusCodeBadRequest, "invalid parent"); - } - } - - // This is a new folder, so no existing UUID is available - // or appropriate - - if (result.ID == UUID.Zero) - { - result.ID = UUID.Random(); - } - - // Treat this as a new context. Any other information is - // obsolete as a consequence. - - ic.Push(result); - } - - /// - /// This method is called to handle the construction of an Item - /// instance from the supplied request entity. It is called - /// whenever an Item start tag is detected. - /// An instance of an Item is created and initialized to default - /// values. These values are then overridden from values supplied - /// as attributes to the Item element. - /// This item is then stored in the XmlInventoryCollection and - /// will be verified by Validate. - /// All context is reset whenever the effective folder changes - /// or an item is successfully validated. - /// - private void CollectItem(XmlInventoryCollection ic) - { - Rest.Log.DebugFormat("{0} Interpret item element", MsgId); - - InventoryItemBase result = new InventoryItemBase(); - - result.Name = String.Empty; - result.Description = String.Empty; - result.ID = UUID.Zero; - result.Folder = UUID.Zero; - result.Owner = ic.UserID; - result.CreatorId = ic.UserID.ToString(); - result.AssetID = UUID.Zero; - result.GroupID = UUID.Zero; - result.GroupOwned = false; - result.InvType = (int) InventoryType.Unknown; - result.AssetType = (int) AssetType.Unknown; - - if (ic.xml.HasAttributes) - { - for (int i = 0; i < ic.xml.AttributeCount; i++) - { - ic.xml.MoveToAttribute(i); - - switch (ic.xml.Name) - { - case "name": - result.Name = ic.xml.Value; - break; - case "desc": - result.Description = ic.xml.Value; - break; - case "uuid": - result.ID = new UUID(ic.xml.Value); - break; - case "folder": - result.Folder = new UUID(ic.xml.Value); - break; - case "owner": - result.Owner = new UUID(ic.xml.Value); - break; - case "invtype": - result.InvType = Int32.Parse(ic.xml.Value); - break; - case "creator": - result.CreatorId = ic.xml.Value; - break; - case "assettype": - result.AssetType = Int32.Parse(ic.xml.Value); - break; - case "groupowned": - result.GroupOwned = Boolean.Parse(ic.xml.Value); - break; - case "groupid": - result.GroupID = new UUID(ic.xml.Value); - break; - case "flags": - result.Flags = UInt32.Parse(ic.xml.Value); - break; - case "creationdate": - result.CreationDate = Int32.Parse(ic.xml.Value); - break; - case "saletype": - result.SaleType = Byte.Parse(ic.xml.Value); - break; - case "saleprice": - result.SalePrice = Int32.Parse(ic.xml.Value); - break; - - default: - Rest.Log.DebugFormat("{0} Item: Unrecognized attribute: {1}:{2}", - MsgId, ic.xml.Name, ic.xml.Value); - ic.Fail(Rest.HttpStatusCodeBadRequest, String.Format("unrecognized attribute", - ic.xml.Name)); - break; - } - } - } - - ic.xml.MoveToElement(); - - ic.Push(result); - } - - /// - /// This method assembles an asset instance from the - /// information supplied in the request's entity. It is - /// called as a result of detecting a start tag for a - /// type of Asset. - /// The information is collected locally, and an asset - /// instance is created only if the basic XML parsing - /// completes successfully. - /// Default values for all parts of the asset are - /// established before overriding them from the supplied - /// XML. - /// If an asset has inline=true as an attribute, then - /// the element contains the data representing the - /// asset. This is saved as the data component. - /// inline=false means that the element's payload is - /// simply the UUID of the asset referenced by the - /// item being constructed. - /// An asset, if created is stored in the - /// XmlInventoryCollection - /// - private void CollectAsset(XmlInventoryCollection ic) - { - Rest.Log.DebugFormat("{0} Interpret asset element", MsgId); - - string name = String.Empty; - string desc = String.Empty; - sbyte type = (sbyte) AssetType.Unknown; - bool temp = false; - bool local = false; - - // This is not a persistent attribute - bool inline = false; - - UUID uuid = UUID.Zero; - - // Attribute is optional - if (ic.xml.HasAttributes) - { - for (int i = 0; i < ic.xml.AttributeCount; i++) - { - ic.xml.MoveToAttribute(i); - switch (ic.xml.Name) - { - case "name" : - name = ic.xml.Value; - break; - - case "type" : - type = SByte.Parse(ic.xml.Value); - break; - - case "description" : - desc = ic.xml.Value; - break; - - case "temporary" : - temp = Boolean.Parse(ic.xml.Value); - break; - - case "uuid" : - uuid = new UUID(ic.xml.Value); - break; - - case "inline" : - inline = Boolean.Parse(ic.xml.Value); - break; - - case "local" : - local = Boolean.Parse(ic.xml.Value); - break; - - default : - Rest.Log.DebugFormat("{0} Asset: Unrecognized attribute: {1}:{2}", - MsgId, ic.xml.Name, ic.xml.Value); - ic.Fail(Rest.HttpStatusCodeBadRequest, - String.Format("unrecognized attribute <{0}>", ic.xml.Name)); - break; - } - } - } - - ic.xml.MoveToElement(); - - // If this is a reference to an existing asset, just store the - // asset ID into the item. - - if (!inline) - { - if (ic.Item != null) - { - ic.Item.AssetID = new UUID(ic.xml.ReadElementContentAsString()); - Rest.Log.DebugFormat("{0} Asset ID supplied: {1}", MsgId, ic.Item.AssetID); - } - else - { - Rest.Log.DebugFormat("{0} LLUID unimbedded asset must be inline", MsgId); - ic.Fail(Rest.HttpStatusCodeBadRequest, "no context for asset"); - } - } - - // Otherwise, generate an asset ID, store that into the item, and - // create an entry in the asset list for the inlined asset. But - // only if the size is non-zero. - - else - { - AssetBase asset = null; - string b64string = null; - - // Generate a UUID if none were given, and generally none should - // be. Ever. - - if (uuid == UUID.Zero) - { - uuid = UUID.Random(); - } - - // Create AssetBase entity to hold the inlined asset - - asset = new AssetBase(uuid, name, type, UUID.Zero.ToString()); - - asset.Description = desc; - asset.Local = local; - asset.Temporary = temp; - - b64string = ic.xml.ReadElementContentAsString(); - - Rest.Log.DebugFormat("{0} Data length is {1}", MsgId, b64string.Length); - Rest.Log.DebugFormat("{0} Data content starts with: \n\t<{1}>", MsgId, - b64string.Substring(0, b64string.Length > 132 ? 132 : b64string.Length)); - - asset.Data = Convert.FromBase64String(b64string); - - // Ensure the asset always has some kind of data component - - if (asset.Data == null) - { - asset.Data = new byte[1]; - } - - // If this is in the context of an item, establish - // a link with the item in context. - - if (ic.Item != null && ic.Item.AssetID == UUID.Zero) - { - ic.Item.AssetID = uuid; - } - - ic.Push(asset); - } - } - - /// - /// Store any permissions information provided by the request. - /// This overrides the default permissions set when the - /// XmlInventoryCollection object was created. - /// - private void CollectPermissions(XmlInventoryCollection ic) - { - if (ic.xml.HasAttributes) - { - for (int i = 0; i < ic.xml.AttributeCount; i++) - { - ic.xml.MoveToAttribute(i); - switch (ic.xml.Name) - { - case "current": - ic.CurrentPermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber); - break; - case "next": - ic.NextPermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber); - break; - case "group": - ic.GroupPermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber); - break; - case "everyone": - ic.EveryOnePermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber); - break; - case "base": - ic.BasePermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber); - break; - default: - Rest.Log.DebugFormat("{0} Permissions: invalid attribute {1}:{2}", - MsgId,ic.xml.Name, ic.xml.Value); - ic.Fail(Rest.HttpStatusCodeBadRequest, - String.Format("invalid attribute <{0}>", ic.xml.Name)); - break; - } - } - } - - ic.xml.MoveToElement(); - } - - /// - /// This method is called whenever an Item has been successfully - /// reconstituted from the request's entity. - /// It uses the information curren tin the XmlInventoryCollection - /// to complete the item's specification, including any implied - /// context and asset associations. - /// It fails the request if any necessary item or asset information - /// is missing. - /// - - private void Validate(XmlInventoryCollection ic) - { - // There really should be an item present if we've - // called validate. So fail if there is not. - - if (ic.Item == null) - { - Rest.Log.ErrorFormat("{0} Unable to parse request", MsgId); - ic.Fail(Rest.HttpStatusCodeBadRequest, "request parse error"); - } - - // Every item is required to have a name (via REST anyway) - - if (ic.Item.Name == String.Empty) - { - Rest.Log.ErrorFormat("{0} An item name MUST be specified", MsgId); - ic.Fail(Rest.HttpStatusCodeBadRequest, "item name required"); - } - - // An item MUST have an asset ID. AssetID should never be zero - // here. It should always get set from the information stored - // when the Asset element was processed. - - if (ic.Item.AssetID == UUID.Zero) - { - Rest.Log.ErrorFormat("{0} Unable to complete request", MsgId); - Rest.Log.InfoFormat("{0} Asset information is missing", MsgId); - ic.Fail(Rest.HttpStatusCodeBadRequest, "asset information required"); - } - - // If the item is new, then assign it an ID - - if (ic.Item.ID == UUID.Zero) - { - ic.Item.ID = UUID.Random(); - } - - // If the context is being implied, obtain the current - // folder item's ID. If it was specified explicitly, make - // sure that theparent folder exists. - - if (ic.Item.Folder == UUID.Zero) - { - ic.Item.Folder = ic.Parent(); - } - else - { - bool found = false; - - foreach (InventoryFolderBase parent in ic.rdata.folders) - { - if (parent.ID == ic.Item.Folder) - { - found = true; - break; - } - } - - if (!found) - { - Rest.Log.ErrorFormat("{0} Invalid parent ID ({1}) in item {2}", - MsgId, ic.Item.Folder, ic.Item.ID); - ic.Fail(Rest.HttpStatusCodeBadRequest, "parent information required"); - } - } - - // If this is an inline asset being constructed in the context - // of a new Item, then use the itm's name here too. - - if (ic.Asset != null) - { - if (ic.Asset.Name == String.Empty) - ic.Asset.Name = ic.Item.Name; - if (ic.Asset.Description == String.Empty) - ic.Asset.Description = ic.Item.Description; - } - - // Assign permissions - - ic.Item.CurrentPermissions = ic.CurrentPermissions; - ic.Item.EveryOnePermissions = ic.EveryOnePermissions; - ic.Item.BasePermissions = ic.BasePermissions; - ic.Item.GroupPermissions = ic.GroupPermissions; - ic.Item.NextPermissions = ic.NextPermissions; - - // If no type was specified for this item, we can attempt to - // infer something from the file type maybe. This is NOT as - // good as having type be specified in the XML. - - if (ic.Item.AssetType == (int) AssetType.Unknown || - ic.Item.InvType == (int) InventoryType.Unknown) - { - Rest.Log.DebugFormat("{0} Attempting to infer item type", MsgId); - - string[] parts = ic.Item.Name.Split(Rest.CA_PERIOD); - - if (Rest.DEBUG) - { - for (int i = 0; i < parts.Length; i++) - { - Rest.Log.DebugFormat("{0} Name part {1} : {2}", - MsgId, i, parts[i]); - } - } - - // If the associated item name is multi-part, then maybe - // the last part will indicate the item type - if we're - // lucky. - - if (parts.Length > 1) - { - Rest.Log.DebugFormat("{0} File type is {1}", - MsgId, parts[parts.Length - 1]); - switch (parts[parts.Length - 1]) - { - case "jpeg2000" : - case "jpeg-2000" : - case "jpg2000" : - case "jpg-2000" : - Rest.Log.DebugFormat("{0} Type {1} inferred", - MsgId, parts[parts.Length-1]); - if (ic.Item.AssetType == (int) AssetType.Unknown) - ic.Item.AssetType = (int) AssetType.ImageJPEG; - if (ic.Item.InvType == (int) InventoryType.Unknown) - ic.Item.InvType = (int) InventoryType.Texture; - break; - case "jpg" : - case "jpeg" : - Rest.Log.DebugFormat("{0} Type {1} inferred", - MsgId, parts[parts.Length - 1]); - if (ic.Item.AssetType == (int) AssetType.Unknown) - ic.Item.AssetType = (int) AssetType.ImageJPEG; - if (ic.Item.InvType == (int) InventoryType.Unknown) - ic.Item.InvType = (int) InventoryType.Texture; - break; - case "tga" : - if (parts[parts.Length - 2].IndexOf("_texture") != -1) - { - if (ic.Item.AssetType == (int) AssetType.Unknown) - ic.Item.AssetType = (int) AssetType.TextureTGA; - if (ic.Item.InvType == (int) AssetType.Unknown) - ic.Item.InvType = (int) InventoryType.Texture; - } - else - { - if (ic.Item.AssetType == (int) AssetType.Unknown) - ic.Item.AssetType = (int) AssetType.ImageTGA; - if (ic.Item.InvType == (int) InventoryType.Unknown) - ic.Item.InvType = (int) InventoryType.Snapshot; - } - break; - default : - Rest.Log.DebugFormat("{0} Asset/Inventory type could not be inferred for {1}", - MsgId,ic.Item.Name); - break; - } - } - } - - /// If this is a TGA remember the fact - - if (ic.Item.AssetType == (int) AssetType.TextureTGA || - ic.Item.AssetType == (int) AssetType.ImageTGA) - { - Bitmap temp; - Stream tgadata = new MemoryStream(ic.Asset.Data); - - temp = LoadTGAClass.LoadTGA(tgadata); - try - { - ic.Asset.Data = OpenJPEG.EncodeFromImage(temp, true); - } - catch (DllNotFoundException) - { - Rest.Log.ErrorFormat("OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", ic.Item.Name); - ic.Asset.Data = new Byte[0]; - } - catch (IndexOutOfRangeException) - { - Rest.Log.ErrorFormat("OpenJpeg was unable to encode this. Asset Data is empty for {0}", ic.Item.Name); - ic.Asset.Data = new Byte[0]; - } - catch (Exception) - { - Rest.Log.ErrorFormat("OpenJpeg was unable to encode this. Asset Data is empty for {0}", ic.Item.Name); - ic.Asset.Data = new Byte[0]; - } - } - - ic.reset(); - } - - #region Inventory RequestData extension - - internal class InventoryRequestData : RequestData - { - /// - /// These are the inventory specific request/response state - /// extensions. - /// - - internal UUID uuid = UUID.Zero; - internal bool HaveInventory = false; - internal ICollection folders = null; - internal ICollection items = null; - internal UserProfileData userProfile = null; - internal InventoryFolderBase root = null; - internal bool timeout = false; - internal Timer watchDog = new Timer(); - - internal InventoryRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) - : base(request, response, prefix) - { - } - - internal void startWD(double interval) - { - Rest.Log.DebugFormat("{0} Setting watchdog", MsgId); - watchDog.Elapsed += new ElapsedEventHandler(OnTimeOut); - watchDog.Interval = interval; - watchDog.AutoReset = false; - watchDog.Enabled = true; - lock (watchDog) - watchDog.Start(); - - } - - internal void stopWD() - { - Rest.Log.DebugFormat("{0} Reset watchdog", MsgId); - lock (watchDog) - watchDog.Stop(); - } - - /// - /// This is the callback method required by the inventory watchdog. The - /// requestor issues an inventory request and then blocks until the - /// request completes, or this method signals the monitor. - /// - - private void OnTimeOut(object sender, ElapsedEventArgs args) - { - Rest.Log.DebugFormat("{0} Asynchronous inventory update timed-out", MsgId); - // InventoryRequestData rdata = (InventoryRequestData) sender; - lock (this) - { - this.folders = null; - this.items = null; - this.HaveInventory = false; - this.timeout = true; - Monitor.Pulse(this); - } - } - - /// - /// This is the callback method required by inventory services. The - /// requestor issues an inventory request and then blocks until this - /// method signals the monitor. - /// - - internal void GetUserInventory(ICollection folders, ICollection items) - { - Rest.Log.DebugFormat("{0} Asynchronously updating inventory data", MsgId); - lock (this) - { - if (watchDog.Enabled) - { - this.stopWD(); - } - this.folders = folders; - this.items = items; - this.HaveInventory = true; - this.timeout = false; - Monitor.Pulse(this); - } - } - } - - #endregion Inventory RequestData extension - - /// - /// This class is used to record and manage the hierarchy - /// constructed from the entity supplied in the request for - /// PUT and POST. - /// - - internal class XmlInventoryCollection : InventoryCollection - { - internal InventoryRequestData rdata; - private Stack stk; - - internal List Assets; - - internal InventoryItemBase Item; - internal AssetBase Asset; - internal XmlReader xml; - - internal /*static*/ const uint DefaultCurrent = 0x7FFFFFFF; - internal /*static*/ const uint DefaultNext = 0x82000; - internal /*static*/ const uint DefaultBase = 0x7FFFFFFF; - internal /*static*/ const uint DefaultEveryOne = 0x0; - internal /*static*/ const uint DefaultGroup = 0x0; - - internal uint CurrentPermissions = 0x00; - internal uint NextPermissions = 0x00; - internal uint BasePermissions = 0x00; - internal uint EveryOnePermissions = 0x00; - internal uint GroupPermissions = 0x00; - - internal XmlInventoryCollection() - { - Folders = new List(); - Items = new List(); - Assets = new List(); - } - - internal void init(InventoryRequestData p_rdata) - { - rdata = p_rdata; - UserID = rdata.uuid; - stk = new Stack(); - rdata.initXmlReader(); - xml = rdata.reader; - initPermissions(); - } - - internal void initPermissions() - { - CurrentPermissions = DefaultCurrent; - NextPermissions = DefaultNext; - BasePermissions = DefaultBase; - GroupPermissions = DefaultGroup; - EveryOnePermissions = DefaultEveryOne; - } - - internal UUID Parent() - { - if (stk.Count != 0) - { - return stk.Peek().ID; - } - else - { - return UUID.Zero; - } - } - - internal void Push(InventoryFolderBase folder) - { - stk.Push(folder); - Folders.Add(folder); - reset(); - } - - internal void Push(InventoryItemBase item) - { - Item = item; - Items.Add(item); - } - - internal void Push(AssetBase asset) - { - Asset = asset; - Assets.Add(asset); - } - - internal void Pop() - { - stk.Pop(); - reset(); - } - - internal void reset() - { - Item = null; - Asset = null; - initPermissions(); - } - - internal void Fail(int code, string addendum) - { - rdata.Fail(code, addendum); - } - } - } -} 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - public class RestTestServices : IRest - { - private bool enabled = false; - private string qPrefix = "test"; - - // A simple constructor is used to handle any once-only - // initialization of working classes. - - public RestTestServices() - { - Rest.Log.InfoFormat("{0} Test services initializing", MsgId); - Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); - - // If a relative path was specified, make it absolute by adding - // the standard prefix, e.g. /admin - - if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) - { - Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId); - qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); - Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix); - } - - // Load test cases - - loadTests(); - foreach (ITest test in tests) - { - test.Initialize(); - } - - // Register interface - - Rest.Plugin.AddPathHandler(DoTests,qPrefix,Allocate); - - // Activate - - enabled = true; - - Rest.Log.InfoFormat("{0} Test services initialization complete", MsgId); - } - - // Post-construction, pre-enabled initialization opportunity - // Not currently exploited. - - public void Initialize() - { - } - - // Called by the plug-in to halt REST processing. Local processing is - // disabled, and control blocks until all current processing has - // completed. No new processing will be started - - public void Close() - { - enabled = false; - foreach (ITest test in tests) - { - test.Close(); - } - Rest.Log.InfoFormat("{0} Test services closing down", MsgId); - } - - // Properties - - internal string MsgId - { - get { return Rest.MsgId; } - } - - #region Interface - - private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) - { - return new RequestData(request, response, prefix); - } - - // Inventory Handler - - private void DoTests(RequestData rdata) - { - if (!enabled) - return; - - // Now that we know this is a serious attempt to - // access inventory data, we should find out who - // is asking, and make sure they are authorized - // to do so. We need to validate the caller's - // identity before revealing anything about the - // status quo. Authenticate throws an exception - // via Fail if no identity information is present. - // - // With the present HTTP server we can't use the - // builtin authentication mechanisms because they - // would be enforced for all in-bound requests. - // Instead we look at the headers ourselves and - // handle authentication directly. - - try - { - if (!rdata.IsAuthenticated) - { - rdata.Fail(Rest.HttpStatusCodeNotAuthorized, - String.Format("user \"{0}\" could not be authenticated", rdata.userName)); - } - } - catch (RestException e) - { - if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) - { - Rest.Log.WarnFormat("{0} User not authenticated", MsgId); - Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); - } - else - { - Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); - Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); - } - throw (e); - } - - // Check that a test was specified - - if (rdata.Parameters.Length < 1) - { - Rest.Log.DebugFormat("{0} Insufficient parameters", MsgId); - rdata.Fail(Rest.HttpStatusCodeBadRequest, "not enough parameters"); - } - - // Select the test - - foreach (ITest test in tests) - { - if (!rdata.handled) - test.Execute(rdata); - } - } - - #endregion Interface - - private static bool testsLoaded = false; - private static List classes = new List(); - private static List tests = new List(); - private static Type[] parms = new Type[0]; - private static Object[] args = new Object[0]; - - static RestTestServices() - { - Module[] mods = Assembly.GetExecutingAssembly().GetModules(); - foreach (Module m in mods) - { - Type[] types = m.GetTypes(); - foreach (Type t in types) - { - try - { - if (t.GetInterface("ITest") != null) - { - classes.Add(t); - } - } - catch (Exception e) - { - Rest.Log.WarnFormat("[STATIC-TEST] Unable to include test {0} : {1}", t, e.Message); - } - } - } - } - - /// - /// This routine loads all of the handlers discovered during - /// instance initialization. Each handler is responsible for - /// registering itself with this handler. - /// I was not able to make this code work in a constructor. - /// - - private void loadTests() - { - lock (tests) - { - if (!testsLoaded) - { - - ConstructorInfo ci; - Object ht; - - foreach (Type t in classes) - { - try - { - if (t.GetInterface("ITest") != null) - { - ci = t.GetConstructor(parms); - ht = ci.Invoke(args); - tests.Add((ITest)ht); - Rest.Log.InfoFormat("{0} Test {1} added", MsgId, t); - } - } - catch (Exception e) - { - Rest.Log.WarnFormat("{0} Unable to load test {1} : {2}", MsgId, t, e.Message); - } - } - testsLoaded = true; - } - } - } - - } -} 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 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSimulator Project nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -*/ - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - - /// - /// This interface represents the boundary between the general purpose - /// REST plugin handling, and the functionally specific handlers. The - /// handler knows only to initialzie and terminate all such handlers - /// that it finds. - /// - - internal interface ITest - { - void Initialize(); - void Execute(RequestData rdata); - void Close(); - } - -} 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using OpenMetaverse; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory.Tests -{ - public class Remote : ITest - { - private static readonly int PARM_TESTID = 0; - private static readonly int PARM_COMMAND = 1; - - private static readonly int PARM_MOVE_AVATAR = 2; - private static readonly int PARM_MOVE_X = 3; - private static readonly int PARM_MOVE_Y = 4; - private static readonly int PARM_MOVE_Z = 5; - - private bool enabled = false; - - // No constructor code is required. - - public Remote() - { - Rest.Log.InfoFormat("{0} Remote services constructor", MsgId); - } - - // Post-construction, pre-enabled initialization opportunity - // Not currently exploited. - - public void Initialize() - { - enabled = true; - Rest.Log.InfoFormat("{0} Remote services initialized", MsgId); - } - - // Called by the plug-in to halt REST processing. Local processing is - // disabled, and control blocks until all current processing has - // completed. No new processing will be started - - public void Close() - { - enabled = false; - Rest.Log.InfoFormat("{0} Remote services closing down", MsgId); - } - - // Properties - - internal string MsgId - { - get { return Rest.MsgId; } - } - - // Remote Handler - // Key information of interest here is the Parameters array, each - // entry represents an element of the URI, with element zero being - // the - - public void Execute(RequestData rdata) - { - if (!enabled) return; - - // If we can't relate to what's there, leave it for others. - - if (rdata.Parameters.Length == 0 || rdata.Parameters[PARM_TESTID] != "remote") - return; - - Rest.Log.DebugFormat("{0} REST Remote handler ENTRY", MsgId); - - // Remove the prefix and what's left are the parameters. If we don't have - // the parameters we need, fail the request. Parameters do NOT include - // any supplied query values. - - if (rdata.Parameters.Length > 1) - { - switch (rdata.Parameters[PARM_COMMAND].ToLower()) - { - case "move" : - DoMove(rdata); - break; - default : - DoHelp(rdata); - break; - } - } - else - { - DoHelp(rdata); - } - } - - private void DoHelp(RequestData rdata) - { - rdata.body = Help; - rdata.Complete(); - rdata.Respond("Help"); - } - - private void DoMove(RequestData rdata) - { - if (rdata.Parameters.Length < 6) - { - Rest.Log.WarnFormat("{0} Move: No movement information provided", MsgId); - rdata.Fail(Rest.HttpStatusCodeBadRequest, "no movement information provided"); - } - else - { - string[] names = rdata.Parameters[PARM_MOVE_AVATAR].Split(Rest.CA_SPACE); - ScenePresence presence = null; - Scene scene = null; - - if (names.Length != 2) - { - rdata.Fail(Rest.HttpStatusCodeBadRequest, - String.Format("invalid avatar name: <{0}>",rdata.Parameters[PARM_MOVE_AVATAR])); - } - - Rest.Log.WarnFormat("{0} '{1}' command received for {2} {3}", - MsgId, rdata.Parameters[0], names[0], names[1]); - - // The first parameter should be an avatar name, look for the - // avatar in the known regions first. - - Rest.main.SceneManager.ForEachScene(delegate(Scene s) - { - s.ForEachRootScenePresence(delegate(ScenePresence sp) - { - if (sp.Firstname == names[0] && sp.Lastname == names[1]) - { - scene = s; - presence = sp; - } - }); - }); - - if (presence != null) - { - Rest.Log.DebugFormat("{0} Move : Avatar {1} located in region {2}", - MsgId, rdata.Parameters[PARM_MOVE_AVATAR], scene.RegionInfo.RegionName); - - try - { - float x = Convert.ToSingle(rdata.Parameters[PARM_MOVE_X]); - float y = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Y]); - float z = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Z]); - Vector3 vector = new Vector3(x, y, z); - presence.MoveToTarget(vector, false, false); - } - catch (Exception e) - { - rdata.Fail(Rest.HttpStatusCodeBadRequest, - String.Format("invalid parameters: {0}", e.Message)); - } - } - else - { - rdata.Fail(Rest.HttpStatusCodeBadRequest, - String.Format("avatar {0} not present", rdata.Parameters[PARM_MOVE_AVATAR])); - } - - rdata.Complete(); - rdata.Respond("OK"); - } - } - - private static readonly string Help = - "" - + "Remote Command Usage" - + "" - + "

Supported commands are:

" - + "
" - + "
move/avatar-name/x/y/z
" - + "
moves the specified avatar to another location
" - + "
" - + "" - + "" - ; - } -} 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Xml.Serialization; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.ApplicationPlugins.Rest.Regions -{ - public partial class RestRegionPlugin : RestPlugin - { - #region GET methods - public string GetHandler(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - // foreach (string h in httpRequest.Headers.AllKeys) - // foreach (string v in httpRequest.Headers.GetValues(h)) - // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v); - - MsgID = RequestID; - m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param); - - try - { - // param empty: regions list - if (String.IsNullOrEmpty(param)) return GetHandlerRegions(httpResponse); - - // param not empty: specific region - return GetHandlerRegion(httpResponse, param); - } - catch (Exception e) - { - return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e); - } - } - - public string GetHandlerRegions(IOSHttpResponse httpResponse) - { - RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); - - rxw.WriteStartElement(String.Empty, "regions", String.Empty); - foreach (Scene s in App.SceneManager.Scenes) - { - rxw.WriteStartElement(String.Empty, "uuid", String.Empty); - rxw.WriteString(s.RegionInfo.RegionID.ToString()); - rxw.WriteEndElement(); - } - rxw.WriteEndElement(); - - return rxw.ToString(); - } - - protected string ShortRegionInfo(string key, string value) - { - RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); - - if (String.IsNullOrEmpty(value) || - String.IsNullOrEmpty(key)) return null; - - rxw.WriteStartElement(String.Empty, "region", String.Empty); - rxw.WriteStartElement(String.Empty, key, String.Empty); - rxw.WriteString(value); - rxw.WriteEndDocument(); - - return rxw.ToString(); - } - - public string GetHandlerRegion(IOSHttpResponse httpResponse, string param) - { - // be resilient and don't get confused by a terminating '/' - param = param.TrimEnd(new char[]{'/'}); - string[] comps = param.Split('/'); - UUID regionID = (UUID)comps[0]; - - m_log.DebugFormat("{0} GET region UUID {1}", MsgID, regionID.ToString()); - - if (UUID.Zero == regionID) throw new Exception("missing region ID"); - - Scene scene = null; - App.SceneManager.TryGetScene(regionID, out scene); - if (null == scene) return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound, - "GET", "cannot find region {0}", regionID.ToString()); - - RegionDetails details = new RegionDetails(scene.RegionInfo); - - // m_log.DebugFormat("{0} GET comps {1}", MsgID, comps.Length); - // for (int i = 0; i < comps.Length; i++) m_log.DebugFormat("{0} GET comps[{1}] >{2}<", MsgID, i, comps[i]); - - if (1 == comps.Length) - { - // complete region details requested - RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); - XmlSerializer xs = new XmlSerializer(typeof(RegionDetails)); - xs.Serialize(rxw, details, _xmlNs); - return rxw.ToString(); - } - - if (2 == comps.Length) - { - string resp = ShortRegionInfo(comps[1], details[comps[1]]); - if (null != resp) return resp; - - // m_log.DebugFormat("{0} GET comps advanced: >{1}<", MsgID, comps[1]); - - // check for {terrain,stats,prims} - switch (comps[1].ToLower()) - { - case "terrain": - return RegionTerrain(httpResponse, scene); - - case "stats": - return RegionStats(httpResponse, scene); - - case "prims": - return RegionPrims(httpResponse, scene, Vector3.Zero, Vector3.Zero); - } - } - - if (3 == comps.Length) - { - switch (comps[1].ToLower()) - { - case "prims": - string[] subregion = comps[2].Split(','); - if (subregion.Length == 6) - { - Vector3 min, max; - try - { - min = new Vector3((float)Double.Parse(subregion[0], Culture.NumberFormatInfo), (float)Double.Parse(subregion[1], Culture.NumberFormatInfo), (float)Double.Parse(subregion[2], Culture.NumberFormatInfo)); - max = new Vector3((float)Double.Parse(subregion[3], Culture.NumberFormatInfo), (float)Double.Parse(subregion[4], Culture.NumberFormatInfo), (float)Double.Parse(subregion[5], Culture.NumberFormatInfo)); - } - catch (Exception) - { - return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest, - "GET", "invalid subregion parameter"); - } - return RegionPrims(httpResponse, scene, min, max); - } - else - { - return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest, - "GET", "invalid subregion parameter"); - } - } - } - - return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest, - "GET", "too many parameters {0}", param); - } - #endregion GET methods - - protected string RegionTerrain(IOSHttpResponse httpResponse, Scene scene) - { - httpResponse.SendChunked = true; - httpResponse.ContentType = "text/xml"; - - return scene.Heightmap.SaveToXmlString(); - //return Failure(httpResponse, OSHttpStatusCode.ServerErrorNotImplemented, - // "GET", "terrain not implemented"); - } - - protected string RegionStats(IOSHttpResponse httpResponse, Scene scene) - { - int users = scene.GetRootAgentCount(); - int objects = scene.Entities.Count - users; - - RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); - - rxw.WriteStartElement(String.Empty, "region", String.Empty); - rxw.WriteStartElement(String.Empty, "stats", String.Empty); - - rxw.WriteStartElement(String.Empty, "users", String.Empty); - rxw.WriteString(users.ToString()); - rxw.WriteEndElement(); - - rxw.WriteStartElement(String.Empty, "objects", String.Empty); - rxw.WriteString(objects.ToString()); - rxw.WriteEndElement(); - - rxw.WriteEndDocument(); - - return rxw.ToString(); - } - - protected string RegionPrims(IOSHttpResponse httpResponse, Scene scene, Vector3 min, Vector3 max) - { - httpResponse.SendChunked = true; - httpResponse.ContentType = "text/xml"; - - IRegionSerialiserModule serialiser = scene.RequestModuleInterface(); - if (serialiser != null) - serialiser.SavePrimsToXml2(scene, new StreamWriter(httpResponse.OutputStream), min, max); - - return ""; - } - } -} 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Xml.Serialization; -using OpenMetaverse; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.ApplicationPlugins.Rest.Regions -{ - public partial class RestRegionPlugin : RestPlugin - { - #region GET methods - public string GetRegionInfoHandler(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - // foreach (string h in httpRequest.Headers.AllKeys) - // foreach (string v in httpRequest.Headers.GetValues(h)) - // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v); - - MsgID = RequestID; - m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param); - - try - { - // param empty: regions list - // if (String.IsNullOrEmpty(param)) - return GetRegionInfoHandlerRegions(httpResponse); - - // // param not empty: specific region - // return GetRegionInfoHandlerRegion(httpResponse, param); - } - catch (Exception e) - { - return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e); - } - } - - public string GetRegionInfoHandlerRegions(IOSHttpResponse httpResponse) - { - RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); - - // regions info - rxw.WriteStartElement(String.Empty, "regions", String.Empty); - { - // regions info: number of regions - rxw.WriteStartAttribute(String.Empty, "number", String.Empty); - rxw.WriteValue(App.SceneManager.Scenes.Count); - rxw.WriteEndAttribute(); - - // regions info: max number of regions - rxw.WriteStartAttribute(String.Empty, "max", String.Empty); - if (App.ConfigSource.Source.Configs["RemoteAdmin"] != null) - { - rxw.WriteValue(App.ConfigSource.Source.Configs["RemoteAdmin"].GetInt("region_limit", -1)); - } - else - { - rxw.WriteValue(-1); - } - rxw.WriteEndAttribute(); - - // regions info: region - foreach (Scene s in App.SceneManager.Scenes) - { - rxw.WriteStartElement(String.Empty, "region", String.Empty); - - rxw.WriteStartAttribute(String.Empty, "uuid", String.Empty); - rxw.WriteString(s.RegionInfo.RegionID.ToString()); - rxw.WriteEndAttribute(); - - rxw.WriteStartAttribute(String.Empty, "name", String.Empty); - rxw.WriteString(s.RegionInfo.RegionName); - rxw.WriteEndAttribute(); - - rxw.WriteStartAttribute(String.Empty, "x", String.Empty); - rxw.WriteValue(s.RegionInfo.RegionLocX); - rxw.WriteEndAttribute(); - - rxw.WriteStartAttribute(String.Empty, "y", String.Empty); - rxw.WriteValue(s.RegionInfo.RegionLocY); - rxw.WriteEndAttribute(); - - rxw.WriteStartAttribute(String.Empty, "external_hostname", String.Empty); - rxw.WriteString(s.RegionInfo.ExternalHostName); - rxw.WriteEndAttribute(); - - rxw.WriteStartAttribute(String.Empty, "ip", String.Empty); - rxw.WriteString(s.RegionInfo.InternalEndPoint.ToString()); - rxw.WriteEndAttribute(); - - int users = s.GetRootAgentCount(); - rxw.WriteStartAttribute(String.Empty, "avatars", String.Empty); - rxw.WriteValue(users); - rxw.WriteEndAttribute(); - - rxw.WriteStartAttribute(String.Empty, "objects", String.Empty); - rxw.WriteValue(s.Entities.Count - users); - rxw.WriteEndAttribute(); - - rxw.WriteEndElement(); - } - } - return rxw.ToString(); - } - #endregion GET methods - } -} 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using OpenMetaverse; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.ApplicationPlugins.Rest.Regions -{ - public partial class RestRegionPlugin : RestPlugin - { - #region POST methods - - public string PostHandler(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - // foreach (string h in httpRequest.Headers.AllKeys) - // foreach (string v in httpRequest.Headers.GetValues(h)) - // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v); - - MsgID = RequestID; - m_log.DebugFormat("{0} POST path {1} param {2}", MsgID, path, param); - - try - { - // param empty: new region post - if (!IsGod(httpRequest)) - // XXX: this needs to be turned into a FailureUnauthorized(...) - return Failure(httpResponse, OSHttpStatusCode.ClientErrorUnauthorized, - "GET", "you are not god"); - - if (String.IsNullOrEmpty(param)) return CreateRegion(httpRequest, httpResponse); - - // Parse region ID and other parameters - param = param.TrimEnd(new char[] {'/'}); - string[] comps = param.Split('/'); - UUID regionID = (UUID) comps[0]; - - m_log.DebugFormat("{0} POST region UUID {1}", MsgID, regionID.ToString()); - if (UUID.Zero == regionID) throw new Exception("missing region ID"); - - Scene scene = null; - App.SceneManager.TryGetScene(regionID, out scene); - if (null == scene) - return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound, - "POST", "cannot find region {0}", regionID.ToString()); - - if (2 == comps.Length) - { - // check for {prims} - switch (comps[1].ToLower()) - { - case "prims": - return LoadPrims(request, httpRequest, httpResponse, scene); - } - } - - return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound, - "POST", "url {0} not supported", param); - } - catch (Exception e) - { - return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "POST", e); - } - } - - public string CreateRegion(IOSHttpRequest request, IOSHttpResponse response) - { - RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); - - rxw.WriteStartElement(String.Empty, "regions", String.Empty); - foreach (Scene s in App.SceneManager.Scenes) - { - rxw.WriteStartElement(String.Empty, "uuid", String.Empty); - rxw.WriteString(s.RegionInfo.RegionID.ToString()); - rxw.WriteEndElement(); - } - rxw.WriteEndElement(); - - return rxw.ToString(); - } - - public string LoadPrims(string requestBody, IOSHttpRequest request, IOSHttpResponse response, Scene scene) - { - IRegionSerialiserModule serialiser = scene.RequestModuleInterface(); - if (serialiser != null) - serialiser.LoadPrimsFromXml2(scene, new StringReader(requestBody), true); - - return ""; - } - - #endregion POST methods - } -} 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Xml.Serialization; -using OpenMetaverse; -using OpenSim.Framework; - -namespace OpenSim.ApplicationPlugins.Rest.Regions -{ - [XmlRoot(ElementName="region", IsNullable = false)] - public class RegionDetails - { - public string region_name; - public string region_id; - public uint region_x; - public uint region_y; - public string region_owner; - public string region_owner_id; - public uint region_http_port; - public uint region_port; - public string region_server_uri; - public string region_external_hostname; - - public RegionDetails() - { - } - - public RegionDetails(RegionInfo regInfo) - { - region_name = regInfo.RegionName; - region_id = regInfo.RegionID.ToString(); - region_x = regInfo.RegionLocX; - region_y = regInfo.RegionLocY; - region_owner_id = regInfo.EstateSettings.EstateOwner.ToString(); - region_http_port = regInfo.HttpPort; - region_server_uri = regInfo.ServerURI; - region_external_hostname = regInfo.ExternalHostName; - - Uri uri = new Uri(region_server_uri); - region_port = (uint)uri.Port; - } - - public string this[string idx] - { - get - { - switch (idx.ToLower()) - { - case "name": - return region_name; - case "id": - return region_id; - case "location": - return String.Format("{0}{1}", region_x, region_y); - case "owner": - return region_owner; - case "owner_id": - return region_owner_id; - case "http_port": - return region_http_port.ToString(); - case "server_uri": - return region_server_uri; - case "external_hostname": - case "hostname": - return region_external_hostname; - - default: - return null; - } - } - } - } -} 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 @@ - - - - - - - - - - - diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs b/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs deleted file mode 100644 index 02ef588..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Xml.Serialization; - -namespace OpenSim.ApplicationPlugins.Rest.Regions -{ - public partial class RestRegionPlugin : RestPlugin - { - private static XmlSerializerNamespaces _xmlNs; - - static RestRegionPlugin() - { - _xmlNs = new XmlSerializerNamespaces(); - _xmlNs.Add(String.Empty, String.Empty); - } - - #region overriding properties - public override string Name - { - get { return "REGION"; } - } - - public override string ConfigName - { - get { return "RestRegionPlugin"; } - } - #endregion overriding properties - - #region overriding methods - /// - /// This method is called by OpenSimMain immediately after loading the - /// plugin and after basic server setup, but before running any server commands. - /// - /// - /// Note that entries MUST be added to the active configuration files before - /// the plugin can be enabled. - /// - public override void Initialise(OpenSimBase openSim) - { - try - { - base.Initialise(openSim); - if (!IsEnabled) - { - //m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID); - return; - } - - m_log.InfoFormat("{0} REST region plugin enabled", MsgID); - - // add REST method handlers - AddRestStreamHandler("GET", "/regions/", GetHandler); - AddRestStreamHandler("POST", "/regions/", PostHandler); - AddRestStreamHandler("GET", "/regioninfo/", GetRegionInfoHandler); - } - catch (Exception e) - { - m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message); - m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString()); - } - } - - public override void Close() - { - } - #endregion overriding methods - } -} 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 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Xml; -using log4net; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; - -namespace OpenSim.ApplicationPlugins.Rest -{ - public abstract class RestPlugin : IApplicationPlugin - { - #region properties - - protected static readonly ILog m_log = - LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private IConfig _config; // Configuration source: Rest Plugins - private IConfig _pluginConfig; // Configuration source: Plugin specific - private OpenSimBase _app; // The 'server' - private BaseHttpServer _httpd; // The server's RPC interface - private string _prefix; // URL prefix below - // which all REST URLs - // are living - // private StringWriter _sw = null; - // private RestXmlWriter _xw = null; - - private string _godkey; - private int _reqk; - - [ThreadStatic] - private static string _threadRequestID = String.Empty; - - /// - /// Return an ever increasing request ID for logging - /// - protected string RequestID - { - get { return _reqk++.ToString(); } - set { _reqk = Convert.ToInt32(value); } - } - - /// - /// Thread-constant message IDs for logging. - /// - protected string MsgID - { - get { return String.Format("[REST-{0}] #{1}", Name, _threadRequestID); } - set { _threadRequestID = value; } - } - - /// - /// Returns true if Rest Plugins are enabled. - /// - public bool PluginsAreEnabled - { - get { return null != _config; } - } - - /// - /// Returns true if specific Rest Plugin is enabled. - /// - public bool IsEnabled - { - get - { - return (null != _pluginConfig) && _pluginConfig.GetBoolean("enabled", false); - } - } - - /// - /// OpenSimMain application - /// - public OpenSimBase App - { - get { return _app; } - } - - /// - /// RPC server - /// - public BaseHttpServer HttpServer - { - get { return _httpd; } - } - - /// - /// URL prefix to use for all REST handlers - /// - public string Prefix - { - get { return _prefix; } - } - - /// - /// Access to GOD password string - /// - protected string GodKey - { - get { return _godkey; } - } - - /// - /// Configuration of the plugin - /// - public IConfig Config - { - get { return _pluginConfig; } - } - - /// - /// Name of the plugin - /// - public abstract string Name { get; } - - /// - /// Return the config section name - /// - public abstract string ConfigName { get; } - - // public XmlTextWriter XmlWriter - // { - // get - // { - // if (null == _xw) - // { - // _sw = new StringWriter(); - // _xw = new RestXmlWriter(_sw); - // _xw.Formatting = Formatting.Indented; - // } - // return _xw; - // } - // } - - // public string XmlWriterResult - // { - // get - // { - // _xw.Flush(); - // _xw.Close(); - // _xw = null; - - // return _sw.ToString(); - // } - // } - - #endregion properties - - #region methods - - // TODO: required by IPlugin, but likely not at all right - private string m_version = "0.0"; - - public string Version - { - get { return m_version; } - } - - public void Initialise() - { - m_log.Info("[RESTPLUGIN]: " + Name + " cannot be default-initialized!"); - throw new PluginNotInitialisedException(Name); - } - - /// - /// This method is called by OpenSimMain immediately after loading the - /// plugin and after basic server setup, but before running any server commands. - /// - /// - /// Note that entries MUST be added to the active configuration files before - /// the plugin can be enabled. - /// - public virtual void Initialise(OpenSimBase openSim) - { - RequestID = "0"; - MsgID = RequestID; - - try - { - if ((_config = openSim.ConfigSource.Source.Configs["RestPlugins"]) == null) - { - m_log.WarnFormat("{0} Rest Plugins not configured", MsgID); - return; - } - - if (!_config.GetBoolean("enabled", false)) - { - //m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID); - return; - } - - _app = openSim; - _httpd = openSim.HttpServer; - - // Retrieve GOD key value, if any. - _godkey = _config.GetString("god_key", String.Empty); - - // Retrive prefix if any. - _prefix = _config.GetString("prefix", "/admin"); - - // Get plugin specific config - _pluginConfig = openSim.ConfigSource.Source.Configs[ConfigName]; - - m_log.InfoFormat("{0} Rest Plugins Enabled", MsgID); - } - catch (Exception e) - { - // we can safely ignore this, as it just means that - // the key lookup in Configs failed, which signals to - // us that noone is interested in our services...they - // don't know what they are missing out on... - // NOTE: Under the present OpenSimulator implementation it is - // not possible for the openSimulator pointer to be null. However - // were the implementation to be changed, this could - // result in a silent initialization failure. Harmless - // except for lack of function and lack of any - // diagnostic indication as to why. The same is true if - // the HTTP server reference is bad. - // We should at least issue a message... - m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message); - m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString()); - } - } - - public virtual void PostInitialise() - { - } - - private List _handlers = new List(); - private Dictionary _agents = new Dictionary(); - - /// - /// Add a REST stream handler to the underlying HTTP server. - /// - /// GET/PUT/POST/DELETE or - /// similar - /// URL prefix - /// RestMethod handler doing the actual work - public virtual void AddRestStreamHandler(string httpMethod, string path, RestMethod method) - { - if (!IsEnabled) return; - - if (!path.StartsWith(_prefix)) - { - path = String.Format("{0}{1}", _prefix, path); - } - - RestStreamHandler h = new RestStreamHandler(httpMethod, path, method); - _httpd.AddStreamHandler(h); - _handlers.Add(h); - - m_log.DebugFormat("{0} Added REST handler {1} {2}", MsgID, httpMethod, path); - } - - /// - /// Add a powerful Agent handler to the underlying HTTP - /// server. - /// - /// name of agent handler - /// agent handler method - /// false when the plugin is disabled or the agent - /// handler could not be added. Any generated exceptions are - /// allowed to drop through to the caller, i.e. ArgumentException. - /// - public bool AddAgentHandler(string agentName, IHttpAgentHandler handler) - { - if (!IsEnabled) return false; - _agents.Add(agentName, handler); -// return _httpd.AddAgentHandler(agentName, handler); - - return false; - } - - /// - /// Remove a powerful Agent handler from the underlying HTTP - /// server. - /// - /// name of agent handler - /// agent handler method - /// false when the plugin is disabled or the agent - /// handler could not be removed. Any generated exceptions are - /// allowed to drop through to the caller, i.e. KeyNotFound. - /// - public bool RemoveAgentHandler(string agentName, IHttpAgentHandler handler) - { - if (!IsEnabled) return false; - if (_agents[agentName] == handler) - { - _agents.Remove(agentName); -// return _httpd.RemoveAgentHandler(agentName, handler); - } - return false; - } - - /// - /// Check whether the HTTP request came from god; that is, is - /// the god_key as configured in the config section supplied - /// via X-OpenSim-Godkey? - /// - /// HTTP request header - /// true when the HTTP request came from god. - protected bool IsGod(IOSHttpRequest request) - { - string[] keys = request.Headers.GetValues("X-OpenSim-Godkey"); - if (null == keys) return false; - - // we take the last key supplied - return keys[keys.Length - 1] == _godkey; - } - - /// - /// Checks wether the X-OpenSim-Password value provided in the - /// HTTP header is indeed the password on file for the avatar - /// specified by the UUID - /// - protected bool IsVerifiedUser(IOSHttpRequest request, UUID uuid) - { - // XXX under construction - return false; - } - - /// - /// Clean up and remove all handlers that were added earlier. - /// - public virtual void Close() - { - foreach (RestStreamHandler h in _handlers) - { - _httpd.RemoveStreamHandler(h.HttpMethod, h.Path); - } - _handlers = null; -// foreach (KeyValuePair h in _agents) -// { -// _httpd.RemoveAgentHandler(h.Key, h.Value); -// } - _agents = null; - } - - public virtual void Dispose() - { - Close(); - } - - /// - /// Return a failure message. - /// - /// origin of the failure message - /// failure message - /// This should probably set a return code as - /// well. (?) - protected string Failure(IOSHttpResponse response, OSHttpStatusCode status, - string method, string format, params string[] msg) - { - string m = String.Format(format, msg); - - response.StatusCode = (int) status; - response.StatusDescription = m; - - m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, m); - return String.Format("{0}", m); - } - - /// - /// Return a failure message. - /// - /// origin of the failure message - /// exception causing the failure message - /// This should probably set a return code as - /// well. (?) - public string Failure(IOSHttpResponse response, OSHttpStatusCode status, - string method, Exception e) - { - string m = String.Format("exception occurred: {0}", e.Message); - - response.StatusCode = (int) status; - response.StatusDescription = m; - - m_log.DebugFormat("{0} {1} failed: {2}", MsgID, method, e.ToString()); - m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, e.Message); - - return String.Format("{0}", e.Message); - } - - #endregion methods - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs b/OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs deleted file mode 100644 index 283fa2e..0000000 --- a/OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.IO; -using System.Text; -using System.Xml; - -namespace OpenSim.ApplicationPlugins.Rest -{ - public class RestXmlWriter: XmlTextWriter - { - private StringWriter m_sw = null; - - public RestXmlWriter(StringWriter sw) : base(sw) - { - m_sw = sw; - Formatting = Formatting.Indented; - } - - public RestXmlWriter(TextWriter textWriter) : base(textWriter) - { - } - - public RestXmlWriter(Stream stream) - : this(stream, Encoding.UTF8) - { - } - - public RestXmlWriter(Stream stream, Encoding enc) : base(stream, enc) - { - } - - public override void WriteStartDocument() - { - } - - public override void WriteStartDocument(bool standalone) - { - } - - public override string ToString() - { - Flush(); - Close(); - return m_sw.ToString(); - } - } -} 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 @@ - - - - - Open Simulator Export/Import XML schema - August 2008 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs index bc6f6f9..049afab 100644 --- a/OpenSim/Capabilities/Caps.cs +++ b/OpenSim/Capabilities/Caps.cs @@ -50,8 +50,7 @@ namespace OpenSim.Framework.Capabilities public class Caps { -// private static readonly ILog m_log = -// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private string m_httpListenerHostName; private uint m_httpListenPort; @@ -63,7 +62,11 @@ namespace OpenSim.Framework.Capabilities public string CapsObjectPath { get { return m_capsObjectPath; } } private CapsHandlers m_capsHandlers; - private Dictionary m_externalCapsHandlers; + + private Dictionary m_pollServiceHandlers + = new Dictionary(); + + private Dictionary m_externalCapsHandlers = new Dictionary(); private IHttpServer m_httpListener; private UUID m_agentID; @@ -132,7 +135,6 @@ namespace OpenSim.Framework.Capabilities m_agentID = agent; m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort, (httpServer == null) ? false : httpServer.UseSSL); - m_externalCapsHandlers = new Dictionary(); m_regionName = regionName; } @@ -143,8 +145,33 @@ namespace OpenSim.Framework.Capabilities /// public void RegisterHandler(string capName, IRequestHandler handler) { - m_capsHandlers[capName] = handler; //m_log.DebugFormat("[CAPS]: Registering handler for \"{0}\": path {1}", capName, handler.Path); + m_capsHandlers[capName] = handler; + } + + public void RegisterPollHandler(string capName, PollServiceEventArgs pollServiceHandler) + { +// m_log.DebugFormat( +// "[CAPS]: Registering handler with name {0}, url {1} for {2}", +// capName, pollServiceHandler.Url, m_agentID, m_regionName); + + m_pollServiceHandlers.Add(capName, pollServiceHandler); + + m_httpListener.AddPollServiceHTTPHandler(pollServiceHandler.Url, pollServiceHandler); + +// uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; +// string protocol = "http"; +// string hostName = m_httpListenerHostName; +// +// if (MainServer.Instance.UseSSL) +// { +// hostName = MainServer.Instance.SSLCommonName; +// port = MainServer.Instance.SSLPort; +// protocol = "https"; +// } + +// RegisterHandler( +// capName, String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, pollServiceHandler.Url)); } /// @@ -163,13 +190,70 @@ namespace OpenSim.Framework.Capabilities /// public void DeregisterHandlers() { - if (m_capsHandlers != null) + foreach (string capsName in m_capsHandlers.Caps) + { + m_capsHandlers.Remove(capsName); + } + + foreach (PollServiceEventArgs handler in m_pollServiceHandlers.Values) { - foreach (string capsName in m_capsHandlers.Caps) + m_httpListener.RemovePollServiceHTTPHandler("", handler.Url); + } + } + + public bool TryGetPollHandler(string name, out PollServiceEventArgs pollHandler) + { + return m_pollServiceHandlers.TryGetValue(name, out pollHandler); + } + + public Dictionary GetPollHandlers() + { + return new Dictionary(m_pollServiceHandlers); + } + + /// + /// Return an LLSD-serializable Hashtable describing the + /// capabilities and their handler details. + /// + /// If true, then exclude the seed cap. + public Hashtable GetCapsDetails(bool excludeSeed, List requestedCaps) + { + Hashtable caps = CapsHandlers.GetCapsDetails(excludeSeed, requestedCaps); + + lock (m_pollServiceHandlers) + { + foreach (KeyValuePair kvp in m_pollServiceHandlers) { - m_capsHandlers.Remove(capsName); + if (!requestedCaps.Contains(kvp.Key)) + continue; + + string hostName = m_httpListenerHostName; + uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; + string protocol = "http"; + + if (MainServer.Instance.UseSSL) + { + hostName = MainServer.Instance.SSLCommonName; + port = MainServer.Instance.SSLPort; + protocol = "https"; + } + // + // caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); + + caps[kvp.Key] = string.Format("{0}://{1}:{2}{3}", protocol, hostName, port, kvp.Value.Url); } } + + // Add the external too + foreach (KeyValuePair kvp in ExternalCapsHandlers) + { + if (!requestedCaps.Contains(kvp.Key)) + continue; + + caps[kvp.Key] = kvp.Value; + } + + return caps; } } -} +} \ No newline at end of file diff --git a/OpenSim/Capabilities/CapsHandlers.cs b/OpenSim/Capabilities/CapsHandlers.cs index 1709f46..890df90 100644 --- a/OpenSim/Capabilities/CapsHandlers.cs +++ b/OpenSim/Capabilities/CapsHandlers.cs @@ -39,7 +39,7 @@ namespace OpenSim.Framework.Capabilities /// public class CapsHandlers { - private Dictionary m_capsHandlers = new Dictionary(); + private Dictionary m_capsHandlers = new Dictionary(); private IHttpServer m_httpListener; private string m_httpListenerHostName; private uint m_httpListenerPort; @@ -158,7 +158,7 @@ namespace OpenSim.Framework.Capabilities /// capabilities and their handler details. /// /// If true, then exclude the seed cap. - public Hashtable GetCapsDetails(bool excludeSeed) + public Hashtable GetCapsDetails(bool excludeSeed, List requestedCaps) { Hashtable caps = new Hashtable(); string protocol = "http://"; @@ -175,11 +175,26 @@ namespace OpenSim.Framework.Capabilities if (excludeSeed && "SEED" == capsName) continue; + if (requestedCaps != null && !requestedCaps.Contains(capsName)) + continue; + caps[capsName] = baseUrl + m_capsHandlers[capsName].Path; } } return caps; } + + /// + /// Returns a copy of the dictionary of all the HTTP cap handlers + /// + /// + /// The dictionary copy. The key is the capability name, the value is the HTTP handler. + /// + public Dictionary GetCapsHandlers() + { + lock (m_capsHandlers) + return new Dictionary(m_capsHandlers); + } } } \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs new file mode 100644 index 0000000..426174d --- /dev/null +++ b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs @@ -0,0 +1,116 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Reflection; +using System.Web; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +//using OpenSim.Region.Framework.Interfaces; +using OpenSim.Services.Interfaces; +using Caps = OpenSim.Framework.Capabilities.Caps; + +namespace OpenSim.Capabilities.Handlers +{ + public class AvatarPickerSearchHandler : BaseStreamHandler + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private IPeople m_PeopleService; + + public AvatarPickerSearchHandler(string path, IPeople peopleService, string name, string description) + : base("GET", path, name, description) + { + m_PeopleService = peopleService; + } + + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + // Try to parse the texture ID from the request URL + NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); + string names = query.GetOne("names"); + string psize = query.GetOne("page_size"); + string pnumber = query.GetOne("page"); + + if (m_PeopleService == null) + return FailureResponse(names, (int)System.Net.HttpStatusCode.InternalServerError, httpResponse); + + if (string.IsNullOrEmpty(names) || names.Length < 3) + return FailureResponse(names, (int)System.Net.HttpStatusCode.BadRequest, httpResponse); + + m_log.DebugFormat("[AVATAR PICKER SEARCH]: search for {0}", names); + + int page_size = (string.IsNullOrEmpty(psize) ? 500 : Int32.Parse(psize)); + int page_number = (string.IsNullOrEmpty(pnumber) ? 1 : Int32.Parse(pnumber)); + + // Full content request + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK; + //httpResponse.ContentLength = ??; + httpResponse.ContentType = "application/llsd+xml"; + + List users = m_PeopleService.GetUserData(names, page_size, page_number); + + LLSDAvatarPicker osdReply = new LLSDAvatarPicker(); + osdReply.next_page_url = httpRequest.RawUrl; + foreach (UserData u in users) + osdReply.agents.Array.Add(ConvertUserData(u)); + + string reply = LLSDHelpers.SerialiseLLSDReply(osdReply); + return System.Text.Encoding.UTF8.GetBytes(reply); + } + + private LLSDPerson ConvertUserData(UserData user) + { + LLSDPerson p = new LLSDPerson(); + p.legacy_first_name = user.FirstName; + p.legacy_last_name = user.LastName; + p.display_name = user.FirstName + " " + user.LastName; + if (user.LastName.StartsWith("@")) + p.username = user.FirstName.ToLower() + user.LastName.ToLower(); + else + p.username = user.FirstName.ToLower() + "." + user.LastName.ToLower(); + p.id = user.Id; + p.is_display_name_default = false; + return p; + } + + private byte[] FailureResponse(string names, int statuscode, IOSHttpResponse httpResponse) + { + m_log.Error("[AVATAR PICKER SEARCH]: Error searching for " + names); + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return System.Text.Encoding.UTF8.GetBytes(string.Empty); + } + } +} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs new file mode 100644 index 0000000..7197049 --- /dev/null +++ b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs @@ -0,0 +1,848 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Framework.Capabilities; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Services.Interfaces; +using Caps = OpenSim.Framework.Capabilities.Caps; + +namespace OpenSim.Capabilities.Handlers +{ + public class FetchInvDescHandler + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IInventoryService m_InventoryService; + private ILibraryService m_LibraryService; + private IScene m_Scene; +// private object m_fetchLock = new Object(); + + public FetchInvDescHandler(IInventoryService invService, ILibraryService libService, IScene s) + { + m_InventoryService = invService; + m_LibraryService = libService; + m_Scene = s; + } + + + public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); + + // nasty temporary hack here, the linden client falsely + // identifies the uuid 00000000-0000-0000-0000-000000000000 + // as a string which breaks us + // + // correctly mark it as a uuid + // + request = request.Replace("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000000"); + + // another hack 1 results in a + // System.ArgumentException: Object type System.Int32 cannot + // be converted to target type: System.Boolean + // + request = request.Replace("fetch_folders0", "fetch_folders0"); + request = request.Replace("fetch_folders1", "fetch_folders1"); + + Hashtable hash = new Hashtable(); + try + { + hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); + } + catch (LLSD.LLSDParseException e) + { + m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); + m_log.Error("Request: " + request); + } + + ArrayList foldersrequested = (ArrayList)hash["folders"]; + + string response = ""; + string bad_folders_response = ""; + + List folders = new List(); + for (int i = 0; i < foldersrequested.Count; i++) + { + Hashtable inventoryhash = (Hashtable)foldersrequested[i]; + + LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); + + try + { + LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); + } + catch (Exception e) + { + m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); + continue; + } + + // Filter duplicate folder ids that bad viewers may send + if (folders.Find(f => f.folder_id == llsdRequest.folder_id) == null) + folders.Add(llsdRequest); + + } + + if (folders.Count > 0) + { + List bad_folders = new List(); + List invcollSet = Fetch(folders, bad_folders); + //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count); + + if (invcollSet == null) + { + m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Multiple folder fetch failed. Trying old protocol."); +#pragma warning disable 0612 + return FetchInventoryDescendentsRequest(foldersrequested, httpRequest, httpResponse); +#pragma warning restore 0612 + } + + string inventoryitemstr = string.Empty; + foreach (InventoryCollectionWithDescendents icoll in invcollSet) + { + LLSDInventoryDescendents reply = ToLLSD(icoll.Collection, icoll.Descendents); + + inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); + inventoryitemstr = inventoryitemstr.Replace("folders", ""); + inventoryitemstr = inventoryitemstr.Replace("", ""); + + response += inventoryitemstr; + } + + //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders)); + foreach (UUID bad in bad_folders) + bad_folders_response += "" + bad + ""; + } + + if (response.Length == 0) + { + /* Viewers expect a bad_folders array when not available */ + if (bad_folders_response.Length != 0) + { + response = "bad_folders" + bad_folders_response + ""; + } + else + { + response = "folders"; + } + } + else + { + if (bad_folders_response.Length != 0) + { + response = "folders" + response + "bad_folders" + bad_folders_response + ""; + } + else + { + response = "folders" + response + ""; + } + } + + //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request for {0} folders. Item count {1}", folders.Count, item_count); + //m_log.Debug("[WEB FETCH INV DESC HANDLER] " + response); + + return response; + + } + + /// + /// Construct an LLSD reply packet to a CAPS inventory request + /// + /// + /// + private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch) + { + LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); + LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); + contents.agent_id = invFetch.owner_id; + contents.owner_id = invFetch.owner_id; + contents.folder_id = invFetch.folder_id; + + reply.folders.Array.Add(contents); + InventoryCollection inv = new InventoryCollection(); + inv.Folders = new List(); + inv.Items = new List(); + int version = 0; + int descendents = 0; + +#pragma warning disable 0612 + inv = Fetch( + invFetch.owner_id, invFetch.folder_id, invFetch.owner_id, + invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version, out descendents); +#pragma warning restore 0612 + + if (inv != null && inv.Folders != null) + { + foreach (InventoryFolderBase invFolder in inv.Folders) + { + contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); + } + + descendents += inv.Folders.Count; + } + + if (inv != null && inv.Items != null) + { + foreach (InventoryItemBase invItem in inv.Items) + { + contents.items.Array.Add(ConvertInventoryItem(invItem)); + } + } + + contents.descendents = descendents; + contents.version = version; + + //m_log.DebugFormat( + // "[WEB FETCH INV DESC HANDLER]: Replying to request for folder {0} (fetch items {1}, fetch folders {2}) with {3} items and {4} folders for agent {5}", + // invFetch.folder_id, + // invFetch.fetch_items, + // invFetch.fetch_folders, + // contents.items.Array.Count, + // contents.categories.Array.Count, + // invFetch.owner_id); + + return reply; + } + + private LLSDInventoryDescendents ToLLSD(InventoryCollection inv, int descendents) + { + LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); + LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); + contents.agent_id = inv.OwnerID; + contents.owner_id = inv.OwnerID; + contents.folder_id = inv.FolderID; + + reply.folders.Array.Add(contents); + + if (inv.Folders != null) + { + foreach (InventoryFolderBase invFolder in inv.Folders) + { + contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); + } + + descendents += inv.Folders.Count; + } + + if (inv.Items != null) + { + foreach (InventoryItemBase invItem in inv.Items) + { + contents.items.Array.Add(ConvertInventoryItem(invItem)); + } + } + + contents.descendents = descendents; + contents.version = inv.Version; + + return reply; + } + /// + /// Old style. Soon to be deprecated. + /// + /// + /// + /// + /// + [Obsolete] + private string FetchInventoryDescendentsRequest(ArrayList foldersrequested, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request for {0} folders", foldersrequested.Count); + + string response = ""; + string bad_folders_response = ""; + + for (int i = 0; i < foldersrequested.Count; i++) + { + string inventoryitemstr = ""; + Hashtable inventoryhash = (Hashtable)foldersrequested[i]; + + LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); + + try + { + LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); + } + catch (Exception e) + { + m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); + } + + LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); + + if (null == reply) + { + bad_folders_response += "" + llsdRequest.folder_id.ToString() + ""; + } + else + { + inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); + inventoryitemstr = inventoryitemstr.Replace("folders", ""); + inventoryitemstr = inventoryitemstr.Replace("", ""); + } + + response += inventoryitemstr; + } + + if (response.Length == 0) + { + /* Viewers expect a bad_folders array when not available */ + if (bad_folders_response.Length != 0) + { + response = "bad_folders" + bad_folders_response + ""; + } + else + { + response = "folders"; + } + } + else + { + if (bad_folders_response.Length != 0) + { + response = "folders" + response + "bad_folders" + bad_folders_response + ""; + } + else + { + response = "folders" + response + ""; + } + } + + // m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request"); + //m_log.Debug("[WEB FETCH INV DESC HANDLER] "+response); + + return response; + + // } + } + + /// + /// Handle the caps inventory descendents fetch. + /// + /// + /// + /// + /// + /// + /// + /// + /// An empty InventoryCollection if the inventory look up failed + [Obsolete] + private InventoryCollection Fetch( + UUID agentID, UUID folderID, UUID ownerID, + bool fetchFolders, bool fetchItems, int sortOrder, out int version, out int descendents) + { + //m_log.DebugFormat( + // "[WEB FETCH INV DESC HANDLER]: Fetching folders ({0}), items ({1}) from {2} for agent {3}", + // fetchFolders, fetchItems, folderID, agentID); + + // FIXME MAYBE: We're not handling sortOrder! + + version = 0; + descendents = 0; + + InventoryFolderImpl fold; + if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null && agentID == m_LibraryService.LibraryRootFolder.Owner) + { + if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(folderID)) != null) + { + InventoryCollection ret = new InventoryCollection(); + ret.Folders = new List(); + ret.Items = fold.RequestListOfItems(); + descendents = ret.Folders.Count + ret.Items.Count; + + return ret; + } + } + + InventoryCollection contents = new InventoryCollection(); + + if (folderID != UUID.Zero) + { + InventoryCollection fetchedContents = m_InventoryService.GetFolderContent(agentID, folderID); + + if (fetchedContents == null) + { + m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Could not get contents of folder {0} for user {1}", folderID, agentID); + return contents; + } + contents = fetchedContents; + InventoryFolderBase containingFolder = new InventoryFolderBase(); + containingFolder.ID = folderID; + containingFolder.Owner = agentID; + containingFolder = m_InventoryService.GetFolder(containingFolder); + + if (containingFolder != null) + { + //m_log.DebugFormat( + // "[WEB FETCH INV DESC HANDLER]: Retrieved folder {0} {1} for agent id {2}", + // containingFolder.Name, containingFolder.ID, agentID); + + version = containingFolder.Version; + + if (fetchItems) + { + List itemsToReturn = contents.Items; + List originalItems = new List(itemsToReturn); + + // descendents must only include the links, not the linked items we add + descendents = originalItems.Count; + + // Add target items for links in this folder before the links themselves. + foreach (InventoryItemBase item in originalItems) + { + if (item.AssetType == (int)AssetType.Link) + { + InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID)); + + // Take care of genuinely broken links where the target doesn't exist + // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, + // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles + // rather than having to keep track of every folder requested in the recursion. + if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) + itemsToReturn.Insert(0, linkedItem); + } + } + + // Now scan for folder links and insert the items they target and those links at the head of the return data + foreach (InventoryItemBase item in originalItems) + { + if (item.AssetType == (int)AssetType.LinkFolder) + { + InventoryCollection linkedFolderContents = m_InventoryService.GetFolderContent(ownerID, item.AssetID); + List links = linkedFolderContents.Items; + + itemsToReturn.InsertRange(0, links); + + foreach (InventoryItemBase link in linkedFolderContents.Items) + { + // Take care of genuinely broken links where the target doesn't exist + // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, + // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles + // rather than having to keep track of every folder requested in the recursion. + if (link != null) + { +// m_log.DebugFormat( +// "[WEB FETCH INV DESC HANDLER]: Adding item {0} {1} from folder {2} linked from {3}", +// link.Name, (AssetType)link.AssetType, item.AssetID, containingFolder.Name); + + InventoryItemBase linkedItem + = m_InventoryService.GetItem(new InventoryItemBase(link.AssetID)); + + if (linkedItem != null) + itemsToReturn.Insert(0, linkedItem); + } + } + } + } + } + +// foreach (InventoryItemBase item in contents.Items) +// { +// m_log.DebugFormat( +// "[WEB FETCH INV DESC HANDLER]: Returning item {0}, type {1}, parent {2} in {3} {4}", +// item.Name, (AssetType)item.AssetType, item.Folder, containingFolder.Name, containingFolder.ID); +// } + + // ===== + +// +// foreach (InventoryItemBase linkedItem in linkedItemsToAdd) +// { +// m_log.DebugFormat( +// "[WEB FETCH INV DESC HANDLER]: Inserted linked item {0} for link in folder {1} for agent {2}", +// linkedItem.Name, folderID, agentID); +// +// contents.Items.Add(linkedItem); +// } +// +// // If the folder requested contains links, then we need to send those folders first, otherwise the links +// // will be broken in the viewer. +// HashSet linkedItemFolderIdsToSend = new HashSet(); +// foreach (InventoryItemBase item in contents.Items) +// { +// if (item.AssetType == (int)AssetType.Link) +// { +// InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID)); +// +// // Take care of genuinely broken links where the target doesn't exist +// // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, +// // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles +// // rather than having to keep track of every folder requested in the recursion. +// if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) +// { +// // We don't need to send the folder if source and destination of the link are in the same +// // folder. +// if (linkedItem.Folder != containingFolder.ID) +// linkedItemFolderIdsToSend.Add(linkedItem.Folder); +// } +// } +// } +// +// foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend) +// { +// m_log.DebugFormat( +// "[WEB FETCH INV DESC HANDLER]: Recursively fetching folder {0} linked by item in folder {1} for agent {2}", +// linkedItemFolderId, folderID, agentID); +// +// int dummyVersion; +// InventoryCollection linkedCollection +// = Fetch( +// agentID, linkedItemFolderId, ownerID, fetchFolders, fetchItems, sortOrder, out dummyVersion); +// +// InventoryFolderBase linkedFolder = new InventoryFolderBase(linkedItemFolderId); +// linkedFolder.Owner = agentID; +// linkedFolder = m_InventoryService.GetFolder(linkedFolder); +// +//// contents.Folders.AddRange(linkedCollection.Folders); +// +// contents.Folders.Add(linkedFolder); +// contents.Items.AddRange(linkedCollection.Items); +// } +// } + } + } + else + { + // Lost items don't really need a version + version = 1; + } + + return contents; + + } + + private void AddLibraryFolders(List fetchFolders, List result) + { + InventoryFolderImpl fold; + if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null) + { + List libfolders = fetchFolders.FindAll(f => f.owner_id == m_LibraryService.LibraryRootFolder.Owner); + fetchFolders.RemoveAll(f => libfolders.Contains(f)); + + //m_log.DebugFormat("[XXX]: Found {0} library folders in request", libfolders.Count); + + foreach (LLSDFetchInventoryDescendents f in libfolders) + { + if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(f.folder_id)) != null) + { + InventoryCollectionWithDescendents ret = new InventoryCollectionWithDescendents(); + ret.Collection = new InventoryCollection(); + ret.Collection.Folders = new List(); + ret.Collection.Items = fold.RequestListOfItems(); + ret.Collection.OwnerID = m_LibraryService.LibraryRootFolder.Owner; + ret.Collection.FolderID = f.folder_id; + ret.Collection.Version = fold.Version; + + ret.Descendents = ret.Collection.Items.Count; + result.Add(ret); + + //m_log.DebugFormat("[XXX]: Added libfolder {0} ({1}) {2}", ret.Collection.FolderID, ret.Collection.OwnerID); + } + } + } + } + + private List Fetch(List fetchFolders, List bad_folders) + { + //m_log.DebugFormat( + // "[WEB FETCH INV DESC HANDLER]: Fetching {0} folders for owner {1}", fetchFolders.Count, fetchFolders[0].owner_id); + + // FIXME MAYBE: We're not handling sortOrder! + + List result = new List(); + + AddLibraryFolders(fetchFolders, result); + + // Filter folder Zero right here. Some viewers (Firestorm) send request for folder Zero, which doesn't make sense + // and can kill the sim (all root folders have parent_id Zero) + LLSDFetchInventoryDescendents zero = fetchFolders.Find(f => f.folder_id == UUID.Zero); + if (zero != null) + { + fetchFolders.Remove(zero); + BadFolder(zero, null, bad_folders); + } + + if (fetchFolders.Count > 0) + { + UUID[] fids = new UUID[fetchFolders.Count]; + int i = 0; + foreach (LLSDFetchInventoryDescendents f in fetchFolders) + fids[i++] = f.folder_id; + + //m_log.DebugFormat("[XXX]: {0}", string.Join(",", fids)); + + InventoryCollection[] fetchedContents = m_InventoryService.GetMultipleFoldersContent(fetchFolders[0].owner_id, fids); + + if (fetchedContents == null || (fetchedContents != null && fetchedContents.Length == 0)) + { + m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Could not get contents of multiple folders for user {0}", fetchFolders[0].owner_id); + foreach (LLSDFetchInventoryDescendents freq in fetchFolders) + BadFolder(freq, null, bad_folders); + return null; + } + + i = 0; + // Do some post-processing. May need to fetch more from inv server for links + foreach (InventoryCollection contents in fetchedContents) + { + // Find the original request + LLSDFetchInventoryDescendents freq = fetchFolders[i++]; + + InventoryCollectionWithDescendents coll = new InventoryCollectionWithDescendents(); + coll.Collection = contents; + + if (BadFolder(freq, contents, bad_folders)) + continue; + + // Next: link management + ProcessLinks(freq, coll); + + result.Add(coll); + } + } + + return result; + } + + private bool BadFolder(LLSDFetchInventoryDescendents freq, InventoryCollection contents, List bad_folders) + { + bool bad = false; + if (contents == null) + { + bad_folders.Add(freq.folder_id); + bad = true; + } + + // The inventory server isn't sending FolderID in the collection... + // Must fetch it individually + else if (contents.FolderID == UUID.Zero) + { + InventoryFolderBase containingFolder = new InventoryFolderBase(); + containingFolder.ID = freq.folder_id; + containingFolder.Owner = freq.owner_id; + containingFolder = m_InventoryService.GetFolder(containingFolder); + + if (containingFolder != null) + { + contents.FolderID = containingFolder.ID; + contents.OwnerID = containingFolder.Owner; + contents.Version = containingFolder.Version; + } + else + { + // Was it really a request for folder Zero? + // This is an overkill, but Firestorm really asks for folder Zero. + // I'm leaving the code here for the time being, but commented. + if (freq.folder_id == UUID.Zero) + { + //coll.Collection.OwnerID = freq.owner_id; + //coll.Collection.FolderID = contents.FolderID; + //containingFolder = m_InventoryService.GetRootFolder(freq.owner_id); + //if (containingFolder != null) + //{ + // m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Request for parent of folder {0}", containingFolder.ID); + // coll.Collection.Folders.Clear(); + // coll.Collection.Folders.Add(containingFolder); + // if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null) + // { + // InventoryFolderBase lib = new InventoryFolderBase(m_LibraryService.LibraryRootFolder.ID, m_LibraryService.LibraryRootFolder.Owner); + // lib.Name = m_LibraryService.LibraryRootFolder.Name; + // lib.Type = m_LibraryService.LibraryRootFolder.Type; + // lib.Version = m_LibraryService.LibraryRootFolder.Version; + // coll.Collection.Folders.Add(lib); + // } + // coll.Collection.Items.Clear(); + //} + } + else + { + m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Unable to fetch folder {0}", freq.folder_id); + bad_folders.Add(freq.folder_id); + } + bad = true; + } + } + + return bad; + } + + private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollectionWithDescendents coll) + { + InventoryCollection contents = coll.Collection; + + if (freq.fetch_items && contents.Items != null) + { + List itemsToReturn = contents.Items; + + // descendents must only include the links, not the linked items we add + coll.Descendents = itemsToReturn.Count; + + // Add target items for links in this folder before the links themselves. + List itemIDs = new List(); + List folderIDs = new List(); + foreach (InventoryItemBase item in itemsToReturn) + { + //m_log.DebugFormat("[XXX]: {0} {1}", item.Name, item.AssetType); + if (item.AssetType == (int)AssetType.Link) + itemIDs.Add(item.AssetID); + + else if (item.AssetType == (int)AssetType.LinkFolder) + folderIDs.Add(item.AssetID); + } + + //m_log.DebugFormat("[XXX]: folder {0} has {1} links and {2} linkfolders", contents.FolderID, itemIDs.Count, folderIDs.Count); + + // Scan for folder links and insert the items they target and those links at the head of the return data + if (folderIDs.Count > 0) + { + InventoryCollection[] linkedFolders = m_InventoryService.GetMultipleFoldersContent(coll.Collection.OwnerID, folderIDs.ToArray()); + foreach (InventoryCollection linkedFolderContents in linkedFolders) + { + if (linkedFolderContents == null) + continue; + + List links = linkedFolderContents.Items; + + itemsToReturn.InsertRange(0, links); + + } + } + + if (itemIDs.Count > 0) + { + InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray()); + if (linked == null) + { + // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated + m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); + linked = new InventoryItemBase[itemIDs.Count]; + int i = 0; + InventoryItemBase item = new InventoryItemBase(); + item.Owner = freq.owner_id; + foreach (UUID id in itemIDs) + { + item.ID = id; + linked[i++] = m_InventoryService.GetItem(item); + } + } + + //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Processing folder {0}. Existing items:", freq.folder_id); + //foreach (InventoryItemBase item in itemsToReturn) + // m_log.DebugFormat("[XXX]: {0} {1} {2}", item.Name, item.AssetType, item.Folder); + + if (linked != null) + { + foreach (InventoryItemBase linkedItem in linked) + { + // Take care of genuinely broken links where the target doesn't exist + // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, + // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles + // rather than having to keep track of every folder requested in the recursion. + if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) + { + itemsToReturn.Insert(0, linkedItem); + //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder); + } + } + } + } + } + + } + + /// + /// Convert an internal inventory folder object into an LLSD object. + /// + /// + /// + private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder) + { + LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder(); + llsdFolder.folder_id = invFolder.ID; + llsdFolder.parent_id = invFolder.ParentID; + llsdFolder.name = invFolder.Name; + llsdFolder.type = invFolder.Type; + llsdFolder.preferred_type = -1; + + return llsdFolder; + } + + /// + /// Convert an internal inventory item object into an LLSD object. + /// + /// + /// + private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem) + { + LLSDInventoryItem llsdItem = new LLSDInventoryItem(); + llsdItem.asset_id = invItem.AssetID; + llsdItem.created_at = invItem.CreationDate; + llsdItem.desc = invItem.Description; + llsdItem.flags = (int)invItem.Flags; + llsdItem.item_id = invItem.ID; + llsdItem.name = invItem.Name; + llsdItem.parent_id = invItem.Folder; + llsdItem.type = invItem.AssetType; + llsdItem.inv_type = invItem.InvType; + + llsdItem.permissions = new LLSDPermissions(); + llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid; + llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions; + llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions; + llsdItem.permissions.group_id = invItem.GroupID; + llsdItem.permissions.group_mask = (int)invItem.GroupPermissions; + llsdItem.permissions.is_owner_group = invItem.GroupOwned; + llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions; + llsdItem.permissions.owner_id = invItem.Owner; + llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions; + llsdItem.sale_info = new LLSDSaleInfo(); + llsdItem.sale_info.sale_price = invItem.SalePrice; + llsdItem.sale_info.sale_type = invItem.SaleType; + + return llsdItem; + } + } + + class InventoryCollectionWithDescendents + { + public InventoryCollection Collection; + public int Descendents; + } +} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescServerConnector.cs b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescServerConnector.cs new file mode 100644 index 0000000..9dcfaa4 --- /dev/null +++ b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescServerConnector.cs @@ -0,0 +1,82 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using Nini.Config; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; +using OpenMetaverse; + +namespace OpenSim.Capabilities.Handlers +{ + public class FetchInvDescServerConnector : ServiceConnector + { + private IInventoryService m_InventoryService; + private ILibraryService m_LibraryService; + private string m_ConfigName = "CapsService"; + + public FetchInvDescServerConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + if (configName != String.Empty) + m_ConfigName = configName; + + IConfig serverConfig = config.Configs[m_ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName)); + + string invService = serverConfig.GetString("InventoryService", String.Empty); + + if (invService == String.Empty) + throw new Exception("No InventoryService in config file"); + + Object[] args = new Object[] { config }; + m_InventoryService = + ServerUtils.LoadPlugin(invService, args); + + if (m_InventoryService == null) + throw new Exception(String.Format("Failed to load InventoryService from {0}; config is {1}", invService, m_ConfigName)); + + string libService = serverConfig.GetString("LibraryService", String.Empty); + m_LibraryService = + ServerUtils.LoadPlugin(libService, args); + + FetchInvDescHandler webFetchHandler = new FetchInvDescHandler(m_InventoryService, m_LibraryService, null); + IRequestHandler reqHandler + = new RestStreamHandler( + "POST", + "/CAPS/WebFetchInvDesc/" /*+ UUID.Random()*/, + webFetchHandler.FetchInventoryDescendentsRequest, + "FetchInvDescendents", + null); + server.AddStreamHandler(reqHandler); + } + + } +} diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs new file mode 100644 index 0000000..c904392 --- /dev/null +++ b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs @@ -0,0 +1,141 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Reflection; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Services.Interfaces; +using OSDArray = OpenMetaverse.StructuredData.OSDArray; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; + +using log4net; + +namespace OpenSim.Capabilities.Handlers +{ + public class FetchInventory2Handler + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IInventoryService m_inventoryService; + private UUID m_agentID; + + public FetchInventory2Handler(IInventoryService invService, UUID agentId) + { + m_inventoryService = invService; + m_agentID = agentId; + } + + public string FetchInventoryRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + //m_log.DebugFormat("[FETCH INVENTORY HANDLER]: Received FetchInventory capability request {0}", request); + + OSDMap requestmap = (OSDMap)OSDParser.DeserializeLLSDXml(Utils.StringToBytes(request)); + OSDArray itemsRequested = (OSDArray)requestmap["items"]; + + string reply; + LLSDFetchInventory llsdReply = new LLSDFetchInventory(); + + UUID[] itemIDs = new UUID[itemsRequested.Count]; + int i = 0; + foreach (OSDMap osdItemId in itemsRequested) + { + itemIDs[i++] = osdItemId["item_id"].AsUUID(); + } + + InventoryItemBase[] items = m_inventoryService.GetMultipleItems(m_agentID, itemIDs); + + if (items == null) + { + // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated + m_log.WarnFormat("[FETCH INVENTORY HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); + items = new InventoryItemBase[itemsRequested.Count]; + i = 0; + InventoryItemBase item = new InventoryItemBase(); + item.Owner = m_agentID; + foreach (UUID id in itemIDs) + { + item.ID = id; + items[i++] = m_inventoryService.GetItem(item); + } + } + + foreach (InventoryItemBase item in items) + { + if (item != null) + { + // We don't know the agent that this request belongs to so we'll use the agent id of the item + // which will be the same for all items. + llsdReply.agent_id = item.Owner; + + llsdReply.items.Array.Add(ConvertInventoryItem(item)); + } + } + + reply = LLSDHelpers.SerialiseLLSDReply(llsdReply); + + return reply; + } + + /// + /// Convert an internal inventory item object into an LLSD object. + /// + /// + /// + private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem) + { + LLSDInventoryItem llsdItem = new LLSDInventoryItem(); + llsdItem.asset_id = invItem.AssetID; + llsdItem.created_at = invItem.CreationDate; + llsdItem.desc = invItem.Description; + llsdItem.flags = (int)invItem.Flags; + llsdItem.item_id = invItem.ID; + llsdItem.name = invItem.Name; + llsdItem.parent_id = invItem.Folder; + llsdItem.type = invItem.AssetType; + llsdItem.inv_type = invItem.InvType; + + llsdItem.permissions = new LLSDPermissions(); + llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid; + llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions; + llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions; + llsdItem.permissions.group_id = invItem.GroupID; + llsdItem.permissions.group_mask = (int)invItem.GroupPermissions; + llsdItem.permissions.is_owner_group = invItem.GroupOwned; + llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions; + llsdItem.permissions.owner_id = invItem.Owner; + llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions; + llsdItem.sale_info = new LLSDSaleInfo(); + llsdItem.sale_info.sale_price = invItem.SalePrice; + llsdItem.sale_info.sale_type = invItem.SaleType; + + return llsdItem; + } + } +} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs new file mode 100644 index 0000000..8af3c64 --- /dev/null +++ b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs @@ -0,0 +1,170 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text.RegularExpressions; +using log4net; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Capabilities.Handlers; +using OpenSim.Framework; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests +{ + [TestFixture] + public class FetchInventory2HandlerTests : OpenSimTestCase + { + private UUID m_userID = UUID.Random(); + private Scene m_scene; + private UUID m_rootFolderID; + private UUID m_notecardsFolder; + private UUID m_objectsFolder; + + private void Init() + { + // Create an inventory that looks like this: + // + // /My Inventory + // + // /Objects + // Object 1 + // Object 2 + // Object 3 + // /Notecards + // Notecard 1 + // Notecard 2 + // Notecard 3 + // Notecard 4 + // Notecard 5 + + m_scene = new SceneHelpers().SetupScene(); + + m_scene.InventoryService.CreateUserInventory(m_userID); + + m_rootFolderID = m_scene.InventoryService.GetRootFolder(m_userID).ID; + + InventoryFolderBase of = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object); + m_objectsFolder = of.ID; + + // Add 3 objects + InventoryItemBase item; + for (int i = 1; i <= 3; i++) + { + item = new InventoryItemBase(new UUID("b0000000-0000-0000-0000-0000000000b" + i), m_userID); + item.AssetID = UUID.Random(); + item.AssetType = (int)AssetType.Object; + item.Folder = m_objectsFolder; + item.Name = "Object " + i; + m_scene.InventoryService.AddItem(item); + } + + InventoryFolderBase ncf = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Notecard); + m_notecardsFolder = ncf.ID; + + // Add 5 notecards + for (int i = 1; i <= 5; i++) + { + item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-00000000000" + i), m_userID); + item.AssetID = UUID.Random(); + item.AssetType = (int)AssetType.Notecard; + item.Folder = m_notecardsFolder; + item.Name = "Notecard " + i; + m_scene.InventoryService.AddItem(item); + } + + } + + [Test] + public void Test_001_RequestOne() + { + TestHelpers.InMethod(); + + Init(); + + FetchInventory2Handler handler = new FetchInventory2Handler(m_scene.InventoryService, m_userID); + TestOSHttpRequest req = new TestOSHttpRequest(); + TestOSHttpResponse resp = new TestOSHttpResponse(); + + string request = "itemsitem_id"; + request += "10000000-0000-0000-0000-000000000001"; // Notecard 1 + request += ""; + + string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp); + + Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); + Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); + Assert.That(llsdresponse.Contains(m_userID.ToString()), Is.True, "Response should contain userID"); + + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Response does not contain item uuid"); + Assert.That(llsdresponse.Contains("Notecard 1"), Is.True, "Response does not contain item Name"); + Console.WriteLine(llsdresponse); + } + + [Test] + public void Test_002_RequestMany() + { + TestHelpers.InMethod(); + + Init(); + + FetchInventory2Handler handler = new FetchInventory2Handler(m_scene.InventoryService, m_userID); + TestOSHttpRequest req = new TestOSHttpRequest(); + TestOSHttpResponse resp = new TestOSHttpResponse(); + + string request = "items"; + request += "item_id10000000-0000-0000-0000-000000000001"; // Notecard 1 + request += "item_id10000000-0000-0000-0000-000000000002"; // Notecard 2 + request += "item_id10000000-0000-0000-0000-000000000003"; // Notecard 3 + request += "item_id10000000-0000-0000-0000-000000000004"; // Notecard 4 + request += "item_id10000000-0000-0000-0000-000000000005"; // Notecard 5 + request += ""; + + string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp); + + Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); + Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); + Assert.That(llsdresponse.Contains(m_userID.ToString()), Is.True, "Response should contain userID"); + + Console.WriteLine(llsdresponse); + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Response does not contain notecard 1"); + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000002"), Is.True, "Response does not contain notecard 2"); + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000003"), Is.True, "Response does not contain notecard 3"); + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000004"), Is.True, "Response does not contain notecard 4"); + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000005"), Is.True, "Response does not contain notecard 5"); + } + + } + +} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs new file mode 100644 index 0000000..2d5531a --- /dev/null +++ b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs @@ -0,0 +1,292 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text.RegularExpressions; +using log4net; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Capabilities.Handlers; +using OpenSim.Framework; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests +{ + [TestFixture] + public class FetchInventoryDescendents2HandlerTests : OpenSimTestCase + { + private UUID m_userID = UUID.Zero; + private Scene m_scene; + private UUID m_rootFolderID; + private int m_rootDescendents; + private UUID m_notecardsFolder; + private UUID m_objectsFolder; + + private void Init() + { + // Create an inventory that looks like this: + // + // /My Inventory + // + // /Objects + // Some Object + // /Notecards + // Notecard 1 + // Notecard 2 + // /Test Folder + // Link to notecard -> /Notecards/Notecard 2 + // Link to Objects folder -> /Objects + + m_scene = new SceneHelpers().SetupScene(); + + m_scene.InventoryService.CreateUserInventory(m_userID); + + m_rootFolderID = m_scene.InventoryService.GetRootFolder(m_userID).ID; + + InventoryFolderBase of = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object); + m_objectsFolder = of.ID; + + // Add an object + InventoryItemBase item = new InventoryItemBase(new UUID("b0000000-0000-0000-0000-00000000000b"), m_userID); + item.AssetID = UUID.Random(); + item.AssetType = (int)AssetType.Object; + item.Folder = m_objectsFolder; + item.Name = "Some Object"; + m_scene.InventoryService.AddItem(item); + + InventoryFolderBase ncf = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Notecard); + m_notecardsFolder = ncf.ID; + + // Add a notecard + item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-000000000001"), m_userID); + item.AssetID = UUID.Random(); + item.AssetType = (int)AssetType.Notecard; + item.Folder = m_notecardsFolder; + item.Name = "Test Notecard 1"; + m_scene.InventoryService.AddItem(item); + // Add another notecard + item.ID = new UUID("20000000-0000-0000-0000-000000000002"); + item.AssetID = new UUID("a0000000-0000-0000-0000-00000000000a"); + item.Name = "Test Notecard 2"; + m_scene.InventoryService.AddItem(item); + + // Add a folder + InventoryFolderBase folder = new InventoryFolderBase(new UUID("f0000000-0000-0000-0000-00000000000f"), "Test Folder", m_userID, m_rootFolderID); + m_scene.InventoryService.AddFolder(folder); + + // Add a link to notecard 2 in Test Folder + item.AssetID = item.ID; // use item ID of notecard 2 + item.ID = new UUID("40000000-0000-0000-0000-000000000004"); + item.AssetType = (int)AssetType.Link; + item.Folder = folder.ID; + item.Name = "Link to notecard"; + m_scene.InventoryService.AddItem(item); + + // Add a link to the Objects folder in Test Folder + item.AssetID = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object).ID; // use item ID of Objects folder + item.ID = new UUID("50000000-0000-0000-0000-000000000005"); + item.AssetType = (int)AssetType.LinkFolder; + item.Folder = folder.ID; + item.Name = "Link to Objects folder"; + m_scene.InventoryService.AddItem(item); + + InventoryCollection coll = m_scene.InventoryService.GetFolderContent(m_userID, m_rootFolderID); + m_rootDescendents = coll.Items.Count + coll.Folders.Count; + Console.WriteLine("Number of descendents: " + m_rootDescendents); + } + + [Test] + public void Test_001_SimpleFolder() + { + TestHelpers.InMethod(); + + Init(); + + FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); + TestOSHttpRequest req = new TestOSHttpRequest(); + TestOSHttpResponse resp = new TestOSHttpResponse(); + + string request = "foldersfetch_folders1fetch_items1folder_id"; + request += m_rootFolderID; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + + string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp); + + Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); + Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); + Assert.That(llsdresponse.Contains("00000000-0000-0000-0000-000000000000"), Is.True, "Response should contain userID"); + + string descendents = "descendents" + m_rootDescendents + ""; + Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents"); + Console.WriteLine(llsdresponse); + } + + [Test] + public void Test_002_MultipleFolders() + { + TestHelpers.InMethod(); + + FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); + TestOSHttpRequest req = new TestOSHttpRequest(); + TestOSHttpResponse resp = new TestOSHttpResponse(); + + string request = "folders"; + request += "fetch_folders1fetch_items1folder_id"; + request += m_rootFolderID; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + request += "fetch_folders1fetch_items1folder_id"; + request += m_notecardsFolder; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + request += ""; + + string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp); + Console.WriteLine(llsdresponse); + + string descendents = "descendents" + m_rootDescendents + ""; + Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for root folder"); + descendents = "descendents2"; + Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for Notecard folder"); + + Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Notecard 1 is missing from response"); + Assert.That(llsdresponse.Contains("20000000-0000-0000-0000-000000000002"), Is.True, "Notecard 2 is missing from response"); + } + + [Test] + public void Test_003_Links() + { + TestHelpers.InMethod(); + + FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); + TestOSHttpRequest req = new TestOSHttpRequest(); + TestOSHttpResponse resp = new TestOSHttpResponse(); + + string request = "foldersfetch_folders1fetch_items1folder_id"; + request += "f0000000-0000-0000-0000-00000000000f"; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + + string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp); + Console.WriteLine(llsdresponse); + + string descendents = "descendents2"; + Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for Test Folder"); + + // Make sure that the note card link is included + Assert.That(llsdresponse.Contains("Link to notecard"), Is.True, "Link to notecard is missing"); + + //Make sure the notecard item itself is included + Assert.That(llsdresponse.Contains("Test Notecard 2"), Is.True, "Notecard 2 item (the source) is missing"); + + // Make sure that the source item is before the link item + int pos1 = llsdresponse.IndexOf("Test Notecard 2"); + int pos2 = llsdresponse.IndexOf("Link to notecard"); + Assert.Less(pos1, pos2, "Source of link is after link"); + + // Make sure the folder link is included + Assert.That(llsdresponse.Contains("Link to Objects folder"), Is.True, "Link to Objects folder is missing"); + + // Make sure the objects inside the Objects folder are included + // Note: I'm not entirely sure this is needed, but that's what I found in the implementation + Assert.That(llsdresponse.Contains("Some Object"), Is.True, "Some Object item (contents of the source) is missing"); + + // Make sure that the source item is before the link item + pos1 = llsdresponse.IndexOf("Some Object"); + pos2 = llsdresponse.IndexOf("Link to Objects folder"); + Assert.Less(pos1, pos2, "Contents of source of folder link is after folder link"); + } + + [Test] + public void Test_004_DuplicateFolders() + { + TestHelpers.InMethod(); + + FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); + TestOSHttpRequest req = new TestOSHttpRequest(); + TestOSHttpResponse resp = new TestOSHttpResponse(); + + string request = "folders"; + request += "fetch_folders1fetch_items1folder_id"; + request += m_rootFolderID; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + request += "fetch_folders1fetch_items1folder_id"; + request += m_notecardsFolder; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + request += "fetch_folders1fetch_items1folder_id"; + request += m_rootFolderID; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + request += "fetch_folders1fetch_items1folder_id"; + request += m_notecardsFolder; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + request += ""; + + string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp); + Console.WriteLine(llsdresponse); + + string root_folder = "folder_id" + m_rootFolderID + ""; + string notecards_folder = "folder_id" + m_notecardsFolder + ""; + + Assert.That(llsdresponse.Contains(root_folder), "Missing root folder"); + Assert.That(llsdresponse.Contains(notecards_folder), "Missing notecards folder"); + int count = Regex.Matches(llsdresponse, root_folder).Count; + Assert.AreEqual(1, count, "More than 1 root folder in response"); + count = Regex.Matches(llsdresponse, notecards_folder).Count; + Assert.AreEqual(2, count, "More than 1 notecards folder in response"); // Notecards will also be under root, so 2 + } + + [Test] + public void Test_005_FolderZero() + { + TestHelpers.InMethod(); + + Init(); + + FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); + TestOSHttpRequest req = new TestOSHttpRequest(); + TestOSHttpResponse resp = new TestOSHttpResponse(); + + string request = "foldersfetch_folders1fetch_items1folder_id"; + request += UUID.Zero; + request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; + + string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp); + + Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); + Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); + Assert.That(llsdresponse.Contains("bad_folders00000000-0000-0000-0000-000000000000"), Is.True, "Folder Zero should be a bad folder"); + + Console.WriteLine(llsdresponse); + } + + } + +} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs deleted file mode 100644 index c0ca1e1..0000000 --- a/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using log4net; -using Nini.Config; -using OpenMetaverse; -using OpenMetaverse.StructuredData; -using OpenSim.Framework; -using OpenSim.Framework.Capabilities; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Services.Interfaces; -using Caps = OpenSim.Framework.Capabilities.Caps; -using OSDArray = OpenMetaverse.StructuredData.OSDArray; -using OSDMap = OpenMetaverse.StructuredData.OSDMap; - -namespace OpenSim.Capabilities.Handlers -{ - public class FetchInventory2Handler - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private IInventoryService m_inventoryService; - - public FetchInventory2Handler(IInventoryService invService) - { - m_inventoryService = invService; - } - - public string FetchInventoryRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { -// m_log.DebugFormat("[FETCH INVENTORY HANDLER]: Received FetchInventory capabilty request"); - - OSDMap requestmap = (OSDMap)OSDParser.DeserializeLLSDXml(Utils.StringToBytes(request)); - OSDArray itemsRequested = (OSDArray)requestmap["items"]; - - string reply; - LLSDFetchInventory llsdReply = new LLSDFetchInventory(); - - foreach (OSDMap osdItemId in itemsRequested) - { - UUID itemId = osdItemId["item_id"].AsUUID(); - - InventoryItemBase item = m_inventoryService.GetItem(new InventoryItemBase(itemId)); - - if (item != null) - { - // We don't know the agent that this request belongs to so we'll use the agent id of the item - // which will be the same for all items. - llsdReply.agent_id = item.Owner; - - llsdReply.items.Array.Add(ConvertInventoryItem(item)); - } - } - - reply = LLSDHelpers.SerialiseLLSDReply(llsdReply); - - return reply; - } - - /// - /// Convert an internal inventory item object into an LLSD object. - /// - /// - /// - private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem) - { - LLSDInventoryItem llsdItem = new LLSDInventoryItem(); - llsdItem.asset_id = invItem.AssetID; - llsdItem.created_at = invItem.CreationDate; - llsdItem.desc = invItem.Description; - llsdItem.flags = (int)invItem.Flags; - llsdItem.item_id = invItem.ID; - llsdItem.name = invItem.Name; - llsdItem.parent_id = invItem.Folder; - llsdItem.type = invItem.AssetType; - llsdItem.inv_type = invItem.InvType; - - llsdItem.permissions = new LLSDPermissions(); - llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid; - llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions; - llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions; - llsdItem.permissions.group_id = invItem.GroupID; - llsdItem.permissions.group_mask = (int)invItem.GroupPermissions; - llsdItem.permissions.is_owner_group = invItem.GroupOwned; - llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions; - llsdItem.permissions.owner_id = invItem.Owner; - llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions; - llsdItem.sale_info = new LLSDSaleInfo(); - llsdItem.sale_info.sale_price = invItem.SalePrice; - llsdItem.sale_info.sale_type = invItem.SaleType; - - return llsdItem; - } - } -} diff --git a/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2ServerConnector.cs b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2ServerConnector.cs deleted file mode 100644 index 5bab52f..0000000 --- a/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2ServerConnector.cs +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using Nini.Config; -using OpenSim.Server.Base; -using OpenSim.Services.Interfaces; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Server.Handlers.Base; -using OpenMetaverse; - -namespace OpenSim.Capabilities.Handlers -{ - public class FetchInventory2ServerConnector : ServiceConnector - { - private IInventoryService m_InventoryService; - private string m_ConfigName = "CapsService"; - - public FetchInventory2ServerConnector(IConfigSource config, IHttpServer server, string configName) - : base(config, server, configName) - { - if (configName != String.Empty) - m_ConfigName = configName; - - IConfig serverConfig = config.Configs[m_ConfigName]; - if (serverConfig == null) - throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName)); - - string invService = serverConfig.GetString("InventoryService", String.Empty); - - if (invService == String.Empty) - throw new Exception("No InventoryService in config file"); - - Object[] args = new Object[] { config }; - m_InventoryService = ServerUtils.LoadPlugin(invService, args); - - if (m_InventoryService == null) - throw new Exception(String.Format("Failed to load InventoryService from {0}; config is {1}", invService, m_ConfigName)); - - FetchInventory2Handler fiHandler = new FetchInventory2Handler(m_InventoryService); - IRequestHandler reqHandler - = new RestStreamHandler( - "POST", "/CAPS/FetchInventory/", fiHandler.FetchInventoryRequest, "FetchInventory", null); - server.AddStreamHandler(reqHandler); - } - } -} diff --git a/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesHandler.cs b/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesHandler.cs new file mode 100644 index 0000000..589602d --- /dev/null +++ b/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesHandler.cs @@ -0,0 +1,120 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Drawing; +using System.Drawing.Imaging; +using System.Reflection; +using System.IO; +using System.Web; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Imaging; +using OpenSim.Framework; +using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Services.Interfaces; +using Caps = OpenSim.Framework.Capabilities.Caps; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; +using OSDArray = OpenMetaverse.StructuredData.OSDArray; + +namespace OpenSim.Capabilities.Handlers +{ + public class GetDisplayNamesHandler : BaseStreamHandler + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private IUserManagement m_UserManagement; + + public GetDisplayNamesHandler(string path, IUserManagement umService, string name, string description) + : base("GET", path, name, description) + { + m_UserManagement = umService; + } + + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + m_log.DebugFormat("[GET_DISPLAY_NAMES]: called {0}", httpRequest.Url.Query); + + NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); + string[] ids = query.GetValues("ids"); + + + if (m_UserManagement == null) + { + m_log.Error("[GET_DISPLAY_NAMES]: Cannot fetch display names without a user management component"); + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; + return new byte[0]; + } + + OSDMap osdReply = new OSDMap(); + OSDArray agents = new OSDArray(); + + osdReply["agents"] = agents; + foreach (string id in ids) + { + UUID uuid = UUID.Zero; + if (UUID.TryParse(id, out uuid)) + { + string name = m_UserManagement.GetUserName(uuid); + if (!string.IsNullOrEmpty(name)) + { + string[] parts = name.Split(new char[] {' '}); + OSDMap osdname = new OSDMap(); + osdname["display_name_next_update"] = OSD.FromDate(DateTime.MinValue); + osdname["display_name_expires"] = OSD.FromDate(DateTime.Now.AddMonths(1)); + osdname["display_name"] = OSD.FromString(name); + osdname["legacy_first_name"] = parts[0]; + osdname["legacy_last_name"] = parts[1]; + osdname["username"] = OSD.FromString(name); + osdname["id"] = OSD.FromUUID(uuid); + osdname["is_display_name_default"] = OSD.FromBoolean(true); + + agents.Add(osdname); + } + } + } + + // Full content request + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK; + //httpResponse.ContentLength = ??; + httpResponse.ContentType = "application/llsd+xml"; + + string reply = OSDParser.SerializeLLSDXmlString(osdReply); + return System.Text.Encoding.UTF8.GetBytes(reply); + + } + + } +} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesServerConnector.cs b/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesServerConnector.cs new file mode 100644 index 0000000..d42de56 --- /dev/null +++ b/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesServerConnector.cs @@ -0,0 +1,71 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using Nini.Config; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; +using OpenMetaverse; + +namespace OpenSim.Capabilities.Handlers +{ + public class GetDisplayNamesServerConnector : ServiceConnector + { + private IUserManagement m_UserManagement; + private string m_ConfigName = "CapsService"; + + public GetDisplayNamesServerConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + if (configName != String.Empty) + m_ConfigName = configName; + + IConfig serverConfig = config.Configs[m_ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName)); + + string umService = serverConfig.GetString("AssetService", String.Empty); + + if (umService == String.Empty) + throw new Exception("No AssetService in config file"); + + Object[] args = new Object[] { config }; + m_UserManagement = + ServerUtils.LoadPlugin(umService, args); + + if (m_UserManagement == null) + throw new Exception(String.Format("Failed to load UserManagement from {0}; config is {1}", umService, m_ConfigName)); + + string rurl = serverConfig.GetString("GetTextureRedirectURL"); + + server.AddStreamHandler( + new GetDisplayNamesHandler("/CAPS/agents/", m_UserManagement, "GetDisplayNames", null)); + } + } +} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs index 720640e..6b67da1 100644 --- a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs +++ b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs @@ -25,92 +25,229 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -using System; -using System.Collections; -using System.Collections.Specialized; -using System.Reflection; -using System.IO; -using System.Web; using log4net; -using Nini.Config; using OpenMetaverse; -using OpenMetaverse.StructuredData; +using OpenMetaverse.Imaging; using OpenSim.Framework; -using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; -using Caps = OpenSim.Framework.Capabilities.Caps; +using System; +using System.Collections.Specialized; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Reflection; +using System.Web; namespace OpenSim.Capabilities.Handlers { - public class GetMeshHandler + public class GetMeshHandler : BaseStreamHandler { -// private static readonly ILog m_log = -// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IAssetService m_assetService; - public GetMeshHandler(IAssetService assService) + // TODO: Change this to a config option + private string m_RedirectURL = null; + + public GetMeshHandler(string path, IAssetService assService, string name, string description, string redirectURL) + : base("GET", path, name, description) { m_assetService = assService; + m_RedirectURL = redirectURL; + if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/")) + m_RedirectURL += "/"; } - public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap) + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { - Hashtable responsedata = new Hashtable(); - responsedata["int_response_code"] = 400; //501; //410; //404; - responsedata["content_type"] = "text/plain"; - responsedata["keepalive"] = false; - responsedata["str_response_string"] = "Request wasn't what was expected"; + // Try to parse the texture ID from the request URL + NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); + string textureStr = query.GetOne("mesh_id"); - string meshStr = string.Empty; - - if (request.ContainsKey("mesh_id")) - meshStr = request["mesh_id"].ToString(); + if (m_assetService == null) + { + m_log.Error("[GETMESH]: Cannot fetch mesh " + textureStr + " without an asset service"); + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + } - UUID meshID = UUID.Zero; - if (!String.IsNullOrEmpty(meshStr) && UUID.TryParse(meshStr, out meshID)) + UUID meshID; + if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out meshID)) { - if (m_assetService == null) + // OK, we have an array with preferred formats, possibly with only one entry + + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + AssetBase mesh; + + if (!String.IsNullOrEmpty(m_RedirectURL)) { - responsedata["int_response_code"] = 404; //501; //410; //404; - responsedata["content_type"] = "text/plain"; - responsedata["keepalive"] = false; - responsedata["str_response_string"] = "The asset service is unavailable. So is your mesh."; - return responsedata; + // Only try to fetch locally cached meshes. Misses are redirected + mesh = m_assetService.GetCached(meshID.ToString()); + + if (mesh != null) + { + if (mesh.Type != (sbyte)AssetType.Mesh) + { + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + } + WriteMeshData(httpRequest, httpResponse, mesh); + } + else + { + string textureUrl = m_RedirectURL + "?mesh_id="+ meshID.ToString(); + m_log.Debug("[GETMESH]: Redirecting mesh request to " + textureUrl); + httpResponse.StatusCode = (int)OSHttpStatusCode.RedirectMovedPermanently; + httpResponse.RedirectLocation = textureUrl; + return null; + } + } + else // no redirect + { + // try the cache + mesh = m_assetService.GetCached(meshID.ToString()); + + if (mesh == null) + { + // Fetch locally or remotely. Misses return a 404 + mesh = m_assetService.Get(meshID.ToString()); + + if (mesh != null) + { + if (mesh.Type != (sbyte)AssetType.Mesh) + { + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return null; + } + WriteMeshData(httpRequest, httpResponse, mesh); + return null; + } + } + else // it was on the cache + { + if (mesh.Type != (sbyte)AssetType.Mesh) + { + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return null; + } + WriteMeshData(httpRequest, httpResponse, mesh); + return null; + } } - AssetBase mesh = m_assetService.Get(meshID.ToString()); + // not found + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return null; + } + else + { + m_log.Warn("[GETTEXTURE]: Failed to parse a mesh_id from GetMesh request: " + httpRequest.Url); + } + + return null; + } + + private void WriteMeshData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture) + { + string range = request.Headers.GetOne("Range"); - if (mesh != null) + if (!String.IsNullOrEmpty(range)) + { + // Range request + int start, end; + if (TryParseRange(range, out start, out end)) { - if (mesh.Type == (SByte)AssetType.Mesh) + // Before clamping start make sure we can satisfy it in order to avoid + // sending back the last byte instead of an error status + if (start >= texture.Data.Length) { - responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data); - responsedata["content_type"] = "application/vnd.ll.mesh"; - responsedata["int_response_code"] = 200; + response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; + response.ContentType = texture.Metadata.ContentType; } - // Optionally add additional mesh types here else { - responsedata["int_response_code"] = 404; //501; //410; //404; - responsedata["content_type"] = "text/plain"; - responsedata["keepalive"] = false; - responsedata["str_response_string"] = "Unfortunately, this asset isn't a mesh."; - return responsedata; + // Handle the case where no second range value was given. This is equivalent to requesting + // the rest of the entity. + if (end == -1) + end = int.MaxValue; + + end = Utils.Clamp(end, 0, texture.Data.Length - 1); + start = Utils.Clamp(start, 0, end); + int len = end - start + 1; + + if (0 == start && len == texture.Data.Length) + { + response.StatusCode = (int)System.Net.HttpStatusCode.OK; + } + else + { + response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; + response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); + } + + response.ContentLength = len; + response.ContentType = "application/vnd.ll.mesh"; + + response.Body.Write(texture.Data, start, len); } } else { - responsedata["int_response_code"] = 404; //501; //410; //404; - responsedata["content_type"] = "text/plain"; - responsedata["keepalive"] = false; - responsedata["str_response_string"] = "Your Mesh wasn't found. Sorry!"; - return responsedata; + m_log.Warn("[GETMESH]: Malformed Range header: " + range); + response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; + } + } + else + { + // Full content request + response.StatusCode = (int)System.Net.HttpStatusCode.OK; + response.ContentLength = texture.Data.Length; + response.ContentType = "application/vnd.ll.mesh"; + response.Body.Write(texture.Data, 0, texture.Data.Length); + } + } + + /// + /// Parse a range header. + /// + /// + /// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, + /// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-). + /// Where there is no value, -1 is returned. + /// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1 + /// for start. + /// + /// + /// Start of the range. Undefined if this was not a number. + /// End of the range. Will be -1 if no end specified. Undefined if there was a raw string but this was not a number. + private bool TryParseRange(string header, out int start, out int end) + { + start = end = 0; + + if (header.StartsWith("bytes=")) + { + string[] rangeValues = header.Substring(6).Split('-'); + + if (rangeValues.Length == 2) + { + if (!Int32.TryParse(rangeValues[0], out start)) + return false; + + string rawEnd = rangeValues[1]; + + if (rawEnd == "") + { + end = -1; + return true; + } + else if (Int32.TryParse(rawEnd, out end)) + { + return true; + } } } - return responsedata; + start = end = 0; + return false; } } } \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshServerConnector.cs b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshServerConnector.cs index 8a275f3..19de3cf 100644 --- a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshServerConnector.cs +++ b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshServerConnector.cs @@ -25,16 +25,13 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -using System; -using System.Collections; using Nini.Config; -using OpenSim.Server.Base; -using OpenSim.Services.Interfaces; +using OpenMetaverse; using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Base; using OpenSim.Server.Handlers.Base; -using OpenSim.Framework.Servers; - -using OpenMetaverse; +using OpenSim.Services.Interfaces; +using System; namespace OpenSim.Capabilities.Handlers { @@ -65,15 +62,15 @@ namespace OpenSim.Capabilities.Handlers if (m_AssetService == null) throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName)); - GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService); - IRequestHandler reqHandler - = new RestHTTPHandler( - "GET", - "/CAPS/" + UUID.Random(), - httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null), - "GetMesh", - null); - server.AddStreamHandler(reqHandler); + string rurl = serverConfig.GetString("GetMeshRedirectURL"); + + server.AddStreamHandler( + new GetTextureHandler("/CAPS/GetMesh/" /*+ UUID.Random() */, m_AssetService, "GetMesh", null, rurl)); + + rurl = serverConfig.GetString("GetMesh2RedirectURL"); + + server.AddStreamHandler( + new GetTextureHandler("/CAPS/GetMesh2/" /*+ UUID.Random() */, m_AssetService, "GetMesh2", null, rurl)); } } } \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs index b497fde..828e943 100644 --- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs +++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs @@ -56,15 +56,18 @@ namespace OpenSim.Capabilities.Handlers public const string DefaultFormat = "x-j2c"; // TODO: Change this to a config option - const string REDIRECT_URL = null; + private string m_RedirectURL = null; - public GetTextureHandler(string path, IAssetService assService, string name, string description) + public GetTextureHandler(string path, IAssetService assService, string name, string description, string redirectURL) : base("GET", path, name, description) { m_assetService = assService; + m_RedirectURL = redirectURL; + if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/")) + m_RedirectURL += "/"; } - public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // Try to parse the texture ID from the request URL NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); @@ -85,7 +88,7 @@ namespace OpenSim.Capabilities.Handlers // m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID); string[] formats; - if (format != null && format != string.Empty) + if (!string.IsNullOrEmpty(format)) { formats = new string[1] { format.ToLower() }; } @@ -134,7 +137,7 @@ namespace OpenSim.Capabilities.Handlers if (format != DefaultFormat) fullID = fullID + "-" + format; - if (!String.IsNullOrEmpty(REDIRECT_URL)) + if (!String.IsNullOrEmpty(m_RedirectURL)) { // Only try to fetch locally cached textures. Misses are redirected texture = m_assetService.GetCached(fullID); @@ -150,8 +153,9 @@ namespace OpenSim.Capabilities.Handlers } else { - string textureUrl = REDIRECT_URL + textureID.ToString(); + string textureUrl = m_RedirectURL + "?texture_id="+ textureID.ToString(); m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl); + httpResponse.StatusCode = (int)OSHttpStatusCode.RedirectMovedPermanently; httpResponse.RedirectLocation = textureUrl; return true; } @@ -189,6 +193,7 @@ namespace OpenSim.Capabilities.Handlers newTexture.Flags = AssetFlags.Collectable; newTexture.Temporary = true; + newTexture.Local = true; m_assetService.Store(newTexture); WriteTextureData(httpRequest, httpResponse, newTexture, format); return true; diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureServerConnector.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureServerConnector.cs index 71cf033..fa0b228 100644 --- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureServerConnector.cs +++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureServerConnector.cs @@ -62,8 +62,10 @@ namespace OpenSim.Capabilities.Handlers if (m_AssetService == null) throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName)); + string rurl = serverConfig.GetString("GetTextureRedirectURL"); + ; server.AddStreamHandler( - new GetTextureHandler("/CAPS/GetTexture/" /*+ UUID.Random() */, m_AssetService, "GetTexture", null)); + new GetTextureHandler("/CAPS/GetTexture/" /*+ UUID.Random() */, m_AssetService, "GetTexture", null, rurl)); } } } \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs b/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs index d4d6d10..e5d9618 100644 --- a/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs +++ b/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs @@ -37,7 +37,6 @@ using OpenSim.Framework; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Capabilities.Handlers.GetTexture.Tests { @@ -52,7 +51,7 @@ namespace OpenSim.Capabilities.Handlers.GetTexture.Tests // Overkill - we only really need the asset service, not a whole scene. Scene scene = new SceneHelpers().SetupScene(); - GetTextureHandler handler = new GetTextureHandler(null, scene.AssetService, "TestGetTexture", null); + GetTextureHandler handler = new GetTextureHandler("/gettexture", scene.AssetService, "TestGetTexture", null, null); TestOSHttpRequest req = new TestOSHttpRequest(); TestOSHttpResponse resp = new TestOSHttpResponse(); req.Url = new Uri("http://localhost/?texture_id=00000000-0000-1111-9999-000000000012"); diff --git a/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs b/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs index a681fb6..1a6d04f 100644 --- a/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs +++ b/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureServerConnector.cs b/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureServerConnector.cs new file mode 100644 index 0000000..10ea8ee --- /dev/null +++ b/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureServerConnector.cs @@ -0,0 +1,76 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using Nini.Config; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; +using OpenMetaverse; + +namespace OpenSim.Capabilities.Handlers +{ + public class UploadBakedTextureServerConnector : ServiceConnector + { + private IAssetService m_AssetService; + private string m_ConfigName = "CapsService"; + + public UploadBakedTextureServerConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + if (configName != String.Empty) + m_ConfigName = configName; + + IConfig serverConfig = config.Configs[m_ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName)); + + string assetService = serverConfig.GetString("AssetService", String.Empty); + + if (assetService == String.Empty) + throw new Exception("No AssetService in config file"); + + Object[] args = new Object[] { config }; + m_AssetService = + ServerUtils.LoadPlugin(assetService, args); + + if (m_AssetService == null) + throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName)); + + // NEED TO FIX THIS + OpenSim.Framework.Capabilities.Caps caps = new OpenSim.Framework.Capabilities.Caps(server, "", server.Port, "", UUID.Zero, ""); + server.AddStreamHandler(new RestStreamHandler( + "POST", + "/CAPS/UploadBakedTexture/", + new UploadBakedTextureHandler(caps, m_AssetService, true).UploadBakedTexture, + "UploadBakedTexture", + "Upload Baked Texture Capability")); + + } + } +} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs deleted file mode 100644 index 9a6ca86..0000000 --- a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using log4net; -using Nini.Config; -using OpenMetaverse; -using OpenMetaverse.StructuredData; -using OpenSim.Framework; -using OpenSim.Framework.Capabilities; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Services.Interfaces; -using Caps = OpenSim.Framework.Capabilities.Caps; - -namespace OpenSim.Capabilities.Handlers -{ - public class WebFetchInvDescHandler - { - private static readonly ILog m_log = - LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private IInventoryService m_InventoryService; - private ILibraryService m_LibraryService; -// private object m_fetchLock = new Object(); - - public WebFetchInvDescHandler(IInventoryService invService, ILibraryService libService) - { - m_InventoryService = invService; - m_LibraryService = libService; - } - - public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { -// lock (m_fetchLock) -// { -// m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request {0}", request); - - // nasty temporary hack here, the linden client falsely - // identifies the uuid 00000000-0000-0000-0000-000000000000 - // as a string which breaks us - // - // correctly mark it as a uuid - // - request = request.Replace("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000000"); - - // another hack 1 results in a - // System.ArgumentException: Object type System.Int32 cannot - // be converted to target type: System.Boolean - // - request = request.Replace("fetch_folders0", "fetch_folders0"); - request = request.Replace("fetch_folders1", "fetch_folders1"); - - Hashtable hash = new Hashtable(); - try - { - hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); - } - catch (LLSD.LLSDParseException e) - { - m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); - m_log.Error("Request: " + request); - } - - ArrayList foldersrequested = (ArrayList)hash["folders"]; - - string response = ""; - - for (int i = 0; i < foldersrequested.Count; i++) - { - string inventoryitemstr = ""; - Hashtable inventoryhash = (Hashtable)foldersrequested[i]; - - LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); - - try - { - LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); - } - catch (Exception e) - { - m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); - } - LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); - - inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); - inventoryitemstr = inventoryitemstr.Replace("folders", ""); - inventoryitemstr = inventoryitemstr.Replace("", ""); - - response += inventoryitemstr; - } - - if (response.Length == 0) - { - // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. - // Therefore, I'm concluding that the client only has so many threads available to do requests - // and when a thread stalls.. is stays stalled. - // Therefore we need to return something valid - response = "folders"; - } - else - { - response = "folders" + response + ""; - } - -// m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request"); - //m_log.Debug("[WEB FETCH INV DESC HANDLER] "+response); - - return response; - -// } - } - - /// - /// Construct an LLSD reply packet to a CAPS inventory request - /// - /// - /// - private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch) - { - LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); - LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); - contents.agent_id = invFetch.owner_id; - contents.owner_id = invFetch.owner_id; - contents.folder_id = invFetch.folder_id; - - reply.folders.Array.Add(contents); - InventoryCollection inv = new InventoryCollection(); - inv.Folders = new List(); - inv.Items = new List(); - int version = 0; - int descendents = 0; - - inv - = Fetch( - invFetch.owner_id, invFetch.folder_id, invFetch.owner_id, - invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version, out descendents); - - if (inv != null && inv.Folders != null) - { - foreach (InventoryFolderBase invFolder in inv.Folders) - { - contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); - } - - descendents += inv.Folders.Count; - } - - if (inv != null && inv.Items != null) - { - foreach (InventoryItemBase invItem in inv.Items) - { - contents.items.Array.Add(ConvertInventoryItem(invItem)); - } - } - - contents.descendents = descendents; - contents.version = version; - -// m_log.DebugFormat( -// "[WEB FETCH INV DESC HANDLER]: Replying to request for folder {0} (fetch items {1}, fetch folders {2}) with {3} items and {4} folders for agent {5}", -// invFetch.folder_id, -// invFetch.fetch_items, -// invFetch.fetch_folders, -// contents.items.Array.Count, -// contents.categories.Array.Count, -// invFetch.owner_id); - - return reply; - } - - /// - /// Handle the caps inventory descendents fetch. - /// - /// - /// - /// - /// - /// - /// - /// - /// An empty InventoryCollection if the inventory look up failed - private InventoryCollection Fetch( - UUID agentID, UUID folderID, UUID ownerID, - bool fetchFolders, bool fetchItems, int sortOrder, out int version, out int descendents) - { -// m_log.DebugFormat( -// "[WEB FETCH INV DESC HANDLER]: Fetching folders ({0}), items ({1}) from {2} for agent {3}", -// fetchFolders, fetchItems, folderID, agentID); - - // FIXME MAYBE: We're not handling sortOrder! - - version = 0; - descendents = 0; - - InventoryFolderImpl fold; - if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null && agentID == m_LibraryService.LibraryRootFolder.Owner) - { - if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(folderID)) != null) - { - InventoryCollection ret = new InventoryCollection(); - ret.Folders = new List(); - ret.Items = fold.RequestListOfItems(); - descendents = ret.Folders.Count + ret.Items.Count; - - return ret; - } - } - - InventoryCollection contents = new InventoryCollection(); - - if (folderID != UUID.Zero) - { - contents = m_InventoryService.GetFolderContent(agentID, folderID); - InventoryFolderBase containingFolder = new InventoryFolderBase(); - containingFolder.ID = folderID; - containingFolder.Owner = agentID; - containingFolder = m_InventoryService.GetFolder(containingFolder); - - if (containingFolder != null) - { -// m_log.DebugFormat( -// "[WEB FETCH INV DESC HANDLER]: Retrieved folder {0} {1} for agent id {2}", -// containingFolder.Name, containingFolder.ID, agentID); - - version = containingFolder.Version; - - if (fetchItems) - { - List itemsToReturn = contents.Items; - List originalItems = new List(itemsToReturn); - - // descendents must only include the links, not the linked items we add - descendents = originalItems.Count; - - // Add target items for links in this folder before the links themselves. - foreach (InventoryItemBase item in originalItems) - { - if (item.AssetType == (int)AssetType.Link) - { - InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID)); - - // Take care of genuinely broken links where the target doesn't exist - // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, - // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles - // rather than having to keep track of every folder requested in the recursion. - if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) - itemsToReturn.Insert(0, linkedItem); - } - } - - // Now scan for folder links and insert the items they target and those links at the head of the return data - foreach (InventoryItemBase item in originalItems) - { - if (item.AssetType == (int)AssetType.LinkFolder) - { - InventoryCollection linkedFolderContents = m_InventoryService.GetFolderContent(ownerID, item.AssetID); - List links = linkedFolderContents.Items; - - itemsToReturn.InsertRange(0, links); - - foreach (InventoryItemBase link in linkedFolderContents.Items) - { - // Take care of genuinely broken links where the target doesn't exist - // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, - // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles - // rather than having to keep track of every folder requested in the recursion. - if (link != null) - { -// m_log.DebugFormat( -// "[WEB FETCH INV DESC HANDLER]: Adding item {0} {1} from folder {2} linked from {3}", -// link.Name, (AssetType)link.AssetType, item.AssetID, containingFolder.Name); - - InventoryItemBase linkedItem - = m_InventoryService.GetItem(new InventoryItemBase(link.AssetID)); - - if (linkedItem != null) - itemsToReturn.Insert(0, linkedItem); - } - } - } - } - } - -// foreach (InventoryItemBase item in contents.Items) -// { -// m_log.DebugFormat( -// "[WEB FETCH INV DESC HANDLER]: Returning item {0}, type {1}, parent {2} in {3} {4}", -// item.Name, (AssetType)item.AssetType, item.Folder, containingFolder.Name, containingFolder.ID); -// } - - // ===== - -// -// foreach (InventoryItemBase linkedItem in linkedItemsToAdd) -// { -// m_log.DebugFormat( -// "[WEB FETCH INV DESC HANDLER]: Inserted linked item {0} for link in folder {1} for agent {2}", -// linkedItem.Name, folderID, agentID); -// -// contents.Items.Add(linkedItem); -// } -// -// // If the folder requested contains links, then we need to send those folders first, otherwise the links -// // will be broken in the viewer. -// HashSet linkedItemFolderIdsToSend = new HashSet(); -// foreach (InventoryItemBase item in contents.Items) -// { -// if (item.AssetType == (int)AssetType.Link) -// { -// InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID)); -// -// // Take care of genuinely broken links where the target doesn't exist -// // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, -// // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles -// // rather than having to keep track of every folder requested in the recursion. -// if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) -// { -// // We don't need to send the folder if source and destination of the link are in the same -// // folder. -// if (linkedItem.Folder != containingFolder.ID) -// linkedItemFolderIdsToSend.Add(linkedItem.Folder); -// } -// } -// } -// -// foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend) -// { -// m_log.DebugFormat( -// "[WEB FETCH INV DESC HANDLER]: Recursively fetching folder {0} linked by item in folder {1} for agent {2}", -// linkedItemFolderId, folderID, agentID); -// -// int dummyVersion; -// InventoryCollection linkedCollection -// = Fetch( -// agentID, linkedItemFolderId, ownerID, fetchFolders, fetchItems, sortOrder, out dummyVersion); -// -// InventoryFolderBase linkedFolder = new InventoryFolderBase(linkedItemFolderId); -// linkedFolder.Owner = agentID; -// linkedFolder = m_InventoryService.GetFolder(linkedFolder); -// -//// contents.Folders.AddRange(linkedCollection.Folders); -// -// contents.Folders.Add(linkedFolder); -// contents.Items.AddRange(linkedCollection.Items); -// } -// } - } - } - else - { - // Lost items don't really need a version - version = 1; - } - - return contents; - - } - /// - /// Convert an internal inventory folder object into an LLSD object. - /// - /// - /// - private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder) - { - LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder(); - llsdFolder.folder_id = invFolder.ID; - llsdFolder.parent_id = invFolder.ParentID; - llsdFolder.name = invFolder.Name; - llsdFolder.type = invFolder.Type; - llsdFolder.preferred_type = -1; - - return llsdFolder; - } - - /// - /// Convert an internal inventory item object into an LLSD object. - /// - /// - /// - private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem) - { - LLSDInventoryItem llsdItem = new LLSDInventoryItem(); - llsdItem.asset_id = invItem.AssetID; - llsdItem.created_at = invItem.CreationDate; - llsdItem.desc = invItem.Description; - llsdItem.flags = (int)invItem.Flags; - llsdItem.item_id = invItem.ID; - llsdItem.name = invItem.Name; - llsdItem.parent_id = invItem.Folder; - llsdItem.type = invItem.AssetType; - llsdItem.inv_type = invItem.InvType; - - llsdItem.permissions = new LLSDPermissions(); - llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid; - llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions; - llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions; - llsdItem.permissions.group_id = invItem.GroupID; - llsdItem.permissions.group_mask = (int)invItem.GroupPermissions; - llsdItem.permissions.is_owner_group = invItem.GroupOwned; - llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions; - llsdItem.permissions.owner_id = invItem.Owner; - llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions; - llsdItem.sale_info = new LLSDSaleInfo(); - llsdItem.sale_info.sale_price = invItem.SalePrice; - llsdItem.sale_info.sale_type = invItem.SaleType; - - return llsdItem; - } - } -} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs deleted file mode 100644 index 5d86557..0000000 --- a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using Nini.Config; -using OpenSim.Server.Base; -using OpenSim.Services.Interfaces; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Server.Handlers.Base; -using OpenMetaverse; - -namespace OpenSim.Capabilities.Handlers -{ - public class WebFetchInvDescServerConnector : ServiceConnector - { - private IInventoryService m_InventoryService; - private ILibraryService m_LibraryService; - private string m_ConfigName = "CapsService"; - - public WebFetchInvDescServerConnector(IConfigSource config, IHttpServer server, string configName) : - base(config, server, configName) - { - if (configName != String.Empty) - m_ConfigName = configName; - - IConfig serverConfig = config.Configs[m_ConfigName]; - if (serverConfig == null) - throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName)); - - string invService = serverConfig.GetString("InventoryService", String.Empty); - - if (invService == String.Empty) - throw new Exception("No InventoryService in config file"); - - Object[] args = new Object[] { config }; - m_InventoryService = - ServerUtils.LoadPlugin(invService, args); - - if (m_InventoryService == null) - throw new Exception(String.Format("Failed to load InventoryService from {0}; config is {1}", invService, m_ConfigName)); - - string libService = serverConfig.GetString("LibraryService", String.Empty); - m_LibraryService = - ServerUtils.LoadPlugin(libService, args); - - WebFetchInvDescHandler webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); - IRequestHandler reqHandler - = new RestStreamHandler( - "POST", - "/CAPS/WebFetchInvDesc/" /*+ UUID.Random()*/, - webFetchHandler.FetchInventoryDescendentsRequest, - "WebFetchInvDesc", - null); - server.AddStreamHandler(reqHandler); - } - - } -} diff --git a/OpenSim/Capabilities/LLSD.cs b/OpenSim/Capabilities/LLSD.cs index eec9e61..c59cede 100644 --- a/OpenSim/Capabilities/LLSD.cs +++ b/OpenSim/Capabilities/LLSD.cs @@ -68,7 +68,10 @@ namespace OpenSim.Framework.Capabilities /// public static object LLSDDeserialize(byte[] b) { - return LLSDDeserialize(new MemoryStream(b, false)); + using (MemoryStream ms = new MemoryStream(b, false)) + { + return LLSDDeserialize(ms); + } } /// @@ -78,21 +81,23 @@ namespace OpenSim.Framework.Capabilities /// public static object LLSDDeserialize(Stream st) { - XmlTextReader reader = new XmlTextReader(st); - reader.Read(); - SkipWS(reader); + using (XmlTextReader reader = new XmlTextReader(st)) + { + reader.Read(); + SkipWS(reader); - if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "llsd") - throw new LLSDParseException("Expected "); + if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "llsd") + throw new LLSDParseException("Expected "); - reader.Read(); - object ret = LLSDParseOne(reader); - SkipWS(reader); + reader.Read(); + object ret = LLSDParseOne(reader); + SkipWS(reader); - if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != "llsd") - throw new LLSDParseException("Expected "); + if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != "llsd") + throw new LLSDParseException("Expected "); - return ret; + return ret; + } } /// diff --git a/OpenSim/Capabilities/LLSDAvatarPicker.cs b/OpenSim/Capabilities/LLSDAvatarPicker.cs new file mode 100644 index 0000000..d0b3f3a --- /dev/null +++ b/OpenSim/Capabilities/LLSDAvatarPicker.cs @@ -0,0 +1,51 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using OpenMetaverse; + +namespace OpenSim.Framework.Capabilities +{ + [OSDMap] + public class LLSDAvatarPicker + { + public string next_page_url; + // an array of LLSDPerson + public OSDArray agents = new OSDArray(); + } + + [OSDMap] + public class LLSDPerson + { + public string username; + public string display_name; + //'display_name_next_update':d"1970-01-01T00:00:00Z" + public string legacy_first_name; + public string legacy_last_name; + public UUID id; + public bool is_display_name_default; + } +} \ No newline at end of file diff --git a/OpenSim/Capabilities/LLSDStreamHandler.cs b/OpenSim/Capabilities/LLSDStreamHandler.cs index 5df24b2..4fa1153 100644 --- a/OpenSim/Capabilities/LLSDStreamHandler.cs +++ b/OpenSim/Capabilities/LLSDStreamHandler.cs @@ -48,7 +48,7 @@ namespace OpenSim.Framework.Capabilities m_method = method; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { //Encoding encoding = Util.UTF8; 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; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] +[assembly: AssemblyVersion("0.7.6.*")] [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; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] +[assembly: AssemblyVersion("0.7.6.*")] [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 ReplyDelegate action) { WebRequest request = WebRequest.Create(requestUrl); - WebResponse response = null; request.Method = "POST"; @@ -64,16 +63,18 @@ namespace OpenSim.ConsoleClient { string reply = String.Empty; - response = request.EndGetResponse(ar); - - try + using (WebResponse response = request.EndGetResponse(ar)) { - StreamReader r = new StreamReader(response.GetResponseStream()); - reply = r.ReadToEnd(); + try + { + using (Stream s = response.GetResponseStream()) + using (StreamReader r = new StreamReader(s)) + reply = r.ReadToEnd(); - } - catch (System.InvalidOperationException) - { + } + catch (System.InvalidOperationException) + { + } } action(requestUrl, data, reply); diff --git a/OpenSim/Data/AssetDataBase.cs b/OpenSim/Data/AssetDataBase.cs index e1a810c..1bb432c 100644 --- a/OpenSim/Data/AssetDataBase.cs +++ b/OpenSim/Data/AssetDataBase.cs @@ -37,9 +37,8 @@ namespace OpenSim.Data public abstract class AssetDataBase : IAssetDataPlugin { public abstract AssetBase GetAsset(UUID uuid); - public abstract void StoreAsset(AssetBase asset); - public abstract bool ExistsAsset(UUID uuid); + public abstract bool[] AssetsExist(UUID[] uuids); public abstract List FetchAssetMetadataSet(int start, int count); diff --git a/OpenSim/Data/IAgentPreferencesData.cs b/OpenSim/Data/IAgentPreferencesData.cs new file mode 100644 index 0000000..8763299 --- /dev/null +++ b/OpenSim/Data/IAgentPreferencesData.cs @@ -0,0 +1,46 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse; +using OpenSim.Framework; + +namespace OpenSim.Data +{ + public class AgentPreferencesData + { + public Dictionary Data; + } + + public interface IAgentPreferencesData + { + bool Store(AgentPreferencesData data); + AgentPreferencesData GetPrefs(UUID agentID); + } +} + diff --git a/OpenSim/Data/IAssetData.cs b/OpenSim/Data/IAssetData.cs index f31b215c..a41e310 100644 --- a/OpenSim/Data/IAssetData.cs +++ b/OpenSim/Data/IAssetData.cs @@ -35,7 +35,7 @@ namespace OpenSim.Data { AssetBase GetAsset(UUID uuid); void StoreAsset(AssetBase asset); - bool ExistsAsset(UUID uuid); + bool[] AssetsExist(UUID[] uuids); List FetchAssetMetadataSet(int start, int count); void Initialise(string connect); bool Delete(string id); diff --git a/OpenSim/Data/IEstateDataStore.cs b/OpenSim/Data/IEstateDataStore.cs new file mode 100644 index 0000000..f9070ea --- /dev/null +++ b/OpenSim/Data/IEstateDataStore.cs @@ -0,0 +1,120 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Collections.Generic; +using OpenMetaverse; +using OpenSim.Framework; + +namespace OpenSim.Data +{ + public interface IEstateDataStore + { + /// + /// Initialise the data store. + /// + /// + void Initialise(string connectstring); + + /// + /// Load estate settings for a region. + /// + /// + /// If true, then an estate is created if one is not found. + /// + EstateSettings LoadEstateSettings(UUID regionID, bool create); + + /// + /// Load estate settings for an estate ID. + /// + /// + /// + EstateSettings LoadEstateSettings(int estateID); + + /// + /// Create a new estate. + /// + /// + /// A + /// + EstateSettings CreateNewEstate(); + + /// + /// Load/Get all estate settings. + /// + /// An empty list if no estates were found. + List LoadEstateSettingsAll(); + + /// + /// Store estate settings. + /// + /// + /// This is also called by EstateSettings.Save() + /// + void StoreEstateSettings(EstateSettings es); + + /// + /// Get estate IDs. + /// + /// Name of estate to search for. This is the exact name, no parttern matching is done. + /// + List GetEstates(string search); + + /// + /// Get the IDs of all estates owned by the given user. + /// + /// An empty list if no estates were found. + List GetEstatesByOwner(UUID ownerID); + + /// + /// Get the IDs of all estates. + /// + /// An empty list if no estates were found. + List GetEstatesAll(); + + /// + /// Link a region to an estate. + /// + /// + /// + /// true if the link succeeded, false otherwise + bool LinkRegion(UUID regionID, int estateID); + + /// + /// Get the UUIDs of all the regions in an estate. + /// + /// + /// + List GetRegions(int estateID); + + /// + /// Delete an estate + /// + /// + /// true if the delete succeeded, false otherwise + bool DeleteEstate(int estateID); + } +} \ No newline at end of file diff --git a/OpenSim/Data/IFSAssetData.cs b/OpenSim/Data/IFSAssetData.cs new file mode 100644 index 0000000..8751dc0 --- /dev/null +++ b/OpenSim/Data/IFSAssetData.cs @@ -0,0 +1,47 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Collections.Generic; +using OpenMetaverse; +using OpenSim.Framework; + +namespace OpenSim.Data +{ + public delegate string FSStoreDelegate(AssetBase asset, bool force); + + public interface IFSAssetDataPlugin : IPlugin + { + bool[] AssetsExist(UUID[] uuids); + void Initialise(string connect, string realm, int SkipAccessTimeDays); + bool Delete(string id); + + AssetMetadata Get(string id, out string hash); + bool Store(AssetMetadata metadata, string hash); + void Import(string conn, string table, int start, int count, bool force, FSStoreDelegate store); + int Count(); + } +} diff --git a/OpenSim/Data/IGridUserData.cs b/OpenSim/Data/IGridUserData.cs index e15a1f8..9afa477 100644 --- a/OpenSim/Data/IGridUserData.cs +++ b/OpenSim/Data/IGridUserData.cs @@ -50,6 +50,7 @@ namespace OpenSim.Data public interface IGridUserData { GridUserData Get(string userID); + GridUserData[] GetAll(string query); bool Store(GridUserData data); } } \ No newline at end of file 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 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Collections.Generic; +using OpenSim.Data; +using OpenMetaverse; + +namespace OpenSim.Data +{ + public class GroupData + { + public UUID GroupID; + public Dictionary Data; + } + + public class MembershipData + { + public UUID GroupID; + public string PrincipalID; + public Dictionary Data; + } + + public class RoleData + { + public UUID GroupID; + public UUID RoleID; + public Dictionary Data; + } + + public class RoleMembershipData + { + public UUID GroupID; + public UUID RoleID; + public string PrincipalID; + } + + public class PrincipalData + { + public string PrincipalID; + public UUID ActiveGroupID; + } + + public class InvitationData + { + public UUID InviteID; + public UUID GroupID; + public UUID RoleID; + public string PrincipalID; + public Dictionary Data; + } + + public class NoticeData + { + public UUID GroupID; + public UUID NoticeID; + public Dictionary Data; + } + + + public interface IGroupsData + { + // groups table + bool StoreGroup(GroupData data); + GroupData RetrieveGroup(UUID groupID); + GroupData RetrieveGroup(string name); + GroupData[] RetrieveGroups(string pattern); + bool DeleteGroup(UUID groupID); + int GroupsCount(); + + // membership table + MembershipData RetrieveMember(UUID groupID, string pricipalID); + MembershipData[] RetrieveMembers(UUID groupID); + MembershipData[] RetrieveMemberships(string pricipalID); + bool StoreMember(MembershipData data); + bool DeleteMember(UUID groupID, string pricipalID); + int MemberCount(UUID groupID); + + // roles table + bool StoreRole(RoleData data); + RoleData RetrieveRole(UUID groupID, UUID roleID); + RoleData[] RetrieveRoles(UUID groupID); + bool DeleteRole(UUID groupID, UUID roleID); + int RoleCount(UUID groupID); + + // rolememberhip table + RoleMembershipData[] RetrieveRolesMembers(UUID groupID); + RoleMembershipData[] RetrieveRoleMembers(UUID groupID, UUID roleID); + RoleMembershipData[] RetrieveMemberRoles(UUID groupID, string principalID); + RoleMembershipData RetrieveRoleMember(UUID groupID, UUID roleID, string principalID); + int RoleMemberCount(UUID groupID, UUID roleID); + bool StoreRoleMember(RoleMembershipData data); + bool DeleteRoleMember(RoleMembershipData data); + bool DeleteMemberAllRoles(UUID groupID, string principalID); + + // principals table + bool StorePrincipal(PrincipalData data); + PrincipalData RetrievePrincipal(string principalID); + bool DeletePrincipal(string principalID); + + // invites table + bool StoreInvitation(InvitationData data); + InvitationData RetrieveInvitation(UUID inviteID); + InvitationData RetrieveInvitation(UUID groupID, string principalID); + bool DeleteInvite(UUID inviteID); + void DeleteOldInvites(); + + // notices table + bool StoreNotice(NoticeData data); + NoticeData RetrieveNotice(UUID noticeID); + NoticeData[] RetrieveNotices(UUID groupID); + bool DeleteNotice(UUID noticeID); + void DeleteOldNotices(); + + // combinations + MembershipData RetrievePrincipalGroupMembership(string principalID, UUID groupID); + MembershipData[] RetrievePrincipalGroupMemberships(string principalID); + + // Misc + } +} diff --git a/OpenSim/Data/IHGTravelingData.cs b/OpenSim/Data/IHGTravelingData.cs new file mode 100644 index 0000000..452af7b --- /dev/null +++ b/OpenSim/Data/IHGTravelingData.cs @@ -0,0 +1,59 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse; +using OpenSim.Framework; + +namespace OpenSim.Data +{ + // This MUST be a ref type! + public class HGTravelingData + { + public UUID SessionID; + public UUID UserID; + public Dictionary Data; + + public HGTravelingData() + { + Data = new Dictionary(); + } + } + + /// + /// An interface for connecting to the user grid datastore + /// + public interface IHGTravelingData + { + HGTravelingData Get(UUID sessionID); + HGTravelingData[] GetSessions(UUID userID); + bool Store(HGTravelingData data); + bool Delete(UUID sessionID); + void DeleteOld(); + } +} \ No newline at end of file diff --git a/OpenSim/Data/IOfflineIMData.cs b/OpenSim/Data/IOfflineIMData.cs new file mode 100644 index 0000000..58501a3 --- /dev/null +++ b/OpenSim/Data/IOfflineIMData.cs @@ -0,0 +1,50 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Collections.Generic; +using OpenSim.Data; +using OpenMetaverse; + +namespace OpenSim.Data +{ + public class OfflineIMData + { + public UUID PrincipalID; + public UUID FromID; + public Dictionary Data; + } + + + public interface IOfflineIMData + { + OfflineIMData[] Get(string field, string val); + long GetCount(string field, string key); + bool Store(OfflineIMData data); + bool Delete(string field, string val); + void DeleteOld(); + } +} diff --git a/OpenSim/Data/IProfilesData.cs b/OpenSim/Data/IProfilesData.cs new file mode 100644 index 0000000..7fb075d --- /dev/null +++ b/OpenSim/Data/IProfilesData.cs @@ -0,0 +1,58 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; + +namespace OpenSim.Data +{ + + public interface IProfilesData + { + OSDArray GetClassifiedRecords(UUID creatorId); + bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result); + bool DeleteClassifiedRecord(UUID recordId); + OSDArray GetAvatarPicks(UUID avatarId); + UserProfilePick GetPickInfo(UUID avatarId, UUID pickId); + bool UpdatePicksRecord(UserProfilePick pick); + bool DeletePicksRecord(UUID pickId); + bool GetAvatarNotes(ref UserProfileNotes note); + bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result); + bool GetAvatarProperties(ref UserProfileProperties props, ref string result); + bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result); + bool UpdateAvatarInterests(UserProfileProperties up, ref string result); + bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result); + bool UpdateUserPreferences(ref UserPreferences pref, ref string result); + bool GetUserPreferences(ref UserPreferences pref, ref string result); + bool GetUserAppData(ref UserAppData props, ref string result); + bool SetUserAppData(UserAppData props, ref string result); + OSDArray GetUserImageAssets(UUID avatarId); + } +} + diff --git a/OpenSim/Data/IRegionData.cs b/OpenSim/Data/IRegionData.cs index 70e1065..ca9b327 100644 --- a/OpenSim/Data/IRegionData.cs +++ b/OpenSim/Data/IRegionData.cs @@ -52,14 +52,14 @@ namespace OpenSim.Data public int sizeY; /// - /// Return the x-coordinate of this region. + /// Return the x-coordinate of this region in region units. /// - public int coordX { get { return posX / (int)Constants.RegionSize; } } + public int coordX { get { return (int)Util.WorldToRegionLoc((uint)posX); } } /// - /// Return the y-coordinate of this region. + /// Return the y-coordinate of this region in region units. /// - public int coordY { get { return posY / (int)Constants.RegionSize; } } + public int coordY { get { return (int)Util.WorldToRegionLoc((uint)posY); } } public Dictionary Data; } @@ -81,6 +81,7 @@ namespace OpenSim.Data bool Delete(UUID regionID); List GetDefaultRegions(UUID scopeID); + List GetDefaultHypergridRegions(UUID scopeID); List GetFallbackRegions(UUID scopeID, int x, int y); List GetHyperlinks(UUID scopeID); } diff --git a/OpenSim/Data/IXAssetDataPlugin.cs b/OpenSim/Data/IXAssetDataPlugin.cs index 74ad6f4..2d24797 100644 --- a/OpenSim/Data/IXAssetDataPlugin.cs +++ b/OpenSim/Data/IXAssetDataPlugin.cs @@ -39,7 +39,7 @@ namespace OpenSim.Data { AssetBase GetAsset(UUID uuid); void StoreAsset(AssetBase asset); - bool ExistsAsset(UUID uuid); + bool[] AssetsExist(UUID[] uuids); List FetchAssetMetadataSet(int start, int count); void Initialise(string connect); bool Delete(string id); diff --git a/OpenSim/Data/IXGroupData.cs b/OpenSim/Data/IXGroupData.cs index 2965e8c..e5821ef 100644 --- a/OpenSim/Data/IXGroupData.cs +++ b/OpenSim/Data/IXGroupData.cs @@ -48,9 +48,57 @@ namespace OpenSim.Data public ulong everyonePowers; public ulong ownersPowers; + public Dictionary members = new Dictionary(); + public Dictionary notices = new Dictionary(); + public XGroup Clone() { - return (XGroup)MemberwiseClone(); + XGroup clone = (XGroup)MemberwiseClone(); + clone.members = new Dictionary(); + clone.notices = new Dictionary(); + + foreach (KeyValuePair kvp in members) + clone.members[kvp.Key] = kvp.Value.Clone(); + + foreach (KeyValuePair kvp in notices) + clone.notices[kvp.Key] = kvp.Value.Clone(); + + return clone; + } + } + + public class XGroupMember + { + public UUID agentID; + public UUID groupID; + public UUID roleID; + public bool acceptNotices = true; + public bool listInProfile = true; + + public XGroupMember Clone() + { + return (XGroupMember)MemberwiseClone(); + } + } + + public class XGroupNotice + { + public UUID groupID; + public UUID noticeID; + public uint timestamp; + public string fromName; + public string subject; + public string message; + public byte[] binaryBucket; + public bool hasAttachment; + public int assetType; + + public XGroupNotice Clone() + { + XGroupNotice clone = (XGroupNotice)MemberwiseClone(); + clone.binaryBucket = (byte[])binaryBucket.Clone(); + + return clone; } } @@ -58,14 +106,13 @@ namespace OpenSim.Data /// Early stub interface for groups data, not final. /// /// - /// Currently in-use only for regression test purposes. Needs to be filled out over time. + /// Currently in-use only for regression test purposes. /// public interface IXGroupData { bool StoreGroup(XGroup group); - XGroup[] GetGroups(string field, string val); - XGroup[] GetGroups(string[] fields, string[] vals); - bool DeleteGroups(string field, string val); - bool DeleteGroups(string[] fields, string[] vals); + XGroup GetGroup(UUID groupID); + Dictionary GetGroups(); + bool DeleteGroup(UUID groupID); } } \ No newline at end of file diff --git a/OpenSim/Data/MSSQL/MSSQLAssetData.cs b/OpenSim/Data/MSSQL/MSSQLAssetData.cs deleted file mode 100644 index c7488d8..0000000 --- a/OpenSim/Data/MSSQL/MSSQLAssetData.cs +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Data; -using System.Data.SqlClient; -using System.Reflection; -using System.Collections.Generic; -using OpenMetaverse; -using log4net; -using OpenSim.Framework; - -namespace OpenSim.Data.MSSQL -{ - /// - /// A MSSQL Interface for the Asset server - /// - public class MSSQLAssetData : AssetDataBase - { - private const string _migrationStore = "AssetStore"; - - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private long m_ticksToEpoch; - /// - /// Database manager - /// - private MSSQLManager m_database; - private string m_connectionString; - - #region IPlugin Members - - override public void Dispose() { } - - /// - /// Initialises asset interface - /// - // [Obsolete("Cannot be default-initialized!")] - override public void Initialise() - { - m_log.Info("[MSSQLAssetData]: " + Name + " cannot be default-initialized!"); - throw new PluginNotInitialisedException(Name); - } - - /// - /// Initialises asset interface - /// - /// - /// a string instead of file, if someone writes the support - /// - /// connect string - override public void Initialise(string connectionString) - { - m_ticksToEpoch = new System.DateTime(1970, 1, 1).Ticks; - - m_database = new MSSQLManager(connectionString); - m_connectionString = connectionString; - - //New migration to check for DB changes - m_database.CheckMigration(_migrationStore); - } - - /// - /// Database provider version. - /// - override public string Version - { - get { return m_database.getVersion(); } - } - - /// - /// The name of this DB provider. - /// - override public string Name - { - get { return "MSSQL Asset storage engine"; } - } - - #endregion - - #region IAssetDataPlugin Members - - /// - /// Fetch Asset from m_database - /// - /// the asset UUID - /// - override public AssetBase GetAsset(UUID assetID) - { - string sql = "SELECT * FROM assets WHERE id = @id"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(m_database.CreateParameter("id", assetID)); - conn.Open(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (reader.Read()) - { - AssetBase asset = new AssetBase( - DBGuid.FromDB(reader["id"]), - (string)reader["name"], - Convert.ToSByte(reader["assetType"]), - reader["creatorid"].ToString() - ); - // Region Main - asset.Description = (string)reader["description"]; - asset.Local = Convert.ToBoolean(reader["local"]); - asset.Temporary = Convert.ToBoolean(reader["temporary"]); - asset.Flags = (AssetFlags)(Convert.ToInt32(reader["asset_flags"])); - asset.Data = (byte[])reader["data"]; - return asset; - } - return null; // throw new Exception("No rows to return"); - } - } - } - - /// - /// Create asset in m_database - /// - /// the asset - override public void StoreAsset(AssetBase asset) - { - - string sql = - @"IF EXISTS(SELECT * FROM assets WHERE id=@id) - UPDATE assets set name = @name, description = @description, assetType = @assetType, - local = @local, temporary = @temporary, creatorid = @creatorid, data = @data - WHERE id=@id - ELSE - INSERT INTO assets - ([id], [name], [description], [assetType], [local], - [temporary], [create_time], [access_time], [creatorid], [asset_flags], [data]) - VALUES - (@id, @name, @description, @assetType, @local, - @temporary, @create_time, @access_time, @creatorid, @asset_flags, @data)"; - - string assetName = asset.Name; - if (asset.Name.Length > 64) - { - assetName = asset.Name.Substring(0, 64); - m_log.Warn("[ASSET DB]: Name field truncated from " + asset.Name.Length + " to " + assetName.Length + " characters on add"); - } - - string assetDescription = asset.Description; - if (asset.Description.Length > 64) - { - assetDescription = asset.Description.Substring(0, 64); - m_log.Warn("[ASSET DB]: Description field truncated from " + asset.Description.Length + " to " + assetDescription.Length + " characters on add"); - } - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand command = new SqlCommand(sql, conn)) - { - int now = (int)((System.DateTime.Now.Ticks - m_ticksToEpoch) / 10000000); - command.Parameters.Add(m_database.CreateParameter("id", asset.FullID)); - command.Parameters.Add(m_database.CreateParameter("name", assetName)); - command.Parameters.Add(m_database.CreateParameter("description", assetDescription)); - command.Parameters.Add(m_database.CreateParameter("assetType", asset.Type)); - command.Parameters.Add(m_database.CreateParameter("local", asset.Local)); - command.Parameters.Add(m_database.CreateParameter("temporary", asset.Temporary)); - command.Parameters.Add(m_database.CreateParameter("access_time", now)); - command.Parameters.Add(m_database.CreateParameter("create_time", now)); - command.Parameters.Add(m_database.CreateParameter("asset_flags", (int)asset.Flags)); - command.Parameters.Add(m_database.CreateParameter("creatorid", asset.Metadata.CreatorID)); - command.Parameters.Add(m_database.CreateParameter("data", asset.Data)); - conn.Open(); - try - { - command.ExecuteNonQuery(); - } - catch(Exception e) - { - m_log.Error("[ASSET DB]: Error storing item :" + e.Message); - } - } - } - - -// Commented out since currently unused - this probably should be called in GetAsset() -// private void UpdateAccessTime(AssetBase asset) -// { -// using (AutoClosingSqlCommand cmd = m_database.Query("UPDATE assets SET access_time = @access_time WHERE id=@id")) -// { -// int now = (int)((System.DateTime.Now.Ticks - m_ticksToEpoch) / 10000000); -// cmd.Parameters.AddWithValue("@id", asset.FullID.ToString()); -// cmd.Parameters.AddWithValue("@access_time", now); -// try -// { -// cmd.ExecuteNonQuery(); -// } -// catch (Exception e) -// { -// m_log.Error(e.ToString()); -// } -// } -// } - - /// - /// Check if asset exist in m_database - /// - /// - /// true if exist. - override public bool ExistsAsset(UUID uuid) - { - if (GetAsset(uuid) != null) - { - return true; - } - return false; - } - - /// - /// Returns a list of AssetMetadata objects. The list is a subset of - /// the entire data set offset by containing - /// elements. - /// - /// The number of results to discard from the total data set. - /// The number of rows the returned list should contain. - /// A list of AssetMetadata objects. - public override List FetchAssetMetadataSet(int start, int count) - { - List retList = new List(count); - string sql = @"WITH OrderedAssets AS - ( - SELECT id, name, description, assetType, temporary, creatorid, - RowNumber = ROW_NUMBER() OVER (ORDER BY id) - FROM assets - ) - SELECT * - FROM OrderedAssets - WHERE RowNumber BETWEEN @start AND @stop;"; - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(m_database.CreateParameter("start", start)); - cmd.Parameters.Add(m_database.CreateParameter("stop", start + count - 1)); - conn.Open(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - AssetMetadata metadata = new AssetMetadata(); - metadata.FullID = DBGuid.FromDB(reader["id"]); - metadata.Name = (string)reader["name"]; - metadata.Description = (string)reader["description"]; - metadata.Type = Convert.ToSByte(reader["assetType"]); - metadata.Temporary = Convert.ToBoolean(reader["temporary"]); - metadata.CreatorID = (string)reader["creatorid"]; - retList.Add(metadata); - } - } - } - - return retList; - } - - public override bool Delete(string id) - { - return false; - } - #endregion - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLAuthenticationData.cs b/OpenSim/Data/MSSQL/MSSQLAuthenticationData.cs deleted file mode 100644 index 1ae78c4..0000000 --- a/OpenSim/Data/MSSQL/MSSQLAuthenticationData.cs +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Data; -using OpenMetaverse; -using OpenSim.Framework; -using System.Data.SqlClient; -using System.Reflection; -using System.Text; - -namespace OpenSim.Data.MSSQL -{ - public class MSSQLAuthenticationData : IAuthenticationData - { - private string m_Realm; - private List m_ColumnNames = null; - private int m_LastExpire = 0; - private string m_ConnectionString; - private MSSQLManager m_database; - - public MSSQLAuthenticationData(string connectionString, string realm) - { - m_Realm = realm; - m_ConnectionString = connectionString; - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - { - conn.Open(); - Migration m = new Migration(conn, GetType().Assembly, "AuthStore"); - m_database = new MSSQLManager(m_ConnectionString); - m.Update(); - } - } - - public AuthenticationData Get(UUID principalID) - { - AuthenticationData ret = new AuthenticationData(); - ret.Data = new Dictionary(); - - string sql = string.Format("select * from {0} where UUID = @principalID", m_Realm); - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(m_database.CreateParameter("@principalID", principalID)); - conn.Open(); - using (SqlDataReader result = cmd.ExecuteReader()) - { - if (result.Read()) - { - ret.PrincipalID = principalID; - - if (m_ColumnNames == null) - { - m_ColumnNames = new List(); - - DataTable schemaTable = result.GetSchemaTable(); - foreach (DataRow row in schemaTable.Rows) - m_ColumnNames.Add(row["ColumnName"].ToString()); - } - - foreach (string s in m_ColumnNames) - { - if (s == "UUID") - continue; - - ret.Data[s] = result[s].ToString(); - } - return ret; - } - } - } - return null; - } - - public bool Store(AuthenticationData data) - { - if (data.Data.ContainsKey("UUID")) - data.Data.Remove("UUID"); - - string[] fields = new List(data.Data.Keys).ToArray(); - StringBuilder updateBuilder = new StringBuilder(); - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand()) - { - updateBuilder.AppendFormat("update {0} set ", m_Realm); - - bool first = true; - foreach (string field in fields) - { - if (!first) - updateBuilder.Append(", "); - updateBuilder.AppendFormat("{0} = @{0}",field); - - first = false; - cmd.Parameters.Add(m_database.CreateParameter("@" + field, data.Data[field])); - } - - updateBuilder.Append(" where UUID = @principalID"); - - cmd.CommandText = updateBuilder.ToString(); - cmd.Connection = conn; - cmd.Parameters.Add(m_database.CreateParameter("@principalID", data.PrincipalID)); - - conn.Open(); - if (cmd.ExecuteNonQuery() < 1) - { - StringBuilder insertBuilder = new StringBuilder(); - - insertBuilder.AppendFormat("insert into {0} (UUID, ", m_Realm); - insertBuilder.Append(String.Join(", ", fields)); - insertBuilder.Append(") values (@principalID, @"); - insertBuilder.Append(String.Join(", @", fields)); - insertBuilder.Append(")"); - - cmd.CommandText = insertBuilder.ToString(); - - if (cmd.ExecuteNonQuery() < 1) - { - return false; - } - } - } - return true; - } - - public bool SetDataItem(UUID principalID, string item, string value) - { - string sql = string.Format("update {0} set {1} = @{1} where UUID = @UUID", m_Realm, item); - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(m_database.CreateParameter("@" + item, value)); - conn.Open(); - if (cmd.ExecuteNonQuery() > 0) - return true; - } - return false; - } - - public bool SetToken(UUID principalID, string token, int lifetime) - { - if (System.Environment.TickCount - m_LastExpire > 30000) - DoExpire(); - - string sql = "insert into tokens (UUID, token, validity) values (@principalID, @token, @lifetime)"; - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(m_database.CreateParameter("@principalID", principalID)); - cmd.Parameters.Add(m_database.CreateParameter("@token", token)); - cmd.Parameters.Add(m_database.CreateParameter("@lifetime", DateTime.Now.AddMinutes(lifetime))); - conn.Open(); - - if (cmd.ExecuteNonQuery() > 0) - { - return true; - } - } - return false; - } - - public bool CheckToken(UUID principalID, string token, int lifetime) - { - if (System.Environment.TickCount - m_LastExpire > 30000) - DoExpire(); - - DateTime validDate = DateTime.Now.AddMinutes(lifetime); - string sql = "update tokens set validity = @validDate where UUID = @principalID and token = @token and validity > GetDate()"; - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(m_database.CreateParameter("@principalID", principalID)); - cmd.Parameters.Add(m_database.CreateParameter("@token", token)); - cmd.Parameters.Add(m_database.CreateParameter("@validDate", validDate)); - conn.Open(); - - if (cmd.ExecuteNonQuery() > 0) - { - return true; - } - } - return false; - } - - private void DoExpire() - { - DateTime currentDateTime = DateTime.Now; - string sql = "delete from tokens where validity < @currentDateTime"; - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - conn.Open(); - cmd.Parameters.Add(m_database.CreateParameter("@currentDateTime", currentDateTime)); - cmd.ExecuteNonQuery(); - } - m_LastExpire = System.Environment.TickCount; - } - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLAvatarData.cs b/OpenSim/Data/MSSQL/MSSQLAvatarData.cs deleted file mode 100644 index 301b424..0000000 --- a/OpenSim/Data/MSSQL/MSSQLAvatarData.cs +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Data; -using System.Reflection; -using System.Threading; -using log4net; -using OpenMetaverse; -using OpenSim.Framework; -using System.Data.SqlClient; - -namespace OpenSim.Data.MSSQL -{ - /// - /// A MSSQL Interface for Avatar Storage - /// - public class MSSQLAvatarData : MSSQLGenericTableHandler, - IAvatarData - { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - public MSSQLAvatarData(string connectionString, string realm) : - base(connectionString, realm, "Avatar") - { - } - - public bool Delete(UUID principalID, string name) - { - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand()) - { - - cmd.CommandText = String.Format("DELETE FROM {0} where [PrincipalID] = @PrincipalID and [Name] = @Name", m_Realm); - cmd.Parameters.Add(m_database.CreateParameter("@PrincipalID", principalID.ToString())); - cmd.Parameters.Add(m_database.CreateParameter("@Name", name)); - cmd.Connection = conn; - conn.Open(); - if (cmd.ExecuteNonQuery() > 0) - return true; - - return false; - } - } - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLEstateData.cs b/OpenSim/Data/MSSQL/MSSQLEstateData.cs deleted file mode 100644 index 1faa249..0000000 --- a/OpenSim/Data/MSSQL/MSSQLEstateData.cs +++ /dev/null @@ -1,577 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.SqlClient; -using System.Reflection; -using log4net; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; - -namespace OpenSim.Data.MSSQL -{ - public class MSSQLEstateStore : IEstateDataStore - { - private const string _migrationStore = "EstateStore"; - - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private MSSQLManager _Database; - private string m_connectionString; - private FieldInfo[] _Fields; - private Dictionary _FieldMap = new Dictionary(); - - #region Public methods - - public MSSQLEstateStore() - { - } - - public MSSQLEstateStore(string connectionString) - { - Initialise(connectionString); - } - - /// - /// Initialises the estatedata class. - /// - /// connectionString. - public void Initialise(string connectionString) - { - if (!string.IsNullOrEmpty(connectionString)) - { - m_connectionString = connectionString; - _Database = new MSSQLManager(connectionString); - } - - //Migration settings - using (SqlConnection conn = new SqlConnection(m_connectionString)) - { - conn.Open(); - Migration m = new Migration(conn, GetType().Assembly, "EstateStore"); - m.Update(); - } - - //Interesting way to get parameters! Maybe implement that also with other types - Type t = typeof(EstateSettings); - _Fields = t.GetFields(BindingFlags.NonPublic | - BindingFlags.Instance | - BindingFlags.DeclaredOnly); - - foreach (FieldInfo f in _Fields) - { - if (f.Name.Substring(0, 2) == "m_") - _FieldMap[f.Name.Substring(2)] = f; - } - } - - /// - /// Loads the estate settings. - /// - /// region ID. - /// - public EstateSettings LoadEstateSettings(UUID regionID, bool create) - { - EstateSettings es = new EstateSettings(); - - string sql = "select estate_settings." + String.Join(",estate_settings.", FieldList) + " from estate_map left join estate_settings on estate_map.EstateID = estate_settings.EstateID where estate_settings.EstateID is not null and RegionID = @RegionID"; - - bool insertEstate = false; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@RegionID", regionID)); - conn.Open(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (reader.Read()) - { - foreach (string name in FieldList) - { - FieldInfo f = _FieldMap[name]; - object v = reader[name]; - if (f.FieldType == typeof(bool)) - { - f.SetValue(es, Convert.ToInt32(v) != 0); - } - else if (f.FieldType == typeof(UUID)) - { - f.SetValue(es, new UUID((Guid)v)); // uuid); - } - else if (f.FieldType == typeof(string)) - { - f.SetValue(es, v.ToString()); - } - else if (f.FieldType == typeof(UInt32)) - { - f.SetValue(es, Convert.ToUInt32(v)); - } - else if (f.FieldType == typeof(Single)) - { - f.SetValue(es, Convert.ToSingle(v)); - } - else - f.SetValue(es, v); - } - } - else - { - insertEstate = true; - } - } - } - - if (insertEstate && create) - { - DoCreate(es); - LinkRegion(regionID, (int)es.EstateID); - } - - LoadBanList(es); - - es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers"); - es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users"); - es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups"); - - //Set event - es.OnSave += StoreEstateSettings; - return es; - } - - public EstateSettings CreateNewEstate() - { - EstateSettings es = new EstateSettings(); - es.OnSave += StoreEstateSettings; - - DoCreate(es); - - LoadBanList(es); - - es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers"); - es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users"); - es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups"); - - return es; - } - - private void DoCreate(EstateSettings es) - { - List names = new List(FieldList); - - names.Remove("EstateID"); - - string sql = string.Format("insert into estate_settings ({0}) values ( @{1})", String.Join(",", names.ToArray()), String.Join(", @", names.ToArray())); - - //_Log.Debug("[DB ESTATE]: SQL: " + sql); - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand insertCommand = new SqlCommand(sql, conn)) - { - insertCommand.CommandText = sql + " SET @ID = SCOPE_IDENTITY()"; - - foreach (string name in names) - { - insertCommand.Parameters.Add(_Database.CreateParameter("@" + name, _FieldMap[name].GetValue(es))); - } - SqlParameter idParameter = new SqlParameter("@ID", SqlDbType.Int); - idParameter.Direction = ParameterDirection.Output; - insertCommand.Parameters.Add(idParameter); - conn.Open(); - insertCommand.ExecuteNonQuery(); - - es.EstateID = Convert.ToUInt32(idParameter.Value); - } - - //TODO check if this is needed?? - es.Save(); - } - - /// - /// Stores the estate settings. - /// - /// estate settings - public void StoreEstateSettings(EstateSettings es) - { - List names = new List(FieldList); - - names.Remove("EstateID"); - - string sql = string.Format("UPDATE estate_settings SET "); - foreach (string name in names) - { - sql += name + " = @" + name + ", "; - } - sql = sql.Remove(sql.LastIndexOf(",")); - sql += " WHERE EstateID = @EstateID"; - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - foreach (string name in names) - { - cmd.Parameters.Add(_Database.CreateParameter("@" + name, _FieldMap[name].GetValue(es))); - } - - cmd.Parameters.Add(_Database.CreateParameter("@EstateID", es.EstateID)); - conn.Open(); - cmd.ExecuteNonQuery(); - } - - SaveBanList(es); - SaveUUIDList(es.EstateID, "estate_managers", es.EstateManagers); - SaveUUIDList(es.EstateID, "estate_users", es.EstateAccess); - SaveUUIDList(es.EstateID, "estate_groups", es.EstateGroups); - } - - #endregion - - #region Private methods - - private string[] FieldList - { - get { return new List(_FieldMap.Keys).ToArray(); } - } - - private void LoadBanList(EstateSettings es) - { - es.ClearBans(); - - string sql = "select bannedUUID from estateban where EstateID = @EstateID"; - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - SqlParameter idParameter = new SqlParameter("@EstateID", SqlDbType.Int); - idParameter.Value = es.EstateID; - cmd.Parameters.Add(idParameter); - conn.Open(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - EstateBan eb = new EstateBan(); - - eb.BannedUserID = new UUID((Guid)reader["bannedUUID"]); //uuid; - eb.BannedHostAddress = "0.0.0.0"; - eb.BannedHostIPMask = "0.0.0.0"; - es.AddBan(eb); - } - } - } - } - - private UUID[] LoadUUIDList(uint estateID, string table) - { - List uuids = new List(); - - string sql = string.Format("select uuid from {0} where EstateID = @EstateID", table); - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@EstateID", estateID)); - conn.Open(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - uuids.Add(new UUID((Guid)reader["uuid"])); //uuid); - } - } - } - - return uuids.ToArray(); - } - - private void SaveBanList(EstateSettings es) - { - //Delete first - using (SqlConnection conn = new SqlConnection(m_connectionString)) - { - conn.Open(); - using (SqlCommand cmd = conn.CreateCommand()) - { - cmd.CommandText = "delete from estateban where EstateID = @EstateID"; - cmd.Parameters.AddWithValue("@EstateID", (int)es.EstateID); - cmd.ExecuteNonQuery(); - - //Insert after - cmd.CommandText = "insert into estateban (EstateID, bannedUUID,bannedIp, bannedIpHostMask, bannedNameMask) values ( @EstateID, @bannedUUID, '','','' )"; - cmd.Parameters.AddWithValue("@bannedUUID", Guid.Empty); - foreach (EstateBan b in es.EstateBans) - { - cmd.Parameters["@bannedUUID"].Value = b.BannedUserID.Guid; - cmd.ExecuteNonQuery(); - } - } - } - } - - private void SaveUUIDList(uint estateID, string table, UUID[] data) - { - using (SqlConnection conn = new SqlConnection(m_connectionString)) - { - conn.Open(); - using (SqlCommand cmd = conn.CreateCommand()) - { - cmd.Parameters.AddWithValue("@EstateID", (int)estateID); - cmd.CommandText = string.Format("delete from {0} where EstateID = @EstateID", table); - cmd.ExecuteNonQuery(); - - cmd.CommandText = string.Format("insert into {0} (EstateID, uuid) values ( @EstateID, @uuid )", table); - cmd.Parameters.AddWithValue("@uuid", Guid.Empty); - foreach (UUID uuid in data) - { - cmd.Parameters["@uuid"].Value = uuid.Guid; //.ToString(); //TODO check if this works - cmd.ExecuteNonQuery(); - } - } - } - } - - public EstateSettings LoadEstateSettings(int estateID) - { - EstateSettings es = new EstateSettings(); - string sql = "select estate_settings." + String.Join(",estate_settings.", FieldList) + " from estate_settings where EstateID = @EstateID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - { - conn.Open(); - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.AddWithValue("@EstateID", (int)estateID); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (reader.Read()) - { - foreach (string name in FieldList) - { - FieldInfo f = _FieldMap[name]; - object v = reader[name]; - if (f.FieldType == typeof(bool)) - { - f.SetValue(es, Convert.ToInt32(v) != 0); - } - else if (f.FieldType == typeof(UUID)) - { - f.SetValue(es, new UUID((Guid)v)); // uuid); - } - else if (f.FieldType == typeof(string)) - { - f.SetValue(es, v.ToString()); - } - else if (f.FieldType == typeof(UInt32)) - { - f.SetValue(es, Convert.ToUInt32(v)); - } - else if (f.FieldType == typeof(Single)) - { - f.SetValue(es, Convert.ToSingle(v)); - } - else - f.SetValue(es, v); - } - } - - } - } - } - LoadBanList(es); - - es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers"); - es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users"); - es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups"); - - //Set event - es.OnSave += StoreEstateSettings; - return es; - - } - - public List LoadEstateSettingsAll() - { - List allEstateSettings = new List(); - - List allEstateIds = GetEstatesAll(); - - foreach (int estateId in allEstateIds) - allEstateSettings.Add(LoadEstateSettings(estateId)); - - return allEstateSettings; - } - - public List GetEstates(string search) - { - List result = new List(); - string sql = "select estateID from estate_settings where EstateName = @EstateName"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - { - conn.Open(); - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.AddWithValue("@EstateName", search); - - using (IDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - result.Add(Convert.ToInt32(reader["EstateID"])); - } - reader.Close(); - } - } - } - - return result; - } - - public List GetEstatesAll() - { - List result = new List(); - string sql = "select estateID from estate_settings"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - { - conn.Open(); - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - using (IDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - result.Add(Convert.ToInt32(reader["EstateID"])); - } - reader.Close(); - } - } - } - - return result; - } - - public List GetEstatesByOwner(UUID ownerID) - { - List result = new List(); - string sql = "select estateID from estate_settings where EstateOwner = @EstateOwner"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - { - conn.Open(); - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.AddWithValue("@EstateOwner", ownerID); - - using (IDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - result.Add(Convert.ToInt32(reader["EstateID"])); - } - reader.Close(); - } - } - } - - return result; - } - - public bool LinkRegion(UUID regionID, int estateID) - { - string deleteSQL = "delete from estate_map where RegionID = @RegionID"; - string insertSQL = "insert into estate_map values (@RegionID, @EstateID)"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - { - conn.Open(); - SqlTransaction transaction = conn.BeginTransaction(); - - try - { - using (SqlCommand cmd = new SqlCommand(deleteSQL, conn)) - { - cmd.Transaction = transaction; - cmd.Parameters.AddWithValue("@RegionID", regionID.Guid); - - cmd.ExecuteNonQuery(); - } - - using (SqlCommand cmd = new SqlCommand(insertSQL, conn)) - { - cmd.Transaction = transaction; - cmd.Parameters.AddWithValue("@RegionID", regionID.Guid); - cmd.Parameters.AddWithValue("@EstateID", estateID); - - int ret = cmd.ExecuteNonQuery(); - - if (ret != 0) - transaction.Commit(); - else - transaction.Rollback(); - - return (ret != 0); - } - } - catch (Exception ex) - { - m_log.Error("[REGION DB]: LinkRegion failed: " + ex.Message); - transaction.Rollback(); - } - } - return false; - } - - public List GetRegions(int estateID) - { - List result = new List(); - string sql = "select RegionID from estate_map where EstateID = @EstateID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - { - conn.Open(); - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.AddWithValue("@EstateID", estateID); - - using (IDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - result.Add(DBGuid.FromDB(reader["RegionID"])); - } - reader.Close(); - } - } - } - - return result; - } - - public bool DeleteEstate(int estateID) - { - // TODO: Implementation! - return false; - } - #endregion - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLFriendsData.cs b/OpenSim/Data/MSSQL/MSSQLFriendsData.cs deleted file mode 100644 index fef6978..0000000 --- a/OpenSim/Data/MSSQL/MSSQLFriendsData.cs +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Data; -using OpenMetaverse; -using OpenSim.Framework; -using System.Data.SqlClient; -using System.Reflection; -using System.Text; - -namespace OpenSim.Data.MSSQL -{ - public class MSSQLFriendsData : MSSQLGenericTableHandler, IFriendsData - { - public MSSQLFriendsData(string connectionString, string realm) - : base(connectionString, realm, "FriendsStore") - { - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - { - conn.Open(); - Migration m = new Migration(conn, GetType().Assembly, "FriendsStore"); - m.Update(); - } - } - - public bool Delete(UUID principalID, string friend) - { - return Delete(principalID.ToString(), friend); - } - - public bool Delete(string principalID, string friend) - { - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand()) - { - cmd.CommandText = String.Format("delete from {0} where PrincipalID = @PrincipalID and Friend = @Friend", m_Realm); - cmd.Parameters.Add(m_database.CreateParameter("@PrincipalID", principalID.ToString())); - cmd.Parameters.Add(m_database.CreateParameter("@Friend", friend)); - cmd.Connection = conn; - conn.Open(); - cmd.ExecuteNonQuery(); - - return true; - } - } - - public FriendsData[] GetFriends(UUID principalID) - { - return GetFriends(principalID.ToString()); - } - - public FriendsData[] GetFriends(string principalID) - { - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand()) - { - - cmd.CommandText = String.Format("select a.*,case when b.Flags is null then -1 else b.Flags end as TheirFlags from {0} as a left join {0} as b on a.PrincipalID = b.Friend and a.Friend = b.PrincipalID where a.PrincipalID = @PrincipalID", m_Realm); - cmd.Parameters.Add(m_database.CreateParameter("@PrincipalID", principalID.ToString())); - cmd.Connection = conn; - conn.Open(); - return DoQuery(cmd); - } - } - - public FriendsData[] GetFriends(Guid principalID) - { - return GetFriends(principalID.ToString()); - } - - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs b/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs deleted file mode 100644 index 4145d95..0000000 --- a/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Data; -using System.Reflection; -using log4net; -using System.Data.SqlClient; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; -using System.Text; - -namespace OpenSim.Data.MSSQL -{ - public class MSSQLGenericTableHandler where T : class, new() - { -// private static readonly ILog m_log = -// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - protected string m_ConnectionString; - protected MSSQLManager m_database; //used for parameter type translation - protected Dictionary m_Fields = - new Dictionary(); - - protected List m_ColumnNames = null; - protected string m_Realm; - protected FieldInfo m_DataField = null; - - public MSSQLGenericTableHandler(string connectionString, - string realm, string storeName) - { - m_Realm = realm; - - m_ConnectionString = connectionString; - - if (storeName != String.Empty) - { - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - { - conn.Open(); - Migration m = new Migration(conn, GetType().Assembly, storeName); - m.Update(); - } - - } - m_database = new MSSQLManager(m_ConnectionString); - - Type t = typeof(T); - FieldInfo[] fields = t.GetFields(BindingFlags.Public | - BindingFlags.Instance | - BindingFlags.DeclaredOnly); - - if (fields.Length == 0) - return; - - foreach (FieldInfo f in fields) - { - if (f.Name != "Data") - m_Fields[f.Name] = f; - else - m_DataField = f; - } - - } - - private void CheckColumnNames(SqlDataReader reader) - { - if (m_ColumnNames != null) - return; - - m_ColumnNames = new List(); - - DataTable schemaTable = reader.GetSchemaTable(); - foreach (DataRow row in schemaTable.Rows) - { - if (row["ColumnName"] != null && - (!m_Fields.ContainsKey(row["ColumnName"].ToString()))) - m_ColumnNames.Add(row["ColumnName"].ToString()); - - } - } - - private List GetConstraints() - { - List constraints = new List(); - string query = string.Format(@"SELECT - COL_NAME(ic.object_id,ic.column_id) AS column_name - FROM sys.indexes AS i - INNER JOIN sys.index_columns AS ic - ON i.object_id = ic.object_id AND i.index_id = ic.index_id - WHERE i.is_primary_key = 1 - AND i.object_id = OBJECT_ID('{0}');", m_Realm); - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand(query, conn)) - { - conn.Open(); - using (SqlDataReader rdr = cmd.ExecuteReader()) - { - while (rdr.Read()) - { - // query produces 0 to many rows of single column, so always add the first item in each row - constraints.Add((string)rdr[0]); - } - } - return constraints; - } - } - - public virtual T[] Get(string field, string key) - { - return Get(new string[] { field }, new string[] { key }); - } - - public virtual T[] Get(string[] fields, string[] keys) - { - if (fields.Length != keys.Length) - return new T[0]; - - List terms = new List(); - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand()) - { - - for (int i = 0; i < fields.Length; i++) - { - cmd.Parameters.Add(m_database.CreateParameter(fields[i], keys[i])); - terms.Add("[" + fields[i] + "] = @" + fields[i]); - } - - string where = String.Join(" AND ", terms.ToArray()); - - string query = String.Format("SELECT * FROM {0} WHERE {1}", - m_Realm, where); - - cmd.Connection = conn; - cmd.CommandText = query; - conn.Open(); - return DoQuery(cmd); - } - } - - protected T[] DoQuery(SqlCommand cmd) - { - List result = new List(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (reader == null) - return new T[0]; - - CheckColumnNames(reader); - - while (reader.Read()) - { - T row = new T(); - - foreach (string name in m_Fields.Keys) - { - if (m_Fields[name].GetValue(row) is bool) - { - int v = Convert.ToInt32(reader[name]); - m_Fields[name].SetValue(row, v != 0 ? true : false); - } - else if (m_Fields[name].GetValue(row) is UUID) - { - UUID uuid = UUID.Zero; - - UUID.TryParse(reader[name].ToString(), out uuid); - m_Fields[name].SetValue(row, uuid); - } - else if (m_Fields[name].GetValue(row) is int) - { - int v = Convert.ToInt32(reader[name]); - m_Fields[name].SetValue(row, v); - } - else - { - m_Fields[name].SetValue(row, reader[name]); - } - } - - if (m_DataField != null) - { - Dictionary data = - new Dictionary(); - - foreach (string col in m_ColumnNames) - { - data[col] = reader[col].ToString(); - if (data[col] == null) - data[col] = String.Empty; - } - - m_DataField.SetValue(row, data); - } - - result.Add(row); - } - return result.ToArray(); - } - } - - public virtual T[] Get(string where) - { - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand()) - { - - string query = String.Format("SELECT * FROM {0} WHERE {1}", - m_Realm, where); - cmd.Connection = conn; - cmd.CommandText = query; - - //m_log.WarnFormat("[MSSQLGenericTable]: SELECT {0} WHERE {1}", m_Realm, where); - - conn.Open(); - return DoQuery(cmd); - } - } - - public virtual bool Store(T row) - { - List constraintFields = GetConstraints(); - List> constraints = new List>(); - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand()) - { - - StringBuilder query = new StringBuilder(); - List names = new List(); - List values = new List(); - - foreach (FieldInfo fi in m_Fields.Values) - { - names.Add(fi.Name); - values.Add("@" + fi.Name); - // Temporarily return more information about what field is unexpectedly null for - // http://opensimulator.org/mantis/view.php?id=5403. This might be due to a bug in the - // InventoryTransferModule or we may be required to substitute a DBNull here. - if (fi.GetValue(row) == null) - throw new NullReferenceException( - string.Format( - "[MSSQL GENERIC TABLE HANDLER]: Trying to store field {0} for {1} which is unexpectedly null", - fi.Name, row)); - - if (constraintFields.Count > 0 && constraintFields.Contains(fi.Name)) - { - constraints.Add(new KeyValuePair(fi.Name, fi.GetValue(row).ToString())); - } - cmd.Parameters.Add(m_database.CreateParameter(fi.Name, fi.GetValue(row).ToString())); - } - - if (m_DataField != null) - { - Dictionary data = - (Dictionary)m_DataField.GetValue(row); - - foreach (KeyValuePair kvp in data) - { - if (constraintFields.Count > 0 && constraintFields.Contains(kvp.Key)) - { - constraints.Add(new KeyValuePair(kvp.Key, kvp.Key)); - } - names.Add(kvp.Key); - values.Add("@" + kvp.Key); - cmd.Parameters.Add(m_database.CreateParameter("@" + kvp.Key, kvp.Value)); - } - - } - - query.AppendFormat("UPDATE {0} SET ", m_Realm); - int i = 0; - for (i = 0; i < names.Count - 1; i++) - { - query.AppendFormat("[{0}] = {1}, ", names[i], values[i]); - } - query.AppendFormat("[{0}] = {1} ", names[i], values[i]); - if (constraints.Count > 0) - { - List terms = new List(); - for (int j = 0; j < constraints.Count; j++) - { - terms.Add(" [" + constraints[j].Key + "] = @" + constraints[j].Key); - } - string where = String.Join(" AND ", terms.ToArray()); - query.AppendFormat(" WHERE {0} ", where); - - } - cmd.Connection = conn; - cmd.CommandText = query.ToString(); - - conn.Open(); - if (cmd.ExecuteNonQuery() > 0) - { - //m_log.WarnFormat("[MSSQLGenericTable]: Updating {0}", m_Realm); - return true; - } - else - { - // assume record has not yet been inserted - - query = new StringBuilder(); - query.AppendFormat("INSERT INTO {0} ([", m_Realm); - query.Append(String.Join("],[", names.ToArray())); - query.Append("]) values (" + String.Join(",", values.ToArray()) + ")"); - cmd.Connection = conn; - cmd.CommandText = query.ToString(); - //m_log.WarnFormat("[MSSQLGenericTable]: Inserting into {0}", m_Realm); - if (conn.State != ConnectionState.Open) - conn.Open(); - if (cmd.ExecuteNonQuery() > 0) - return true; - } - - return false; - } - } - - public virtual bool Delete(string field, string key) - { - return Delete(new string[] { field }, new string[] { key }); - } - - public virtual bool Delete(string[] fields, string[] keys) - { - if (fields.Length != keys.Length) - return false; - - List terms = new List(); - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand()) - { - for (int i = 0; i < fields.Length; i++) - { - cmd.Parameters.Add(m_database.CreateParameter(fields[i], keys[i])); - terms.Add("[" + fields[i] + "] = @" + fields[i]); - } - - string where = String.Join(" AND ", terms.ToArray()); - - string query = String.Format("DELETE FROM {0} WHERE {1}", m_Realm, where); - - cmd.Connection = conn; - cmd.CommandText = query; - conn.Open(); - - if (cmd.ExecuteNonQuery() > 0) - { - //m_log.Warn("[MSSQLGenericTable]: " + deleteCommand); - return true; - } - return false; - } - } - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs b/OpenSim/Data/MSSQL/MSSQLGridUserData.cs deleted file mode 100644 index 9e215f9..0000000 --- a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Data; -using System.Reflection; -using System.Threading; -using log4net; -using OpenMetaverse; -using OpenSim.Framework; -using System.Data.SqlClient; - -namespace OpenSim.Data.MSSQL -{ - /// - /// A MSSQL Interface for Avatar Storage - /// - public class MSSQLGridUserData : MSSQLGenericTableHandler, - IGridUserData - { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - public MSSQLGridUserData(string connectionString, string realm) : - base(connectionString, realm, "GridUserStore") - { - } - - public GridUserData Get(string userID) - { - GridUserData[] ret = Get("UserID", userID); - - if (ret.Length == 0) - return null; - - return ret[0]; - } - - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLInventoryData.cs b/OpenSim/Data/MSSQL/MSSQLInventoryData.cs deleted file mode 100644 index 961593f..0000000 --- a/OpenSim/Data/MSSQL/MSSQLInventoryData.cs +++ /dev/null @@ -1,831 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.SqlClient; -using System.Reflection; -using log4net; -using OpenMetaverse; -using OpenSim.Framework; - -namespace OpenSim.Data.MSSQL -{ - /// - /// A MSSQL interface for the inventory server - /// - public class MSSQLInventoryData : IInventoryDataPlugin - { - private const string _migrationStore = "InventoryStore"; - - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// The database manager - /// - private MSSQLManager database; - private string m_connectionString; - - #region IPlugin members - - [Obsolete("Cannot be default-initialized!")] - public void Initialise() - { - m_log.Info("[MSSQLInventoryData]: " + Name + " cannot be default-initialized!"); - throw new PluginNotInitialisedException(Name); - } - - /// - /// Loads and initialises the MSSQL inventory storage interface - /// - /// connect string - /// use mssql_connection.ini - public void Initialise(string connectionString) - { - m_connectionString = connectionString; - database = new MSSQLManager(connectionString); - - //New migrations check of store - database.CheckMigration(_migrationStore); - } - - /// - /// The name of this DB provider - /// - /// A string containing the name of the DB provider - public string Name - { - get { return "MSSQL Inventory Data Interface"; } - } - - /// - /// Closes this DB provider - /// - public void Dispose() - { - database = null; - } - - /// - /// Returns the version of this DB provider - /// - /// A string containing the DB provider - public string Version - { - get { return database.getVersion(); } - } - - #endregion - - #region Folder methods - - /// - /// Returns a list of the root folders within a users inventory - /// - /// The user whos inventory is to be searched - /// A list of folder objects - public List getUserRootFolders(UUID user) - { - if (user == UUID.Zero) - return new List(); - - return getInventoryFolders(UUID.Zero, user); - } - - /// - /// see InventoryItemBase.getUserRootFolder - /// - /// the User UUID - /// - public InventoryFolderBase getUserRootFolder(UUID user) - { - List items = getUserRootFolders(user); - - InventoryFolderBase rootFolder = null; - - // There should only ever be one root folder for a user. However, if there's more - // than one we'll simply use the first one rather than failing. It would be even - // nicer to print some message to this effect, but this feels like it's too low a - // to put such a message out, and it's too minor right now to spare the time to - // suitably refactor. - if (items.Count > 0) - { - rootFolder = items[0]; - } - - return rootFolder; - } - - /// - /// Returns a list of folders in a users inventory contained within the specified folder - /// - /// The folder to search - /// A list of inventory folders - public List getInventoryFolders(UUID parentID) - { - return getInventoryFolders(parentID, UUID.Zero); - } - - /// - /// Returns a specified inventory folder - /// - /// The folder to return - /// A folder class - public InventoryFolderBase getInventoryFolder(UUID folderID) - { - string sql = "SELECT * FROM inventoryfolders WHERE folderID = @folderID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(database.CreateParameter("folderID", folderID)); - conn.Open(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (reader.Read()) - { - return readInventoryFolder(reader); - } - } - } - m_log.InfoFormat("[INVENTORY DB] : Found no inventory folder with ID : {0}", folderID); - return null; - } - - /// - /// Returns all child folders in the hierarchy from the parent folder and down. - /// Does not return the parent folder itself. - /// - /// The folder to get subfolders for - /// A list of inventory folders - public List getFolderHierarchy(UUID parentID) - { - //Note maybe change this to use a Dataset that loading in all folders of a user and then go throw it that way. - //Note this is changed so it opens only one connection to the database and not everytime it wants to get data. - - /* NOTE: the implementation below is very inefficient (makes a separate request to get subfolders for - * every found folder, recursively). Inventory code for other DBs has been already rewritten to get ALL - * inventory for a specific user at once. - * - * Meanwhile, one little thing is corrected: getFolderHierarchy(UUID.Zero) doesn't make sense and should never - * be used, so check for that and return an empty list. - */ - - List folders = new List(); - - if (parentID == UUID.Zero) - return folders; - - string sql = "SELECT * FROM inventoryfolders WHERE parentFolderID = @parentID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(database.CreateParameter("@parentID", parentID)); - conn.Open(); - folders.AddRange(getInventoryFolders(cmd)); - - List tempFolders = new List(); - - foreach (InventoryFolderBase folderBase in folders) - { - tempFolders.AddRange(getFolderHierarchy(folderBase.ID, cmd)); - } - if (tempFolders.Count > 0) - { - folders.AddRange(tempFolders); - } - } - return folders; - } - - /// - /// Creates a new inventory folder - /// - /// Folder to create - public void addInventoryFolder(InventoryFolderBase folder) - { - string sql = @"INSERT INTO inventoryfolders ([folderID], [agentID], [parentFolderID], [folderName], [type], [version]) - VALUES (@folderID, @agentID, @parentFolderID, @folderName, @type, @version);"; - - string folderName = folder.Name; - if (folderName.Length > 64) - { - folderName = folderName.Substring(0, 64); - m_log.Warn("[INVENTORY DB]: Name field truncated from " + folder.Name.Length.ToString() + " to " + folderName.Length + " characters on add"); - } - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(database.CreateParameter("folderID", folder.ID)); - cmd.Parameters.Add(database.CreateParameter("agentID", folder.Owner)); - cmd.Parameters.Add(database.CreateParameter("parentFolderID", folder.ParentID)); - cmd.Parameters.Add(database.CreateParameter("folderName", folderName)); - cmd.Parameters.Add(database.CreateParameter("type", folder.Type)); - cmd.Parameters.Add(database.CreateParameter("version", folder.Version)); - conn.Open(); - try - { - cmd.ExecuteNonQuery(); - } - catch (Exception e) - { - m_log.ErrorFormat("[INVENTORY DB]: Error : {0}", e.Message); - } - } - } - - /// - /// Updates an inventory folder - /// - /// Folder to update - public void updateInventoryFolder(InventoryFolderBase folder) - { - string sql = @"UPDATE inventoryfolders SET agentID = @agentID, - parentFolderID = @parentFolderID, - folderName = @folderName, - type = @type, - version = @version - WHERE folderID = @folderID"; - - string folderName = folder.Name; - if (folderName.Length > 64) - { - folderName = folderName.Substring(0, 64); - m_log.Warn("[INVENTORY DB]: Name field truncated from " + folder.Name.Length.ToString() + " to " + folderName.Length + " characters on update"); - } - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(database.CreateParameter("folderID", folder.ID)); - cmd.Parameters.Add(database.CreateParameter("agentID", folder.Owner)); - cmd.Parameters.Add(database.CreateParameter("parentFolderID", folder.ParentID)); - cmd.Parameters.Add(database.CreateParameter("folderName", folderName)); - cmd.Parameters.Add(database.CreateParameter("type", folder.Type)); - cmd.Parameters.Add(database.CreateParameter("version", folder.Version)); - conn.Open(); - try - { - cmd.ExecuteNonQuery(); - } - catch (Exception e) - { - m_log.ErrorFormat("[INVENTORY DB]: Error : {0}", e.Message); - } - } - } - - /// - /// Updates an inventory folder - /// - /// Folder to update - public void moveInventoryFolder(InventoryFolderBase folder) - { - string sql = @"UPDATE inventoryfolders SET parentFolderID = @parentFolderID WHERE folderID = @folderID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(database.CreateParameter("parentFolderID", folder.ParentID)); - cmd.Parameters.Add(database.CreateParameter("folderID", folder.ID)); - conn.Open(); - try - { - cmd.ExecuteNonQuery(); - } - catch (Exception e) - { - m_log.ErrorFormat("[INVENTORY DB]: Error : {0}", e.Message); - } - } - } - - /// - /// Delete an inventory folder - /// - /// Id of folder to delete - public void deleteInventoryFolder(UUID folderID) - { - string sql = "SELECT * FROM inventoryfolders WHERE parentFolderID = @parentID"; - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - List subFolders; - cmd.Parameters.Add(database.CreateParameter("@parentID", UUID.Zero)); - conn.Open(); - subFolders = getFolderHierarchy(folderID, cmd); - - - //Delete all sub-folders - foreach (InventoryFolderBase f in subFolders) - { - DeleteOneFolder(f.ID, conn); - DeleteItemsInFolder(f.ID, conn); - } - - //Delete the actual row - DeleteOneFolder(folderID, conn); - DeleteItemsInFolder(folderID, conn); - } - } - - #endregion - - #region Item Methods - - /// - /// Returns a list of items in a specified folder - /// - /// The folder to search - /// A list containing inventory items - public List getInventoryInFolder(UUID folderID) - { - string sql = "SELECT * FROM inventoryitems WHERE parentFolderID = @parentFolderID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(database.CreateParameter("parentFolderID", folderID)); - conn.Open(); - List items = new List(); - - using (SqlDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - items.Add(readInventoryItem(reader)); - } - } - return items; - } - } - - /// - /// Returns a specified inventory item - /// - /// The item ID - /// An inventory item - public InventoryItemBase getInventoryItem(UUID itemID) - { - string sql = "SELECT * FROM inventoryitems WHERE inventoryID = @inventoryID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(database.CreateParameter("inventoryID", itemID)); - conn.Open(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (reader.Read()) - { - return readInventoryItem(reader); - } - } - } - - m_log.InfoFormat("[INVENTORY DB]: Found no inventory item with ID : {0}", itemID); - return null; - } - - /// - /// Adds a specified item to the database - /// - /// The inventory item - public void addInventoryItem(InventoryItemBase item) - { - if (getInventoryItem(item.ID) != null) - { - updateInventoryItem(item); - return; - } - - string sql = @"INSERT INTO inventoryitems - ([inventoryID], [assetID], [assetType], [parentFolderID], [avatarID], [inventoryName], - [inventoryDescription], [inventoryNextPermissions], [inventoryCurrentPermissions], - [invType], [creatorID], [inventoryBasePermissions], [inventoryEveryOnePermissions], [inventoryGroupPermissions], - [salePrice], [saleType], [creationDate], [groupID], [groupOwned], [flags]) - VALUES - (@inventoryID, @assetID, @assetType, @parentFolderID, @avatarID, @inventoryName, @inventoryDescription, - @inventoryNextPermissions, @inventoryCurrentPermissions, @invType, @creatorID, - @inventoryBasePermissions, @inventoryEveryOnePermissions, @inventoryGroupPermissions, @salePrice, @saleType, - @creationDate, @groupID, @groupOwned, @flags)"; - - string itemName = item.Name; - if (item.Name.Length > 64) - { - itemName = item.Name.Substring(0, 64); - m_log.Warn("[INVENTORY DB]: Name field truncated from " + item.Name.Length.ToString() + " to " + itemName.Length.ToString() + " characters"); - } - - string itemDesc = item.Description; - if (item.Description.Length > 128) - { - itemDesc = item.Description.Substring(0, 128); - m_log.Warn("[INVENTORY DB]: Description field truncated from " + item.Description.Length.ToString() + " to " + itemDesc.Length.ToString() + " characters"); - } - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand command = new SqlCommand(sql, conn)) - { - command.Parameters.Add(database.CreateParameter("inventoryID", item.ID)); - command.Parameters.Add(database.CreateParameter("assetID", item.AssetID)); - command.Parameters.Add(database.CreateParameter("assetType", item.AssetType)); - command.Parameters.Add(database.CreateParameter("parentFolderID", item.Folder)); - command.Parameters.Add(database.CreateParameter("avatarID", item.Owner)); - command.Parameters.Add(database.CreateParameter("inventoryName", itemName)); - command.Parameters.Add(database.CreateParameter("inventoryDescription", itemDesc)); - command.Parameters.Add(database.CreateParameter("inventoryNextPermissions", item.NextPermissions)); - command.Parameters.Add(database.CreateParameter("inventoryCurrentPermissions", item.CurrentPermissions)); - command.Parameters.Add(database.CreateParameter("invType", item.InvType)); - command.Parameters.Add(database.CreateParameter("creatorID", item.CreatorId)); - command.Parameters.Add(database.CreateParameter("inventoryBasePermissions", item.BasePermissions)); - command.Parameters.Add(database.CreateParameter("inventoryEveryOnePermissions", item.EveryOnePermissions)); - command.Parameters.Add(database.CreateParameter("inventoryGroupPermissions", item.GroupPermissions)); - command.Parameters.Add(database.CreateParameter("salePrice", item.SalePrice)); - command.Parameters.Add(database.CreateParameter("saleType", item.SaleType)); - command.Parameters.Add(database.CreateParameter("creationDate", item.CreationDate)); - command.Parameters.Add(database.CreateParameter("groupID", item.GroupID)); - command.Parameters.Add(database.CreateParameter("groupOwned", item.GroupOwned)); - command.Parameters.Add(database.CreateParameter("flags", item.Flags)); - conn.Open(); - try - { - command.ExecuteNonQuery(); - } - catch (Exception e) - { - m_log.Error("[INVENTORY DB]: Error inserting item :" + e.Message); - } - } - - sql = "UPDATE inventoryfolders SET version = version + 1 WHERE folderID = @folderID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand command = new SqlCommand(sql, conn)) - { - command.Parameters.Add(database.CreateParameter("folderID", item.Folder.ToString())); - conn.Open(); - try - { - command.ExecuteNonQuery(); - } - catch (Exception e) - { - m_log.Error("[INVENTORY DB] Error updating inventory folder for new item :" + e.Message); - } - } - } - - /// - /// Updates the specified inventory item - /// - /// Inventory item to update - public void updateInventoryItem(InventoryItemBase item) - { - string sql = @"UPDATE inventoryitems SET assetID = @assetID, - assetType = @assetType, - parentFolderID = @parentFolderID, - avatarID = @avatarID, - inventoryName = @inventoryName, - inventoryDescription = @inventoryDescription, - inventoryNextPermissions = @inventoryNextPermissions, - inventoryCurrentPermissions = @inventoryCurrentPermissions, - invType = @invType, - creatorID = @creatorID, - inventoryBasePermissions = @inventoryBasePermissions, - inventoryEveryOnePermissions = @inventoryEveryOnePermissions, - inventoryGroupPermissions = @inventoryGroupPermissions, - salePrice = @salePrice, - saleType = @saleType, - creationDate = @creationDate, - groupID = @groupID, - groupOwned = @groupOwned, - flags = @flags - WHERE inventoryID = @inventoryID"; - - string itemName = item.Name; - if (item.Name.Length > 64) - { - itemName = item.Name.Substring(0, 64); - m_log.Warn("[INVENTORY DB]: Name field truncated from " + item.Name.Length.ToString() + " to " + itemName.Length.ToString() + " characters on update"); - } - - string itemDesc = item.Description; - if (item.Description.Length > 128) - { - itemDesc = item.Description.Substring(0, 128); - m_log.Warn("[INVENTORY DB]: Description field truncated from " + item.Description.Length.ToString() + " to " + itemDesc.Length.ToString() + " characters on update"); - } - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand command = new SqlCommand(sql, conn)) - { - command.Parameters.Add(database.CreateParameter("inventoryID", item.ID)); - command.Parameters.Add(database.CreateParameter("assetID", item.AssetID)); - command.Parameters.Add(database.CreateParameter("assetType", item.AssetType)); - command.Parameters.Add(database.CreateParameter("parentFolderID", item.Folder)); - command.Parameters.Add(database.CreateParameter("avatarID", item.Owner)); - command.Parameters.Add(database.CreateParameter("inventoryName", itemName)); - command.Parameters.Add(database.CreateParameter("inventoryDescription", itemDesc)); - command.Parameters.Add(database.CreateParameter("inventoryNextPermissions", item.NextPermissions)); - command.Parameters.Add(database.CreateParameter("inventoryCurrentPermissions", item.CurrentPermissions)); - command.Parameters.Add(database.CreateParameter("invType", item.InvType)); - command.Parameters.Add(database.CreateParameter("creatorID", item.CreatorId)); - command.Parameters.Add(database.CreateParameter("inventoryBasePermissions", item.BasePermissions)); - command.Parameters.Add(database.CreateParameter("inventoryEveryOnePermissions", item.EveryOnePermissions)); - command.Parameters.Add(database.CreateParameter("inventoryGroupPermissions", item.GroupPermissions)); - command.Parameters.Add(database.CreateParameter("salePrice", item.SalePrice)); - command.Parameters.Add(database.CreateParameter("saleType", item.SaleType)); - command.Parameters.Add(database.CreateParameter("creationDate", item.CreationDate)); - command.Parameters.Add(database.CreateParameter("groupID", item.GroupID)); - command.Parameters.Add(database.CreateParameter("groupOwned", item.GroupOwned)); - command.Parameters.Add(database.CreateParameter("flags", item.Flags)); - conn.Open(); - try - { - command.ExecuteNonQuery(); - } - catch (Exception e) - { - m_log.Error("[INVENTORY DB]: Error updating item :" + e.Message); - } - } - } - - // See IInventoryDataPlugin - - /// - /// Delete an item in inventory database - /// - /// the item UUID - public void deleteInventoryItem(UUID itemID) - { - string sql = "DELETE FROM inventoryitems WHERE inventoryID=@inventoryID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(database.CreateParameter("inventoryID", itemID)); - try - { - conn.Open(); - cmd.ExecuteNonQuery(); - } - catch (Exception e) - { - m_log.Error("[INVENTORY DB]: Error deleting item :" + e.Message); - } - } - } - - public InventoryItemBase queryInventoryItem(UUID itemID) - { - return getInventoryItem(itemID); - } - - public InventoryFolderBase queryInventoryFolder(UUID folderID) - { - return getInventoryFolder(folderID); - } - - /// - /// Returns all activated gesture-items in the inventory of the specified avatar. - /// - /// The of the avatar - /// - /// The list of gestures (s) - /// - public List fetchActiveGestures(UUID avatarID) - { - string sql = "SELECT * FROM inventoryitems WHERE avatarId = @uuid AND assetType = @assetType and flags = 1"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(database.CreateParameter("uuid", avatarID)); - cmd.Parameters.Add(database.CreateParameter("assetType", (int)AssetType.Gesture)); - conn.Open(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - List gestureList = new List(); - while (reader.Read()) - { - gestureList.Add(readInventoryItem(reader)); - } - return gestureList; - } - } - } - - #endregion - - #region Private methods - - /// - /// Delete an item in inventory database - /// - /// the item ID - /// connection to the database - private void DeleteItemsInFolder(UUID folderID, SqlConnection connection) - { - using (SqlCommand command = new SqlCommand("DELETE FROM inventoryitems WHERE folderID=@folderID", connection)) - { - command.Parameters.Add(database.CreateParameter("folderID", folderID)); - - try - { - command.ExecuteNonQuery(); - } - catch (Exception e) - { - m_log.Error("[INVENTORY DB] Error deleting item :" + e.Message); - } - } - } - - /// - /// Gets the folder hierarchy in a loop. - /// - /// parent ID. - /// SQL command/connection to database - /// - private static List getFolderHierarchy(UUID parentID, SqlCommand command) - { - command.Parameters["@parentID"].Value = parentID.Guid; //.ToString(); - - List folders = getInventoryFolders(command); - - if (folders.Count > 0) - { - List tempFolders = new List(); - - foreach (InventoryFolderBase folderBase in folders) - { - tempFolders.AddRange(getFolderHierarchy(folderBase.ID, command)); - } - - if (tempFolders.Count > 0) - { - folders.AddRange(tempFolders); - } - } - return folders; - } - - /// - /// Gets the inventory folders. - /// - /// parentID, use UUID.Zero to get root - /// user id, use UUID.Zero, if you want all folders from a parentID. - /// - private List getInventoryFolders(UUID parentID, UUID user) - { - string sql = "SELECT * FROM inventoryfolders WHERE parentFolderID = @parentID AND agentID LIKE @uuid"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand command = new SqlCommand(sql, conn)) - { - if (user == UUID.Zero) - { - command.Parameters.Add(database.CreateParameter("uuid", "%")); - } - else - { - command.Parameters.Add(database.CreateParameter("uuid", user)); - } - command.Parameters.Add(database.CreateParameter("parentID", parentID)); - conn.Open(); - return getInventoryFolders(command); - } - } - - /// - /// Gets the inventory folders. - /// - /// SQLcommand. - /// - private static List getInventoryFolders(SqlCommand command) - { - using (SqlDataReader reader = command.ExecuteReader()) - { - - List items = new List(); - while (reader.Read()) - { - items.Add(readInventoryFolder(reader)); - } - return items; - } - } - - /// - /// Reads a list of inventory folders returned by a query. - /// - /// A MSSQL Data Reader - /// A List containing inventory folders - protected static InventoryFolderBase readInventoryFolder(SqlDataReader reader) - { - try - { - InventoryFolderBase folder = new InventoryFolderBase(); - folder.Owner = DBGuid.FromDB(reader["agentID"]); - folder.ParentID = DBGuid.FromDB(reader["parentFolderID"]); - folder.ID = DBGuid.FromDB(reader["folderID"]); - folder.Name = (string)reader["folderName"]; - folder.Type = (short)reader["type"]; - folder.Version = Convert.ToUInt16(reader["version"]); - - return folder; - } - catch (Exception e) - { - m_log.Error("[INVENTORY DB] Error reading inventory folder :" + e.Message); - } - - return null; - } - - /// - /// Reads a one item from an SQL result - /// - /// The SQL Result - /// the item read - private static InventoryItemBase readInventoryItem(IDataRecord reader) - { - try - { - InventoryItemBase item = new InventoryItemBase(); - - item.ID = DBGuid.FromDB(reader["inventoryID"]); - item.AssetID = DBGuid.FromDB(reader["assetID"]); - item.AssetType = Convert.ToInt32(reader["assetType"].ToString()); - item.Folder = DBGuid.FromDB(reader["parentFolderID"]); - item.Owner = DBGuid.FromDB(reader["avatarID"]); - item.Name = reader["inventoryName"].ToString(); - item.Description = reader["inventoryDescription"].ToString(); - item.NextPermissions = Convert.ToUInt32(reader["inventoryNextPermissions"]); - item.CurrentPermissions = Convert.ToUInt32(reader["inventoryCurrentPermissions"]); - item.InvType = Convert.ToInt32(reader["invType"].ToString()); - item.CreatorId = reader["creatorID"].ToString(); - item.BasePermissions = Convert.ToUInt32(reader["inventoryBasePermissions"]); - item.EveryOnePermissions = Convert.ToUInt32(reader["inventoryEveryOnePermissions"]); - item.GroupPermissions = Convert.ToUInt32(reader["inventoryGroupPermissions"]); - item.SalePrice = Convert.ToInt32(reader["salePrice"]); - item.SaleType = Convert.ToByte(reader["saleType"]); - item.CreationDate = Convert.ToInt32(reader["creationDate"]); - item.GroupID = DBGuid.FromDB(reader["groupID"]); - item.GroupOwned = Convert.ToBoolean(reader["groupOwned"]); - item.Flags = Convert.ToUInt32(reader["flags"]); - - return item; - } - catch (SqlException e) - { - m_log.Error("[INVENTORY DB]: Error reading inventory item :" + e.Message); - } - - return null; - } - - /// - /// Delete a folder in inventory databasae - /// - /// the folder UUID - /// connection to database - private void DeleteOneFolder(UUID folderID, SqlConnection connection) - { - try - { - using (SqlCommand command = new SqlCommand("DELETE FROM inventoryfolders WHERE folderID=@folderID and type=-1", connection)) - { - command.Parameters.Add(database.CreateParameter("folderID", folderID)); - - command.ExecuteNonQuery(); - } - } - catch (SqlException e) - { - m_log.Error("[INVENTORY DB]: Error deleting folder :" + e.Message); - } - } - - #endregion - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLManager.cs b/OpenSim/Data/MSSQL/MSSQLManager.cs deleted file mode 100644 index 9a0015c..0000000 --- a/OpenSim/Data/MSSQL/MSSQLManager.cs +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.SqlClient; -using System.IO; -using System.Reflection; -using log4net; -using OpenMetaverse; - -namespace OpenSim.Data.MSSQL -{ - /// - /// A management class for the MS SQL Storage Engine - /// - public class MSSQLManager - { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// Connection string for ADO.net - /// - private readonly string connectionString; - - /// - /// Initialize the manager and set the connectionstring - /// - /// - public MSSQLManager(string connection) - { - connectionString = connection; - } - - /// - /// Type conversion to a SQLDbType functions - /// - /// - /// - internal SqlDbType DbtypeFromType(Type type) - { - if (type == typeof(string)) - { - return SqlDbType.VarChar; - } - if (type == typeof(double)) - { - return SqlDbType.Float; - } - if (type == typeof(Single)) - { - return SqlDbType.Float; - } - if (type == typeof(int)) - { - return SqlDbType.Int; - } - if (type == typeof(bool)) - { - return SqlDbType.Bit; - } - if (type == typeof(UUID)) - { - return SqlDbType.UniqueIdentifier; - } - if (type == typeof(sbyte)) - { - return SqlDbType.Int; - } - if (type == typeof(Byte[])) - { - return SqlDbType.Image; - } - if (type == typeof(uint) || type == typeof(ushort)) - { - return SqlDbType.Int; - } - if (type == typeof(ulong)) - { - return SqlDbType.BigInt; - } - if (type == typeof(DateTime)) - { - return SqlDbType.DateTime; - } - - return SqlDbType.VarChar; - } - - /// - /// Creates value for parameter. - /// - /// The value. - /// - private static object CreateParameterValue(object value) - { - Type valueType = value.GetType(); - - if (valueType == typeof(UUID)) //TODO check if this works - { - return ((UUID) value).Guid; - } - if (valueType == typeof(UUID)) - { - return ((UUID)value).Guid; - } - if (valueType == typeof(bool)) - { - return (bool)value ? 1 : 0; - } - if (valueType == typeof(Byte[])) - { - return value; - } - if (valueType == typeof(int)) - { - return value; - } - return value; - } - - /// - /// Create a parameter for a command - /// - /// Name of the parameter. - /// parameter object. - /// - internal SqlParameter CreateParameter(string parameterName, object parameterObject) - { - return CreateParameter(parameterName, parameterObject, false); - } - - /// - /// Creates the parameter for a command. - /// - /// Name of the parameter. - /// parameter object. - /// if set to true parameter is a output parameter - /// - internal SqlParameter CreateParameter(string parameterName, object parameterObject, bool parameterOut) - { - //Tweak so we dont always have to add @ sign - if (!parameterName.StartsWith("@")) parameterName = "@" + parameterName; - - //HACK if object is null, it is turned into a string, there are no nullable type till now - if (parameterObject == null) parameterObject = ""; - - SqlParameter parameter = new SqlParameter(parameterName, DbtypeFromType(parameterObject.GetType())); - - if (parameterOut) - { - parameter.Direction = ParameterDirection.Output; - } - else - { - parameter.Direction = ParameterDirection.Input; - parameter.Value = CreateParameterValue(parameterObject); - } - - return parameter; - } - - /// - /// Checks if we need to do some migrations to the database - /// - /// migrationStore. - public void CheckMigration(string migrationStore) - { - using (SqlConnection connection = new SqlConnection(connectionString)) - { - connection.Open(); - Assembly assem = GetType().Assembly; - MSSQLMigration migration = new MSSQLMigration(connection, assem, migrationStore); - - migration.Update(); - } - } - - /// - /// Returns the version of this DB provider - /// - /// A string containing the DB provider - public string getVersion() - { - Module module = GetType().Module; - // string dllName = module.Assembly.ManifestModule.Name; - Version dllVersion = module.Assembly.GetName().Version; - - return - string.Format("{0}.{1}.{2}.{3}", dllVersion.Major, dllVersion.Minor, dllVersion.Build, - dllVersion.Revision); - } - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLMigration.cs b/OpenSim/Data/MSSQL/MSSQLMigration.cs deleted file mode 100644 index c2fecef..0000000 --- a/OpenSim/Data/MSSQL/MSSQLMigration.cs +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Data; -using System.Data.Common; -using System.Reflection; -using System.Data.SqlClient; - -namespace OpenSim.Data.MSSQL -{ - public class MSSQLMigration : Migration - { - public MSSQLMigration(DbConnection conn, Assembly assem, string type) - : base(conn, assem, type) - { - } - - public MSSQLMigration(DbConnection conn, Assembly assem, string subtype, string type) - : base(conn, assem, subtype, type) - { - } - - protected override int FindVersion(DbConnection conn, string type) - { - int version = 0; - using (DbCommand cmd = conn.CreateCommand()) - { - try - { - cmd.CommandText = "select top 1 version from migrations where name = '" + type + "' order by version desc"; //Must be - using (IDataReader reader = cmd.ExecuteReader()) - { - if (reader.Read()) - { - version = Convert.ToInt32(reader["version"]); - } - reader.Close(); - } - } - catch - { - // Return -1 to indicate table does not exist - return -1; - } - } - return version; - } - - protected override void ExecuteScript(DbConnection conn, string[] script) - { - if (!(conn is SqlConnection)) - { - base.ExecuteScript(conn, script); - return; - } - - foreach (string sql in script) - { - try - { - using (SqlCommand cmd = new SqlCommand(sql, (SqlConnection)conn)) - { - cmd.ExecuteNonQuery(); - } - } - catch (Exception) - { - throw new Exception(sql); - - } - } - } - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLPresenceData.cs b/OpenSim/Data/MSSQL/MSSQLPresenceData.cs deleted file mode 100644 index 0c71e79..0000000 --- a/OpenSim/Data/MSSQL/MSSQLPresenceData.cs +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Data; -using System.Reflection; -using System.Threading; -using log4net; -using OpenMetaverse; -using OpenSim.Framework; -using System.Data.SqlClient; - -namespace OpenSim.Data.MSSQL -{ - /// - /// A MySQL Interface for the Presence Server - /// - public class MSSQLPresenceData : MSSQLGenericTableHandler, - IPresenceData - { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - public MSSQLPresenceData(string connectionString, string realm) : - base(connectionString, realm, "Presence") - { - } - - public PresenceData Get(UUID sessionID) - { - PresenceData[] ret = Get("SessionID", - sessionID.ToString()); - - if (ret.Length == 0) - return null; - - return ret[0]; - } - - public void LogoutRegionAgents(UUID regionID) - { - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand()) - { - - cmd.CommandText = String.Format("DELETE FROM {0} WHERE [RegionID]=@RegionID", m_Realm); - - cmd.Parameters.Add(m_database.CreateParameter("@RegionID", regionID.ToString())); - cmd.Connection = conn; - conn.Open(); - cmd.ExecuteNonQuery(); - } - } - - public bool ReportAgent(UUID sessionID, UUID regionID) - { - PresenceData[] pd = Get("SessionID", sessionID.ToString()); - if (pd.Length == 0) - return false; - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand()) - { - - cmd.CommandText = String.Format(@"UPDATE {0} SET - [RegionID] = @RegionID - WHERE [SessionID] = @SessionID", m_Realm); - - cmd.Parameters.Add(m_database.CreateParameter("@SessionID", sessionID.ToString())); - cmd.Parameters.Add(m_database.CreateParameter("@RegionID", regionID.ToString())); - cmd.Connection = conn; - conn.Open(); - if (cmd.ExecuteNonQuery() == 0) - return false; - } - return true; - } - - public bool VerifyAgent(UUID agentId, UUID secureSessionID) - { - PresenceData[] ret = Get("SecureSessionID", - secureSessionID.ToString()); - - if (ret.Length == 0) - return false; - - if(ret[0].UserID != agentId.ToString()) - return false; - - return true; - } - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLRegionData.cs b/OpenSim/Data/MSSQL/MSSQLRegionData.cs deleted file mode 100644 index 0d89706..0000000 --- a/OpenSim/Data/MSSQL/MSSQLRegionData.cs +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.SqlClient; -using System.Drawing; -using System.IO; -using System.Reflection; -using log4net; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; -using RegionFlags = OpenSim.Framework.RegionFlags; - -namespace OpenSim.Data.MSSQL -{ - /// - /// A MSSQL Interface for the Region Server. - /// - public class MSSQLRegionData : IRegionData - { - private string m_Realm; - private List m_ColumnNames = null; - private string m_ConnectionString; - private MSSQLManager m_database; - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - public MSSQLRegionData(string connectionString, string realm) - { - m_Realm = realm; - m_ConnectionString = connectionString; - m_database = new MSSQLManager(connectionString); - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - { - conn.Open(); - Migration m = new Migration(conn, GetType().Assembly, "GridStore"); - m.Update(); - } - } - - public List Get(string regionName, UUID scopeID) - { - string sql = "select * from ["+m_Realm+"] where regionName like @regionName"; - if (scopeID != UUID.Zero) - sql += " and ScopeID = @scopeID"; - sql += " order by regionName"; - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(m_database.CreateParameter("@regionName", regionName)); - cmd.Parameters.Add(m_database.CreateParameter("@scopeID", scopeID)); - conn.Open(); - return RunCommand(cmd); - } - } - - public RegionData Get(int posX, int posY, UUID scopeID) - { - string sql = "select * from ["+m_Realm+"] where locX = @posX and locY = @posY"; - if (scopeID != UUID.Zero) - sql += " and ScopeID = @scopeID"; - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(m_database.CreateParameter("@posX", posX.ToString())); - cmd.Parameters.Add(m_database.CreateParameter("@posY", posY.ToString())); - cmd.Parameters.Add(m_database.CreateParameter("@scopeID", scopeID)); - conn.Open(); - List ret = RunCommand(cmd); - if (ret.Count == 0) - return null; - - return ret[0]; - } - } - - public RegionData Get(UUID regionID, UUID scopeID) - { - string sql = "select * from ["+m_Realm+"] where uuid = @regionID"; - if (scopeID != UUID.Zero) - sql += " and ScopeID = @scopeID"; - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(m_database.CreateParameter("@regionID", regionID)); - cmd.Parameters.Add(m_database.CreateParameter("@scopeID", scopeID)); - conn.Open(); - List ret = RunCommand(cmd); - if (ret.Count == 0) - return null; - - return ret[0]; - } - } - - public List Get(int startX, int startY, int endX, int endY, UUID scopeID) - { - string sql = "select * from ["+m_Realm+"] where locX between @startX and @endX and locY between @startY and @endY"; - if (scopeID != UUID.Zero) - sql += " and ScopeID = @scopeID"; - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(m_database.CreateParameter("@startX", startX)); - cmd.Parameters.Add(m_database.CreateParameter("@startY", startY)); - cmd.Parameters.Add(m_database.CreateParameter("@endX", endX)); - cmd.Parameters.Add(m_database.CreateParameter("@endY", endY)); - cmd.Parameters.Add(m_database.CreateParameter("@scopeID", scopeID)); - conn.Open(); - return RunCommand(cmd); - } - } - - public List RunCommand(SqlCommand cmd) - { - List retList = new List(); - - SqlDataReader result = cmd.ExecuteReader(); - - while (result.Read()) - { - RegionData ret = new RegionData(); - ret.Data = new Dictionary(); - - UUID regionID; - UUID.TryParse(result["uuid"].ToString(), out regionID); - ret.RegionID = regionID; - UUID scope; - UUID.TryParse(result["ScopeID"].ToString(), out scope); - ret.ScopeID = scope; - ret.RegionName = result["regionName"].ToString(); - ret.posX = Convert.ToInt32(result["locX"]); - ret.posY = Convert.ToInt32(result["locY"]); - ret.sizeX = Convert.ToInt32(result["sizeX"]); - ret.sizeY = Convert.ToInt32(result["sizeY"]); - - if (m_ColumnNames == null) - { - m_ColumnNames = new List(); - - DataTable schemaTable = result.GetSchemaTable(); - foreach (DataRow row in schemaTable.Rows) - m_ColumnNames.Add(row["ColumnName"].ToString()); - } - - foreach (string s in m_ColumnNames) - { - if (s == "uuid") - continue; - if (s == "ScopeID") - continue; - if (s == "regionName") - continue; - if (s == "locX") - continue; - if (s == "locY") - continue; - - ret.Data[s] = result[s].ToString(); - } - - retList.Add(ret); - } - return retList; - } - - public bool Store(RegionData data) - { - if (data.Data.ContainsKey("uuid")) - data.Data.Remove("uuid"); - if (data.Data.ContainsKey("ScopeID")) - data.Data.Remove("ScopeID"); - if (data.Data.ContainsKey("regionName")) - data.Data.Remove("regionName"); - if (data.Data.ContainsKey("posX")) - data.Data.Remove("posX"); - if (data.Data.ContainsKey("posY")) - data.Data.Remove("posY"); - if (data.Data.ContainsKey("sizeX")) - data.Data.Remove("sizeX"); - if (data.Data.ContainsKey("sizeY")) - data.Data.Remove("sizeY"); - if (data.Data.ContainsKey("locX")) - data.Data.Remove("locX"); - if (data.Data.ContainsKey("locY")) - data.Data.Remove("locY"); - - string[] fields = new List(data.Data.Keys).ToArray(); - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand()) - { - - string update = "update [" + m_Realm + "] set locX=@posX, locY=@posY, sizeX=@sizeX, sizeY=@sizeY "; - - foreach (string field in fields) - { - - update += ", "; - update += "[" + field + "] = @" + field; - - cmd.Parameters.Add(m_database.CreateParameter("@" + field, data.Data[field])); - } - - update += " where uuid = @regionID"; - - if (data.ScopeID != UUID.Zero) - update += " and ScopeID = @scopeID"; - - cmd.CommandText = update; - cmd.Connection = conn; - cmd.Parameters.Add(m_database.CreateParameter("@regionID", data.RegionID)); - cmd.Parameters.Add(m_database.CreateParameter("@regionName", data.RegionName)); - cmd.Parameters.Add(m_database.CreateParameter("@scopeID", data.ScopeID)); - cmd.Parameters.Add(m_database.CreateParameter("@posX", data.posX)); - cmd.Parameters.Add(m_database.CreateParameter("@posY", data.posY)); - cmd.Parameters.Add(m_database.CreateParameter("@sizeX", data.sizeX)); - cmd.Parameters.Add(m_database.CreateParameter("@sizeY", data.sizeY)); - conn.Open(); - try - { - if (cmd.ExecuteNonQuery() < 1) - { - string insert = "insert into [" + m_Realm + "] ([uuid], [ScopeID], [locX], [locY], [sizeX], [sizeY], [regionName], [" + - String.Join("], [", fields) + - "]) values (@regionID, @scopeID, @posX, @posY, @sizeX, @sizeY, @regionName, @" + String.Join(", @", fields) + ")"; - - cmd.CommandText = insert; - - try - { - if (cmd.ExecuteNonQuery() < 1) - { - return false; - } - } - catch (Exception ex) - { - m_log.Warn("[MSSQL Grid]: Error inserting into Regions table: " + ex.Message + ", INSERT sql: " + insert); - } - } - } - catch (Exception ex) - { - m_log.Warn("[MSSQL Grid]: Error updating Regions table: " + ex.Message + ", UPDATE sql: " + update); - } - } - - return true; - } - - public bool SetDataItem(UUID regionID, string item, string value) - { - string sql = "update [" + m_Realm + - "] set [" + item + "] = @" + item + " where uuid = @UUID"; - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(m_database.CreateParameter("@" + item, value)); - cmd.Parameters.Add(m_database.CreateParameter("@UUID", regionID)); - conn.Open(); - if (cmd.ExecuteNonQuery() > 0) - return true; - } - return false; - } - - public bool Delete(UUID regionID) - { - string sql = "delete from [" + m_Realm + - "] where uuid = @UUID"; - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(m_database.CreateParameter("@UUID", regionID)); - conn.Open(); - if (cmd.ExecuteNonQuery() > 0) - return true; - } - return false; - } - - public List GetDefaultRegions(UUID scopeID) - { - return Get((int)RegionFlags.DefaultRegion, scopeID); - } - - public List GetFallbackRegions(UUID scopeID, int x, int y) - { - List regions = Get((int)RegionFlags.FallbackRegion, scopeID); - RegionDataDistanceCompare distanceComparer = new RegionDataDistanceCompare(x, y); - regions.Sort(distanceComparer); - - return regions; - } - - public List GetHyperlinks(UUID scopeID) - { - return Get((int)RegionFlags.Hyperlink, scopeID); - } - - private List Get(int regionFlags, UUID scopeID) - { - string sql = "SELECT * FROM [" + m_Realm + "] WHERE (flags & " + regionFlags.ToString() + ") <> 0"; - if (scopeID != UUID.Zero) - sql += " AND ScopeID = @scopeID"; - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(m_database.CreateParameter("@scopeID", scopeID)); - conn.Open(); - return RunCommand(cmd); - } - } - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs deleted file mode 100644 index 17f42e1..0000000 --- a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs +++ /dev/null @@ -1,2219 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.SqlClient; -using System.Drawing; -using System.IO; -using System.Reflection; -using log4net; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Data.MSSQL -{ - /// - /// A MSSQL Interface for the Region Server. - /// - public class MSSQLSimulationData : ISimulationDataStore - { - private const string _migrationStore = "RegionStore"; - - // private static FileSystemDataStore Instance = new FileSystemDataStore(); - private static readonly ILog _Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// The database manager - /// - private MSSQLManager _Database; - private string m_connectionString; - protected virtual Assembly Assembly - { - get { return GetType().Assembly; } - } - - public MSSQLSimulationData() - { - } - - public MSSQLSimulationData(string connectionString) - { - Initialise(connectionString); - } - - /// - /// Initialises the region datastore - /// - /// The connection string. - public void Initialise(string connectionString) - { - m_connectionString = connectionString; - _Database = new MSSQLManager(connectionString); - - using (SqlConnection conn = new SqlConnection(connectionString)) - { - conn.Open(); - //New Migration settings - Migration m = new Migration(conn, Assembly, "RegionStore"); - m.Update(); - } - } - - /// - /// Dispose the database - /// - public void Dispose() { } - - #region SceneObjectGroup region for loading and Store of the scene. - - /// - /// Loads the objects present in the region. - /// - /// The region UUID. - /// - public List LoadObjects(UUID regionUUID) - { - UUID lastGroupID = UUID.Zero; - - Dictionary prims = new Dictionary(); - Dictionary objects = new Dictionary(); - SceneObjectGroup grp = null; - - string sql = "SELECT *, " + - "sort = CASE WHEN prims.UUID = prims.SceneGroupID THEN 0 ELSE 1 END " + - "FROM prims " + - "LEFT JOIN primshapes ON prims.UUID = primshapes.UUID " + - "WHERE RegionUUID = @RegionUUID " + - "ORDER BY SceneGroupID asc, sort asc, LinkNumber asc"; - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand command = new SqlCommand(sql, conn)) - { - command.Parameters.Add(_Database.CreateParameter("@regionUUID", regionUUID)); - conn.Open(); - using (SqlDataReader reader = command.ExecuteReader()) - { - while (reader.Read()) - { - SceneObjectPart sceneObjectPart = BuildPrim(reader); - if (reader["Shape"] is DBNull) - sceneObjectPart.Shape = PrimitiveBaseShape.Default; - else - sceneObjectPart.Shape = BuildShape(reader); - - prims[sceneObjectPart.UUID] = sceneObjectPart; - - UUID groupID = new UUID((Guid)reader["SceneGroupID"]); - - if (groupID != lastGroupID) // New SOG - { - if (grp != null) - objects[grp.UUID] = grp; - - lastGroupID = groupID; - - // There sometimes exist OpenSim bugs that 'orphan groups' so that none of the prims are - // recorded as the root prim (for which the UUID must equal the persisted group UUID). In - // this case, force the UUID to be the same as the group UUID so that at least these can be - // deleted (we need to change the UUID so that any other prims in the linkset can also be - // deleted). - if (sceneObjectPart.UUID != groupID && groupID != UUID.Zero) - { - _Log.WarnFormat( - "[REGION DB]: Found root prim {0} {1} at {2} where group was actually {3}. Forcing UUID to group UUID", - sceneObjectPart.Name, sceneObjectPart.UUID, sceneObjectPart.GroupPosition, groupID); - - sceneObjectPart.UUID = groupID; - } - - grp = new SceneObjectGroup(sceneObjectPart); - } - else - { - // Black magic to preserve link numbers - // Why is this needed, fix this in AddPart method. - int link = sceneObjectPart.LinkNum; - - grp.AddPart(sceneObjectPart); - - if (link != 0) - sceneObjectPart.LinkNum = link; - } - } - } - } - - if (grp != null) - objects[grp.UUID] = grp; - - // Instead of attempting to LoadItems on every prim, - // most of which probably have no items... get a - // list from DB of all prims which have items and - // LoadItems only on those - List primsWithInventory = new List(); - string qry = "select distinct primID from primitems"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand command = new SqlCommand(qry, conn)) - { - conn.Open(); - using (SqlDataReader itemReader = command.ExecuteReader()) - { - while (itemReader.Read()) - { - if (!(itemReader["primID"] is DBNull)) - { - UUID primID = new UUID(itemReader["primID"].ToString()); - if (prims.ContainsKey(primID)) - { - primsWithInventory.Add(prims[primID]); - } - } - } - } - } - - LoadItems(primsWithInventory); - - _Log.DebugFormat("[REGION DB]: Loaded {0} objects using {1} prims", objects.Count, prims.Count); - - return new List(objects.Values); - } - - /// - /// Load in the prim's persisted inventory. - /// - /// all prims with inventory on a region - private void LoadItems(List allPrimsWithInventory) - { - string sql = "SELECT * FROM primitems WHERE PrimID = @PrimID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand command = new SqlCommand(sql, conn)) - { - conn.Open(); - foreach (SceneObjectPart objectPart in allPrimsWithInventory) - { - command.Parameters.Clear(); - command.Parameters.Add(_Database.CreateParameter("@PrimID", objectPart.UUID)); - - List inventory = new List(); - - using (SqlDataReader reader = command.ExecuteReader()) - { - while (reader.Read()) - { - TaskInventoryItem item = BuildItem(reader); - - item.ParentID = objectPart.UUID; // Values in database are - // often wrong - inventory.Add(item); - } - } - - objectPart.Inventory.RestoreInventoryItems(inventory); - } - } - } - - /// - /// Stores all object's details apart from inventory - /// - /// - /// - public void StoreObject(SceneObjectGroup obj, UUID regionUUID) - { - uint flags = obj.RootPart.GetEffectiveObjectFlags(); - // Eligibility check - // - if ((flags & (uint)PrimFlags.Temporary) != 0) - return; - if ((flags & (uint)PrimFlags.TemporaryOnRez) != 0) - return; - - _Log.DebugFormat("[MSSQL]: Adding/Changing SceneObjectGroup: {0} to region: {1}, object has {2} prims.", obj.UUID, regionUUID, obj.Parts.Length); - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - { - conn.Open(); - SqlTransaction transaction = conn.BeginTransaction(); - - try - { - foreach (SceneObjectPart sceneObjectPart in obj.Parts) - { - //Update prim - using (SqlCommand sqlCommand = conn.CreateCommand()) - { - sqlCommand.Transaction = transaction; - try - { - StoreSceneObjectPrim(sceneObjectPart, sqlCommand, obj.UUID, regionUUID); - } - catch (SqlException sqlEx) - { - _Log.ErrorFormat("[REGION DB]: Store SceneObjectPrim SQL error: {0} at line {1}", sqlEx.Message, sqlEx.LineNumber); - throw; - } - } - - //Update primshapes - using (SqlCommand sqlCommand = conn.CreateCommand()) - { - sqlCommand.Transaction = transaction; - try - { - StoreSceneObjectPrimShapes(sceneObjectPart, sqlCommand, obj.UUID, regionUUID); - } - catch (SqlException sqlEx) - { - _Log.ErrorFormat("[REGION DB]: Store SceneObjectPrimShapes SQL error: {0} at line {1}", sqlEx.Message, sqlEx.LineNumber); - throw; - } - } - } - - transaction.Commit(); - } - catch (Exception ex) - { - _Log.ErrorFormat("[REGION DB]: Store SceneObjectGroup error: {0}, Rolling back...", ex.Message); - try - { - transaction.Rollback(); - } - catch (Exception ex2) - { - //Show error - _Log.InfoFormat("[REGION DB]: Rollback of SceneObjectGroup store transaction failed with error: {0}", ex2.Message); - - } - } - } - } - - /// - /// Stores the prim of the sceneobjectpart. - /// - /// The sceneobjectpart or prim. - /// The SQL command with the transaction. - /// The scenegroup UUID. - /// The region UUID. - private void StoreSceneObjectPrim(SceneObjectPart sceneObjectPart, SqlCommand sqlCommand, UUID sceneGroupID, UUID regionUUID) - { - //Big query to update or insert a new prim. - //Note for SQL Server 2008 this could be simplified - string queryPrims = @" -IF EXISTS (SELECT UUID FROM prims WHERE UUID = @UUID) - BEGIN - UPDATE prims SET - CreationDate = @CreationDate, Name = @Name, Text = @Text, Description = @Description, SitName = @SitName, - TouchName = @TouchName, ObjectFlags = @ObjectFlags, OwnerMask = @OwnerMask, NextOwnerMask = @NextOwnerMask, GroupMask = @GroupMask, - EveryoneMask = @EveryoneMask, BaseMask = @BaseMask, PositionX = @PositionX, PositionY = @PositionY, PositionZ = @PositionZ, - GroupPositionX = @GroupPositionX, GroupPositionY = @GroupPositionY, GroupPositionZ = @GroupPositionZ, VelocityX = @VelocityX, - VelocityY = @VelocityY, VelocityZ = @VelocityZ, AngularVelocityX = @AngularVelocityX, AngularVelocityY = @AngularVelocityY, - AngularVelocityZ = @AngularVelocityZ, AccelerationX = @AccelerationX, AccelerationY = @AccelerationY, - AccelerationZ = @AccelerationZ, RotationX = @RotationX, RotationY = @RotationY, RotationZ = @RotationZ, RotationW = @RotationW, - SitTargetOffsetX = @SitTargetOffsetX, SitTargetOffsetY = @SitTargetOffsetY, SitTargetOffsetZ = @SitTargetOffsetZ, - SitTargetOrientW = @SitTargetOrientW, SitTargetOrientX = @SitTargetOrientX, SitTargetOrientY = @SitTargetOrientY, - SitTargetOrientZ = @SitTargetOrientZ, RegionUUID = @RegionUUID, CreatorID = @CreatorID, OwnerID = @OwnerID, GroupID = @GroupID, - LastOwnerID = @LastOwnerID, SceneGroupID = @SceneGroupID, PayPrice = @PayPrice, PayButton1 = @PayButton1, PayButton2 = @PayButton2, - PayButton3 = @PayButton3, PayButton4 = @PayButton4, LoopedSound = @LoopedSound, LoopedSoundGain = @LoopedSoundGain, - TextureAnimation = @TextureAnimation, OmegaX = @OmegaX, OmegaY = @OmegaY, OmegaZ = @OmegaZ, CameraEyeOffsetX = @CameraEyeOffsetX, - CameraEyeOffsetY = @CameraEyeOffsetY, CameraEyeOffsetZ = @CameraEyeOffsetZ, CameraAtOffsetX = @CameraAtOffsetX, - CameraAtOffsetY = @CameraAtOffsetY, CameraAtOffsetZ = @CameraAtOffsetZ, ForceMouselook = @ForceMouselook, - ScriptAccessPin = @ScriptAccessPin, AllowedDrop = @AllowedDrop, DieAtEdge = @DieAtEdge, SalePrice = @SalePrice, - SaleType = @SaleType, ColorR = @ColorR, ColorG = @ColorG, ColorB = @ColorB, ColorA = @ColorA, ParticleSystem = @ParticleSystem, - ClickAction = @ClickAction, Material = @Material, CollisionSound = @CollisionSound, CollisionSoundVolume = @CollisionSoundVolume, PassTouches = @PassTouches, - LinkNumber = @LinkNumber, MediaURL = @MediaURL - WHERE UUID = @UUID - END -ELSE - BEGIN - INSERT INTO - prims ( - UUID, CreationDate, Name, Text, Description, SitName, TouchName, ObjectFlags, OwnerMask, NextOwnerMask, GroupMask, - EveryoneMask, BaseMask, PositionX, PositionY, PositionZ, GroupPositionX, GroupPositionY, GroupPositionZ, VelocityX, - VelocityY, VelocityZ, AngularVelocityX, AngularVelocityY, AngularVelocityZ, AccelerationX, AccelerationY, AccelerationZ, - RotationX, RotationY, RotationZ, RotationW, SitTargetOffsetX, SitTargetOffsetY, SitTargetOffsetZ, SitTargetOrientW, - SitTargetOrientX, SitTargetOrientY, SitTargetOrientZ, RegionUUID, CreatorID, OwnerID, GroupID, LastOwnerID, SceneGroupID, - PayPrice, PayButton1, PayButton2, PayButton3, PayButton4, LoopedSound, LoopedSoundGain, TextureAnimation, OmegaX, - OmegaY, OmegaZ, CameraEyeOffsetX, CameraEyeOffsetY, CameraEyeOffsetZ, CameraAtOffsetX, CameraAtOffsetY, CameraAtOffsetZ, - ForceMouselook, ScriptAccessPin, AllowedDrop, DieAtEdge, SalePrice, SaleType, ColorR, ColorG, ColorB, ColorA, - ParticleSystem, ClickAction, Material, CollisionSound, CollisionSoundVolume, PassTouches, LinkNumber, MediaURL - ) VALUES ( - @UUID, @CreationDate, @Name, @Text, @Description, @SitName, @TouchName, @ObjectFlags, @OwnerMask, @NextOwnerMask, @GroupMask, - @EveryoneMask, @BaseMask, @PositionX, @PositionY, @PositionZ, @GroupPositionX, @GroupPositionY, @GroupPositionZ, @VelocityX, - @VelocityY, @VelocityZ, @AngularVelocityX, @AngularVelocityY, @AngularVelocityZ, @AccelerationX, @AccelerationY, @AccelerationZ, - @RotationX, @RotationY, @RotationZ, @RotationW, @SitTargetOffsetX, @SitTargetOffsetY, @SitTargetOffsetZ, @SitTargetOrientW, - @SitTargetOrientX, @SitTargetOrientY, @SitTargetOrientZ, @RegionUUID, @CreatorID, @OwnerID, @GroupID, @LastOwnerID, @SceneGroupID, - @PayPrice, @PayButton1, @PayButton2, @PayButton3, @PayButton4, @LoopedSound, @LoopedSoundGain, @TextureAnimation, @OmegaX, - @OmegaY, @OmegaZ, @CameraEyeOffsetX, @CameraEyeOffsetY, @CameraEyeOffsetZ, @CameraAtOffsetX, @CameraAtOffsetY, @CameraAtOffsetZ, - @ForceMouselook, @ScriptAccessPin, @AllowedDrop, @DieAtEdge, @SalePrice, @SaleType, @ColorR, @ColorG, @ColorB, @ColorA, - @ParticleSystem, @ClickAction, @Material, @CollisionSound, @CollisionSoundVolume, @PassTouches, @LinkNumber, @MediaURL - ) - END"; - - //Set commandtext. - sqlCommand.CommandText = queryPrims; - //Add parameters - sqlCommand.Parameters.AddRange(CreatePrimParameters(sceneObjectPart, sceneGroupID, regionUUID)); - - //Execute the query. If it fails then error is trapped in calling function - sqlCommand.ExecuteNonQuery(); - } - - /// - /// Stores the scene object prim shapes. - /// - /// The sceneobjectpart containing prim shape. - /// The SQL command with the transaction. - /// The scenegroup UUID. - /// The region UUID. - private void StoreSceneObjectPrimShapes(SceneObjectPart sceneObjectPart, SqlCommand sqlCommand, UUID sceneGroupID, UUID regionUUID) - { - //Big query to or insert or update primshapes - //Note for SQL Server 2008 this can be simplified - string queryPrimShapes = @" -IF EXISTS (SELECT UUID FROM primshapes WHERE UUID = @UUID) - BEGIN - UPDATE primshapes SET - Shape = @Shape, ScaleX = @ScaleX, ScaleY = @ScaleY, ScaleZ = @ScaleZ, PCode = @PCode, PathBegin = @PathBegin, - PathEnd = @PathEnd, PathScaleX = @PathScaleX, PathScaleY = @PathScaleY, PathShearX = @PathShearX, PathShearY = @PathShearY, - PathSkew = @PathSkew, PathCurve = @PathCurve, PathRadiusOffset = @PathRadiusOffset, PathRevolutions = @PathRevolutions, - PathTaperX = @PathTaperX, PathTaperY = @PathTaperY, PathTwist = @PathTwist, PathTwistBegin = @PathTwistBegin, - ProfileBegin = @ProfileBegin, ProfileEnd = @ProfileEnd, ProfileCurve = @ProfileCurve, ProfileHollow = @ProfileHollow, - Texture = @Texture, ExtraParams = @ExtraParams, State = @State, Media = @Media - WHERE UUID = @UUID - END -ELSE - BEGIN - INSERT INTO - primshapes ( - UUID, Shape, ScaleX, ScaleY, ScaleZ, PCode, PathBegin, PathEnd, PathScaleX, PathScaleY, PathShearX, PathShearY, - PathSkew, PathCurve, PathRadiusOffset, PathRevolutions, PathTaperX, PathTaperY, PathTwist, PathTwistBegin, ProfileBegin, - ProfileEnd, ProfileCurve, ProfileHollow, Texture, ExtraParams, State, Media - ) VALUES ( - @UUID, @Shape, @ScaleX, @ScaleY, @ScaleZ, @PCode, @PathBegin, @PathEnd, @PathScaleX, @PathScaleY, @PathShearX, @PathShearY, - @PathSkew, @PathCurve, @PathRadiusOffset, @PathRevolutions, @PathTaperX, @PathTaperY, @PathTwist, @PathTwistBegin, @ProfileBegin, - @ProfileEnd, @ProfileCurve, @ProfileHollow, @Texture, @ExtraParams, @State, @Media - ) - END"; - - //Set commandtext. - sqlCommand.CommandText = queryPrimShapes; - - //Add parameters - sqlCommand.Parameters.AddRange(CreatePrimShapeParameters(sceneObjectPart, sceneGroupID, regionUUID)); - - //Execute the query. If it fails then error is trapped in calling function - sqlCommand.ExecuteNonQuery(); - - } - - /// - /// Removes a object from the database. - /// Meaning removing it from tables Prims, PrimShapes and PrimItems - /// - /// id of scenegroup - /// regionUUID (is this used anyway - public void RemoveObject(UUID objectID, UUID regionUUID) - { - _Log.InfoFormat("[MSSQL]: Removing obj: {0} from region: {1}", objectID, regionUUID); - - //Remove from prims and primsitem table - string sqlPrims = "DELETE FROM PRIMS WHERE SceneGroupID = @objectID"; - string sqlPrimItems = "DELETE FROM PRIMITEMS WHERE primID in (SELECT UUID FROM PRIMS WHERE SceneGroupID = @objectID)"; - string sqlPrimShapes = "DELETE FROM PRIMSHAPES WHERE uuid in (SELECT UUID FROM PRIMS WHERE SceneGroupID = @objectID)"; - - lock (_Database) - { - //Using the non transaction mode. - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand()) - { - cmd.Connection = conn; - cmd.CommandText = sqlPrimShapes; - conn.Open(); - cmd.Parameters.Add(_Database.CreateParameter("objectID", objectID)); - cmd.ExecuteNonQuery(); - - cmd.CommandText = sqlPrimItems; - cmd.ExecuteNonQuery(); - - cmd.CommandText = sqlPrims; - cmd.ExecuteNonQuery(); - } - } - } - - /// - /// Store the inventory of a prim. Warning deletes everything first and then adds all again. - /// - /// - /// - public void StorePrimInventory(UUID primID, ICollection items) - { - //_Log.InfoFormat("[REGION DB: Persisting Prim Inventory with prim ID {0}", primID); - - //Statement from MySQL section! - // For now, we're just going to crudely remove all the previous inventory items - // no matter whether they have changed or not, and replace them with the current set. - - //Delete everything from PrimID - //TODO add index on PrimID in DB, if not already exist - - string sql = "DELETE PRIMITEMS WHERE primID = @primID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@primID", primID)); - conn.Open(); - cmd.ExecuteNonQuery(); - } - - sql = - @"INSERT INTO primitems ( - itemID,primID,assetID,parentFolderID,invType,assetType,name,description,creationDate,creatorID,ownerID,lastOwnerID,groupID, - nextPermissions,currentPermissions,basePermissions,everyonePermissions,groupPermissions,flags) - VALUES (@itemID,@primID,@assetID,@parentFolderID,@invType,@assetType,@name,@description,@creationDate,@creatorID,@ownerID, - @lastOwnerID,@groupID,@nextPermissions,@currentPermissions,@basePermissions,@everyonePermissions,@groupPermissions,@flags)"; - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - conn.Open(); - foreach (TaskInventoryItem taskItem in items) - { - cmd.Parameters.AddRange(CreatePrimInventoryParameters(taskItem)); - cmd.ExecuteNonQuery(); - cmd.Parameters.Clear(); - } - } - } - - #endregion - - /// - /// Loads the terrain map. - /// - /// regionID. - /// - public double[,] LoadTerrain(UUID regionID) - { - double[,] terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize]; - terrain.Initialize(); - - string sql = "select top 1 RegionUUID, Revision, Heightfield from terrain where RegionUUID = @RegionUUID order by Revision desc"; - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - // MySqlParameter param = new MySqlParameter(); - cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID)); - conn.Open(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - int rev; - if (reader.Read()) - { - MemoryStream str = new MemoryStream((byte[])reader["Heightfield"]); - BinaryReader br = new BinaryReader(str); - for (int x = 0; x < (int)Constants.RegionSize; x++) - { - for (int y = 0; y < (int)Constants.RegionSize; y++) - { - terrain[x, y] = br.ReadDouble(); - } - } - rev = (int)reader["Revision"]; - } - else - { - _Log.Info("[REGION DB]: No terrain found for region"); - return null; - } - _Log.Info("[REGION DB]: Loaded terrain revision r" + rev); - } - } - - return terrain; - } - - /// - /// Stores the terrain map to DB. - /// - /// terrain map data. - /// regionID. - public void StoreTerrain(double[,] terrain, UUID regionID) - { - int revision = Util.UnixTimeSinceEpoch(); - - //Delete old terrain map - string sql = "delete from terrain where RegionUUID=@RegionUUID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID)); - conn.Open(); - cmd.ExecuteNonQuery(); - } - - sql = "insert into terrain(RegionUUID, Revision, Heightfield) values(@RegionUUID, @Revision, @Heightfield)"; - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID)); - cmd.Parameters.Add(_Database.CreateParameter("@Revision", revision)); - cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", serializeTerrain(terrain))); - conn.Open(); - cmd.ExecuteNonQuery(); - } - - _Log.Info("[REGION DB]: Stored terrain revision r " + revision); - } - - /// - /// Loads all the land objects of a region. - /// - /// The region UUID. - /// - public List LoadLandObjects(UUID regionUUID) - { - List LandDataForRegion = new List(); - - string sql = "select * from land where RegionUUID = @RegionUUID"; - - //Retrieve all land data from region - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionUUID)); - conn.Open(); - using (SqlDataReader readerLandData = cmd.ExecuteReader()) - { - while (readerLandData.Read()) - { - LandDataForRegion.Add(BuildLandData(readerLandData)); - } - } - } - - //Retrieve all accesslist data for all landdata - foreach (LandData LandData in LandDataForRegion) - { - sql = "select * from landaccesslist where LandUUID = @LandUUID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@LandUUID", LandData.GlobalID)); - conn.Open(); - using (SqlDataReader readerAccessList = cmd.ExecuteReader()) - { - while (readerAccessList.Read()) - { - LandData.ParcelAccessList.Add(BuildLandAccessData(readerAccessList)); - } - } - } - } - - //Return data - return LandDataForRegion; - } - - /// - /// Stores land object with landaccess list. - /// - /// parcel data. - public void StoreLandObject(ILandObject parcel) - { - //As this is only one record in land table I just delete all and then add a new record. - //As the delete landaccess is already in the mysql code - - //Delete old values - RemoveLandObject(parcel.LandData.GlobalID); - - //Insert new values - string sql = @"INSERT INTO [land] -([UUID],[RegionUUID],[LocalLandID],[Bitmap],[Name],[Description],[OwnerUUID],[IsGroupOwned],[Area],[AuctionID],[Category],[ClaimDate],[ClaimPrice],[GroupUUID],[SalePrice],[LandStatus],[LandFlags],[LandingType],[MediaAutoScale],[MediaTextureUUID],[MediaURL],[MusicURL],[PassHours],[PassPrice],[SnapshotUUID],[UserLocationX],[UserLocationY],[UserLocationZ],[UserLookAtX],[UserLookAtY],[UserLookAtZ],[AuthbuyerID],[OtherCleanTime]) -VALUES -(@UUID,@RegionUUID,@LocalLandID,@Bitmap,@Name,@Description,@OwnerUUID,@IsGroupOwned,@Area,@AuctionID,@Category,@ClaimDate,@ClaimPrice,@GroupUUID,@SalePrice,@LandStatus,@LandFlags,@LandingType,@MediaAutoScale,@MediaTextureUUID,@MediaURL,@MusicURL,@PassHours,@PassPrice,@SnapshotUUID,@UserLocationX,@UserLocationY,@UserLocationZ,@UserLookAtX,@UserLookAtY,@UserLookAtZ,@AuthbuyerID,@OtherCleanTime)"; - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.AddRange(CreateLandParameters(parcel.LandData, parcel.RegionUUID)); - conn.Open(); - cmd.ExecuteNonQuery(); - } - - sql = "INSERT INTO [landaccesslist] ([LandUUID],[AccessUUID],[Flags],[Expires]) VALUES (@LandUUID,@AccessUUID,@Flags,@Expires)"; - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - conn.Open(); - foreach (LandAccessEntry parcelAccessEntry in parcel.LandData.ParcelAccessList) - { - cmd.Parameters.AddRange(CreateLandAccessParameters(parcelAccessEntry, parcel.RegionUUID)); - - cmd.ExecuteNonQuery(); - cmd.Parameters.Clear(); - } - } - } - - /// - /// Removes a land object from DB. - /// - /// UUID of landobject - public void RemoveLandObject(UUID globalID) - { - string sql = "delete from land where UUID=@UUID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@UUID", globalID)); - conn.Open(); - cmd.ExecuteNonQuery(); - } - sql = "delete from landaccesslist where LandUUID=@UUID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@UUID", globalID)); - conn.Open(); - cmd.ExecuteNonQuery(); - } - } - public RegionLightShareData LoadRegionWindlightSettings(UUID regionUUID) - { - RegionLightShareData nWP = new RegionLightShareData(); - nWP.OnSave += StoreRegionWindlightSettings; - string sql = "select * from [regionwindlight] where region_id = @regionID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@regionID", regionUUID)); - conn.Open(); - using (SqlDataReader result = cmd.ExecuteReader()) - { - if (!result.Read()) - { - //No result, so store our default windlight profile and return it - nWP.regionID = regionUUID; - StoreRegionWindlightSettings(nWP); - return nWP; - } - else - { - nWP.regionID = DBGuid.FromDB(result["region_id"]); - nWP.waterColor.X = Convert.ToSingle(result["water_color_r"]); - nWP.waterColor.Y = Convert.ToSingle(result["water_color_g"]); - nWP.waterColor.Z = Convert.ToSingle(result["water_color_b"]); - nWP.waterFogDensityExponent = Convert.ToSingle(result["water_fog_density_exponent"]); - nWP.underwaterFogModifier = Convert.ToSingle(result["underwater_fog_modifier"]); - nWP.reflectionWaveletScale.X = Convert.ToSingle(result["reflection_wavelet_scale_1"]); - nWP.reflectionWaveletScale.Y = Convert.ToSingle(result["reflection_wavelet_scale_2"]); - nWP.reflectionWaveletScale.Z = Convert.ToSingle(result["reflection_wavelet_scale_3"]); - nWP.fresnelScale = Convert.ToSingle(result["fresnel_scale"]); - nWP.fresnelOffset = Convert.ToSingle(result["fresnel_offset"]); - nWP.refractScaleAbove = Convert.ToSingle(result["refract_scale_above"]); - nWP.refractScaleBelow = Convert.ToSingle(result["refract_scale_below"]); - nWP.blurMultiplier = Convert.ToSingle(result["blur_multiplier"]); - nWP.bigWaveDirection.X = Convert.ToSingle(result["big_wave_direction_x"]); - nWP.bigWaveDirection.Y = Convert.ToSingle(result["big_wave_direction_y"]); - nWP.littleWaveDirection.X = Convert.ToSingle(result["little_wave_direction_x"]); - nWP.littleWaveDirection.Y = Convert.ToSingle(result["little_wave_direction_y"]); - UUID.TryParse(result["normal_map_texture"].ToString(), out nWP.normalMapTexture); - nWP.horizon.X = Convert.ToSingle(result["horizon_r"]); - nWP.horizon.Y = Convert.ToSingle(result["horizon_g"]); - nWP.horizon.Z = Convert.ToSingle(result["horizon_b"]); - nWP.horizon.W = Convert.ToSingle(result["horizon_i"]); - nWP.hazeHorizon = Convert.ToSingle(result["haze_horizon"]); - nWP.blueDensity.X = Convert.ToSingle(result["blue_density_r"]); - nWP.blueDensity.Y = Convert.ToSingle(result["blue_density_g"]); - nWP.blueDensity.Z = Convert.ToSingle(result["blue_density_b"]); - nWP.blueDensity.W = Convert.ToSingle(result["blue_density_i"]); - nWP.hazeDensity = Convert.ToSingle(result["haze_density"]); - nWP.densityMultiplier = Convert.ToSingle(result["density_multiplier"]); - nWP.distanceMultiplier = Convert.ToSingle(result["distance_multiplier"]); - nWP.maxAltitude = Convert.ToUInt16(result["max_altitude"]); - nWP.sunMoonColor.X = Convert.ToSingle(result["sun_moon_color_r"]); - nWP.sunMoonColor.Y = Convert.ToSingle(result["sun_moon_color_g"]); - nWP.sunMoonColor.Z = Convert.ToSingle(result["sun_moon_color_b"]); - nWP.sunMoonColor.W = Convert.ToSingle(result["sun_moon_color_i"]); - nWP.sunMoonPosition = Convert.ToSingle(result["sun_moon_position"]); - nWP.ambient.X = Convert.ToSingle(result["ambient_r"]); - nWP.ambient.Y = Convert.ToSingle(result["ambient_g"]); - nWP.ambient.Z = Convert.ToSingle(result["ambient_b"]); - nWP.ambient.W = Convert.ToSingle(result["ambient_i"]); - nWP.eastAngle = Convert.ToSingle(result["east_angle"]); - nWP.sunGlowFocus = Convert.ToSingle(result["sun_glow_focus"]); - nWP.sunGlowSize = Convert.ToSingle(result["sun_glow_size"]); - nWP.sceneGamma = Convert.ToSingle(result["scene_gamma"]); - nWP.starBrightness = Convert.ToSingle(result["star_brightness"]); - nWP.cloudColor.X = Convert.ToSingle(result["cloud_color_r"]); - nWP.cloudColor.Y = Convert.ToSingle(result["cloud_color_g"]); - nWP.cloudColor.Z = Convert.ToSingle(result["cloud_color_b"]); - nWP.cloudColor.W = Convert.ToSingle(result["cloud_color_i"]); - nWP.cloudXYDensity.X = Convert.ToSingle(result["cloud_x"]); - nWP.cloudXYDensity.Y = Convert.ToSingle(result["cloud_y"]); - nWP.cloudXYDensity.Z = Convert.ToSingle(result["cloud_density"]); - nWP.cloudCoverage = Convert.ToSingle(result["cloud_coverage"]); - nWP.cloudScale = Convert.ToSingle(result["cloud_scale"]); - nWP.cloudDetailXYDensity.X = Convert.ToSingle(result["cloud_detail_x"]); - nWP.cloudDetailXYDensity.Y = Convert.ToSingle(result["cloud_detail_y"]); - nWP.cloudDetailXYDensity.Z = Convert.ToSingle(result["cloud_detail_density"]); - nWP.cloudScrollX = Convert.ToSingle(result["cloud_scroll_x"]); - nWP.cloudScrollXLock = Convert.ToBoolean(result["cloud_scroll_x_lock"]); - nWP.cloudScrollY = Convert.ToSingle(result["cloud_scroll_y"]); - nWP.cloudScrollYLock = Convert.ToBoolean(result["cloud_scroll_y_lock"]); - nWP.drawClassicClouds = Convert.ToBoolean(result["draw_classic_clouds"]); - nWP.valid = true; - } - } - } - return nWP; - } - - public void RemoveRegionWindlightSettings(UUID regionID) - { - string sql = "delete from [regionwindlight] where region_id = @region_id"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - conn.Open(); - cmd.Parameters.Add(_Database.CreateParameter("@region_id", regionID)); - cmd.ExecuteNonQuery(); - } - } - - public void StoreRegionWindlightSettings(RegionLightShareData wl) - { - string sql = "select count (region_id) from regionwindlight where region_id = @region_id"; - bool exists = false; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - { - conn.Open(); - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@region_id", wl.regionID)); - exists = (int)cmd.ExecuteScalar() > 0; - } - } - if (exists) - { - RemoveRegionWindlightSettings(wl.regionID); - } - - // sql insert - sql = @"INSERT INTO [regionwindlight] - ([region_id] - ,[water_color_r] - ,[water_color_g] - ,[water_color_b] - ,[water_fog_density_exponent] - ,[underwater_fog_modifier] - ,[reflection_wavelet_scale_1] - ,[reflection_wavelet_scale_2] - ,[reflection_wavelet_scale_3] - ,[fresnel_scale] - ,[fresnel_offset] - ,[refract_scale_above] - ,[refract_scale_below] - ,[blur_multiplier] - ,[big_wave_direction_x] - ,[big_wave_direction_y] - ,[little_wave_direction_x] - ,[little_wave_direction_y] - ,[normal_map_texture] - ,[horizon_r] - ,[horizon_g] - ,[horizon_b] - ,[horizon_i] - ,[haze_horizon] - ,[blue_density_r] - ,[blue_density_g] - ,[blue_density_b] - ,[blue_density_i] - ,[haze_density] - ,[density_multiplier] - ,[distance_multiplier] - ,[max_altitude] - ,[sun_moon_color_r] - ,[sun_moon_color_g] - ,[sun_moon_color_b] - ,[sun_moon_color_i] - ,[sun_moon_position] - ,[ambient_r] - ,[ambient_g] - ,[ambient_b] - ,[ambient_i] - ,[east_angle] - ,[sun_glow_focus] - ,[sun_glow_size] - ,[scene_gamma] - ,[star_brightness] - ,[cloud_color_r] - ,[cloud_color_g] - ,[cloud_color_b] - ,[cloud_color_i] - ,[cloud_x] - ,[cloud_y] - ,[cloud_density] - ,[cloud_coverage] - ,[cloud_scale] - ,[cloud_detail_x] - ,[cloud_detail_y] - ,[cloud_detail_density] - ,[cloud_scroll_x] - ,[cloud_scroll_x_lock] - ,[cloud_scroll_y] - ,[cloud_scroll_y_lock] - ,[draw_classic_clouds]) - VALUES - (@region_id - ,@water_color_r - ,@water_color_g - ,@water_color_b - ,@water_fog_density_exponent - ,@underwater_fog_modifier - ,@reflection_wavelet_scale_1 - ,@reflection_wavelet_scale_2 - ,@reflection_wavelet_scale_3 - ,@fresnel_scale - ,@fresnel_offset - ,@refract_scale_above - ,@refract_scale_below - ,@blur_multiplier - ,@big_wave_direction_x - ,@big_wave_direction_y - ,@little_wave_direction_x - ,@little_wave_direction_y - ,@normal_map_texture - ,@horizon_r - ,@horizon_g - ,@horizon_b - ,@horizon_i - ,@haze_horizon - ,@blue_density_r - ,@blue_density_g - ,@blue_density_b - ,@blue_density_i - ,@haze_density - ,@density_multiplier - ,@distance_multiplier - ,@max_altitude - ,@sun_moon_color_r - ,@sun_moon_color_g - ,@sun_moon_color_b - ,@sun_moon_color_i - ,@sun_moon_position - ,@ambient_r - ,@ambient_g - ,@ambient_b - ,@ambient_i - ,@east_angle - ,@sun_glow_focus - ,@sun_glow_size - ,@scene_gamma - ,@star_brightness - ,@cloud_color_r - ,@cloud_color_g - ,@cloud_color_b - ,@cloud_color_i - ,@cloud_x - ,@cloud_y - ,@cloud_density - ,@cloud_coverage - ,@cloud_scale - ,@cloud_detail_x - ,@cloud_detail_y - ,@cloud_detail_density - ,@cloud_scroll_x - ,@cloud_scroll_x_lock - ,@cloud_scroll_y - ,@cloud_scroll_y_lock - ,@draw_classic_clouds)"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - { - conn.Open(); - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("region_id", wl.regionID)); - cmd.Parameters.Add(_Database.CreateParameter("water_color_r", wl.waterColor.X)); - cmd.Parameters.Add(_Database.CreateParameter("water_color_g", wl.waterColor.Y)); - cmd.Parameters.Add(_Database.CreateParameter("water_color_b", wl.waterColor.Z)); - cmd.Parameters.Add(_Database.CreateParameter("water_fog_density_exponent", wl.waterFogDensityExponent)); - cmd.Parameters.Add(_Database.CreateParameter("underwater_fog_modifier", wl.underwaterFogModifier)); - cmd.Parameters.Add(_Database.CreateParameter("reflection_wavelet_scale_1", wl.reflectionWaveletScale.X)); - cmd.Parameters.Add(_Database.CreateParameter("reflection_wavelet_scale_2", wl.reflectionWaveletScale.Y)); - cmd.Parameters.Add(_Database.CreateParameter("reflection_wavelet_scale_3", wl.reflectionWaveletScale.Z)); - cmd.Parameters.Add(_Database.CreateParameter("fresnel_scale", wl.fresnelScale)); - cmd.Parameters.Add(_Database.CreateParameter("fresnel_offset", wl.fresnelOffset)); - cmd.Parameters.Add(_Database.CreateParameter("refract_scale_above", wl.refractScaleAbove)); - cmd.Parameters.Add(_Database.CreateParameter("refract_scale_below", wl.refractScaleBelow)); - cmd.Parameters.Add(_Database.CreateParameter("blur_multiplier", wl.blurMultiplier)); - cmd.Parameters.Add(_Database.CreateParameter("big_wave_direction_x", wl.bigWaveDirection.X)); - cmd.Parameters.Add(_Database.CreateParameter("big_wave_direction_y", wl.bigWaveDirection.Y)); - cmd.Parameters.Add(_Database.CreateParameter("little_wave_direction_x", wl.littleWaveDirection.X)); - cmd.Parameters.Add(_Database.CreateParameter("little_wave_direction_y", wl.littleWaveDirection.Y)); - cmd.Parameters.Add(_Database.CreateParameter("normal_map_texture", wl.normalMapTexture)); - cmd.Parameters.Add(_Database.CreateParameter("horizon_r", wl.horizon.X)); - cmd.Parameters.Add(_Database.CreateParameter("horizon_g", wl.horizon.Y)); - cmd.Parameters.Add(_Database.CreateParameter("horizon_b", wl.horizon.Z)); - cmd.Parameters.Add(_Database.CreateParameter("horizon_i", wl.horizon.W)); - cmd.Parameters.Add(_Database.CreateParameter("haze_horizon", wl.hazeHorizon)); - cmd.Parameters.Add(_Database.CreateParameter("blue_density_r", wl.blueDensity.X)); - cmd.Parameters.Add(_Database.CreateParameter("blue_density_g", wl.blueDensity.Y)); - cmd.Parameters.Add(_Database.CreateParameter("blue_density_b", wl.blueDensity.Z)); - cmd.Parameters.Add(_Database.CreateParameter("blue_density_i", wl.blueDensity.W)); - cmd.Parameters.Add(_Database.CreateParameter("haze_density", wl.hazeDensity)); - cmd.Parameters.Add(_Database.CreateParameter("density_multiplier", wl.densityMultiplier)); - cmd.Parameters.Add(_Database.CreateParameter("distance_multiplier", wl.distanceMultiplier)); - cmd.Parameters.Add(_Database.CreateParameter("max_altitude", wl.maxAltitude)); - cmd.Parameters.Add(_Database.CreateParameter("sun_moon_color_r", wl.sunMoonColor.X)); - cmd.Parameters.Add(_Database.CreateParameter("sun_moon_color_g", wl.sunMoonColor.Y)); - cmd.Parameters.Add(_Database.CreateParameter("sun_moon_color_b", wl.sunMoonColor.Z)); - cmd.Parameters.Add(_Database.CreateParameter("sun_moon_color_i", wl.sunMoonColor.W)); - cmd.Parameters.Add(_Database.CreateParameter("sun_moon_position", wl.sunMoonPosition)); - cmd.Parameters.Add(_Database.CreateParameter("ambient_r", wl.ambient.X)); - cmd.Parameters.Add(_Database.CreateParameter("ambient_g", wl.ambient.Y)); - cmd.Parameters.Add(_Database.CreateParameter("ambient_b", wl.ambient.Z)); - cmd.Parameters.Add(_Database.CreateParameter("ambient_i", wl.ambient.W)); - cmd.Parameters.Add(_Database.CreateParameter("east_angle", wl.eastAngle)); - cmd.Parameters.Add(_Database.CreateParameter("sun_glow_focus", wl.sunGlowFocus)); - cmd.Parameters.Add(_Database.CreateParameter("sun_glow_size", wl.sunGlowSize)); - cmd.Parameters.Add(_Database.CreateParameter("scene_gamma", wl.sceneGamma)); - cmd.Parameters.Add(_Database.CreateParameter("star_brightness", wl.starBrightness)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_color_r", wl.cloudColor.X)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_color_g", wl.cloudColor.Y)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_color_b", wl.cloudColor.Z)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_color_i", wl.cloudColor.W)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_x", wl.cloudXYDensity.X)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_y", wl.cloudXYDensity.Y)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_density", wl.cloudXYDensity.Z)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_coverage", wl.cloudCoverage)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_scale", wl.cloudScale)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_detail_x", wl.cloudDetailXYDensity.X)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_detail_y", wl.cloudDetailXYDensity.Y)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_detail_density", wl.cloudDetailXYDensity.Z)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_scroll_x", wl.cloudScrollX)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_scroll_x_lock", wl.cloudScrollXLock)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_scroll_y", wl.cloudScrollY)); - cmd.Parameters.Add(_Database.CreateParameter("cloud_scroll_y_lock", wl.cloudScrollYLock)); - cmd.Parameters.Add(_Database.CreateParameter("draw_classic_clouds", wl.drawClassicClouds)); - - cmd.ExecuteNonQuery(); - } - } - #region update - // } - // else - // { - // // sql update - // sql = @"UPDATE [OpenSim].[dbo].[regionwindlight] - // SET [region_id] = @region_id - // ,[water_color_r] = @water_color_r - // ,[water_color_g] = @water_color_g - // ,[water_color_b] = @water_color_b - // ,[water_fog_density_exponent] = @water_fog_density_exponent - // ,[underwater_fog_modifier] = @underwater_fog_modifier - // ,[reflection_wavelet_scale_1] = @reflection_wavelet_scale_1 - // ,[reflection_wavelet_scale_2] = @reflection_wavelet_scale_2 - // ,[reflection_wavelet_scale_3] = @reflection_wavelet_scale_3 - // ,[fresnel_scale] = @fresnel_scale - // ,[fresnel_offset] = @fresnel_offset - // ,[refract_scale_above] = @refract_scale_above - // ,[refract_scale_below] = @refract_scale_below - // ,[blur_multiplier] = @blur_multiplier - // ,[big_wave_direction_x] = @big_wave_direction_x - // ,[big_wave_direction_y] = @big_wave_direction_y - // ,[little_wave_direction_x] = @little_wave_direction_x - // ,[little_wave_direction_y] = @little_wave_direction_y - // ,[normal_map_texture] = @normal_map_texture - // ,[horizon_r] = @horizon_r - // ,[horizon_g] = @horizon_g - // ,[horizon_b] = @horizon_b - // ,[horizon_i] = @horizon_i - // ,[haze_horizon] = @haze_horizon - // ,[blue_density_r] = @blue_density_r - // ,[blue_density_g] = @blue_density_g - // ,[blue_density_b] = @blue_density_b - // ,[blue_density_i] = @blue_density_i - // ,[haze_density] = @haze_density - // ,[density_multiplier] = @density_multiplier - // ,[distance_multiplier] = @distance_multiplier - // ,[max_altitude] = @max_altitude - // ,[sun_moon_color_r] = @sun_moon_color_r - // ,[sun_moon_color_g] = @sun_moon_color_g - // ,[sun_moon_color_b] = @sun_moon_color_b - // ,[sun_moon_color_i] = @sun_moon_color_i - // ,[sun_moon_position] = @sun_moon_position - // ,[ambient_r] = @ambient_r - // ,[ambient_g] = @ambient_g - // ,[ambient_b] = @ambient_b - // ,[ambient_i] = @ambient_i - // ,[east_angle] = @east_angle - // ,[sun_glow_focus] = @sun_glow_focus - // ,[sun_glow_size] = @sun_glow_size - // ,[scene_gamma] = @scene_gamma - // ,[star_brightness] = @star_brightness - // ,[cloud_color_r] = @cloud_color_r - // ,[cloud_color_g] = @cloud_color_g - // ,[cloud_color_b] = @cloud_color_b - // ,[cloud_color_i] = @cloud_color_i - // ,[cloud_x] = @cloud_x - // ,[cloud_y] = @cloud_y - // ,[cloud_density] = @cloud_density - // ,[cloud_coverage] = @cloud_coverage - // ,[cloud_scale] = @cloud_scale - // ,[cloud_detail_x] = @cloud_detail_x - // ,[cloud_detail_y] = @cloud_detail_y - // ,[cloud_detail_density] = @cloud_detail_density - // ,[cloud_scroll_x] = @cloud_scroll_x - // ,[cloud_scroll_x_lock] = @cloud_scroll_x_lock - // ,[cloud_scroll_y] = @cloud_scroll_y - // ,[cloud_scroll_y_lock] = @cloud_scroll_y_lock - // ,[draw_classic_clouds] = @draw_classic_clouds - // WHERE region_id = @region_id"; - // using (SqlConnection conn = new SqlConnection(m_connectionString)) - // { - // conn.Open(); - // using (SqlCommand cmd = new SqlCommand(sql, conn)) - // { - // cmd.Parameters.AddWithValue("region_id", wl.regionID); - // cmd.Parameters.AddWithValue("water_color_r", wl.waterColor.X); - // cmd.Parameters.AddWithValue("water_color_g", wl.waterColor.Y); - // cmd.Parameters.AddWithValue("water_color_b", wl.waterColor.Z); - // cmd.Parameters.AddWithValue("water_fog_density_exponent", wl.waterFogDensityExponent); - // cmd.Parameters.AddWithValue("underwater_fog_modifier", wl.underwaterFogModifier); - // cmd.Parameters.AddWithValue("reflection_wavelet_scale_1", wl.reflectionWaveletScale.X); - // cmd.Parameters.AddWithValue("reflection_wavelet_scale_2", wl.reflectionWaveletScale.Y); - // cmd.Parameters.AddWithValue("reflection_wavelet_scale_3", wl.reflectionWaveletScale.Z); - // cmd.Parameters.AddWithValue("fresnel_scale", wl.fresnelScale); - // cmd.Parameters.AddWithValue("fresnel_offset", wl.fresnelOffset); - // cmd.Parameters.AddWithValue("refract_scale_above", wl.refractScaleAbove); - // cmd.Parameters.AddWithValue("refract_scale_below", wl.refractScaleBelow); - // cmd.Parameters.AddWithValue("blur_multiplier", wl.blurMultiplier); - // cmd.Parameters.AddWithValue("big_wave_direction_x", wl.bigWaveDirection.X); - // cmd.Parameters.AddWithValue("big_wave_direction_y", wl.bigWaveDirection.Y); - // cmd.Parameters.AddWithValue("little_wave_direction_x", wl.littleWaveDirection.X); - // cmd.Parameters.AddWithValue("little_wave_direction_y", wl.littleWaveDirection.Y); - // cmd.Parameters.AddWithValue("normal_map_texture", wl.normalMapTexture); - // cmd.Parameters.AddWithValue("horizon_r", wl.horizon.X); - // cmd.Parameters.AddWithValue("horizon_g", wl.horizon.Y); - // cmd.Parameters.AddWithValue("horizon_b", wl.horizon.Z); - // cmd.Parameters.AddWithValue("horizon_i", wl.horizon.W); - // cmd.Parameters.AddWithValue("haze_horizon", wl.hazeHorizon); - // cmd.Parameters.AddWithValue("blue_density_r", wl.blueDensity.X); - // cmd.Parameters.AddWithValue("blue_density_g", wl.blueDensity.Y); - // cmd.Parameters.AddWithValue("blue_density_b", wl.blueDensity.Z); - // cmd.Parameters.AddWithValue("blue_density_i", wl.blueDensity.W); - // cmd.Parameters.AddWithValue("haze_density", wl.hazeDensity); - // cmd.Parameters.AddWithValue("density_multiplier", wl.densityMultiplier); - // cmd.Parameters.AddWithValue("distance_multiplier", wl.distanceMultiplier); - // cmd.Parameters.AddWithValue("max_altitude", wl.maxAltitude); - // cmd.Parameters.AddWithValue("sun_moon_color_r", wl.sunMoonColor.X); - // cmd.Parameters.AddWithValue("sun_moon_color_g", wl.sunMoonColor.Y); - // cmd.Parameters.AddWithValue("sun_moon_color_b", wl.sunMoonColor.Z); - // cmd.Parameters.AddWithValue("sun_moon_color_i", wl.sunMoonColor.W); - // cmd.Parameters.AddWithValue("sun_moon_position", wl.sunMoonPosition); - // cmd.Parameters.AddWithValue("ambient_r", wl.ambient.X); - // cmd.Parameters.AddWithValue("ambient_g", wl.ambient.Y); - // cmd.Parameters.AddWithValue("ambient_b", wl.ambient.Z); - // cmd.Parameters.AddWithValue("ambient_i", wl.ambient.W); - // cmd.Parameters.AddWithValue("east_angle", wl.eastAngle); - // cmd.Parameters.AddWithValue("sun_glow_focus", wl.sunGlowFocus); - // cmd.Parameters.AddWithValue("sun_glow_size", wl.sunGlowSize); - // cmd.Parameters.AddWithValue("scene_gamma", wl.sceneGamma); - // cmd.Parameters.AddWithValue("star_brightness", wl.starBrightness); - // cmd.Parameters.AddWithValue("cloud_color_r", wl.cloudColor.X); - // cmd.Parameters.AddWithValue("cloud_color_g", wl.cloudColor.Y); - // cmd.Parameters.AddWithValue("cloud_color_b", wl.cloudColor.Z); - // cmd.Parameters.AddWithValue("cloud_color_i", wl.cloudColor.W); - // cmd.Parameters.AddWithValue("cloud_x", wl.cloudXYDensity.X); - // cmd.Parameters.AddWithValue("cloud_y", wl.cloudXYDensity.Y); - // cmd.Parameters.AddWithValue("cloud_density", wl.cloudXYDensity.Z); - // cmd.Parameters.AddWithValue("cloud_coverage", wl.cloudCoverage); - // cmd.Parameters.AddWithValue("cloud_scale", wl.cloudScale); - // cmd.Parameters.AddWithValue("cloud_detail_x", wl.cloudDetailXYDensity.X); - // cmd.Parameters.AddWithValue("cloud_detail_y", wl.cloudDetailXYDensity.Y); - // cmd.Parameters.AddWithValue("cloud_detail_density", wl.cloudDetailXYDensity.Z); - // cmd.Parameters.AddWithValue("cloud_scroll_x", wl.cloudScrollX); - // cmd.Parameters.AddWithValue("cloud_scroll_x_lock", wl.cloudScrollXLock); - // cmd.Parameters.AddWithValue("cloud_scroll_y", wl.cloudScrollY); - // cmd.Parameters.AddWithValue("cloud_scroll_y_lock", wl.cloudScrollYLock); - // cmd.Parameters.AddWithValue("draw_classic_clouds", wl.drawClassicClouds); - - // cmd.ExecuteNonQuery(); - // } - // } - // } - #endregion - } - - #region Environment Settings - public string LoadRegionEnvironmentSettings(UUID regionUUID) - { - string sql = "select * from [regionenvironment] where region_id = @region_id"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@region_id", regionUUID)); - conn.Open(); - using (SqlDataReader result = cmd.ExecuteReader()) - { - if (!result.Read()) - { - return String.Empty; - } - else - { - return Convert.ToString(result["llsd_settings"]); - } - } - } - } - - public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) - { - { - string sql = "DELETE FROM [regionenvironment] WHERE region_id = @region_id"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@region_id", regionUUID)); - conn.Open(); - cmd.ExecuteNonQuery(); - } - - sql = "INSERT INTO [regionenvironment] (region_id, llsd_settings) VALUES (@region_id, @llsd_settings)"; - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@region_id", regionUUID)); - cmd.Parameters.Add(_Database.CreateParameter("@llsd_settings", settings)); - - conn.Open(); - cmd.ExecuteNonQuery(); - } - } - } - - public void RemoveRegionEnvironmentSettings(UUID regionUUID) - { - string sql = "delete from [regionenvironment] where region_id = @region_id"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@region_id", regionUUID)); - - conn.Open(); - cmd.ExecuteNonQuery(); - } - } - #endregion - - /// - /// Loads the settings of a region. - /// - /// The region UUID. - /// - public RegionSettings LoadRegionSettings(UUID regionUUID) - { - string sql = "select * from regionsettings where regionUUID = @regionUUID"; - RegionSettings regionSettings; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@regionUUID", regionUUID)); - conn.Open(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (reader.Read()) - { - regionSettings = BuildRegionSettings(reader); - regionSettings.OnSave += StoreRegionSettings; - - return regionSettings; - } - } - } - - //If we reach this point then there are new region settings for that region - regionSettings = new RegionSettings(); - regionSettings.RegionUUID = regionUUID; - regionSettings.OnSave += StoreRegionSettings; - - //Store new values - StoreNewRegionSettings(regionSettings); - - LoadSpawnPoints(regionSettings); - - return regionSettings; - } - - /// - /// Store region settings, need to check if the check is really necesary. If we can make something for creating new region. - /// - /// region settings. - public void StoreRegionSettings(RegionSettings regionSettings) - { - //Little check if regionUUID already exist in DB - string regionUUID; - string sql = "SELECT regionUUID FROM regionsettings WHERE regionUUID = @regionUUID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@regionUUID", regionSettings.RegionUUID)); - conn.Open(); - regionUUID = cmd.ExecuteScalar().ToString(); - } - - if (string.IsNullOrEmpty(regionUUID)) - { - StoreNewRegionSettings(regionSettings); - } - else - { - //This method only updates region settings!!! First call LoadRegionSettings to create new region settings in DB - sql = - @"UPDATE [regionsettings] SET [block_terraform] = @block_terraform ,[block_fly] = @block_fly ,[allow_damage] = @allow_damage -,[restrict_pushing] = @restrict_pushing ,[allow_land_resell] = @allow_land_resell ,[allow_land_join_divide] = @allow_land_join_divide -,[block_show_in_search] = @block_show_in_search ,[agent_limit] = @agent_limit ,[object_bonus] = @object_bonus ,[maturity] = @maturity -,[disable_scripts] = @disable_scripts ,[disable_collisions] = @disable_collisions ,[disable_physics] = @disable_physics -,[terrain_texture_1] = @terrain_texture_1 ,[terrain_texture_2] = @terrain_texture_2 ,[terrain_texture_3] = @terrain_texture_3 -,[terrain_texture_4] = @terrain_texture_4 ,[elevation_1_nw] = @elevation_1_nw ,[elevation_2_nw] = @elevation_2_nw -,[elevation_1_ne] = @elevation_1_ne ,[elevation_2_ne] = @elevation_2_ne ,[elevation_1_se] = @elevation_1_se ,[elevation_2_se] = @elevation_2_se -,[elevation_1_sw] = @elevation_1_sw ,[elevation_2_sw] = @elevation_2_sw ,[water_height] = @water_height ,[terrain_raise_limit] = @terrain_raise_limit -,[terrain_lower_limit] = @terrain_lower_limit ,[use_estate_sun] = @use_estate_sun ,[fixed_sun] = @fixed_sun ,[sun_position] = @sun_position -,[covenant] = @covenant ,[covenant_datetime] = @covenant_datetime, [sunvectorx] = @sunvectorx, [sunvectory] = @sunvectory, [sunvectorz] = @sunvectorz, [Sandbox] = @Sandbox, [loaded_creation_datetime] = @loaded_creation_datetime, [loaded_creation_id] = @loaded_creation_id, [map_tile_id] = @TerrainImageID, [telehubobject] = @telehubobject, [parcel_tile_id] = @ParcelImageID - WHERE [regionUUID] = @regionUUID"; - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.AddRange(CreateRegionSettingParameters(regionSettings)); - conn.Open(); - cmd.ExecuteNonQuery(); - } - } - SaveSpawnPoints(regionSettings); - } - - public void Shutdown() - { - //Not used?? - } - - #region Private Methods - - /// - /// Serializes the terrain data for storage in DB. - /// - /// terrain data - /// - private static Array serializeTerrain(double[,] val) - { - MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize) * sizeof(double)); - BinaryWriter bw = new BinaryWriter(str); - - // TODO: COMPATIBILITY - Add byte-order conversions - for (int x = 0; x < (int)Constants.RegionSize; x++) - for (int y = 0; y < (int)Constants.RegionSize; y++) - { - double height = val[x, y]; - if (height == 0.0) - height = double.Epsilon; - - bw.Write(height); - } - - return str.ToArray(); - } - - /// - /// Stores new regionsettings. - /// - /// The region settings. - private void StoreNewRegionSettings(RegionSettings regionSettings) - { - string sql = @"INSERT INTO [regionsettings] - ([regionUUID],[block_terraform],[block_fly],[allow_damage],[restrict_pushing],[allow_land_resell],[allow_land_join_divide], - [block_show_in_search],[agent_limit],[object_bonus],[maturity],[disable_scripts],[disable_collisions],[disable_physics], - [terrain_texture_1],[terrain_texture_2],[terrain_texture_3],[terrain_texture_4],[elevation_1_nw],[elevation_2_nw],[elevation_1_ne], - [elevation_2_ne],[elevation_1_se],[elevation_2_se],[elevation_1_sw],[elevation_2_sw],[water_height],[terrain_raise_limit], - [terrain_lower_limit],[use_estate_sun],[fixed_sun],[sun_position],[covenant],[covenant_datetime],[sunvectorx], [sunvectory], [sunvectorz],[Sandbox], [loaded_creation_datetime], [loaded_creation_id] - ) - VALUES - (@regionUUID,@block_terraform,@block_fly,@allow_damage,@restrict_pushing,@allow_land_resell,@allow_land_join_divide, - @block_show_in_search,@agent_limit,@object_bonus,@maturity,@disable_scripts,@disable_collisions,@disable_physics, - @terrain_texture_1,@terrain_texture_2,@terrain_texture_3,@terrain_texture_4,@elevation_1_nw,@elevation_2_nw,@elevation_1_ne, - @elevation_2_ne,@elevation_1_se,@elevation_2_se,@elevation_1_sw,@elevation_2_sw,@water_height,@terrain_raise_limit, - @terrain_lower_limit,@use_estate_sun,@fixed_sun,@sun_position,@covenant, @covenant_datetime, @sunvectorx,@sunvectory, @sunvectorz, @Sandbox, @loaded_creation_datetime, @loaded_creation_id)"; - - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.AddRange(CreateRegionSettingParameters(regionSettings)); - conn.Open(); - cmd.ExecuteNonQuery(); - } - } - - #region Private DataRecord conversion methods - - /// - /// Builds the region settings from a datarecod. - /// - /// datarecord with regionsettings. - /// - private static RegionSettings BuildRegionSettings(IDataRecord row) - { - //TODO change this is some more generic code so we doesnt have to change it every time a new field is added? - RegionSettings newSettings = new RegionSettings(); - - newSettings.RegionUUID = new UUID((Guid)row["regionUUID"]); - newSettings.BlockTerraform = Convert.ToBoolean(row["block_terraform"]); - newSettings.AllowDamage = Convert.ToBoolean(row["allow_damage"]); - newSettings.BlockFly = Convert.ToBoolean(row["block_fly"]); - newSettings.RestrictPushing = Convert.ToBoolean(row["restrict_pushing"]); - newSettings.AllowLandResell = Convert.ToBoolean(row["allow_land_resell"]); - newSettings.AllowLandJoinDivide = Convert.ToBoolean(row["allow_land_join_divide"]); - newSettings.BlockShowInSearch = Convert.ToBoolean(row["block_show_in_search"]); - newSettings.AgentLimit = Convert.ToInt32(row["agent_limit"]); - newSettings.ObjectBonus = Convert.ToDouble(row["object_bonus"]); - newSettings.Maturity = Convert.ToInt32(row["maturity"]); - newSettings.DisableScripts = Convert.ToBoolean(row["disable_scripts"]); - newSettings.DisableCollisions = Convert.ToBoolean(row["disable_collisions"]); - newSettings.DisablePhysics = Convert.ToBoolean(row["disable_physics"]); - newSettings.TerrainTexture1 = new UUID((Guid)row["terrain_texture_1"]); - newSettings.TerrainTexture2 = new UUID((Guid)row["terrain_texture_2"]); - newSettings.TerrainTexture3 = new UUID((Guid)row["terrain_texture_3"]); - newSettings.TerrainTexture4 = new UUID((Guid)row["terrain_texture_4"]); - newSettings.Elevation1NW = Convert.ToDouble(row["elevation_1_nw"]); - newSettings.Elevation2NW = Convert.ToDouble(row["elevation_2_nw"]); - newSettings.Elevation1NE = Convert.ToDouble(row["elevation_1_ne"]); - newSettings.Elevation2NE = Convert.ToDouble(row["elevation_2_ne"]); - newSettings.Elevation1SE = Convert.ToDouble(row["elevation_1_se"]); - newSettings.Elevation2SE = Convert.ToDouble(row["elevation_2_se"]); - newSettings.Elevation1SW = Convert.ToDouble(row["elevation_1_sw"]); - newSettings.Elevation2SW = Convert.ToDouble(row["elevation_2_sw"]); - newSettings.WaterHeight = Convert.ToDouble(row["water_height"]); - newSettings.TerrainRaiseLimit = Convert.ToDouble(row["terrain_raise_limit"]); - newSettings.TerrainLowerLimit = Convert.ToDouble(row["terrain_lower_limit"]); - newSettings.UseEstateSun = Convert.ToBoolean(row["use_estate_sun"]); - newSettings.Sandbox = Convert.ToBoolean(row["Sandbox"]); - newSettings.FixedSun = Convert.ToBoolean(row["fixed_sun"]); - newSettings.SunPosition = Convert.ToDouble(row["sun_position"]); - newSettings.SunVector = new Vector3( - Convert.ToSingle(row["sunvectorx"]), - Convert.ToSingle(row["sunvectory"]), - Convert.ToSingle(row["sunvectorz"]) - ); - newSettings.Covenant = new UUID((Guid)row["covenant"]); - newSettings.CovenantChangedDateTime = Convert.ToInt32(row["covenant_datetime"]); - newSettings.LoadedCreationDateTime = Convert.ToInt32(row["loaded_creation_datetime"]); - - if (row["loaded_creation_id"] is DBNull) - newSettings.LoadedCreationID = ""; - else - newSettings.LoadedCreationID = (String)row["loaded_creation_id"]; - - newSettings.TerrainImageID = new UUID((string)row["map_tile_ID"]); - newSettings.ParcelImageID = new UUID((Guid)row["parcel_tile_ID"]); - newSettings.TelehubObject = new UUID((Guid)row["TelehubObject"]); - - return newSettings; - } - - /// - /// Builds the land data from a datarecord. - /// - /// datarecord with land data - /// - private static LandData BuildLandData(IDataRecord row) - { - LandData newData = new LandData(); - - newData.GlobalID = new UUID((Guid)row["UUID"]); - newData.LocalID = Convert.ToInt32(row["LocalLandID"]); - - // Bitmap is a byte[512] - newData.Bitmap = (Byte[])row["Bitmap"]; - - newData.Name = (string)row["Name"]; - newData.Description = (string)row["Description"]; - newData.OwnerID = new UUID((Guid)row["OwnerUUID"]); - newData.IsGroupOwned = Convert.ToBoolean(row["IsGroupOwned"]); - newData.Area = Convert.ToInt32(row["Area"]); - newData.AuctionID = Convert.ToUInt32(row["AuctionID"]); //Unemplemented - newData.Category = (ParcelCategory)Convert.ToInt32(row["Category"]); - //Enum libsecondlife.Parcel.ParcelCategory - newData.ClaimDate = Convert.ToInt32(row["ClaimDate"]); - newData.ClaimPrice = Convert.ToInt32(row["ClaimPrice"]); - newData.GroupID = new UUID((Guid)row["GroupUUID"]); - newData.SalePrice = Convert.ToInt32(row["SalePrice"]); - newData.Status = (ParcelStatus)Convert.ToInt32(row["LandStatus"]); - //Enum. libsecondlife.Parcel.ParcelStatus - newData.Flags = Convert.ToUInt32(row["LandFlags"]); - newData.LandingType = Convert.ToByte(row["LandingType"]); - newData.MediaAutoScale = Convert.ToByte(row["MediaAutoScale"]); - newData.MediaID = new UUID((Guid)row["MediaTextureUUID"]); - newData.MediaURL = (string)row["MediaURL"]; - newData.MusicURL = (string)row["MusicURL"]; - newData.PassHours = Convert.ToSingle(row["PassHours"]); - newData.PassPrice = Convert.ToInt32(row["PassPrice"]); - - // UUID authedbuyer; - // UUID snapshotID; - // - // if (UUID.TryParse((string)row["AuthBuyerID"], out authedbuyer)) - // newData.AuthBuyerID = authedbuyer; - // - // if (UUID.TryParse((string)row["SnapshotUUID"], out snapshotID)) - // newData.SnapshotID = snapshotID; - newData.AuthBuyerID = new UUID((Guid)row["AuthBuyerID"]); - newData.SnapshotID = new UUID((Guid)row["SnapshotUUID"]); - - newData.OtherCleanTime = Convert.ToInt32(row["OtherCleanTime"]); - - try - { - newData.UserLocation = - new Vector3(Convert.ToSingle(row["UserLocationX"]), Convert.ToSingle(row["UserLocationY"]), - Convert.ToSingle(row["UserLocationZ"])); - newData.UserLookAt = - new Vector3(Convert.ToSingle(row["UserLookAtX"]), Convert.ToSingle(row["UserLookAtY"]), - Convert.ToSingle(row["UserLookAtZ"])); - } - catch (InvalidCastException) - { - newData.UserLocation = Vector3.Zero; - newData.UserLookAt = Vector3.Zero; - _Log.ErrorFormat("[PARCEL]: unable to get parcel telehub settings for {1}", newData.Name); - } - - newData.ParcelAccessList = new List(); - newData.MediaDescription = (string)row["MediaDescription"]; - newData.MediaType = (string)row["MediaType"]; - newData.MediaWidth = Convert.ToInt32((((string)row["MediaSize"]).Split(','))[0]); - newData.MediaHeight = Convert.ToInt32((((string)row["MediaSize"]).Split(','))[1]); - newData.MediaLoop = Convert.ToBoolean(row["MediaLoop"]); - newData.ObscureMusic = Convert.ToBoolean(row["ObscureMusic"]); - newData.ObscureMedia = Convert.ToBoolean(row["ObscureMedia"]); - - return newData; - } - - /// - /// Builds the landaccess data from a data record. - /// - /// datarecord with landaccess data - /// - private static LandAccessEntry BuildLandAccessData(IDataRecord row) - { - LandAccessEntry entry = new LandAccessEntry(); - entry.AgentID = new UUID((Guid)row["AccessUUID"]); - entry.Flags = (AccessList)Convert.ToInt32(row["Flags"]); - entry.Expires = Convert.ToInt32(row["Expires"]); - return entry; - } - - /// - /// Builds the prim from a datarecord. - /// - /// datarecord - /// - private static SceneObjectPart BuildPrim(IDataRecord primRow) - { - SceneObjectPart prim = new SceneObjectPart(); - - prim.UUID = new UUID((Guid)primRow["UUID"]); - // explicit conversion of integers is required, which sort - // of sucks. No idea if there is a shortcut here or not. - prim.CreationDate = Convert.ToInt32(primRow["CreationDate"]); - prim.Name = (string)primRow["Name"]; - // various text fields - prim.Text = (string)primRow["Text"]; - prim.Color = Color.FromArgb(Convert.ToInt32(primRow["ColorA"]), - Convert.ToInt32(primRow["ColorR"]), - Convert.ToInt32(primRow["ColorG"]), - Convert.ToInt32(primRow["ColorB"])); - prim.Description = (string)primRow["Description"]; - prim.SitName = (string)primRow["SitName"]; - prim.TouchName = (string)primRow["TouchName"]; - // permissions - prim.Flags = (PrimFlags)Convert.ToUInt32(primRow["ObjectFlags"]); - //prim.CreatorID = new UUID((Guid)primRow["CreatorID"]); - prim.CreatorIdentification = (string)primRow["CreatorID"]; - prim.OwnerID = new UUID((Guid)primRow["OwnerID"]); - prim.GroupID = new UUID((Guid)primRow["GroupID"]); - prim.LastOwnerID = new UUID((Guid)primRow["LastOwnerID"]); - prim.OwnerMask = Convert.ToUInt32(primRow["OwnerMask"]); - prim.NextOwnerMask = Convert.ToUInt32(primRow["NextOwnerMask"]); - prim.GroupMask = Convert.ToUInt32(primRow["GroupMask"]); - prim.EveryoneMask = Convert.ToUInt32(primRow["EveryoneMask"]); - prim.BaseMask = Convert.ToUInt32(primRow["BaseMask"]); - // vectors - prim.OffsetPosition = new Vector3( - Convert.ToSingle(primRow["PositionX"]), - Convert.ToSingle(primRow["PositionY"]), - Convert.ToSingle(primRow["PositionZ"])); - - prim.GroupPosition = new Vector3( - Convert.ToSingle(primRow["GroupPositionX"]), - Convert.ToSingle(primRow["GroupPositionY"]), - Convert.ToSingle(primRow["GroupPositionZ"])); - - prim.Velocity = new Vector3( - Convert.ToSingle(primRow["VelocityX"]), - Convert.ToSingle(primRow["VelocityY"]), - Convert.ToSingle(primRow["VelocityZ"])); - - prim.AngularVelocity = new Vector3( - Convert.ToSingle(primRow["AngularVelocityX"]), - Convert.ToSingle(primRow["AngularVelocityY"]), - Convert.ToSingle(primRow["AngularVelocityZ"])); - - prim.Acceleration = new Vector3( - Convert.ToSingle(primRow["AccelerationX"]), - Convert.ToSingle(primRow["AccelerationY"]), - Convert.ToSingle(primRow["AccelerationZ"])); - - // quaternions - prim.RotationOffset = new Quaternion( - Convert.ToSingle(primRow["RotationX"]), - Convert.ToSingle(primRow["RotationY"]), - Convert.ToSingle(primRow["RotationZ"]), - Convert.ToSingle(primRow["RotationW"])); - - prim.SitTargetPositionLL = new Vector3( - Convert.ToSingle(primRow["SitTargetOffsetX"]), - Convert.ToSingle(primRow["SitTargetOffsetY"]), - Convert.ToSingle(primRow["SitTargetOffsetZ"])); - - prim.SitTargetOrientationLL = new Quaternion( - Convert.ToSingle(primRow["SitTargetOrientX"]), - Convert.ToSingle(primRow["SitTargetOrientY"]), - Convert.ToSingle(primRow["SitTargetOrientZ"]), - Convert.ToSingle(primRow["SitTargetOrientW"])); - - prim.PayPrice[0] = Convert.ToInt32(primRow["PayPrice"]); - prim.PayPrice[1] = Convert.ToInt32(primRow["PayButton1"]); - prim.PayPrice[2] = Convert.ToInt32(primRow["PayButton2"]); - prim.PayPrice[3] = Convert.ToInt32(primRow["PayButton3"]); - prim.PayPrice[4] = Convert.ToInt32(primRow["PayButton4"]); - - prim.Sound = new UUID((Guid)primRow["LoopedSound"]); - prim.SoundGain = Convert.ToSingle(primRow["LoopedSoundGain"]); - prim.SoundFlags = 1; // If it's persisted at all, it's looped - - if (!(primRow["TextureAnimation"] is DBNull)) - prim.TextureAnimation = (Byte[])primRow["TextureAnimation"]; - if (!(primRow["ParticleSystem"] is DBNull)) - prim.ParticleSystem = (Byte[])primRow["ParticleSystem"]; - - prim.AngularVelocity = new Vector3( - Convert.ToSingle(primRow["OmegaX"]), - Convert.ToSingle(primRow["OmegaY"]), - Convert.ToSingle(primRow["OmegaZ"])); - - prim.SetCameraEyeOffset(new Vector3( - Convert.ToSingle(primRow["CameraEyeOffsetX"]), - Convert.ToSingle(primRow["CameraEyeOffsetY"]), - Convert.ToSingle(primRow["CameraEyeOffsetZ"]) - )); - - prim.SetCameraAtOffset(new Vector3( - Convert.ToSingle(primRow["CameraAtOffsetX"]), - Convert.ToSingle(primRow["CameraAtOffsetY"]), - Convert.ToSingle(primRow["CameraAtOffsetZ"]) - )); - - if (Convert.ToInt16(primRow["ForceMouselook"]) != 0) - prim.SetForceMouselook(true); - - prim.ScriptAccessPin = Convert.ToInt32(primRow["ScriptAccessPin"]); - - if (Convert.ToInt16(primRow["AllowedDrop"]) != 0) - prim.AllowedDrop = true; - - if (Convert.ToInt16(primRow["DieAtEdge"]) != 0) - prim.DIE_AT_EDGE = true; - - prim.SalePrice = Convert.ToInt32(primRow["SalePrice"]); - prim.ObjectSaleType = Convert.ToByte(primRow["SaleType"]); - - prim.Material = Convert.ToByte(primRow["Material"]); - - if (!(primRow["ClickAction"] is DBNull)) - prim.ClickAction = Convert.ToByte(primRow["ClickAction"]); - - prim.CollisionSound = new UUID((Guid)primRow["CollisionSound"]); - prim.CollisionSoundVolume = Convert.ToSingle(primRow["CollisionSoundVolume"]); - if (Convert.ToInt16(primRow["PassTouches"]) != 0) - prim.PassTouches = true; - prim.LinkNum = Convert.ToInt32(primRow["LinkNumber"]); - - if (!(primRow["MediaURL"] is System.DBNull)) - prim.MediaUrl = (string)primRow["MediaURL"]; - - return prim; - } - - /// - /// Builds the prim shape from a datarecord. - /// - /// The row. - /// - private static PrimitiveBaseShape BuildShape(IDataRecord shapeRow) - { - PrimitiveBaseShape baseShape = new PrimitiveBaseShape(); - - baseShape.Scale = new Vector3( - (float)Convert.ToDouble(shapeRow["ScaleX"]), - (float)Convert.ToDouble(shapeRow["ScaleY"]), - (float)Convert.ToDouble(shapeRow["ScaleZ"])); - - // paths - baseShape.PCode = Convert.ToByte(shapeRow["PCode"]); - baseShape.PathBegin = Convert.ToUInt16(shapeRow["PathBegin"]); - baseShape.PathEnd = Convert.ToUInt16(shapeRow["PathEnd"]); - baseShape.PathScaleX = Convert.ToByte(shapeRow["PathScaleX"]); - baseShape.PathScaleY = Convert.ToByte(shapeRow["PathScaleY"]); - baseShape.PathShearX = Convert.ToByte(shapeRow["PathShearX"]); - baseShape.PathShearY = Convert.ToByte(shapeRow["PathShearY"]); - baseShape.PathSkew = Convert.ToSByte(shapeRow["PathSkew"]); - baseShape.PathCurve = Convert.ToByte(shapeRow["PathCurve"]); - baseShape.PathRadiusOffset = Convert.ToSByte(shapeRow["PathRadiusOffset"]); - baseShape.PathRevolutions = Convert.ToByte(shapeRow["PathRevolutions"]); - baseShape.PathTaperX = Convert.ToSByte(shapeRow["PathTaperX"]); - baseShape.PathTaperY = Convert.ToSByte(shapeRow["PathTaperY"]); - baseShape.PathTwist = Convert.ToSByte(shapeRow["PathTwist"]); - baseShape.PathTwistBegin = Convert.ToSByte(shapeRow["PathTwistBegin"]); - // profile - baseShape.ProfileBegin = Convert.ToUInt16(shapeRow["ProfileBegin"]); - baseShape.ProfileEnd = Convert.ToUInt16(shapeRow["ProfileEnd"]); - baseShape.ProfileCurve = Convert.ToByte(shapeRow["ProfileCurve"]); - baseShape.ProfileHollow = Convert.ToUInt16(shapeRow["ProfileHollow"]); - - byte[] textureEntry = (byte[])shapeRow["Texture"]; - baseShape.TextureEntry = textureEntry; - - baseShape.ExtraParams = (byte[])shapeRow["ExtraParams"]; - - try - { - baseShape.State = Convert.ToByte(shapeRow["State"]); - } - catch (InvalidCastException) - { - } - - if (!(shapeRow["Media"] is System.DBNull)) - { - baseShape.Media = PrimitiveBaseShape.MediaList.FromXml((string)shapeRow["Media"]); - } - - - return baseShape; - } - - /// - /// Build a prim inventory item from the persisted data. - /// - /// - /// - private static TaskInventoryItem BuildItem(IDataRecord inventoryRow) - { - TaskInventoryItem taskItem = new TaskInventoryItem(); - - taskItem.ItemID = new UUID((Guid)inventoryRow["itemID"]); - taskItem.ParentPartID = new UUID((Guid)inventoryRow["primID"]); - taskItem.AssetID = new UUID((Guid)inventoryRow["assetID"]); - taskItem.ParentID = new UUID((Guid)inventoryRow["parentFolderID"]); - - taskItem.InvType = Convert.ToInt32(inventoryRow["invType"]); - taskItem.Type = Convert.ToInt32(inventoryRow["assetType"]); - - taskItem.Name = (string)inventoryRow["name"]; - taskItem.Description = (string)inventoryRow["description"]; - taskItem.CreationDate = Convert.ToUInt32(inventoryRow["creationDate"]); - //taskItem.CreatorID = new UUID((Guid)inventoryRow["creatorID"]); - taskItem.CreatorIdentification = (string)inventoryRow["creatorID"]; - taskItem.OwnerID = new UUID((Guid)inventoryRow["ownerID"]); - taskItem.LastOwnerID = new UUID((Guid)inventoryRow["lastOwnerID"]); - taskItem.GroupID = new UUID((Guid)inventoryRow["groupID"]); - - taskItem.NextPermissions = Convert.ToUInt32(inventoryRow["nextPermissions"]); - taskItem.CurrentPermissions = Convert.ToUInt32(inventoryRow["currentPermissions"]); - taskItem.BasePermissions = Convert.ToUInt32(inventoryRow["basePermissions"]); - taskItem.EveryonePermissions = Convert.ToUInt32(inventoryRow["everyonePermissions"]); - taskItem.GroupPermissions = Convert.ToUInt32(inventoryRow["groupPermissions"]); - taskItem.Flags = Convert.ToUInt32(inventoryRow["flags"]); - - return taskItem; - } - - #endregion - - #region Create parameters methods - - /// - /// Creates the prim inventory parameters. - /// - /// item in inventory. - /// - private SqlParameter[] CreatePrimInventoryParameters(TaskInventoryItem taskItem) - { - List parameters = new List(); - - parameters.Add(_Database.CreateParameter("itemID", taskItem.ItemID)); - parameters.Add(_Database.CreateParameter("primID", taskItem.ParentPartID)); - parameters.Add(_Database.CreateParameter("assetID", taskItem.AssetID)); - parameters.Add(_Database.CreateParameter("parentFolderID", taskItem.ParentID)); - parameters.Add(_Database.CreateParameter("invType", taskItem.InvType)); - parameters.Add(_Database.CreateParameter("assetType", taskItem.Type)); - - parameters.Add(_Database.CreateParameter("name", taskItem.Name)); - parameters.Add(_Database.CreateParameter("description", taskItem.Description)); - parameters.Add(_Database.CreateParameter("creationDate", taskItem.CreationDate)); - parameters.Add(_Database.CreateParameter("creatorID", taskItem.CreatorID)); - parameters.Add(_Database.CreateParameter("ownerID", taskItem.OwnerID)); - parameters.Add(_Database.CreateParameter("lastOwnerID", taskItem.LastOwnerID)); - parameters.Add(_Database.CreateParameter("groupID", taskItem.GroupID)); - parameters.Add(_Database.CreateParameter("nextPermissions", taskItem.NextPermissions)); - parameters.Add(_Database.CreateParameter("currentPermissions", taskItem.CurrentPermissions)); - parameters.Add(_Database.CreateParameter("basePermissions", taskItem.BasePermissions)); - parameters.Add(_Database.CreateParameter("everyonePermissions", taskItem.EveryonePermissions)); - parameters.Add(_Database.CreateParameter("groupPermissions", taskItem.GroupPermissions)); - parameters.Add(_Database.CreateParameter("flags", taskItem.Flags)); - - return parameters.ToArray(); - } - - /// - /// Creates the region setting parameters. - /// - /// regionsettings. - /// - private SqlParameter[] CreateRegionSettingParameters(RegionSettings settings) - { - List parameters = new List(); - - parameters.Add(_Database.CreateParameter("regionUUID", settings.RegionUUID)); - parameters.Add(_Database.CreateParameter("block_terraform", settings.BlockTerraform)); - parameters.Add(_Database.CreateParameter("block_fly", settings.BlockFly)); - parameters.Add(_Database.CreateParameter("allow_damage", settings.AllowDamage)); - parameters.Add(_Database.CreateParameter("restrict_pushing", settings.RestrictPushing)); - parameters.Add(_Database.CreateParameter("allow_land_resell", settings.AllowLandResell)); - parameters.Add(_Database.CreateParameter("allow_land_join_divide", settings.AllowLandJoinDivide)); - parameters.Add(_Database.CreateParameter("block_show_in_search", settings.BlockShowInSearch)); - parameters.Add(_Database.CreateParameter("agent_limit", settings.AgentLimit)); - parameters.Add(_Database.CreateParameter("object_bonus", settings.ObjectBonus)); - parameters.Add(_Database.CreateParameter("maturity", settings.Maturity)); - parameters.Add(_Database.CreateParameter("disable_scripts", settings.DisableScripts)); - parameters.Add(_Database.CreateParameter("disable_collisions", settings.DisableCollisions)); - parameters.Add(_Database.CreateParameter("disable_physics", settings.DisablePhysics)); - parameters.Add(_Database.CreateParameter("terrain_texture_1", settings.TerrainTexture1)); - parameters.Add(_Database.CreateParameter("terrain_texture_2", settings.TerrainTexture2)); - parameters.Add(_Database.CreateParameter("terrain_texture_3", settings.TerrainTexture3)); - parameters.Add(_Database.CreateParameter("terrain_texture_4", settings.TerrainTexture4)); - parameters.Add(_Database.CreateParameter("elevation_1_nw", settings.Elevation1NW)); - parameters.Add(_Database.CreateParameter("elevation_2_nw", settings.Elevation2NW)); - parameters.Add(_Database.CreateParameter("elevation_1_ne", settings.Elevation1NE)); - parameters.Add(_Database.CreateParameter("elevation_2_ne", settings.Elevation2NE)); - parameters.Add(_Database.CreateParameter("elevation_1_se", settings.Elevation1SE)); - parameters.Add(_Database.CreateParameter("elevation_2_se", settings.Elevation2SE)); - parameters.Add(_Database.CreateParameter("elevation_1_sw", settings.Elevation1SW)); - parameters.Add(_Database.CreateParameter("elevation_2_sw", settings.Elevation2SW)); - parameters.Add(_Database.CreateParameter("water_height", settings.WaterHeight)); - parameters.Add(_Database.CreateParameter("terrain_raise_limit", settings.TerrainRaiseLimit)); - parameters.Add(_Database.CreateParameter("terrain_lower_limit", settings.TerrainLowerLimit)); - parameters.Add(_Database.CreateParameter("use_estate_sun", settings.UseEstateSun)); - parameters.Add(_Database.CreateParameter("Sandbox", settings.Sandbox)); - parameters.Add(_Database.CreateParameter("fixed_sun", settings.FixedSun)); - parameters.Add(_Database.CreateParameter("sun_position", settings.SunPosition)); - parameters.Add(_Database.CreateParameter("sunvectorx", settings.SunVector.X)); - parameters.Add(_Database.CreateParameter("sunvectory", settings.SunVector.Y)); - parameters.Add(_Database.CreateParameter("sunvectorz", settings.SunVector.Z)); - parameters.Add(_Database.CreateParameter("covenant", settings.Covenant)); - parameters.Add(_Database.CreateParameter("covenant_datetime", settings.CovenantChangedDateTime)); - parameters.Add(_Database.CreateParameter("Loaded_Creation_DateTime", settings.LoadedCreationDateTime)); - parameters.Add(_Database.CreateParameter("Loaded_Creation_ID", settings.LoadedCreationID)); - parameters.Add(_Database.CreateParameter("TerrainImageID", settings.TerrainImageID)); - parameters.Add(_Database.CreateParameter("ParcelImageID", settings.ParcelImageID)); - parameters.Add(_Database.CreateParameter("TelehubObject", settings.TelehubObject)); - - return parameters.ToArray(); - } - - /// - /// Creates the land parameters. - /// - /// land parameters. - /// region UUID. - /// - private SqlParameter[] CreateLandParameters(LandData land, UUID regionUUID) - { - List parameters = new List(); - - parameters.Add(_Database.CreateParameter("UUID", land.GlobalID)); - parameters.Add(_Database.CreateParameter("RegionUUID", regionUUID)); - parameters.Add(_Database.CreateParameter("LocalLandID", land.LocalID)); - - // Bitmap is a byte[512] - parameters.Add(_Database.CreateParameter("Bitmap", land.Bitmap)); - - parameters.Add(_Database.CreateParameter("Name", land.Name)); - parameters.Add(_Database.CreateParameter("Description", land.Description)); - parameters.Add(_Database.CreateParameter("OwnerUUID", land.OwnerID)); - parameters.Add(_Database.CreateParameter("IsGroupOwned", land.IsGroupOwned)); - parameters.Add(_Database.CreateParameter("Area", land.Area)); - parameters.Add(_Database.CreateParameter("AuctionID", land.AuctionID)); //Unemplemented - parameters.Add(_Database.CreateParameter("Category", (int)land.Category)); //Enum libsecondlife.Parcel.ParcelCategory - parameters.Add(_Database.CreateParameter("ClaimDate", land.ClaimDate)); - parameters.Add(_Database.CreateParameter("ClaimPrice", land.ClaimPrice)); - parameters.Add(_Database.CreateParameter("GroupUUID", land.GroupID)); - parameters.Add(_Database.CreateParameter("SalePrice", land.SalePrice)); - parameters.Add(_Database.CreateParameter("LandStatus", (int)land.Status)); //Enum. libsecondlife.Parcel.ParcelStatus - parameters.Add(_Database.CreateParameter("LandFlags", land.Flags)); - parameters.Add(_Database.CreateParameter("LandingType", land.LandingType)); - parameters.Add(_Database.CreateParameter("MediaAutoScale", land.MediaAutoScale)); - parameters.Add(_Database.CreateParameter("MediaTextureUUID", land.MediaID)); - parameters.Add(_Database.CreateParameter("MediaURL", land.MediaURL)); - parameters.Add(_Database.CreateParameter("MusicURL", land.MusicURL)); - parameters.Add(_Database.CreateParameter("PassHours", land.PassHours)); - parameters.Add(_Database.CreateParameter("PassPrice", land.PassPrice)); - parameters.Add(_Database.CreateParameter("SnapshotUUID", land.SnapshotID)); - parameters.Add(_Database.CreateParameter("UserLocationX", land.UserLocation.X)); - parameters.Add(_Database.CreateParameter("UserLocationY", land.UserLocation.Y)); - parameters.Add(_Database.CreateParameter("UserLocationZ", land.UserLocation.Z)); - parameters.Add(_Database.CreateParameter("UserLookAtX", land.UserLookAt.X)); - parameters.Add(_Database.CreateParameter("UserLookAtY", land.UserLookAt.Y)); - parameters.Add(_Database.CreateParameter("UserLookAtZ", land.UserLookAt.Z)); - parameters.Add(_Database.CreateParameter("AuthBuyerID", land.AuthBuyerID)); - parameters.Add(_Database.CreateParameter("OtherCleanTime", land.OtherCleanTime)); - - return parameters.ToArray(); - } - - /// - /// Creates the land access parameters. - /// - /// parcel access entry. - /// parcel ID. - /// - private SqlParameter[] CreateLandAccessParameters(LandAccessEntry parcelAccessEntry, UUID parcelID) - { - List parameters = new List(); - - parameters.Add(_Database.CreateParameter("LandUUID", parcelID)); - parameters.Add(_Database.CreateParameter("AccessUUID", parcelAccessEntry.AgentID)); - parameters.Add(_Database.CreateParameter("Flags", parcelAccessEntry.Flags)); - parameters.Add(_Database.CreateParameter("Expires", parcelAccessEntry.Expires)); - - return parameters.ToArray(); - } - - /// - /// Creates the prim parameters for storing in DB. - /// - /// Basic data of SceneObjectpart prim. - /// The scenegroup ID. - /// The region ID. - /// - private SqlParameter[] CreatePrimParameters(SceneObjectPart prim, UUID sceneGroupID, UUID regionUUID) - { - List parameters = new List(); - - parameters.Add(_Database.CreateParameter("UUID", prim.UUID)); - parameters.Add(_Database.CreateParameter("RegionUUID", regionUUID)); - parameters.Add(_Database.CreateParameter("CreationDate", prim.CreationDate)); - parameters.Add(_Database.CreateParameter("Name", prim.Name)); - parameters.Add(_Database.CreateParameter("SceneGroupID", sceneGroupID)); - // the UUID of the root part for this SceneObjectGroup - // various text fields - parameters.Add(_Database.CreateParameter("Text", prim.Text)); - parameters.Add(_Database.CreateParameter("ColorR", prim.Color.R)); - parameters.Add(_Database.CreateParameter("ColorG", prim.Color.G)); - parameters.Add(_Database.CreateParameter("ColorB", prim.Color.B)); - parameters.Add(_Database.CreateParameter("ColorA", prim.Color.A)); - parameters.Add(_Database.CreateParameter("Description", prim.Description)); - parameters.Add(_Database.CreateParameter("SitName", prim.SitName)); - parameters.Add(_Database.CreateParameter("TouchName", prim.TouchName)); - // permissions - parameters.Add(_Database.CreateParameter("ObjectFlags", (uint)prim.Flags)); - parameters.Add(_Database.CreateParameter("CreatorID", prim.CreatorID)); - parameters.Add(_Database.CreateParameter("OwnerID", prim.OwnerID)); - parameters.Add(_Database.CreateParameter("GroupID", prim.GroupID)); - parameters.Add(_Database.CreateParameter("LastOwnerID", prim.LastOwnerID)); - parameters.Add(_Database.CreateParameter("OwnerMask", prim.OwnerMask)); - parameters.Add(_Database.CreateParameter("NextOwnerMask", prim.NextOwnerMask)); - parameters.Add(_Database.CreateParameter("GroupMask", prim.GroupMask)); - parameters.Add(_Database.CreateParameter("EveryoneMask", prim.EveryoneMask)); - parameters.Add(_Database.CreateParameter("BaseMask", prim.BaseMask)); - // vectors - parameters.Add(_Database.CreateParameter("PositionX", prim.OffsetPosition.X)); - parameters.Add(_Database.CreateParameter("PositionY", prim.OffsetPosition.Y)); - parameters.Add(_Database.CreateParameter("PositionZ", prim.OffsetPosition.Z)); - parameters.Add(_Database.CreateParameter("GroupPositionX", prim.GroupPosition.X)); - parameters.Add(_Database.CreateParameter("GroupPositionY", prim.GroupPosition.Y)); - parameters.Add(_Database.CreateParameter("GroupPositionZ", prim.GroupPosition.Z)); - parameters.Add(_Database.CreateParameter("VelocityX", prim.Velocity.X)); - parameters.Add(_Database.CreateParameter("VelocityY", prim.Velocity.Y)); - parameters.Add(_Database.CreateParameter("VelocityZ", prim.Velocity.Z)); - parameters.Add(_Database.CreateParameter("AngularVelocityX", prim.AngularVelocity.X)); - parameters.Add(_Database.CreateParameter("AngularVelocityY", prim.AngularVelocity.Y)); - parameters.Add(_Database.CreateParameter("AngularVelocityZ", prim.AngularVelocity.Z)); - parameters.Add(_Database.CreateParameter("AccelerationX", prim.Acceleration.X)); - parameters.Add(_Database.CreateParameter("AccelerationY", prim.Acceleration.Y)); - parameters.Add(_Database.CreateParameter("AccelerationZ", prim.Acceleration.Z)); - // quaternions - parameters.Add(_Database.CreateParameter("RotationX", prim.RotationOffset.X)); - parameters.Add(_Database.CreateParameter("RotationY", prim.RotationOffset.Y)); - parameters.Add(_Database.CreateParameter("RotationZ", prim.RotationOffset.Z)); - parameters.Add(_Database.CreateParameter("RotationW", prim.RotationOffset.W)); - - // Sit target - Vector3 sitTargetPos = prim.SitTargetPositionLL; - parameters.Add(_Database.CreateParameter("SitTargetOffsetX", sitTargetPos.X)); - parameters.Add(_Database.CreateParameter("SitTargetOffsetY", sitTargetPos.Y)); - parameters.Add(_Database.CreateParameter("SitTargetOffsetZ", sitTargetPos.Z)); - - Quaternion sitTargetOrient = prim.SitTargetOrientationLL; - parameters.Add(_Database.CreateParameter("SitTargetOrientW", sitTargetOrient.W)); - parameters.Add(_Database.CreateParameter("SitTargetOrientX", sitTargetOrient.X)); - parameters.Add(_Database.CreateParameter("SitTargetOrientY", sitTargetOrient.Y)); - parameters.Add(_Database.CreateParameter("SitTargetOrientZ", sitTargetOrient.Z)); - - parameters.Add(_Database.CreateParameter("PayPrice", prim.PayPrice[0])); - parameters.Add(_Database.CreateParameter("PayButton1", prim.PayPrice[1])); - parameters.Add(_Database.CreateParameter("PayButton2", prim.PayPrice[2])); - parameters.Add(_Database.CreateParameter("PayButton3", prim.PayPrice[3])); - parameters.Add(_Database.CreateParameter("PayButton4", prim.PayPrice[4])); - - if ((prim.SoundFlags & 1) != 0) // Looped - { - parameters.Add(_Database.CreateParameter("LoopedSound", prim.Sound)); - parameters.Add(_Database.CreateParameter("LoopedSoundGain", prim.SoundGain)); - } - else - { - parameters.Add(_Database.CreateParameter("LoopedSound", UUID.Zero)); - parameters.Add(_Database.CreateParameter("LoopedSoundGain", 0.0f)); - } - - parameters.Add(_Database.CreateParameter("TextureAnimation", prim.TextureAnimation)); - parameters.Add(_Database.CreateParameter("ParticleSystem", prim.ParticleSystem)); - - parameters.Add(_Database.CreateParameter("OmegaX", prim.AngularVelocity.X)); - parameters.Add(_Database.CreateParameter("OmegaY", prim.AngularVelocity.Y)); - parameters.Add(_Database.CreateParameter("OmegaZ", prim.AngularVelocity.Z)); - - parameters.Add(_Database.CreateParameter("CameraEyeOffsetX", prim.GetCameraEyeOffset().X)); - parameters.Add(_Database.CreateParameter("CameraEyeOffsetY", prim.GetCameraEyeOffset().Y)); - parameters.Add(_Database.CreateParameter("CameraEyeOffsetZ", prim.GetCameraEyeOffset().Z)); - - parameters.Add(_Database.CreateParameter("CameraAtOffsetX", prim.GetCameraAtOffset().X)); - parameters.Add(_Database.CreateParameter("CameraAtOffsetY", prim.GetCameraAtOffset().Y)); - parameters.Add(_Database.CreateParameter("CameraAtOffsetZ", prim.GetCameraAtOffset().Z)); - - if (prim.GetForceMouselook()) - parameters.Add(_Database.CreateParameter("ForceMouselook", 1)); - else - parameters.Add(_Database.CreateParameter("ForceMouselook", 0)); - - parameters.Add(_Database.CreateParameter("ScriptAccessPin", prim.ScriptAccessPin)); - - if (prim.AllowedDrop) - parameters.Add(_Database.CreateParameter("AllowedDrop", 1)); - else - parameters.Add(_Database.CreateParameter("AllowedDrop", 0)); - - if (prim.DIE_AT_EDGE) - parameters.Add(_Database.CreateParameter("DieAtEdge", 1)); - else - parameters.Add(_Database.CreateParameter("DieAtEdge", 0)); - - parameters.Add(_Database.CreateParameter("SalePrice", prim.SalePrice)); - parameters.Add(_Database.CreateParameter("SaleType", prim.ObjectSaleType)); - - byte clickAction = prim.ClickAction; - parameters.Add(_Database.CreateParameter("ClickAction", clickAction)); - - parameters.Add(_Database.CreateParameter("Material", prim.Material)); - - parameters.Add(_Database.CreateParameter("CollisionSound", prim.CollisionSound)); - parameters.Add(_Database.CreateParameter("CollisionSoundVolume", prim.CollisionSoundVolume)); - if (prim.PassTouches) - parameters.Add(_Database.CreateParameter("PassTouches", 1)); - else - parameters.Add(_Database.CreateParameter("PassTouches", 0)); - parameters.Add(_Database.CreateParameter("LinkNumber", prim.LinkNum)); - parameters.Add(_Database.CreateParameter("MediaURL", prim.MediaUrl)); - - return parameters.ToArray(); - } - - /// - /// Creates the primshape parameters for stroing in DB. - /// - /// Basic data of SceneObjectpart prim. - /// The scene group ID. - /// The region UUID. - /// - private SqlParameter[] CreatePrimShapeParameters(SceneObjectPart prim, UUID sceneGroupID, UUID regionUUID) - { - List parameters = new List(); - - PrimitiveBaseShape s = prim.Shape; - parameters.Add(_Database.CreateParameter("UUID", prim.UUID)); - // shape is an enum - parameters.Add(_Database.CreateParameter("Shape", 0)); - // vectors - parameters.Add(_Database.CreateParameter("ScaleX", s.Scale.X)); - parameters.Add(_Database.CreateParameter("ScaleY", s.Scale.Y)); - parameters.Add(_Database.CreateParameter("ScaleZ", s.Scale.Z)); - // paths - parameters.Add(_Database.CreateParameter("PCode", s.PCode)); - parameters.Add(_Database.CreateParameter("PathBegin", s.PathBegin)); - parameters.Add(_Database.CreateParameter("PathEnd", s.PathEnd)); - parameters.Add(_Database.CreateParameter("PathScaleX", s.PathScaleX)); - parameters.Add(_Database.CreateParameter("PathScaleY", s.PathScaleY)); - parameters.Add(_Database.CreateParameter("PathShearX", s.PathShearX)); - parameters.Add(_Database.CreateParameter("PathShearY", s.PathShearY)); - parameters.Add(_Database.CreateParameter("PathSkew", s.PathSkew)); - parameters.Add(_Database.CreateParameter("PathCurve", s.PathCurve)); - parameters.Add(_Database.CreateParameter("PathRadiusOffset", s.PathRadiusOffset)); - parameters.Add(_Database.CreateParameter("PathRevolutions", s.PathRevolutions)); - parameters.Add(_Database.CreateParameter("PathTaperX", s.PathTaperX)); - parameters.Add(_Database.CreateParameter("PathTaperY", s.PathTaperY)); - parameters.Add(_Database.CreateParameter("PathTwist", s.PathTwist)); - parameters.Add(_Database.CreateParameter("PathTwistBegin", s.PathTwistBegin)); - // profile - parameters.Add(_Database.CreateParameter("ProfileBegin", s.ProfileBegin)); - parameters.Add(_Database.CreateParameter("ProfileEnd", s.ProfileEnd)); - parameters.Add(_Database.CreateParameter("ProfileCurve", s.ProfileCurve)); - parameters.Add(_Database.CreateParameter("ProfileHollow", s.ProfileHollow)); - parameters.Add(_Database.CreateParameter("Texture", s.TextureEntry)); - parameters.Add(_Database.CreateParameter("ExtraParams", s.ExtraParams)); - parameters.Add(_Database.CreateParameter("State", s.State)); - - if (null == s.Media) - { - parameters.Add(_Database.CreateParameter("Media", DBNull.Value)); - } - else - { - parameters.Add(_Database.CreateParameter("Media", s.Media.ToXml())); - } - - - return parameters.ToArray(); - } - - #endregion - - #endregion - - private void LoadSpawnPoints(RegionSettings rs) - { - rs.ClearSpawnPoints(); - - string sql = "SELECT Yaw, Pitch, Distance FROM spawn_points WHERE RegionUUID = @RegionUUID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", rs.RegionUUID.ToString())); - conn.Open(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (reader.Read()) - { - SpawnPoint sp = new SpawnPoint(); - - sp.Yaw = (float)reader["Yaw"]; - sp.Pitch = (float)reader["Pitch"]; - sp.Distance = (float)reader["Distance"]; - - rs.AddSpawnPoint(sp); - } - } - } - } - - private void SaveSpawnPoints(RegionSettings rs) - { - string sql = "DELETE FROM spawn_points WHERE RegionUUID = @RegionUUID"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", rs.RegionUUID)); - conn.Open(); - cmd.ExecuteNonQuery(); - } - foreach (SpawnPoint p in rs.SpawnPoints()) - { - sql = "INSERT INTO spawn_points (RegionUUID, Yaw, Pitch, Distance) VALUES (@RegionUUID, @Yaw, @Pitch, @Distance)"; - using (SqlConnection conn = new SqlConnection(m_connectionString)) - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", rs.RegionUUID)); - cmd.Parameters.Add(_Database.CreateParameter("@Yaw", p.Yaw)); - cmd.Parameters.Add(_Database.CreateParameter("@Pitch", p.Pitch)); - cmd.Parameters.Add(_Database.CreateParameter("@Distance", p.Distance)); - conn.Open(); - cmd.ExecuteNonQuery(); - } - } - } - - public void SaveExtra(UUID regionID, string name, string value) - { - } - - public void RemoveExtra(UUID regionID, string name) - { - } - - public Dictionary GetExtra(UUID regionID) - { - return null; - } - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs b/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs deleted file mode 100644 index 7feec91..0000000 --- a/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Data; -using OpenMetaverse; -using OpenSim.Framework; -using System.Data.SqlClient; -using System.Text; - -namespace OpenSim.Data.MSSQL -{ - public class MSSQLUserAccountData : MSSQLGenericTableHandler,IUserAccountData - { - public MSSQLUserAccountData(string connectionString, string realm) : - base(connectionString, realm, "UserAccount") - { - } - //private string m_Realm; - //private List m_ColumnNames = null; - //private MSSQLManager m_database; - - //public MSSQLUserAccountData(string connectionString, string realm) - //{ - // m_Realm = realm; - // m_ConnectionString = connectionString; - // m_database = new MSSQLManager(connectionString); - - // using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - // { - // conn.Open(); - // Migration m = new Migration(conn, GetType().Assembly, "UserStore"); - // m.Update(); - // } - //} - - //public List Query(UUID principalID, UUID scopeID, string query) - //{ - // return null; - //} - - //public UserAccountData Get(UUID principalID, UUID scopeID) - //{ - // UserAccountData ret = new UserAccountData(); - // ret.Data = new Dictionary(); - - // string sql = string.Format("select * from {0} where UUID = @principalID", m_Realm); - // if (scopeID != UUID.Zero) - // sql += " and ScopeID = @scopeID"; - - // using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - // using (SqlCommand cmd = new SqlCommand(sql, conn)) - // { - // cmd.Parameters.Add(m_database.CreateParameter("@principalID", principalID)); - // cmd.Parameters.Add(m_database.CreateParameter("@scopeID", scopeID)); - - // conn.Open(); - // using (SqlDataReader result = cmd.ExecuteReader()) - // { - // if (result.Read()) - // { - // ret.PrincipalID = principalID; - // UUID scope; - // UUID.TryParse(result["ScopeID"].ToString(), out scope); - // ret.ScopeID = scope; - - // if (m_ColumnNames == null) - // { - // m_ColumnNames = new List(); - - // DataTable schemaTable = result.GetSchemaTable(); - // foreach (DataRow row in schemaTable.Rows) - // m_ColumnNames.Add(row["ColumnName"].ToString()); - // } - - // foreach (string s in m_ColumnNames) - // { - // if (s == "UUID") - // continue; - // if (s == "ScopeID") - // continue; - - // ret.Data[s] = result[s].ToString(); - // } - // return ret; - // } - // } - // } - // return null; - //} - - //public bool Store(UserAccountData data) - //{ - // if (data.Data.ContainsKey("UUID")) - // data.Data.Remove("UUID"); - // if (data.Data.ContainsKey("ScopeID")) - // data.Data.Remove("ScopeID"); - - // string[] fields = new List(data.Data.Keys).ToArray(); - - // using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - // using (SqlCommand cmd = new SqlCommand()) - // { - // StringBuilder updateBuilder = new StringBuilder(); - // updateBuilder.AppendFormat("update {0} set ", m_Realm); - // bool first = true; - // foreach (string field in fields) - // { - // if (!first) - // updateBuilder.Append(", "); - // updateBuilder.AppendFormat("{0} = @{0}", field); - - // first = false; - // cmd.Parameters.Add(m_database.CreateParameter("@" + field, data.Data[field])); - // } - - // updateBuilder.Append(" where UUID = @principalID"); - - // if (data.ScopeID != UUID.Zero) - // updateBuilder.Append(" and ScopeID = @scopeID"); - - // cmd.CommandText = updateBuilder.ToString(); - // cmd.Connection = conn; - // cmd.Parameters.Add(m_database.CreateParameter("@principalID", data.PrincipalID)); - // cmd.Parameters.Add(m_database.CreateParameter("@scopeID", data.ScopeID)); - // conn.Open(); - - // if (cmd.ExecuteNonQuery() < 1) - // { - // StringBuilder insertBuilder = new StringBuilder(); - // insertBuilder.AppendFormat("insert into {0} (UUID, ScopeID, ", m_Realm); - // insertBuilder.Append(String.Join(", ", fields)); - // insertBuilder.Append(") values (@principalID, @scopeID, @"); - // insertBuilder.Append(String.Join(", @", fields)); - // insertBuilder.Append(")"); - - // cmd.CommandText = insertBuilder.ToString(); - - // if (cmd.ExecuteNonQuery() < 1) - // { - // return false; - // } - // } - // } - // return true; - //} - - //public bool Store(UserAccountData data, UUID principalID, string token) - //{ - // return false; - //} - - //public bool SetDataItem(UUID principalID, string item, string value) - //{ - // string sql = string.Format("update {0} set {1} = @{1} where UUID = @UUID", m_Realm, item); - // using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - // using (SqlCommand cmd = new SqlCommand(sql, conn)) - // { - // cmd.Parameters.Add(m_database.CreateParameter("@" + item, value)); - // cmd.Parameters.Add(m_database.CreateParameter("@UUID", principalID)); - - // conn.Open(); - - // if (cmd.ExecuteNonQuery() > 0) - // return true; - // } - // return false; - //} - - //public UserAccountData[] Get(string[] keys, string[] vals) - //{ - // return null; - //} - - public UserAccountData[] GetUsers(UUID scopeID, string query) - { - string[] words = query.Split(new char[] { ' ' }); - - for (int i = 0; i < words.Length; i++) - { - if (words[i].Length < 3) - { - if (i != words.Length - 1) - Array.Copy(words, i + 1, words, i, words.Length - i - 1); - Array.Resize(ref words, words.Length - 1); - } - } - - if (words.Length == 0) - return new UserAccountData[0]; - - if (words.Length > 2) - return new UserAccountData[0]; - - string sql = ""; - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - using (SqlCommand cmd = new SqlCommand()) - { - if (words.Length == 1) - { - sql = String.Format("select * from {0} where ([ScopeID]=@ScopeID or [ScopeID]='00000000-0000-0000-0000-000000000000') and ([FirstName] like @search or [LastName] like @search)", m_Realm); - cmd.Parameters.Add(m_database.CreateParameter("@scopeID", scopeID)); - cmd.Parameters.Add(m_database.CreateParameter("@search", "%" + words[0] + "%")); - } - else - { - sql = String.Format("select * from {0} where ([ScopeID]=@ScopeID or [ScopeID]='00000000-0000-0000-0000-000000000000') and ([FirstName] like @searchFirst or [LastName] like @searchLast)", m_Realm); - cmd.Parameters.Add(m_database.CreateParameter("@searchFirst", "%" + words[0] + "%")); - cmd.Parameters.Add(m_database.CreateParameter("@searchLast", "%" + words[1] + "%")); - cmd.Parameters.Add(m_database.CreateParameter("@ScopeID", scopeID.ToString())); - } - cmd.Connection = conn; - cmd.CommandText = sql; - conn.Open(); - return DoQuery(cmd); - } - } - } -} diff --git a/OpenSim/Data/MSSQL/MSSQLXInventoryData.cs b/OpenSim/Data/MSSQL/MSSQLXInventoryData.cs deleted file mode 100644 index 9164ffe..0000000 --- a/OpenSim/Data/MSSQL/MSSQLXInventoryData.cs +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Data; -using OpenMetaverse; -using OpenSim.Framework; -using System.Data.SqlClient; -using System.Reflection; -using System.Text; -using log4net; - -namespace OpenSim.Data.MSSQL -{ - public class MSSQLXInventoryData : IXInventoryData - { -// private static readonly ILog m_log = LogManager.GetLogger( -// MethodBase.GetCurrentMethod().DeclaringType); - - private MSSQLFolderHandler m_Folders; - private MSSQLItemHandler m_Items; - - public MSSQLXInventoryData(string conn, string realm) - { - m_Folders = new MSSQLFolderHandler( - conn, "inventoryfolders", "InventoryStore"); - m_Items = new MSSQLItemHandler( - conn, "inventoryitems", String.Empty); - } - - public XInventoryFolder[] GetFolders(string[] fields, string[] vals) - { - return m_Folders.Get(fields, vals); - } - - public XInventoryItem[] GetItems(string[] fields, string[] vals) - { - return m_Items.Get(fields, vals); - } - - public bool StoreFolder(XInventoryFolder folder) - { - if (folder.folderName.Length > 64) - folder.folderName = folder.folderName.Substring(0, 64); - return m_Folders.Store(folder); - } - - public bool StoreItem(XInventoryItem item) - { - if (item.inventoryName.Length > 64) - item.inventoryName = item.inventoryName.Substring(0, 64); - if (item.inventoryDescription.Length > 128) - item.inventoryDescription = item.inventoryDescription.Substring(0, 128); - - return m_Items.Store(item); - } - - public bool DeleteFolders(string field, string val) - { - return m_Folders.Delete(field, val); - } - - public bool DeleteFolders(string[] fields, string[] vals) - { - return m_Folders.Delete(fields, vals); - } - - public bool DeleteItems(string field, string val) - { - return m_Items.Delete(field, val); - } - - public bool DeleteItems(string[] fields, string[] vals) - { - return m_Items.Delete(fields, vals); - } - - public bool MoveItem(string id, string newParent) - { - return m_Items.MoveItem(id, newParent); - } - - public bool MoveFolder(string id, string newParent) - { - return m_Folders.MoveFolder(id, newParent); - } - - public XInventoryItem[] GetActiveGestures(UUID principalID) - { - return m_Items.GetActiveGestures(principalID); - } - - public int GetAssetPermissions(UUID principalID, UUID assetID) - { - return m_Items.GetAssetPermissions(principalID, assetID); - } - } - - public class MSSQLItemHandler : MSSQLInventoryHandler - { - public MSSQLItemHandler(string c, string t, string m) : - base(c, t, m) - { - } - - public bool MoveItem(string id, string newParent) - { - XInventoryItem[] retrievedItems = Get(new string[] { "inventoryID" }, new string[] { id }); - if (retrievedItems.Length == 0) - return false; - - UUID oldParent = retrievedItems[0].parentFolderID; - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - { - using (SqlCommand cmd = new SqlCommand()) - { - - cmd.CommandText = String.Format("update {0} set parentFolderID = @ParentFolderID where inventoryID = @InventoryID", m_Realm); - cmd.Parameters.Add(m_database.CreateParameter("@ParentFolderID", newParent)); - cmd.Parameters.Add(m_database.CreateParameter("@InventoryID", id)); - cmd.Connection = conn; - conn.Open(); - - if (cmd.ExecuteNonQuery() == 0) - return false; - } - } - - IncrementFolderVersion(oldParent); - IncrementFolderVersion(newParent); - - return true; - } - - public XInventoryItem[] GetActiveGestures(UUID principalID) - { - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - { - using (SqlCommand cmd = new SqlCommand()) - { - cmd.CommandText = String.Format("select * from inventoryitems where avatarId = @uuid and assetType = @type and flags = 1", m_Realm); - - cmd.Parameters.Add(m_database.CreateParameter("@uuid", principalID.ToString())); - cmd.Parameters.Add(m_database.CreateParameter("@type", (int)AssetType.Gesture)); - cmd.Connection = conn; - conn.Open(); - return DoQuery(cmd); - } - } - } - - public int GetAssetPermissions(UUID principalID, UUID assetID) - { - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - { - using (SqlCommand cmd = new SqlCommand()) - { - cmd.CommandText = String.Format("select bit_or(inventoryCurrentPermissions) as inventoryCurrentPermissions from inventoryitems where avatarID = @PrincipalID and assetID = @AssetID group by assetID", m_Realm); - cmd.Parameters.Add(m_database.CreateParameter("@PrincipalID", principalID.ToString())); - cmd.Parameters.Add(m_database.CreateParameter("@AssetID", assetID.ToString())); - cmd.Connection = conn; - conn.Open(); - using (SqlDataReader reader = cmd.ExecuteReader()) - { - - int perms = 0; - - if (reader.Read()) - { - perms = Convert.ToInt32(reader["inventoryCurrentPermissions"]); - } - - return perms; - } - - } - } - } - - public override bool Store(XInventoryItem item) - { - if (!base.Store(item)) - return false; - - IncrementFolderVersion(item.parentFolderID); - - return true; - } - } - - public class MSSQLFolderHandler : MSSQLInventoryHandler - { - public MSSQLFolderHandler(string c, string t, string m) : - base(c, t, m) - { - } - - public bool MoveFolder(string id, string newParentFolderID) - { - XInventoryFolder[] folders = Get(new string[] { "folderID" }, new string[] { id }); - - if (folders.Length == 0) - return false; - - UUID oldParentFolderUUID = folders[0].parentFolderID; - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - { - using (SqlCommand cmd = new SqlCommand()) - { - - cmd.CommandText = String.Format("update {0} set parentFolderID = @ParentFolderID where folderID = @folderID", m_Realm); - cmd.Parameters.Add(m_database.CreateParameter("@ParentFolderID", newParentFolderID)); - cmd.Parameters.Add(m_database.CreateParameter("@folderID", id)); - cmd.Connection = conn; - conn.Open(); - - if (cmd.ExecuteNonQuery() == 0) - return false; - } - } - - IncrementFolderVersion(oldParentFolderUUID); - IncrementFolderVersion(newParentFolderID); - - return true; - } - - public override bool Store(XInventoryFolder folder) - { - if (!base.Store(folder)) - return false; - - IncrementFolderVersion(folder.parentFolderID); - - return true; - } - } - - public class MSSQLInventoryHandler : MSSQLGenericTableHandler where T: class, new() - { - public MSSQLInventoryHandler(string c, string t, string m) : base(c, t, m) {} - - protected bool IncrementFolderVersion(UUID folderID) - { - return IncrementFolderVersion(folderID.ToString()); - } - - protected bool IncrementFolderVersion(string folderID) - { -// m_log.DebugFormat("[MYSQL ITEM HANDLER]: Incrementing version on folder {0}", folderID); -// Util.PrintCallStack(); - - string sql = "update inventoryfolders set version=version+1 where folderID = ?folderID"; - - using (SqlConnection conn = new SqlConnection(m_ConnectionString)) - { - using (SqlCommand cmd = new SqlCommand(sql, conn)) - { - conn.Open(); - - cmd.Parameters.AddWithValue("@folderID", folderID); - - try - { - cmd.ExecuteNonQuery(); - } - catch (Exception) - { - return false; - } - } - } - - return true; - } - } -} \ No newline at end of file diff --git a/OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs b/OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs deleted file mode 100644 index 1a67e70..0000000 --- a/OpenSim/Data/MSSQL/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Reflection; -using System.Runtime.InteropServices; - -// General information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. - -[assembly : AssemblyTitle("OpenSim.Data.MSSQL")] -[assembly : AssemblyDescription("")] -[assembly : AssemblyConfiguration("")] -[assembly : AssemblyCompany("http://opensimulator.org")] -[assembly : AssemblyProduct("OpenSim.Data.MSSQL")] -[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers 2007-2009")] -[assembly : AssemblyTrademark("")] -[assembly : AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. - -[assembly : ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM - -[assembly : Guid("0e1c1ca4-2cf2-4315-b0e7-432c02feea8a")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: - -[assembly : AssemblyVersion("0.7.5.*")] -[assembly : AssemblyFileVersion("0.6.5.0")] diff --git a/OpenSim/Data/MSSQL/Resources/AssetStore.migrations b/OpenSim/Data/MSSQL/Resources/AssetStore.migrations deleted file mode 100644 index 8664ce9..0000000 --- a/OpenSim/Data/MSSQL/Resources/AssetStore.migrations +++ /dev/null @@ -1,106 +0,0 @@ -:VERSION 1 - -CREATE TABLE [assets] ( - [id] [varchar](36) NOT NULL, - [name] [varchar](64) NOT NULL, - [description] [varchar](64) NOT NULL, - [assetType] [tinyint] NOT NULL, - [local] [tinyint] NOT NULL, - [temporary] [tinyint] NOT NULL, - [data] [image] NOT NULL, -PRIMARY KEY CLUSTERED -( - [id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] -) ON [PRIMARY] - - -:VERSION 2 - -BEGIN TRANSACTION - -CREATE TABLE Tmp_assets - ( - id varchar(36) NOT NULL, - name varchar(64) NOT NULL, - description varchar(64) NOT NULL, - assetType tinyint NOT NULL, - local bit NOT NULL, - temporary bit NOT NULL, - data image NOT NULL - ) ON [PRIMARY] - TEXTIMAGE_ON [PRIMARY] - -IF EXISTS(SELECT * FROM assets) - EXEC('INSERT INTO Tmp_assets (id, name, description, assetType, local, temporary, data) - SELECT id, name, description, assetType, CONVERT(bit, local), CONVERT(bit, temporary), data FROM assets WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE assets - -EXECUTE sp_rename N'Tmp_assets', N'assets', 'OBJECT' - -ALTER TABLE dbo.assets ADD CONSTRAINT - PK__assets__id PRIMARY KEY CLUSTERED - ( - id - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 3 - -BEGIN TRANSACTION - -ALTER TABLE assets add create_time integer default 0 -ALTER TABLE assets add access_time integer default 0 - -COMMIT - - -:VERSION 4 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_assets - ( - id uniqueidentifier NOT NULL, - name varchar(64) NOT NULL, - description varchar(64) NOT NULL, - assetType tinyint NOT NULL, - local bit NOT NULL, - temporary bit NOT NULL, - data image NOT NULL, - create_time int NULL, - access_time int NULL - ) ON [PRIMARY] - TEXTIMAGE_ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.assets) - EXEC('INSERT INTO dbo.Tmp_assets (id, name, description, assetType, local, temporary, data, create_time, access_time) - SELECT CONVERT(uniqueidentifier, id), name, description, assetType, local, temporary, data, create_time, access_time FROM dbo.assets WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE assets - -EXECUTE sp_rename N'Tmp_assets', N'assets', 'OBJECT' - -ALTER TABLE dbo.assets ADD CONSTRAINT - PK__assets__id PRIMARY KEY CLUSTERED - ( - id - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 5 - -DELETE FROM assets WHERE id = 'dc4b9f0b-d008-45c6-96a4-01dd947ac621'; - -:VERSION 6 - -ALTER TABLE assets ADD asset_flags INTEGER NOT NULL DEFAULT 0; - -:VERSION 7 - -alter table assets add creatorid varchar(36) not null default ''; diff --git a/OpenSim/Data/MSSQL/Resources/AuthStore.migrations b/OpenSim/Data/MSSQL/Resources/AuthStore.migrations deleted file mode 100644 index eb91296..0000000 --- a/OpenSim/Data/MSSQL/Resources/AuthStore.migrations +++ /dev/null @@ -1,32 +0,0 @@ -:VERSION 1 - -BEGIN TRANSACTION - -CREATE TABLE [auth] ( - [uuid] [uniqueidentifier] NOT NULL default '00000000-0000-0000-0000-000000000000', - [passwordHash] [varchar](32) NOT NULL, - [passwordSalt] [varchar](32) NOT NULL, - [webLoginKey] [varchar](255) NOT NULL, - [accountType] VARCHAR(32) NOT NULL DEFAULT 'UserAccount', -) ON [PRIMARY] - -CREATE TABLE [tokens] ( - [uuid] [uniqueidentifier] NOT NULL default '00000000-0000-0000-0000-000000000000', - [token] [varchar](255) NOT NULL, - [validity] [datetime] NOT NULL ) - ON [PRIMARY] - -COMMIT - -:VERSION 2 - -BEGIN TRANSACTION - -IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[users]') AND type in (N'U')) - INSERT INTO auth (UUID, passwordHash, passwordSalt, webLoginKey, accountType) SELECT [UUID] AS UUID, [passwordHash] AS passwordHash, [passwordSalt] AS passwordSalt, [webLoginKey] AS webLoginKey, 'UserAccount' as [accountType] FROM users; - -COMMIT - - - - diff --git a/OpenSim/Data/MSSQL/Resources/Avatar.migrations b/OpenSim/Data/MSSQL/Resources/Avatar.migrations deleted file mode 100644 index 61f7b56..0000000 --- a/OpenSim/Data/MSSQL/Resources/Avatar.migrations +++ /dev/null @@ -1,64 +0,0 @@ -:VERSION 1 - -BEGIN TRANSACTION - -CREATE TABLE [Avatars] ( -[PrincipalID] uniqueidentifier NOT NULL, -[Name] varchar(32) NOT NULL, -[Value] varchar(255) NOT NULL DEFAULT '', -PRIMARY KEY CLUSTERED -( - [PrincipalID] ASC, [Name] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] -) ON [PRIMARY] - - -COMMIT - -:VERSION 2 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_Avatars - ( - PrincipalID uniqueidentifier NOT NULL, - [Name] varchar(32) NOT NULL, - Value text NOT NULL DEFAULT '', - ) ON [PRIMARY] - TEXTIMAGE_ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.Avatars) - EXEC('INSERT INTO dbo.Tmp_Avatars (PrincipalID, Name, Value) - SELECT PrincipalID, CONVERT(text, Name), Value FROM dbo.Avatars WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.Avatars - -EXECUTE sp_rename N'dbo.Tmp_Avatars', N'Avatars', 'OBJECT' - -COMMIT - -:VERSION 3 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_Avatars - ( - PrincipalID uniqueidentifier NOT NULL, - [Name] varchar(32) NOT NULL, - Value text NOT NULL DEFAULT '', - PRIMARY KEY CLUSTERED -( - [PrincipalID] ASC, [Name] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] -) ON [PRIMARY] - TEXTIMAGE_ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.Avatars) - EXEC('INSERT INTO dbo.Tmp_Avatars (PrincipalID, Name, Value) - SELECT PrincipalID, CONVERT(text, Name), Value FROM dbo.Avatars WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.Avatars - -EXECUTE sp_rename N'dbo.Tmp_Avatars', N'Avatars', 'OBJECT' -COMMIT - diff --git a/OpenSim/Data/MSSQL/Resources/EstateStore.migrations b/OpenSim/Data/MSSQL/Resources/EstateStore.migrations deleted file mode 100644 index 64b2d2b..0000000 --- a/OpenSim/Data/MSSQL/Resources/EstateStore.migrations +++ /dev/null @@ -1,334 +0,0 @@ -:VERSION 1 - -BEGIN TRANSACTION - -CREATE TABLE [dbo].[estate_managers]( - [EstateID] [int] NOT NULL, - [uuid] [varchar](36) NOT NULL, - CONSTRAINT [PK_estate_managers] PRIMARY KEY CLUSTERED -( - [EstateID] ASC -)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY]; - -CREATE TABLE [dbo].[estate_groups]( - [EstateID] [int] NOT NULL, - [uuid] [varchar](36) NOT NULL, - CONSTRAINT [PK_estate_groups] PRIMARY KEY CLUSTERED -( - [EstateID] ASC -)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY]; - - -CREATE TABLE [dbo].[estate_users]( - [EstateID] [int] NOT NULL, - [uuid] [varchar](36) NOT NULL, - CONSTRAINT [PK_estate_users] PRIMARY KEY CLUSTERED -( - [EstateID] ASC -)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY]; - - -CREATE TABLE [dbo].[estateban]( - [EstateID] [int] NOT NULL, - [bannedUUID] [varchar](36) NOT NULL, - [bannedIp] [varchar](16) NOT NULL, - [bannedIpHostMask] [varchar](16) NOT NULL, - [bannedNameMask] [varchar](64) NULL DEFAULT (NULL), - CONSTRAINT [PK_estateban] PRIMARY KEY CLUSTERED -( - [EstateID] ASC -)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY]; - -CREATE TABLE [dbo].[estate_settings]( - [EstateID] [int] IDENTITY(1,100) NOT NULL, - [EstateName] [varchar](64) NULL DEFAULT (NULL), - [AbuseEmailToEstateOwner] [bit] NOT NULL, - [DenyAnonymous] [bit] NOT NULL, - [ResetHomeOnTeleport] [bit] NOT NULL, - [FixedSun] [bit] NOT NULL, - [DenyTransacted] [bit] NOT NULL, - [BlockDwell] [bit] NOT NULL, - [DenyIdentified] [bit] NOT NULL, - [AllowVoice] [bit] NOT NULL, - [UseGlobalTime] [bit] NOT NULL, - [PricePerMeter] [int] NOT NULL, - [TaxFree] [bit] NOT NULL, - [AllowDirectTeleport] [bit] NOT NULL, - [RedirectGridX] [int] NOT NULL, - [RedirectGridY] [int] NOT NULL, - [ParentEstateID] [int] NOT NULL, - [SunPosition] [float] NOT NULL, - [EstateSkipScripts] [bit] NOT NULL, - [BillableFactor] [float] NOT NULL, - [PublicAccess] [bit] NOT NULL, - [AbuseEmail] [varchar](255) NOT NULL, - [EstateOwner] [varchar](36) NOT NULL, - [DenyMinors] [bit] NOT NULL, - CONSTRAINT [PK_estate_settings] PRIMARY KEY CLUSTERED -( - [EstateID] ASC -)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY]; - - -CREATE TABLE [dbo].[estate_map]( - [RegionID] [varchar](36) NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), - [EstateID] [int] NOT NULL, - CONSTRAINT [PK_estate_map] PRIMARY KEY CLUSTERED -( - [RegionID] ASC -)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY]; - -COMMIT - -:VERSION 2 - -BEGIN TRANSACTION - -ALTER TABLE dbo.estate_managers DROP CONSTRAINT PK_estate_managers - -CREATE NONCLUSTERED INDEX IX_estate_managers ON dbo.estate_managers - ( - EstateID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -ALTER TABLE dbo.estate_groups DROP CONSTRAINT PK_estate_groups - -CREATE NONCLUSTERED INDEX IX_estate_groups ON dbo.estate_groups - ( - EstateID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - - -ALTER TABLE dbo.estate_users DROP CONSTRAINT PK_estate_users - -CREATE NONCLUSTERED INDEX IX_estate_users ON dbo.estate_users - ( - EstateID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 3 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_estateban - ( - EstateID int NOT NULL, - bannedUUID varchar(36) NOT NULL, - bannedIp varchar(16) NULL, - bannedIpHostMask varchar(16) NULL, - bannedNameMask varchar(64) NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.estateban) - EXEC('INSERT INTO dbo.Tmp_estateban (EstateID, bannedUUID, bannedIp, bannedIpHostMask, bannedNameMask) - SELECT EstateID, bannedUUID, bannedIp, bannedIpHostMask, bannedNameMask FROM dbo.estateban') - -DROP TABLE dbo.estateban - -EXECUTE sp_rename N'dbo.Tmp_estateban', N'estateban', 'OBJECT' - -CREATE NONCLUSTERED INDEX IX_estateban ON dbo.estateban - ( - EstateID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 4 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_estate_managers - ( - EstateID int NOT NULL, - uuid uniqueidentifier NOT NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.estate_managers) - EXEC('INSERT INTO dbo.Tmp_estate_managers (EstateID, uuid) - SELECT EstateID, CONVERT(uniqueidentifier, uuid) FROM dbo.estate_managers WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.estate_managers - -EXECUTE sp_rename N'dbo.Tmp_estate_managers', N'estate_managers', 'OBJECT' - -CREATE NONCLUSTERED INDEX IX_estate_managers ON dbo.estate_managers - ( - EstateID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 5 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_estate_groups - ( - EstateID int NOT NULL, - uuid uniqueidentifier NOT NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.estate_groups) - EXEC('INSERT INTO dbo.Tmp_estate_groups (EstateID, uuid) - SELECT EstateID, CONVERT(uniqueidentifier, uuid) FROM dbo.estate_groups WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.estate_groups - -EXECUTE sp_rename N'dbo.Tmp_estate_groups', N'estate_groups', 'OBJECT' - -CREATE NONCLUSTERED INDEX IX_estate_groups ON dbo.estate_groups - ( - EstateID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 6 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_estate_users - ( - EstateID int NOT NULL, - uuid uniqueidentifier NOT NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.estate_users) - EXEC('INSERT INTO dbo.Tmp_estate_users (EstateID, uuid) - SELECT EstateID, CONVERT(uniqueidentifier, uuid) FROM dbo.estate_users WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.estate_users - -EXECUTE sp_rename N'dbo.Tmp_estate_users', N'estate_users', 'OBJECT' - -CREATE NONCLUSTERED INDEX IX_estate_users ON dbo.estate_users - ( - EstateID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 7 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_estateban - ( - EstateID int NOT NULL, - bannedUUID uniqueidentifier NOT NULL, - bannedIp varchar(16) NULL, - bannedIpHostMask varchar(16) NULL, - bannedNameMask varchar(64) NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.estateban) - EXEC('INSERT INTO dbo.Tmp_estateban (EstateID, bannedUUID, bannedIp, bannedIpHostMask, bannedNameMask) - SELECT EstateID, CONVERT(uniqueidentifier, bannedUUID), bannedIp, bannedIpHostMask, bannedNameMask FROM dbo.estateban WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.estateban - -EXECUTE sp_rename N'dbo.Tmp_estateban', N'estateban', 'OBJECT' - -CREATE NONCLUSTERED INDEX IX_estateban ON dbo.estateban - ( - EstateID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 8 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_estate_settings - ( - EstateID int NOT NULL IDENTITY (1, 100), - EstateName varchar(64) NULL DEFAULT (NULL), - AbuseEmailToEstateOwner bit NOT NULL, - DenyAnonymous bit NOT NULL, - ResetHomeOnTeleport bit NOT NULL, - FixedSun bit NOT NULL, - DenyTransacted bit NOT NULL, - BlockDwell bit NOT NULL, - DenyIdentified bit NOT NULL, - AllowVoice bit NOT NULL, - UseGlobalTime bit NOT NULL, - PricePerMeter int NOT NULL, - TaxFree bit NOT NULL, - AllowDirectTeleport bit NOT NULL, - RedirectGridX int NOT NULL, - RedirectGridY int NOT NULL, - ParentEstateID int NOT NULL, - SunPosition float(53) NOT NULL, - EstateSkipScripts bit NOT NULL, - BillableFactor float(53) NOT NULL, - PublicAccess bit NOT NULL, - AbuseEmail varchar(255) NOT NULL, - EstateOwner uniqueidentifier NOT NULL, - DenyMinors bit NOT NULL - ) ON [PRIMARY] - -SET IDENTITY_INSERT dbo.Tmp_estate_settings ON - -IF EXISTS(SELECT * FROM dbo.estate_settings) - EXEC('INSERT INTO dbo.Tmp_estate_settings (EstateID, EstateName, AbuseEmailToEstateOwner, DenyAnonymous, ResetHomeOnTeleport, FixedSun, DenyTransacted, BlockDwell, DenyIdentified, AllowVoice, UseGlobalTime, PricePerMeter, TaxFree, AllowDirectTeleport, RedirectGridX, RedirectGridY, ParentEstateID, SunPosition, EstateSkipScripts, BillableFactor, PublicAccess, AbuseEmail, EstateOwner, DenyMinors) - SELECT EstateID, EstateName, AbuseEmailToEstateOwner, DenyAnonymous, ResetHomeOnTeleport, FixedSun, DenyTransacted, BlockDwell, DenyIdentified, AllowVoice, UseGlobalTime, PricePerMeter, TaxFree, AllowDirectTeleport, RedirectGridX, RedirectGridY, ParentEstateID, SunPosition, EstateSkipScripts, BillableFactor, PublicAccess, AbuseEmail, CONVERT(uniqueidentifier, EstateOwner), DenyMinors FROM dbo.estate_settings WITH (HOLDLOCK TABLOCKX)') - -SET IDENTITY_INSERT dbo.Tmp_estate_settings OFF - -DROP TABLE dbo.estate_settings - -EXECUTE sp_rename N'dbo.Tmp_estate_settings', N'estate_settings', 'OBJECT' - -ALTER TABLE dbo.estate_settings ADD CONSTRAINT - PK_estate_settings PRIMARY KEY CLUSTERED - ( - EstateID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 9 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_estate_map - ( - RegionID uniqueidentifier NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), - EstateID int NOT NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.estate_map) - EXEC('INSERT INTO dbo.Tmp_estate_map (RegionID, EstateID) - SELECT CONVERT(uniqueidentifier, RegionID), EstateID FROM dbo.estate_map WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.estate_map - -EXECUTE sp_rename N'dbo.Tmp_estate_map', N'estate_map', 'OBJECT' - -ALTER TABLE dbo.estate_map ADD CONSTRAINT - PK_estate_map PRIMARY KEY CLUSTERED - ( - RegionID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - - -COMMIT - - diff --git a/OpenSim/Data/MSSQL/Resources/FriendsStore.migrations b/OpenSim/Data/MSSQL/Resources/FriendsStore.migrations deleted file mode 100644 index cc94c4e..0000000 --- a/OpenSim/Data/MSSQL/Resources/FriendsStore.migrations +++ /dev/null @@ -1,50 +0,0 @@ -:VERSION 1 - -BEGIN TRANSACTION - -CREATE TABLE [Friends] ( -[PrincipalID] uniqueidentifier NOT NULL, -[Friend] varchar(255) NOT NULL, -[Flags] char(16) NOT NULL DEFAULT '0', -[Offered] varchar(32) NOT NULL DEFAULT 0) - ON [PRIMARY] - -COMMIT - -:VERSION 2 - -BEGIN TRANSACTION - -IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[userfriends]') AND type in (N'U')) -INSERT INTO Friends (PrincipalID, Friend, Flags, Offered) -SELECT [ownerID], [friendID], [friendPerms], 0 FROM userfriends; - -COMMIT - -:VERSION 3 - -BEGIN TRANSACTION - -CREATE TABLE [Tmp_Friends] - ([PrincipalID] varchar(255) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', -[Friend] varchar(255) NOT NULL, -[Flags] char(16) NOT NULL DEFAULT '0', -[Offered] varchar(32) NOT NULL DEFAULT 0) -ON [PRIMARY] - - -IF EXISTS(SELECT * FROM dbo.Friends) - EXEC('INSERT INTO dbo.Tmp_Friends (PrincipalID, Friend, Flags, Offered) - SELECT CONVERT(varchar(255),PrincipalID), Friend, Flags, Offered FROM dbo.Friends WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.Friends - -EXECUTE sp_rename N'dbo.Tmp_Friends', N'Friends', 'OBJECT' - -ALTER TABLE dbo.Friends ADD - PRIMARY KEY CLUSTERED -( - [PrincipalID] ASC, [Friend] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT \ No newline at end of file diff --git a/OpenSim/Data/MSSQL/Resources/GridStore.migrations b/OpenSim/Data/MSSQL/Resources/GridStore.migrations deleted file mode 100644 index de0cea7..0000000 --- a/OpenSim/Data/MSSQL/Resources/GridStore.migrations +++ /dev/null @@ -1,245 +0,0 @@ -:VERSION 1 - -BEGIN TRANSACTION - -CREATE TABLE [dbo].[regions]( - [regionHandle] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [regionName] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [uuid] [varchar](255) COLLATE Latin1_General_CI_AS NOT NULL, - [regionRecvKey] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [regionSecret] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [regionSendKey] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [regionDataURI] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [serverIP] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [serverPort] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [serverURI] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [locX] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [locY] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [locZ] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [eastOverrideHandle] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [westOverrideHandle] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [southOverrideHandle] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [northOverrideHandle] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [regionAssetURI] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [regionAssetRecvKey] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [regionAssetSendKey] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [regionUserURI] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [regionUserRecvKey] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [regionUserSendKey] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [regionMapTexture] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [serverHttpPort] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [serverRemotingPort] [varchar](255) COLLATE Latin1_General_CI_AS NULL, - [owner_uuid] [varchar](36) COLLATE Latin1_General_CI_AS NULL, -PRIMARY KEY CLUSTERED -( - [uuid] ASC -)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] - -COMMIT - - -:VERSION 2 - -BEGIN TRANSACTION - -CREATE TABLE Tmp_regions - ( - uuid varchar(36) COLLATE Latin1_General_CI_AS NOT NULL, - regionHandle bigint NULL, - regionName varchar(20) NULL, - regionRecvKey varchar(128) NULL, - regionSendKey varchar(128) NULL, - regionSecret varchar(128) NULL, - regionDataURI varchar(128) NULL, - serverIP varchar(64) NULL, - serverPort int NULL, - serverURI varchar(255) NULL, - locX int NULL, - locY int NULL, - locZ int NULL, - eastOverrideHandle bigint NULL, - westOverrideHandle bigint NULL, - southOverrideHandle bigint NULL, - northOverrideHandle bigint NULL, - regionAssetURI varchar(255) NULL, - regionAssetRecvKey varchar(128) NULL, - regionAssetSendKey varchar(128) NULL, - regionUserURI varchar(255) NULL, - regionUserRecvKey varchar(128) NULL, - regionUserSendKey varchar(128) NULL, - regionMapTexture varchar(36) NULL, - serverHttpPort int NULL, - serverRemotingPort int NULL, - owner_uuid varchar(36) NULL, - originUUID varchar(36) NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000') - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM regions) - EXEC('INSERT INTO Tmp_regions (uuid, regionHandle, regionName, regionRecvKey, regionSendKey, regionSecret, regionDataURI, serverIP, serverPort, serverURI, locX, locY, locZ, eastOverrideHandle, westOverrideHandle, southOverrideHandle, northOverrideHandle, regionAssetURI, regionAssetRecvKey, regionAssetSendKey, regionUserURI, regionUserRecvKey, regionUserSendKey, regionMapTexture, serverHttpPort, serverRemotingPort, owner_uuid) - SELECT CONVERT(varchar(36), uuid), CONVERT(bigint, regionHandle), CONVERT(varchar(20), regionName), CONVERT(varchar(128), regionRecvKey), CONVERT(varchar(128), regionSendKey), CONVERT(varchar(128), regionSecret), CONVERT(varchar(128), regionDataURI), CONVERT(varchar(64), serverIP), CONVERT(int, serverPort), serverURI, CONVERT(int, locX), CONVERT(int, locY), CONVERT(int, locZ), CONVERT(bigint, eastOverrideHandle), CONVERT(bigint, westOverrideHandle), CONVERT(bigint, southOverrideHandle), CONVERT(bigint, northOverrideHandle), regionAssetURI, CONVERT(varchar(128), regionAssetRecvKey), CONVERT(varchar(128), regionAssetSendKey), regionUserURI, CONVERT(varchar(128), regionUserRecvKey), CONVERT(varchar(128), regionUserSendKey), CONVERT(varchar(36), regionMapTexture), CONVERT(int, serverHttpPort), CONVERT(int, serverRemotingPort), owner_uuid FROM regions') - -DROP TABLE regions - -EXECUTE sp_rename N'Tmp_regions', N'regions', 'OBJECT' - -ALTER TABLE regions ADD CONSTRAINT - PK__regions__uuid PRIMARY KEY CLUSTERED - ( - uuid - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - -:VERSION 3 - -BEGIN TRANSACTION - -CREATE NONCLUSTERED INDEX IX_regions_name ON dbo.regions - ( - regionName - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX IX_regions_handle ON dbo.regions - ( - regionHandle - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - - -CREATE NONCLUSTERED INDEX IX_regions_override ON dbo.regions - ( - eastOverrideHandle, - westOverrideHandle, - southOverrideHandle, - northOverrideHandle - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 4 - -/* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/ -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_regions - ( - uuid uniqueidentifier NOT NULL, - regionHandle bigint NULL, - regionName varchar(20) NULL, - regionRecvKey varchar(128) NULL, - regionSendKey varchar(128) NULL, - regionSecret varchar(128) NULL, - regionDataURI varchar(128) NULL, - serverIP varchar(64) NULL, - serverPort int NULL, - serverURI varchar(255) NULL, - locX int NULL, - locY int NULL, - locZ int NULL, - eastOverrideHandle bigint NULL, - westOverrideHandle bigint NULL, - southOverrideHandle bigint NULL, - northOverrideHandle bigint NULL, - regionAssetURI varchar(255) NULL, - regionAssetRecvKey varchar(128) NULL, - regionAssetSendKey varchar(128) NULL, - regionUserURI varchar(255) NULL, - regionUserRecvKey varchar(128) NULL, - regionUserSendKey varchar(128) NULL, - regionMapTexture uniqueidentifier NULL, - serverHttpPort int NULL, - serverRemotingPort int NULL, - owner_uuid uniqueidentifier NOT NULL, - originUUID uniqueidentifier NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000') - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.regions) - EXEC('INSERT INTO dbo.Tmp_regions (uuid, regionHandle, regionName, regionRecvKey, regionSendKey, regionSecret, regionDataURI, serverIP, serverPort, serverURI, locX, locY, locZ, eastOverrideHandle, westOverrideHandle, southOverrideHandle, northOverrideHandle, regionAssetURI, regionAssetRecvKey, regionAssetSendKey, regionUserURI, regionUserRecvKey, regionUserSendKey, regionMapTexture, serverHttpPort, serverRemotingPort, owner_uuid, originUUID) - SELECT CONVERT(uniqueidentifier, uuid), regionHandle, regionName, regionRecvKey, regionSendKey, regionSecret, regionDataURI, serverIP, serverPort, serverURI, locX, locY, locZ, eastOverrideHandle, westOverrideHandle, southOverrideHandle, northOverrideHandle, regionAssetURI, regionAssetRecvKey, regionAssetSendKey, regionUserURI, regionUserRecvKey, regionUserSendKey, CONVERT(uniqueidentifier, regionMapTexture), serverHttpPort, serverRemotingPort, CONVERT(uniqueidentifier, owner_uuid), CONVERT(uniqueidentifier, originUUID) FROM dbo.regions WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.regions - -EXECUTE sp_rename N'dbo.Tmp_regions', N'regions', 'OBJECT' - -ALTER TABLE dbo.regions ADD CONSTRAINT - PK__regions__uuid PRIMARY KEY CLUSTERED - ( - uuid - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX IX_regions_name ON dbo.regions - ( - regionName - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX IX_regions_handle ON dbo.regions - ( - regionHandle - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX IX_regions_override ON dbo.regions - ( - eastOverrideHandle, - westOverrideHandle, - southOverrideHandle, - northOverrideHandle - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 5 - -BEGIN TRANSACTION - -ALTER TABLE regions ADD access int default 0; - -COMMIT - - -:VERSION 6 - -BEGIN TRANSACTION - -ALTER TABLE regions ADD scopeid uniqueidentifier default '00000000-0000-0000-0000-000000000000'; -ALTER TABLE regions ADD DEFAULT ('00000000-0000-0000-0000-000000000000') FOR [owner_uuid]; -ALTER TABLE regions ADD sizeX integer not null default 0; -ALTER TABLE regions ADD sizeY integer not null default 0; - -COMMIT - - -:VERSION 7 - -BEGIN TRANSACTION - -ALTER TABLE regions ADD [flags] integer NOT NULL DEFAULT 0; -CREATE INDEX [flags] ON regions(flags); -ALTER TABLE [regions] ADD [last_seen] integer NOT NULL DEFAULT 0; -ALTER TABLE [regions] ADD [PrincipalID] uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'; -ALTER TABLE [regions] ADD [Token] varchar(255) NOT NULL DEFAULT 0; - -COMMIT - -:VERSION 8 - -BEGIN TRANSACTION -ALTER TABLE regions ALTER COLUMN regionName VarChar(128) - -DROP INDEX IX_regions_name ON dbo.regions -ALTER TABLE regions ALTER COLUMN regionName VarChar(128) null - -CREATE NONCLUSTERED INDEX IX_regions_name ON dbo.regions - ( - regionName - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - -:VERSION 9 - -BEGIN TRANSACTION -ALTER TABLE regions ADD parcelMapTexture uniqueidentifier NULL; - -COMMIT diff --git a/OpenSim/Data/MSSQL/Resources/GridUserStore.migrations b/OpenSim/Data/MSSQL/Resources/GridUserStore.migrations deleted file mode 100644 index ecd3f4d..0000000 --- a/OpenSim/Data/MSSQL/Resources/GridUserStore.migrations +++ /dev/null @@ -1,65 +0,0 @@ -:VERSION 1 # -------------------------- - -BEGIN TRANSACTION - -CREATE TABLE "GridUser" ( - "UserID" VARCHAR(255) NOT NULL, - "HomeRegionID" CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', - "HomePosition" CHAR(64) NOT NULL DEFAULT '<0,0,0>', - "HomeLookAt" CHAR(64) NOT NULL DEFAULT '<0,0,0>', - "LastRegionID" CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', - "LastPosition" CHAR(64) NOT NULL DEFAULT '<0,0,0>', - "LastLookAt" CHAR(64) NOT NULL DEFAULT '<0,0,0>', - "Online" CHAR(5) NOT NULL DEFAULT 'false', - "Login" CHAR(16) NOT NULL DEFAULT '0', - "Logout" CHAR(16) NOT NULL DEFAULT '0', - PRIMARY KEY ("UserID") -) - -COMMIT - -:VERSION 2 # -------------------------- - -BEGIN TRANSACTION - -CREATE TABLE [GridUser_tmp] ( - [UserID] VARCHAR(255) NOT NULL, - [HomeRegionID] uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', - [HomePosition] CHAR(64) NOT NULL DEFAULT '<0,0,0>', - [HomeLookAt] CHAR(64) NOT NULL DEFAULT '<0,0,0>', - [LastRegionID] uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', - [LastPosition] CHAR(64) NOT NULL DEFAULT '<0,0,0>', - [LastLookAt] CHAR(64) NOT NULL DEFAULT '<0,0,0>', - [Online] CHAR(5) NOT NULL DEFAULT 'false', - [Login] CHAR(16) NOT NULL DEFAULT '0', - [Logout] CHAR(16) NOT NULL DEFAULT '0', - - PRIMARY KEY CLUSTERED - ( - [UserID] ASC - )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - ) ON [PRIMARY] - -COMMIT - -IF EXISTS(SELECT * FROM dbo.GridUser) - EXEC('INSERT INTO dbo.GridUser_tmp ([UserID] - ,[HomeRegionID] - ,[HomePosition] - ,[HomeLookAt] - ,[LastRegionID] - ,[LastPosition] - ,[LastLookAt] - ,[Online] - ,[Login] - ,[Logout]) - SELECT CONVERT(varchar(36), [HomeRegionID]), [HomePosition] ,[HomeLookAt] , CONVERT(varchar(36),[LastRegionID]) - ,[LastPosition] - ,[LastLookAt] - ,[Online] - ,[Login] - ,[Logout] FROM dbo.GridUser WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.GridUser - -EXECUTE sp_rename N'dbo.GridUser_tmp', N'GridUser', 'OBJECT' \ No newline at end of file diff --git a/OpenSim/Data/MSSQL/Resources/InventoryStore.migrations b/OpenSim/Data/MSSQL/Resources/InventoryStore.migrations deleted file mode 100644 index 4e43653..0000000 --- a/OpenSim/Data/MSSQL/Resources/InventoryStore.migrations +++ /dev/null @@ -1,279 +0,0 @@ -:VERSION 1 - -BEGIN TRANSACTION - -CREATE TABLE [inventoryfolders] ( - [folderID] [varchar](36) NOT NULL default '', - [agentID] [varchar](36) default NULL, - [parentFolderID] [varchar](36) default NULL, - [folderName] [varchar](64) default NULL, - [type] [smallint] NOT NULL default 0, - [version] [int] NOT NULL default 0, - PRIMARY KEY CLUSTERED -( - [folderID] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] -) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX [owner] ON [inventoryfolders] -( - [agentID] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX [parent] ON [inventoryfolders] -( - [parentFolderID] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - - -CREATE TABLE [inventoryitems] ( - [inventoryID] [varchar](36) NOT NULL default '', - [assetID] [varchar](36) default NULL, - [assetType] [int] default NULL, - [parentFolderID] [varchar](36) default NULL, - [avatarID] [varchar](36) default NULL, - [inventoryName] [varchar](64) default NULL, - [inventoryDescription] [varchar](128) default NULL, - [inventoryNextPermissions] [int] default NULL, - [inventoryCurrentPermissions] [int] default NULL, - [invType] [int] default NULL, - [creatorID] [varchar](36) default NULL, - [inventoryBasePermissions] [int] NOT NULL default 0, - [inventoryEveryOnePermissions] [int] NOT NULL default 0, - [salePrice] [int] default NULL, - [saleType] [tinyint] default NULL, - [creationDate] [int] default NULL, - [groupID] [varchar](36) default NULL, - [groupOwned] [bit] default NULL, - [flags] [int] default NULL, - PRIMARY KEY CLUSTERED -( - [inventoryID] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] -) ON [PRIMARY] - - -CREATE NONCLUSTERED INDEX [owner] ON [inventoryitems] -( - [avatarID] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX [folder] ON [inventoryitems] -( - [parentFolderID] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 2 - -BEGIN TRANSACTION - -ALTER TABLE inventoryitems ADD inventoryGroupPermissions INTEGER NOT NULL default 0 - -COMMIT - -:VERSION 3 - -/* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/ -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_inventoryfolders - ( - folderID uniqueidentifier NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), - agentID uniqueidentifier NULL DEFAULT (NULL), - parentFolderID uniqueidentifier NULL DEFAULT (NULL), - folderName varchar(64) NULL DEFAULT (NULL), - type smallint NOT NULL DEFAULT ((0)), - version int NOT NULL DEFAULT ((0)) - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.inventoryfolders) - EXEC('INSERT INTO dbo.Tmp_inventoryfolders (folderID, agentID, parentFolderID, folderName, type, version) - SELECT CONVERT(uniqueidentifier, folderID), CONVERT(uniqueidentifier, agentID), CONVERT(uniqueidentifier, parentFolderID), folderName, type, version FROM dbo.inventoryfolders WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.inventoryfolders - -EXECUTE sp_rename N'dbo.Tmp_inventoryfolders', N'inventoryfolders', 'OBJECT' - -ALTER TABLE dbo.inventoryfolders ADD CONSTRAINT - PK__inventor__C2FABFB3173876EA PRIMARY KEY CLUSTERED - ( - folderID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX owner ON dbo.inventoryfolders - ( - agentID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX parent ON dbo.inventoryfolders - ( - parentFolderID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 4 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_inventoryitems - ( - inventoryID uniqueidentifier NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), - assetID uniqueidentifier NULL DEFAULT (NULL), - assetType int NULL DEFAULT (NULL), - parentFolderID uniqueidentifier NULL DEFAULT (NULL), - avatarID uniqueidentifier NULL DEFAULT (NULL), - inventoryName varchar(64) NULL DEFAULT (NULL), - inventoryDescription varchar(128) NULL DEFAULT (NULL), - inventoryNextPermissions int NULL DEFAULT (NULL), - inventoryCurrentPermissions int NULL DEFAULT (NULL), - invType int NULL DEFAULT (NULL), - creatorID uniqueidentifier NULL DEFAULT (NULL), - inventoryBasePermissions int NOT NULL DEFAULT ((0)), - inventoryEveryOnePermissions int NOT NULL DEFAULT ((0)), - salePrice int NULL DEFAULT (NULL), - saleType tinyint NULL DEFAULT (NULL), - creationDate int NULL DEFAULT (NULL), - groupID uniqueidentifier NULL DEFAULT (NULL), - groupOwned bit NULL DEFAULT (NULL), - flags int NULL DEFAULT (NULL), - inventoryGroupPermissions int NOT NULL DEFAULT ((0)) - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.inventoryitems) - EXEC('INSERT INTO dbo.Tmp_inventoryitems (inventoryID, assetID, assetType, parentFolderID, avatarID, inventoryName, inventoryDescription, inventoryNextPermissions, inventoryCurrentPermissions, invType, creatorID, inventoryBasePermissions, inventoryEveryOnePermissions, salePrice, saleType, creationDate, groupID, groupOwned, flags, inventoryGroupPermissions) - SELECT CONVERT(uniqueidentifier, inventoryID), CONVERT(uniqueidentifier, assetID), assetType, CONVERT(uniqueidentifier, parentFolderID), CONVERT(uniqueidentifier, avatarID), inventoryName, inventoryDescription, inventoryNextPermissions, inventoryCurrentPermissions, invType, CONVERT(uniqueidentifier, creatorID), inventoryBasePermissions, inventoryEveryOnePermissions, salePrice, saleType, creationDate, CONVERT(uniqueidentifier, groupID), groupOwned, flags, inventoryGroupPermissions FROM dbo.inventoryitems WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.inventoryitems - -EXECUTE sp_rename N'dbo.Tmp_inventoryitems', N'inventoryitems', 'OBJECT' - -ALTER TABLE dbo.inventoryitems ADD CONSTRAINT - PK__inventor__C4B7BC2220C1E124 PRIMARY KEY CLUSTERED - ( - inventoryID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - - -CREATE NONCLUSTERED INDEX owner ON dbo.inventoryitems - ( - avatarID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX folder ON dbo.inventoryitems - ( - parentFolderID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - -:VERSION 5 - -# It would be totally crazy to have to recreate the whole table just to change one column type, -# just because MS SQL treats each DEFAULT as a constraint object that must be dropped -# before anything can be done to the column. Since all defaults here are unnamed, there is -# no easy way to drop them! The hairy piece of code below removes all DEFAULT constraints -# from InventoryItems. - -# SO: anything that's NULLable is by default NULL, so please don't declare DEFAULT(NULL), -# they do nothing but prevent changes to the columns. If you really -# need to have DEFAULTs or other constraints, give them names so they can be dropped when needed! - -BEGIN TRANSACTION -DECLARE @nm varchar(80); -DECLARE x CURSOR LOCAL FORWARD_ONLY READ_ONLY - FOR SELECT name FROM sys.default_constraints where parent_object_id = OBJECT_ID('inventoryitems'); -OPEN x; -FETCH NEXT FROM x INTO @nm; -WHILE @@FETCH_STATUS = 0 -BEGIN - EXEC('alter table inventoryitems drop ' + @nm); - FETCH NEXT FROM x INTO @nm; -END -CLOSE x -DEALLOCATE x -COMMIT - -# all DEFAULTs dropped! - -:GO - -BEGIN TRANSACTION - -# Restoring defaults: -# NOTE: [inventoryID] does NOT need one: it's NOT NULL PK and a unique Guid must be provided every time anyway! - -alter table inventoryitems - add constraint def_baseperm default 0 for inventoryBasePermissions -alter table inventoryitems - add constraint def_allperm default 0 for inventoryEveryOnePermissions -alter table inventoryitems - add constraint def_grpperm default 0 for inventoryGroupPermissions - -COMMIT - -:VERSION 7 - -BEGIN TRANSACTION - -# CreatorID goes back to VARCHAR(36) (???) - -exec sp_rename 'inventoryitems.CreatorID', 'cr_old', 'COLUMN' - -:GO - -alter table inventoryitems - add creatorID varchar(36) NULL - -:GO - -update inventoryitems set creatorID = CONVERT(VARCHAR(36), cr_old) - -alter table inventoryitems - drop column cr_old - -COMMIT - -:VERSION 8 - -ALTER TABLE inventoryitems -ADD CONSTRAINT DF_inventoryitems_creatorID -DEFAULT '00000000-0000-0000-0000-000000000000' FOR creatorID - -:GO - -:VERSION 9 - -BEGIN TRANSACTION - -# CreatorID goes up to VARCHAR(255) - -exec sp_rename 'inventoryitems.CreatorID', 'cr_old', 'COLUMN' - -:GO - -alter table inventoryitems - add creatorID varchar(255) NULL - -:GO - -update inventoryitems set creatorID = cr_old - -alter table inventoryitems -drop CONSTRAINT DF_inventoryitems_creatorID -:GO - -alter table inventoryitems - drop column cr_old - :GO -COMMIT - -ALTER TABLE inventoryitems -ADD CONSTRAINT DF_inventoryitems_creatorID -DEFAULT '00000000-0000-0000-0000-000000000000' FOR creatorID - -:GO \ No newline at end of file diff --git a/OpenSim/Data/MSSQL/Resources/LogStore.migrations b/OpenSim/Data/MSSQL/Resources/LogStore.migrations deleted file mode 100644 index 1430d8d..0000000 --- a/OpenSim/Data/MSSQL/Resources/LogStore.migrations +++ /dev/null @@ -1,19 +0,0 @@ -:VERSION 1 - -BEGIN TRANSACTION - -CREATE TABLE [logs] ( - [logID] [int] NOT NULL, - [target] [varchar](36) default NULL, - [server] [varchar](64) default NULL, - [method] [varchar](64) default NULL, - [arguments] [varchar](255) default NULL, - [priority] [int] default NULL, - [message] [ntext], - PRIMARY KEY CLUSTERED -( - [logID] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] -) ON [PRIMARY] - -COMMIT diff --git a/OpenSim/Data/MSSQL/Resources/Presence.migrations b/OpenSim/Data/MSSQL/Resources/Presence.migrations deleted file mode 100644 index bcb6328..0000000 --- a/OpenSim/Data/MSSQL/Resources/Presence.migrations +++ /dev/null @@ -1,31 +0,0 @@ -:VERSION 1 - -BEGIN TRANSACTION - -CREATE TABLE [Presence] ( -[UserID] varchar(255) NOT NULL, -[RegionID] uniqueidentifier NOT NULL, -[SessionID] uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', -[SecureSessionID] uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', - -) - ON [PRIMARY] - -COMMIT - -:VERSION 2 - -BEGIN TRANSACTION - -CREATE UNIQUE INDEX SessionID ON Presence(SessionID); -CREATE INDEX UserID ON Presence(UserID); - -COMMIT - -:VERSION 2 - -BEGIN TRANSACTION - -ALTER TABLE Presence ADD LastSeen DateTime - -COMMIT \ No newline at end of file diff --git a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations b/OpenSim/Data/MSSQL/Resources/RegionStore.migrations deleted file mode 100644 index 350e548..0000000 --- a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations +++ /dev/null @@ -1,1150 +0,0 @@ -:VERSION 1 - -CREATE TABLE [dbo].[prims]( - [UUID] [varchar](255) NOT NULL, - [RegionUUID] [varchar](255) NULL, - [ParentID] [int] NULL, - [CreationDate] [int] NULL, - [Name] [varchar](255) NULL, - [SceneGroupID] [varchar](255) NULL, - [Text] [varchar](255) NULL, - [Description] [varchar](255) NULL, - [SitName] [varchar](255) NULL, - [TouchName] [varchar](255) NULL, - [ObjectFlags] [int] NULL, - [CreatorID] [varchar](255) NULL, - [OwnerID] [varchar](255) NULL, - [GroupID] [varchar](255) NULL, - [LastOwnerID] [varchar](255) NULL, - [OwnerMask] [int] NULL, - [NextOwnerMask] [int] NULL, - [GroupMask] [int] NULL, - [EveryoneMask] [int] NULL, - [BaseMask] [int] NULL, - [PositionX] [float] NULL, - [PositionY] [float] NULL, - [PositionZ] [float] NULL, - [GroupPositionX] [float] NULL, - [GroupPositionY] [float] NULL, - [GroupPositionZ] [float] NULL, - [VelocityX] [float] NULL, - [VelocityY] [float] NULL, - [VelocityZ] [float] NULL, - [AngularVelocityX] [float] NULL, - [AngularVelocityY] [float] NULL, - [AngularVelocityZ] [float] NULL, - [AccelerationX] [float] NULL, - [AccelerationY] [float] NULL, - [AccelerationZ] [float] NULL, - [RotationX] [float] NULL, - [RotationY] [float] NULL, - [RotationZ] [float] NULL, - [RotationW] [float] NULL, - [SitTargetOffsetX] [float] NULL, - [SitTargetOffsetY] [float] NULL, - [SitTargetOffsetZ] [float] NULL, - [SitTargetOrientW] [float] NULL, - [SitTargetOrientX] [float] NULL, - [SitTargetOrientY] [float] NULL, - [SitTargetOrientZ] [float] NULL, -PRIMARY KEY CLUSTERED -( - [UUID] ASC -)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] - -CREATE TABLE [dbo].[primshapes]( - [UUID] [varchar](255) NOT NULL, - [Shape] [int] NULL, - [ScaleX] [float] NULL, - [ScaleY] [float] NULL, - [ScaleZ] [float] NULL, - [PCode] [int] NULL, - [PathBegin] [int] NULL, - [PathEnd] [int] NULL, - [PathScaleX] [int] NULL, - [PathScaleY] [int] NULL, - [PathShearX] [int] NULL, - [PathShearY] [int] NULL, - [PathSkew] [int] NULL, - [PathCurve] [int] NULL, - [PathRadiusOffset] [int] NULL, - [PathRevolutions] [int] NULL, - [PathTaperX] [int] NULL, - [PathTaperY] [int] NULL, - [PathTwist] [int] NULL, - [PathTwistBegin] [int] NULL, - [ProfileBegin] [int] NULL, - [ProfileEnd] [int] NULL, - [ProfileCurve] [int] NULL, - [ProfileHollow] [int] NULL, - [State] [int] NULL, - [Texture] [image] NULL, - [ExtraParams] [image] NULL, -PRIMARY KEY CLUSTERED -( - [UUID] ASC -)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] - -CREATE TABLE [dbo].[primitems]( - [itemID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, - [primID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [assetID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [parentFolderID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [invType] [int] NULL, - [assetType] [int] NULL, - [name] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [description] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [creationDate] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [creatorID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [ownerID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [lastOwnerID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [groupID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [nextPermissions] [int] NULL, - [currentPermissions] [int] NULL, - [basePermissions] [int] NULL, - [everyonePermissions] [int] NULL, - [groupPermissions] [int] NULL, -PRIMARY KEY CLUSTERED -( - [itemID] ASC -)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] - -CREATE TABLE [dbo].[terrain]( - [RegionUUID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [Revision] [int] NULL, - [Heightfield] [image] NULL -) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] - -CREATE TABLE [dbo].[land]( - [UUID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, - [RegionUUID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [LocalLandID] [int] NULL, - [Bitmap] [image] NULL, - [Name] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [Description] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [OwnerUUID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [IsGroupOwned] [int] NULL, - [Area] [int] NULL, - [AuctionID] [int] NULL, - [Category] [int] NULL, - [ClaimDate] [int] NULL, - [ClaimPrice] [int] NULL, - [GroupUUID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [SalePrice] [int] NULL, - [LandStatus] [int] NULL, - [LandFlags] [int] NULL, - [LandingType] [int] NULL, - [MediaAutoScale] [int] NULL, - [MediaTextureUUID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [MediaURL] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [MusicURL] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [PassHours] [float] NULL, - [PassPrice] [int] NULL, - [SnapshotUUID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [UserLocationX] [float] NULL, - [UserLocationY] [float] NULL, - [UserLocationZ] [float] NULL, - [UserLookAtX] [float] NULL, - [UserLookAtY] [float] NULL, - [UserLookAtZ] [float] NULL, -PRIMARY KEY CLUSTERED -( - [UUID] ASC -)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] - -CREATE TABLE [dbo].[landaccesslist]( - [LandUUID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [AccessUUID] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, - [Flags] [int] NULL -) ON [PRIMARY] - -:VERSION 2 - -BEGIN TRANSACTION - -CREATE TABLE regionban ( - [regionUUID] VARCHAR(36) NOT NULL, - [bannedUUID] VARCHAR(36) NOT NULL, - [bannedIp] VARCHAR(16) NOT NULL, - [bannedIpHostMask] VARCHAR(16) NOT NULL) - -create table [dbo].[regionsettings] ( - [regionUUID] [varchar](36) not null, - [block_terraform] [bit] not null, - [block_fly] [bit] not null, - [allow_damage] [bit] not null, - [restrict_pushing] [bit] not null, - [allow_land_resell] [bit] not null, - [allow_land_join_divide] [bit] not null, - [block_show_in_search] [bit] not null, - [agent_limit] [int] not null, - [object_bonus] [float] not null, - [maturity] [int] not null, - [disable_scripts] [bit] not null, - [disable_collisions] [bit] not null, - [disable_physics] [bit] not null, - [terrain_texture_1] [varchar](36) not null, - [terrain_texture_2] [varchar](36) not null, - [terrain_texture_3] [varchar](36) not null, - [terrain_texture_4] [varchar](36) not null, - [elevation_1_nw] [float] not null, - [elevation_2_nw] [float] not null, - [elevation_1_ne] [float] not null, - [elevation_2_ne] [float] not null, - [elevation_1_se] [float] not null, - [elevation_2_se] [float] not null, - [elevation_1_sw] [float] not null, - [elevation_2_sw] [float] not null, - [water_height] [float] not null, - [terrain_raise_limit] [float] not null, - [terrain_lower_limit] [float] not null, - [use_estate_sun] [bit] not null, - [fixed_sun] [bit] not null, - [sun_position] [float] not null, - [covenant] [varchar](36) default NULL, - [Sandbox] [bit] NOT NULL, -PRIMARY KEY CLUSTERED -( - [regionUUID] ASC -)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] - -COMMIT - -:VERSION 3 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_prims - ( - UUID varchar(36) NOT NULL, - RegionUUID varchar(36) NULL, - ParentID int NULL, - CreationDate int NULL, - Name varchar(255) NULL, - SceneGroupID varchar(36) NULL, - Text varchar(255) NULL, - Description varchar(255) NULL, - SitName varchar(255) NULL, - TouchName varchar(255) NULL, - ObjectFlags int NULL, - CreatorID varchar(36) NULL, - OwnerID varchar(36) NULL, - GroupID varchar(36) NULL, - LastOwnerID varchar(36) NULL, - OwnerMask int NULL, - NextOwnerMask int NULL, - GroupMask int NULL, - EveryoneMask int NULL, - BaseMask int NULL, - PositionX float(53) NULL, - PositionY float(53) NULL, - PositionZ float(53) NULL, - GroupPositionX float(53) NULL, - GroupPositionY float(53) NULL, - GroupPositionZ float(53) NULL, - VelocityX float(53) NULL, - VelocityY float(53) NULL, - VelocityZ float(53) NULL, - AngularVelocityX float(53) NULL, - AngularVelocityY float(53) NULL, - AngularVelocityZ float(53) NULL, - AccelerationX float(53) NULL, - AccelerationY float(53) NULL, - AccelerationZ float(53) NULL, - RotationX float(53) NULL, - RotationY float(53) NULL, - RotationZ float(53) NULL, - RotationW float(53) NULL, - SitTargetOffsetX float(53) NULL, - SitTargetOffsetY float(53) NULL, - SitTargetOffsetZ float(53) NULL, - SitTargetOrientW float(53) NULL, - SitTargetOrientX float(53) NULL, - SitTargetOrientY float(53) NULL, - SitTargetOrientZ float(53) NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.prims) - EXEC('INSERT INTO dbo.Tmp_prims (UUID, RegionUUID, ParentID, CreationDate, Name, SceneGroupID, Text, Description, SitName, TouchName, ObjectFlags, CreatorID, OwnerID, GroupID, LastOwnerID, OwnerMask, NextOwnerMask, GroupMask, EveryoneMask, BaseMask, PositionX, PositionY, PositionZ, GroupPositionX, GroupPositionY, GroupPositionZ, VelocityX, VelocityY, VelocityZ, AngularVelocityX, AngularVelocityY, AngularVelocityZ, AccelerationX, AccelerationY, AccelerationZ, RotationX, RotationY, RotationZ, RotationW, SitTargetOffsetX, SitTargetOffsetY, SitTargetOffsetZ, SitTargetOrientW, SitTargetOrientX, SitTargetOrientY, SitTargetOrientZ) - SELECT CONVERT(varchar(36), UUID), CONVERT(varchar(36), RegionUUID), ParentID, CreationDate, Name, CONVERT(varchar(36), SceneGroupID), Text, Description, SitName, TouchName, ObjectFlags, CONVERT(varchar(36), CreatorID), CONVERT(varchar(36), OwnerID), CONVERT(varchar(36), GroupID), CONVERT(varchar(36), LastOwnerID), OwnerMask, NextOwnerMask, GroupMask, EveryoneMask, BaseMask, PositionX, PositionY, PositionZ, GroupPositionX, GroupPositionY, GroupPositionZ, VelocityX, VelocityY, VelocityZ, AngularVelocityX, AngularVelocityY, AngularVelocityZ, AccelerationX, AccelerationY, AccelerationZ, RotationX, RotationY, RotationZ, RotationW, SitTargetOffsetX, SitTargetOffsetY, SitTargetOffsetZ, SitTargetOrientW, SitTargetOrientX, SitTargetOrientY, SitTargetOrientZ FROM dbo.prims WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.prims - -EXECUTE sp_rename N'dbo.Tmp_prims', N'prims', 'OBJECT' - -ALTER TABLE dbo.prims ADD CONSTRAINT - PK__prims__10566F31 PRIMARY KEY CLUSTERED - ( - UUID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - -:VERSION 4 - -BEGIN TRANSACTION - -CREATE TABLE Tmp_primitems - ( - itemID varchar(36) NOT NULL, - primID varchar(36) NULL, - assetID varchar(36) NULL, - parentFolderID varchar(36) NULL, - invType int NULL, - assetType int NULL, - name varchar(255) NULL, - description varchar(255) NULL, - creationDate varchar(255) NULL, - creatorID varchar(36) NULL, - ownerID varchar(36) NULL, - lastOwnerID varchar(36) NULL, - groupID varchar(36) NULL, - nextPermissions int NULL, - currentPermissions int NULL, - basePermissions int NULL, - everyonePermissions int NULL, - groupPermissions int NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM primitems) - EXEC('INSERT INTO Tmp_primitems (itemID, primID, assetID, parentFolderID, invType, assetType, name, description, creationDate, creatorID, ownerID, lastOwnerID, groupID, nextPermissions, currentPermissions, basePermissions, everyonePermissions, groupPermissions) - SELECT CONVERT(varchar(36), itemID), CONVERT(varchar(36), primID), CONVERT(varchar(36), assetID), CONVERT(varchar(36), parentFolderID), invType, assetType, name, description, creationDate, CONVERT(varchar(36), creatorID), CONVERT(varchar(36), ownerID), CONVERT(varchar(36), lastOwnerID), CONVERT(varchar(36), groupID), nextPermissions, currentPermissions, basePermissions, everyonePermissions, groupPermissions') - -DROP TABLE primitems - -EXECUTE sp_rename N'Tmp_primitems', N'primitems', 'OBJECT' - -ALTER TABLE primitems ADD CONSTRAINT - PK__primitems__0A688BB1 PRIMARY KEY CLUSTERED - ( - itemID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - - -COMMIT - - -:VERSION 5 - -BEGIN TRANSACTION - -CREATE TABLE Tmp_primshapes - ( - UUID varchar(36) NOT NULL, - Shape int NULL, - ScaleX float(53) NULL, - ScaleY float(53) NULL, - ScaleZ float(53) NULL, - PCode int NULL, - PathBegin int NULL, - PathEnd int NULL, - PathScaleX int NULL, - PathScaleY int NULL, - PathShearX int NULL, - PathShearY int NULL, - PathSkew int NULL, - PathCurve int NULL, - PathRadiusOffset int NULL, - PathRevolutions int NULL, - PathTaperX int NULL, - PathTaperY int NULL, - PathTwist int NULL, - PathTwistBegin int NULL, - ProfileBegin int NULL, - ProfileEnd int NULL, - ProfileCurve int NULL, - ProfileHollow int NULL, - State int NULL, - Texture image NULL, - ExtraParams image NULL - ) ON [PRIMARY] - TEXTIMAGE_ON [PRIMARY] - -IF EXISTS(SELECT * FROM primshapes) - EXEC('INSERT INTO Tmp_primshapes (UUID, Shape, ScaleX, ScaleY, ScaleZ, PCode, PathBegin, PathEnd, PathScaleX, PathScaleY, PathShearX, PathShearY, PathSkew, PathCurve, PathRadiusOffset, PathRevolutions, PathTaperX, PathTaperY, PathTwist, PathTwistBegin, ProfileBegin, ProfileEnd, ProfileCurve, ProfileHollow, State, Texture, ExtraParams) - SELECT CONVERT(varchar(36), UUID), Shape, ScaleX, ScaleY, ScaleZ, PCode, PathBegin, PathEnd, PathScaleX, PathScaleY, PathShearX, PathShearY, PathSkew, PathCurve, PathRadiusOffset, PathRevolutions, PathTaperX, PathTaperY, PathTwist, PathTwistBegin, ProfileBegin, ProfileEnd, ProfileCurve, ProfileHollow, State, Texture, ExtraParams FROM primshapes WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE primshapes - -EXECUTE sp_rename N'Tmp_primshapes', N'primshapes', 'OBJECT' - -ALTER TABLE primshapes ADD CONSTRAINT - PK__primshapes__0880433F PRIMARY KEY CLUSTERED - ( - UUID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 6 - -BEGIN TRANSACTION - -ALTER TABLE prims ADD PayPrice int not null default 0 -ALTER TABLE prims ADD PayButton1 int not null default 0 -ALTER TABLE prims ADD PayButton2 int not null default 0 -ALTER TABLE prims ADD PayButton3 int not null default 0 -ALTER TABLE prims ADD PayButton4 int not null default 0 -ALTER TABLE prims ADD LoopedSound varchar(36) not null default '00000000-0000-0000-0000-000000000000'; -ALTER TABLE prims ADD LoopedSoundGain float not null default 0.0; -ALTER TABLE prims ADD TextureAnimation image -ALTER TABLE prims ADD OmegaX float not null default 0.0 -ALTER TABLE prims ADD OmegaY float not null default 0.0 -ALTER TABLE prims ADD OmegaZ float not null default 0.0 -ALTER TABLE prims ADD CameraEyeOffsetX float not null default 0.0 -ALTER TABLE prims ADD CameraEyeOffsetY float not null default 0.0 -ALTER TABLE prims ADD CameraEyeOffsetZ float not null default 0.0 -ALTER TABLE prims ADD CameraAtOffsetX float not null default 0.0 -ALTER TABLE prims ADD CameraAtOffsetY float not null default 0.0 -ALTER TABLE prims ADD CameraAtOffsetZ float not null default 0.0 -ALTER TABLE prims ADD ForceMouselook tinyint not null default 0 -ALTER TABLE prims ADD ScriptAccessPin int not null default 0 -ALTER TABLE prims ADD AllowedDrop tinyint not null default 0 -ALTER TABLE prims ADD DieAtEdge tinyint not null default 0 -ALTER TABLE prims ADD SalePrice int not null default 10 -ALTER TABLE prims ADD SaleType tinyint not null default 0 - -ALTER TABLE primitems add flags integer not null default 0 - -ALTER TABLE land ADD AuthbuyerID varchar(36) NOT NULL default '00000000-0000-0000-0000-000000000000' - -CREATE index prims_regionuuid on prims(RegionUUID) -CREATE index prims_parentid on prims(ParentID) - -CREATE index primitems_primid on primitems(primID) - -COMMIT - - -:VERSION 7 - -BEGIN TRANSACTION - -ALTER TABLE prims ADD ColorR int not null default 0; -ALTER TABLE prims ADD ColorG int not null default 0; -ALTER TABLE prims ADD ColorB int not null default 0; -ALTER TABLE prims ADD ColorA int not null default 0; -ALTER TABLE prims ADD ParticleSystem IMAGE; -ALTER TABLE prims ADD ClickAction tinyint NOT NULL default 0; - -COMMIT - - -:VERSION 8 - -BEGIN TRANSACTION - -ALTER TABLE land ADD OtherCleanTime integer NOT NULL default 0; -ALTER TABLE land ADD Dwell integer NOT NULL default 0; - -COMMIT - -:VERSION 9 - -BEGIN TRANSACTION - -ALTER TABLE prims ADD Material tinyint NOT NULL default 3 - -COMMIT - - -:VERSION 10 - -BEGIN TRANSACTION - -ALTER TABLE regionsettings ADD sunvectorx float NOT NULL default 0; -ALTER TABLE regionsettings ADD sunvectory float NOT NULL default 0; -ALTER TABLE regionsettings ADD sunvectorz float NOT NULL default 0; - -COMMIT - - -:VERSION 11 - -BEGIN TRANSACTION - -ALTER TABLE prims ADD CollisionSound char(36) not null default '00000000-0000-0000-0000-000000000000' -ALTER TABLE prims ADD CollisionSoundVolume float not null default 0.0 - -COMMIT - - -:VERSION 12 - -BEGIN TRANSACTION - -ALTER TABLE prims ADD LinkNumber integer not null default 0 - -COMMIT - - -:VERSION 13 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_prims - ( - UUID uniqueidentifier NOT NULL, - RegionUUID uniqueidentifier NULL, - ParentID int NULL, - CreationDate int NULL, - Name varchar(255) NULL, - SceneGroupID uniqueidentifier NULL, - Text varchar(255) NULL, - Description varchar(255) NULL, - SitName varchar(255) NULL, - TouchName varchar(255) NULL, - ObjectFlags int NULL, - CreatorID uniqueidentifier NULL, - OwnerID uniqueidentifier NULL, - GroupID uniqueidentifier NULL, - LastOwnerID uniqueidentifier NULL, - OwnerMask int NULL, - NextOwnerMask int NULL, - GroupMask int NULL, - EveryoneMask int NULL, - BaseMask int NULL, - PositionX float(53) NULL, - PositionY float(53) NULL, - PositionZ float(53) NULL, - GroupPositionX float(53) NULL, - GroupPositionY float(53) NULL, - GroupPositionZ float(53) NULL, - VelocityX float(53) NULL, - VelocityY float(53) NULL, - VelocityZ float(53) NULL, - AngularVelocityX float(53) NULL, - AngularVelocityY float(53) NULL, - AngularVelocityZ float(53) NULL, - AccelerationX float(53) NULL, - AccelerationY float(53) NULL, - AccelerationZ float(53) NULL, - RotationX float(53) NULL, - RotationY float(53) NULL, - RotationZ float(53) NULL, - RotationW float(53) NULL, - SitTargetOffsetX float(53) NULL, - SitTargetOffsetY float(53) NULL, - SitTargetOffsetZ float(53) NULL, - SitTargetOrientW float(53) NULL, - SitTargetOrientX float(53) NULL, - SitTargetOrientY float(53) NULL, - SitTargetOrientZ float(53) NULL, - PayPrice int NOT NULL DEFAULT ((0)), - PayButton1 int NOT NULL DEFAULT ((0)), - PayButton2 int NOT NULL DEFAULT ((0)), - PayButton3 int NOT NULL DEFAULT ((0)), - PayButton4 int NOT NULL DEFAULT ((0)), - LoopedSound uniqueidentifier NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), - LoopedSoundGain float(53) NOT NULL DEFAULT ((0.0)), - TextureAnimation image NULL, - OmegaX float(53) NOT NULL DEFAULT ((0.0)), - OmegaY float(53) NOT NULL DEFAULT ((0.0)), - OmegaZ float(53) NOT NULL DEFAULT ((0.0)), - CameraEyeOffsetX float(53) NOT NULL DEFAULT ((0.0)), - CameraEyeOffsetY float(53) NOT NULL DEFAULT ((0.0)), - CameraEyeOffsetZ float(53) NOT NULL DEFAULT ((0.0)), - CameraAtOffsetX float(53) NOT NULL DEFAULT ((0.0)), - CameraAtOffsetY float(53) NOT NULL DEFAULT ((0.0)), - CameraAtOffsetZ float(53) NOT NULL DEFAULT ((0.0)), - ForceMouselook tinyint NOT NULL DEFAULT ((0)), - ScriptAccessPin int NOT NULL DEFAULT ((0)), - AllowedDrop tinyint NOT NULL DEFAULT ((0)), - DieAtEdge tinyint NOT NULL DEFAULT ((0)), - SalePrice int NOT NULL DEFAULT ((10)), - SaleType tinyint NOT NULL DEFAULT ((0)), - ColorR int NOT NULL DEFAULT ((0)), - ColorG int NOT NULL DEFAULT ((0)), - ColorB int NOT NULL DEFAULT ((0)), - ColorA int NOT NULL DEFAULT ((0)), - ParticleSystem image NULL, - ClickAction tinyint NOT NULL DEFAULT ((0)), - Material tinyint NOT NULL DEFAULT ((3)), - CollisionSound uniqueidentifier NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), - CollisionSoundVolume float(53) NOT NULL DEFAULT ((0.0)), - LinkNumber int NOT NULL DEFAULT ((0)) - ) ON [PRIMARY] - TEXTIMAGE_ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.prims) - EXEC('INSERT INTO dbo.Tmp_prims (UUID, RegionUUID, ParentID, CreationDate, Name, SceneGroupID, Text, Description, SitName, TouchName, ObjectFlags, CreatorID, OwnerID, GroupID, LastOwnerID, OwnerMask, NextOwnerMask, GroupMask, EveryoneMask, BaseMask, PositionX, PositionY, PositionZ, GroupPositionX, GroupPositionY, GroupPositionZ, VelocityX, VelocityY, VelocityZ, AngularVelocityX, AngularVelocityY, AngularVelocityZ, AccelerationX, AccelerationY, AccelerationZ, RotationX, RotationY, RotationZ, RotationW, SitTargetOffsetX, SitTargetOffsetY, SitTargetOffsetZ, SitTargetOrientW, SitTargetOrientX, SitTargetOrientY, SitTargetOrientZ, PayPrice, PayButton1, PayButton2, PayButton3, PayButton4, LoopedSound, LoopedSoundGain, TextureAnimation, OmegaX, OmegaY, OmegaZ, CameraEyeOffsetX, CameraEyeOffsetY, CameraEyeOffsetZ, CameraAtOffsetX, CameraAtOffsetY, CameraAtOffsetZ, ForceMouselook, ScriptAccessPin, AllowedDrop, DieAtEdge, SalePrice, SaleType, ColorR, ColorG, ColorB, ColorA, ParticleSystem, ClickAction, Material, CollisionSound, CollisionSoundVolume, LinkNumber) - SELECT CONVERT(uniqueidentifier, UUID), CONVERT(uniqueidentifier, RegionUUID), ParentID, CreationDate, Name, CONVERT(uniqueidentifier, SceneGroupID), Text, Description, SitName, TouchName, ObjectFlags, CONVERT(uniqueidentifier, CreatorID), CONVERT(uniqueidentifier, OwnerID), CONVERT(uniqueidentifier, GroupID), CONVERT(uniqueidentifier, LastOwnerID), OwnerMask, NextOwnerMask, GroupMask, EveryoneMask, BaseMask, PositionX, PositionY, PositionZ, GroupPositionX, GroupPositionY, GroupPositionZ, VelocityX, VelocityY, VelocityZ, AngularVelocityX, AngularVelocityY, AngularVelocityZ, AccelerationX, AccelerationY, AccelerationZ, RotationX, RotationY, RotationZ, RotationW, SitTargetOffsetX, SitTargetOffsetY, SitTargetOffsetZ, SitTargetOrientW, SitTargetOrientX, SitTargetOrientY, SitTargetOrientZ, PayPrice, PayButton1, PayButton2, PayButton3, PayButton4, CONVERT(uniqueidentifier, LoopedSound), LoopedSoundGain, TextureAnimation, OmegaX, OmegaY, OmegaZ, CameraEyeOffsetX, CameraEyeOffsetY, CameraEyeOffsetZ, CameraAtOffsetX, CameraAtOffsetY, CameraAtOffsetZ, ForceMouselook, ScriptAccessPin, AllowedDrop, DieAtEdge, SalePrice, SaleType, ColorR, ColorG, ColorB, ColorA, ParticleSystem, ClickAction, Material, CONVERT(uniqueidentifier, CollisionSound), CollisionSoundVolume, LinkNumber FROM dbo.prims WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.prims - -EXECUTE sp_rename N'dbo.Tmp_prims', N'prims', 'OBJECT' - -ALTER TABLE dbo.prims ADD CONSTRAINT - PK__prims__10566F31 PRIMARY KEY CLUSTERED - ( - UUID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - - -CREATE NONCLUSTERED INDEX prims_regionuuid ON dbo.prims - ( - RegionUUID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX prims_parentid ON dbo.prims - ( - ParentID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 14 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_primshapes - ( - UUID uniqueidentifier NOT NULL, - Shape int NULL, - ScaleX float(53) NULL, - ScaleY float(53) NULL, - ScaleZ float(53) NULL, - PCode int NULL, - PathBegin int NULL, - PathEnd int NULL, - PathScaleX int NULL, - PathScaleY int NULL, - PathShearX int NULL, - PathShearY int NULL, - PathSkew int NULL, - PathCurve int NULL, - PathRadiusOffset int NULL, - PathRevolutions int NULL, - PathTaperX int NULL, - PathTaperY int NULL, - PathTwist int NULL, - PathTwistBegin int NULL, - ProfileBegin int NULL, - ProfileEnd int NULL, - ProfileCurve int NULL, - ProfileHollow int NULL, - State int NULL, - Texture image NULL, - ExtraParams image NULL - ) ON [PRIMARY] - TEXTIMAGE_ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.primshapes) - EXEC('INSERT INTO dbo.Tmp_primshapes (UUID, Shape, ScaleX, ScaleY, ScaleZ, PCode, PathBegin, PathEnd, PathScaleX, PathScaleY, PathShearX, PathShearY, PathSkew, PathCurve, PathRadiusOffset, PathRevolutions, PathTaperX, PathTaperY, PathTwist, PathTwistBegin, ProfileBegin, ProfileEnd, ProfileCurve, ProfileHollow, State, Texture, ExtraParams) - SELECT CONVERT(uniqueidentifier, UUID), Shape, ScaleX, ScaleY, ScaleZ, PCode, PathBegin, PathEnd, PathScaleX, PathScaleY, PathShearX, PathShearY, PathSkew, PathCurve, PathRadiusOffset, PathRevolutions, PathTaperX, PathTaperY, PathTwist, PathTwistBegin, ProfileBegin, ProfileEnd, ProfileCurve, ProfileHollow, State, Texture, ExtraParams FROM dbo.primshapes WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.primshapes - -EXECUTE sp_rename N'dbo.Tmp_primshapes', N'primshapes', 'OBJECT' - -ALTER TABLE dbo.primshapes ADD CONSTRAINT - PK__primshapes__0880433F PRIMARY KEY CLUSTERED - ( - UUID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 15 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_primitems - ( - itemID uniqueidentifier NOT NULL, - primID uniqueidentifier NULL, - assetID uniqueidentifier NULL, - parentFolderID uniqueidentifier NULL, - invType int NULL, - assetType int NULL, - name varchar(255) NULL, - description varchar(255) NULL, - creationDate varchar(255) NULL, - creatorID uniqueidentifier NULL, - ownerID uniqueidentifier NULL, - lastOwnerID uniqueidentifier NULL, - groupID uniqueidentifier NULL, - nextPermissions int NULL, - currentPermissions int NULL, - basePermissions int NULL, - everyonePermissions int NULL, - groupPermissions int NULL, - flags int NOT NULL DEFAULT ((0)) - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.primitems) - EXEC('INSERT INTO dbo.Tmp_primitems (itemID, primID, assetID, parentFolderID, invType, assetType, name, description, creationDate, creatorID, ownerID, lastOwnerID, groupID, nextPermissions, currentPermissions, basePermissions, everyonePermissions, groupPermissions, flags) - SELECT CONVERT(uniqueidentifier, itemID), CONVERT(uniqueidentifier, primID), CONVERT(uniqueidentifier, assetID), CONVERT(uniqueidentifier, parentFolderID), invType, assetType, name, description, creationDate, CONVERT(uniqueidentifier, creatorID), CONVERT(uniqueidentifier, ownerID), CONVERT(uniqueidentifier, lastOwnerID), CONVERT(uniqueidentifier, groupID), nextPermissions, currentPermissions, basePermissions, everyonePermissions, groupPermissions, flags FROM dbo.primitems WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.primitems - -EXECUTE sp_rename N'dbo.Tmp_primitems', N'primitems', 'OBJECT' - -ALTER TABLE dbo.primitems ADD CONSTRAINT - PK__primitems__0A688BB1 PRIMARY KEY CLUSTERED - ( - itemID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX primitems_primid ON dbo.primitems - ( - primID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 16 - - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_terrain - ( - RegionUUID uniqueidentifier NULL, - Revision int NULL, - Heightfield image NULL - ) ON [PRIMARY] - TEXTIMAGE_ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.terrain) - EXEC('INSERT INTO dbo.Tmp_terrain (RegionUUID, Revision, Heightfield) - SELECT CONVERT(uniqueidentifier, RegionUUID), Revision, Heightfield FROM dbo.terrain WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.terrain - -EXECUTE sp_rename N'dbo.Tmp_terrain', N'terrain', 'OBJECT' - -COMMIT - - -:VERSION 17 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_land - ( - UUID uniqueidentifier NOT NULL, - RegionUUID uniqueidentifier NULL, - LocalLandID int NULL, - Bitmap image NULL, - Name varchar(255) NULL, - Description varchar(255) NULL, - OwnerUUID uniqueidentifier NULL, - IsGroupOwned int NULL, - Area int NULL, - AuctionID int NULL, - Category int NULL, - ClaimDate int NULL, - ClaimPrice int NULL, - GroupUUID uniqueidentifier NULL, - SalePrice int NULL, - LandStatus int NULL, - LandFlags int NULL, - LandingType int NULL, - MediaAutoScale int NULL, - MediaTextureUUID uniqueidentifier NULL, - MediaURL varchar(255) NULL, - MusicURL varchar(255) NULL, - PassHours float(53) NULL, - PassPrice int NULL, - SnapshotUUID uniqueidentifier NULL, - UserLocationX float(53) NULL, - UserLocationY float(53) NULL, - UserLocationZ float(53) NULL, - UserLookAtX float(53) NULL, - UserLookAtY float(53) NULL, - UserLookAtZ float(53) NULL, - AuthbuyerID uniqueidentifier NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), - OtherCleanTime int NOT NULL DEFAULT ((0)), - Dwell int NOT NULL DEFAULT ((0)) - ) ON [PRIMARY] - TEXTIMAGE_ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.land) - EXEC('INSERT INTO dbo.Tmp_land (UUID, RegionUUID, LocalLandID, Bitmap, Name, Description, OwnerUUID, IsGroupOwned, Area, AuctionID, Category, ClaimDate, ClaimPrice, GroupUUID, SalePrice, LandStatus, LandFlags, LandingType, MediaAutoScale, MediaTextureUUID, MediaURL, MusicURL, PassHours, PassPrice, SnapshotUUID, UserLocationX, UserLocationY, UserLocationZ, UserLookAtX, UserLookAtY, UserLookAtZ, AuthbuyerID, OtherCleanTime, Dwell) - SELECT CONVERT(uniqueidentifier, UUID), CONVERT(uniqueidentifier, RegionUUID), LocalLandID, Bitmap, Name, Description, CONVERT(uniqueidentifier, OwnerUUID), IsGroupOwned, Area, AuctionID, Category, ClaimDate, ClaimPrice, CONVERT(uniqueidentifier, GroupUUID), SalePrice, LandStatus, LandFlags, LandingType, MediaAutoScale, CONVERT(uniqueidentifier, MediaTextureUUID), MediaURL, MusicURL, PassHours, PassPrice, CONVERT(uniqueidentifier, SnapshotUUID), UserLocationX, UserLocationY, UserLocationZ, UserLookAtX, UserLookAtY, UserLookAtZ, CONVERT(uniqueidentifier, AuthbuyerID), OtherCleanTime, Dwell FROM dbo.land WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.land - -EXECUTE sp_rename N'dbo.Tmp_land', N'land', 'OBJECT' - -ALTER TABLE dbo.land ADD CONSTRAINT - PK__land__65A475E71BFD2C07 PRIMARY KEY CLUSTERED - ( - UUID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - - -:VERSION 18 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_landaccesslist - ( - LandUUID uniqueidentifier NULL, - AccessUUID uniqueidentifier NULL, - Flags int NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.landaccesslist) - EXEC('INSERT INTO dbo.Tmp_landaccesslist (LandUUID, AccessUUID, Flags) - SELECT CONVERT(uniqueidentifier, LandUUID), CONVERT(uniqueidentifier, AccessUUID), Flags FROM dbo.landaccesslist WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.landaccesslist - -EXECUTE sp_rename N'dbo.Tmp_landaccesslist', N'landaccesslist', 'OBJECT' - -COMMIT - - - -:VERSION 19 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_regionban - ( - regionUUID uniqueidentifier NOT NULL, - bannedUUID uniqueidentifier NOT NULL, - bannedIp varchar(16) NOT NULL, - bannedIpHostMask varchar(16) NOT NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.regionban) - EXEC('INSERT INTO dbo.Tmp_regionban (regionUUID, bannedUUID, bannedIp, bannedIpHostMask) - SELECT CONVERT(uniqueidentifier, regionUUID), CONVERT(uniqueidentifier, bannedUUID), bannedIp, bannedIpHostMask FROM dbo.regionban WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.regionban - -EXECUTE sp_rename N'dbo.Tmp_regionban', N'regionban', 'OBJECT' - -COMMIT - - -:VERSION 20 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_regionsettings - ( - regionUUID uniqueidentifier NOT NULL, - block_terraform bit NOT NULL, - block_fly bit NOT NULL, - allow_damage bit NOT NULL, - restrict_pushing bit NOT NULL, - allow_land_resell bit NOT NULL, - allow_land_join_divide bit NOT NULL, - block_show_in_search bit NOT NULL, - agent_limit int NOT NULL, - object_bonus float(53) NOT NULL, - maturity int NOT NULL, - disable_scripts bit NOT NULL, - disable_collisions bit NOT NULL, - disable_physics bit NOT NULL, - terrain_texture_1 uniqueidentifier NOT NULL, - terrain_texture_2 uniqueidentifier NOT NULL, - terrain_texture_3 uniqueidentifier NOT NULL, - terrain_texture_4 uniqueidentifier NOT NULL, - elevation_1_nw float(53) NOT NULL, - elevation_2_nw float(53) NOT NULL, - elevation_1_ne float(53) NOT NULL, - elevation_2_ne float(53) NOT NULL, - elevation_1_se float(53) NOT NULL, - elevation_2_se float(53) NOT NULL, - elevation_1_sw float(53) NOT NULL, - elevation_2_sw float(53) NOT NULL, - water_height float(53) NOT NULL, - terrain_raise_limit float(53) NOT NULL, - terrain_lower_limit float(53) NOT NULL, - use_estate_sun bit NOT NULL, - fixed_sun bit NOT NULL, - sun_position float(53) NOT NULL, - covenant uniqueidentifier NULL DEFAULT (NULL), - Sandbox bit NOT NULL, - sunvectorx float(53) NOT NULL DEFAULT ((0)), - sunvectory float(53) NOT NULL DEFAULT ((0)), - sunvectorz float(53) NOT NULL DEFAULT ((0)) - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.regionsettings) - EXEC('INSERT INTO dbo.Tmp_regionsettings (regionUUID, block_terraform, block_fly, allow_damage, restrict_pushing, allow_land_resell, allow_land_join_divide, block_show_in_search, agent_limit, object_bonus, maturity, disable_scripts, disable_collisions, disable_physics, terrain_texture_1, terrain_texture_2, terrain_texture_3, terrain_texture_4, elevation_1_nw, elevation_2_nw, elevation_1_ne, elevation_2_ne, elevation_1_se, elevation_2_se, elevation_1_sw, elevation_2_sw, water_height, terrain_raise_limit, terrain_lower_limit, use_estate_sun, fixed_sun, sun_position, covenant, Sandbox, sunvectorx, sunvectory, sunvectorz) - SELECT CONVERT(uniqueidentifier, regionUUID), block_terraform, block_fly, allow_damage, restrict_pushing, allow_land_resell, allow_land_join_divide, block_show_in_search, agent_limit, object_bonus, maturity, disable_scripts, disable_collisions, disable_physics, CONVERT(uniqueidentifier, terrain_texture_1), CONVERT(uniqueidentifier, terrain_texture_2), CONVERT(uniqueidentifier, terrain_texture_3), CONVERT(uniqueidentifier, terrain_texture_4), elevation_1_nw, elevation_2_nw, elevation_1_ne, elevation_2_ne, elevation_1_se, elevation_2_se, elevation_1_sw, elevation_2_sw, water_height, terrain_raise_limit, terrain_lower_limit, use_estate_sun, fixed_sun, sun_position, CONVERT(uniqueidentifier, covenant), Sandbox, sunvectorx, sunvectory, sunvectorz FROM dbo.regionsettings WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.regionsettings - -EXECUTE sp_rename N'dbo.Tmp_regionsettings', N'regionsettings', 'OBJECT' - -ALTER TABLE dbo.regionsettings ADD CONSTRAINT - PK__regionse__5B35159D21B6055D PRIMARY KEY CLUSTERED - ( - regionUUID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 21 - -BEGIN TRANSACTION - -ALTER TABLE prims ADD PassTouches bit not null default 0 - -COMMIT - - -:VERSION 22 - -BEGIN TRANSACTION - -ALTER TABLE regionsettings ADD loaded_creation_date varchar(20) -ALTER TABLE regionsettings ADD loaded_creation_time varchar(20) -ALTER TABLE regionsettings ADD loaded_creation_id varchar(64) - -COMMIT - -:VERSION 23 - -BEGIN TRANSACTION - -ALTER TABLE regionsettings DROP COLUMN loaded_creation_date -ALTER TABLE regionsettings DROP COLUMN loaded_creation_time -ALTER TABLE regionsettings ADD loaded_creation_datetime int NOT NULL default 0 - -COMMIT - -:VERSION 24 - -BEGIN TRANSACTION - -ALTER TABLE prims ADD MediaURL varchar(255) -ALTER TABLE primshapes ADD Media TEXT NULL - -COMMIT - -:VERSION 25 - -BEGIN TRANSACTION -CREATE TABLE "regionwindlight" ( - "region_id" varchar(36) NOT NULL DEFAULT '000000-0000-0000-0000-000000000000', - "water_color_r" [float] NOT NULL DEFAULT '4.000000', - "water_color_g" [float] NOT NULL DEFAULT '38.000000', - "water_color_b" [float] NOT NULL DEFAULT '64.000000', - "water_fog_density_exponent" [float] NOT NULL DEFAULT '4.0', - "underwater_fog_modifier" [float] NOT NULL DEFAULT '0.25', - "reflection_wavelet_scale_1" [float] NOT NULL DEFAULT '2.0', - "reflection_wavelet_scale_2" [float] NOT NULL DEFAULT '2.0', - "reflection_wavelet_scale_3" [float] NOT NULL DEFAULT '2.0', - "fresnel_scale" [float] NOT NULL DEFAULT '0.40', - "fresnel_offset" [float] NOT NULL DEFAULT '0.50', - "refract_scale_above" [float] NOT NULL DEFAULT '0.03', - "refract_scale_below" [float] NOT NULL DEFAULT '0.20', - "blur_multiplier" [float] NOT NULL DEFAULT '0.040', - "big_wave_direction_x" [float] NOT NULL DEFAULT '1.05', - "big_wave_direction_y" [float] NOT NULL DEFAULT '-0.42', - "little_wave_direction_x" [float] NOT NULL DEFAULT '1.11', - "little_wave_direction_y" [float] NOT NULL DEFAULT '-1.16', - "normal_map_texture" varchar(36) NOT NULL DEFAULT '822ded49-9a6c-f61c-cb89-6df54f42cdf4', - "horizon_r" [float] NOT NULL DEFAULT '0.25', - "horizon_g" [float] NOT NULL DEFAULT '0.25', - "horizon_b" [float] NOT NULL DEFAULT '0.32', - "horizon_i" [float] NOT NULL DEFAULT '0.32', - "haze_horizon" [float] NOT NULL DEFAULT '0.19', - "blue_density_r" [float] NOT NULL DEFAULT '0.12', - "blue_density_g" [float] NOT NULL DEFAULT '0.22', - "blue_density_b" [float] NOT NULL DEFAULT '0.38', - "blue_density_i" [float] NOT NULL DEFAULT '0.38', - "haze_density" [float] NOT NULL DEFAULT '0.70', - "density_multiplier" [float] NOT NULL DEFAULT '0.18', - "distance_multiplier" [float] NOT NULL DEFAULT '0.8', - "max_altitude" int NOT NULL DEFAULT '1605', - "sun_moon_color_r" [float] NOT NULL DEFAULT '0.24', - "sun_moon_color_g" [float] NOT NULL DEFAULT '0.26', - "sun_moon_color_b" [float] NOT NULL DEFAULT '0.30', - "sun_moon_color_i" [float] NOT NULL DEFAULT '0.30', - "sun_moon_position" [float] NOT NULL DEFAULT '0.317', - "ambient_r" [float] NOT NULL DEFAULT '0.35', - "ambient_g" [float] NOT NULL DEFAULT '0.35', - "ambient_b" [float] NOT NULL DEFAULT '0.35', - "ambient_i" [float] NOT NULL DEFAULT '0.35', - "east_angle" [float] NOT NULL DEFAULT '0.00', - "sun_glow_focus" [float] NOT NULL DEFAULT '0.10', - "sun_glow_size" [float] NOT NULL DEFAULT '1.75', - "scene_gamma" [float] NOT NULL DEFAULT '1.00', - "star_brightness" [float] NOT NULL DEFAULT '0.00', - "cloud_color_r" [float] NOT NULL DEFAULT '0.41', - "cloud_color_g" [float] NOT NULL DEFAULT '0.41', - "cloud_color_b" [float] NOT NULL DEFAULT '0.41', - "cloud_color_i" [float] NOT NULL DEFAULT '0.41', - "cloud_x" [float] NOT NULL DEFAULT '1.00', - "cloud_y" [float] NOT NULL DEFAULT '0.53', - "cloud_density" [float] NOT NULL DEFAULT '1.00', - "cloud_coverage" [float] NOT NULL DEFAULT '0.27', - "cloud_scale" [float] NOT NULL DEFAULT '0.42', - "cloud_detail_x" [float] NOT NULL DEFAULT '1.00', - "cloud_detail_y" [float] NOT NULL DEFAULT '0.53', - "cloud_detail_density" [float] NOT NULL DEFAULT '0.12', - "cloud_scroll_x" [float] NOT NULL DEFAULT '0.20', - "cloud_scroll_x_lock" tinyint NOT NULL DEFAULT '0', - "cloud_scroll_y" [float] NOT NULL DEFAULT '0.01', - "cloud_scroll_y_lock" tinyint NOT NULL DEFAULT '0', - "draw_classic_clouds" tinyint NOT NULL DEFAULT '1', - PRIMARY KEY ("region_id") -) - -COMMIT - -:VERSION 26 - -BEGIN TRANSACTION - -ALTER TABLE regionsettings ADD map_tile_ID CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' - -COMMIT - -:VERSION 27 #--------------------- - -BEGIN TRANSACTION -ALTER TABLE land ADD MediaType VARCHAR(32) NOT NULL DEFAULT 'none/none' -ALTER TABLE land ADD MediaDescription VARCHAR(255) NOT NULL DEFAULT '' -ALTER TABLE land ADD MediaSize VARCHAR(16) NOT NULL DEFAULT '0,0' -ALTER TABLE land ADD MediaLoop bit NOT NULL DEFAULT 0 -ALTER TABLE land ADD ObscureMusic bit NOT NULL DEFAULT 0 -ALTER TABLE land ADD ObscureMedia bit NOT NULL DEFAULT 0 -COMMIT - -:VERSION 28 #--------------------- - -BEGIN TRANSACTION - -ALTER TABLE prims -ADD CONSTRAINT DF_prims_CreatorID -DEFAULT '00000000-0000-0000-0000-000000000000' -FOR CreatorID - -ALTER TABLE prims ALTER COLUMN CreatorID uniqueidentifier NOT NULL - -ALTER TABLE primitems -ADD CONSTRAINT DF_primitems_CreatorID -DEFAULT '00000000-0000-0000-0000-000000000000' -FOR CreatorID - -ALTER TABLE primitems ALTER COLUMN CreatorID uniqueidentifier NOT NULL - -COMMIT - -:VERSION 29 #----------------- Region Covenant changed time - -BEGIN TRANSACTION - -ALTER TABLE regionsettings ADD covenant_datetime int NOT NULL default 0 - -COMMIT - -:VERSION 30 #------------------Migrate creatorID storage to varchars instead of UUIDs for HG support - -BEGIN TRANSACTION - -EXECUTE sp_rename N'dbo.prims.creatorid', N'creatoridold', 'COLUMN' -EXECUTE sp_rename N'dbo.primitems.creatorid', N'creatoridold', 'COLUMN' - -COMMIT - -:VERSION 31 #--------------------- - -BEGIN TRANSACTION - -ALTER TABLE prims ADD CreatorID varchar(255) -ALTER TABLE primitems ADD CreatorID varchar(255) - -COMMIT - -:VERSION 32 #--------------------- - -BEGIN TRANSACTION - -UPDATE prims SET prims.CreatorID = CONVERT(varchar(255), creatoridold) -UPDATE primitems SET primitems.CreatorID = CONVERT(varchar(255), creatoridold) - -COMMIT - -:VERSION 33 #--------------------- - -BEGIN TRANSACTION - -ALTER TABLE prims -ADD CONSTRAINT DF_prims_CreatorIDNew -DEFAULT '00000000-0000-0000-0000-000000000000' -FOR CreatorID - -ALTER TABLE prims ALTER COLUMN CreatorID varchar(255) NOT NULL - -ALTER TABLE primitems -ADD CONSTRAINT DF_primitems_CreatorIDNew -DEFAULT '00000000-0000-0000-0000-000000000000' -FOR CreatorID - -ALTER TABLE primitems ALTER COLUMN CreatorID varchar(255) NOT NULL - -COMMIT - -:VERSION 34 #--------------- Telehub support - -BEGIN TRANSACTION - -CREATE TABLE [dbo].[Spawn_Points]( - [RegionUUID] [uniqueidentifier] NOT NULL, - [Yaw] [float] NOT NULL, - [Pitch] [float] NOT NULL, - [Distance] [float] NOT NULL, - PRIMARY KEY CLUSTERED - ( - [RegionUUID] ASC - )WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] - -ALTER TABLE regionsettings ADD TelehubObject uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'; - -COMMIT - -:VERSION 35 #---------------- Parcels for sale - -BEGIN TRANSACTION - -ALTER TABLE regionsettings ADD parcel_tile_ID uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'; - -COMMIT - -:VERSION 36 #---------------- Timed bans/access - -BEGIN TRANSACTION - -ALTER TABLE landaccesslist ADD Expires integer NOT NULL DEFAULT 0; - -COMMIT - -:VERSION 37 #---------------- Environment Settings - -BEGIN TRANSACTION - -CREATE TABLE [dbo].[regionenvironment]( - [region_id] [uniqueidentifier] NOT NULL, - [llsd_settings] [varchar](max) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, - PRIMARY KEY CLUSTERED -( - [region_id] ASC -)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] - -COMMIT diff --git a/OpenSim/Data/MSSQL/Resources/UserAccount.migrations b/OpenSim/Data/MSSQL/Resources/UserAccount.migrations deleted file mode 100644 index a81704d..0000000 --- a/OpenSim/Data/MSSQL/Resources/UserAccount.migrations +++ /dev/null @@ -1,55 +0,0 @@ -:VERSION 1 - -CREATE TABLE [UserAccounts] ( - [PrincipalID] uniqueidentifier NOT NULL, - [ScopeID] uniqueidentifier NOT NULL, - [FirstName] [varchar](64) NOT NULL, - [LastName] [varchar](64) NOT NULL, - [Email] [varchar](64) NULL, - [ServiceURLs] [text] NULL, - [Created] [int] default NULL, - - PRIMARY KEY CLUSTERED -( - [PrincipalID] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] -) ON [PRIMARY] - - -:VERSION 2 - -BEGIN TRANSACTION -IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[users]') AND type in (N'U')) -INSERT INTO UserAccounts (PrincipalID, ScopeID, FirstName, LastName, Email, ServiceURLs, Created) SELECT [UUID] AS PrincipalID, '00000000-0000-0000-0000-000000000000' AS ScopeID, -username AS FirstName, -lastname AS LastName, -email as Email, ( -'AssetServerURI=' + -userAssetURI + ' InventoryServerURI=' + userInventoryURI + ' GatewayURI= HomeURI=') AS ServiceURLs, -created as Created FROM users; - - -COMMIT - -:VERSION 3 - -BEGIN TRANSACTION - -CREATE UNIQUE INDEX PrincipalID ON UserAccounts(PrincipalID); -CREATE INDEX Email ON UserAccounts(Email); -CREATE INDEX FirstName ON UserAccounts(FirstName); -CREATE INDEX LastName ON UserAccounts(LastName); -CREATE INDEX Name ON UserAccounts(FirstName,LastName); - -COMMIT - -:VERSION 4 - -BEGIN TRANSACTION - -ALTER TABLE UserAccounts ADD UserLevel integer NOT NULL DEFAULT 0; -ALTER TABLE UserAccounts ADD UserFlags integer NOT NULL DEFAULT 0; -ALTER TABLE UserAccounts ADD UserTitle varchar(64) NOT NULL DEFAULT ''; - -COMMIT - diff --git a/OpenSim/Data/MSSQL/Resources/UserStore.migrations b/OpenSim/Data/MSSQL/Resources/UserStore.migrations deleted file mode 100644 index 050c544..0000000 --- a/OpenSim/Data/MSSQL/Resources/UserStore.migrations +++ /dev/null @@ -1,421 +0,0 @@ -:VERSION 1 - -CREATE TABLE [users] ( - [UUID] [varchar](36) NOT NULL default '', - [username] [varchar](32) NOT NULL, - [lastname] [varchar](32) NOT NULL, - [passwordHash] [varchar](32) NOT NULL, - [passwordSalt] [varchar](32) NOT NULL, - [homeRegion] [bigint] default NULL, - [homeLocationX] [float] default NULL, - [homeLocationY] [float] default NULL, - [homeLocationZ] [float] default NULL, - [homeLookAtX] [float] default NULL, - [homeLookAtY] [float] default NULL, - [homeLookAtZ] [float] default NULL, - [created] [int] NOT NULL, - [lastLogin] [int] NOT NULL, - [userInventoryURI] [varchar](255) default NULL, - [userAssetURI] [varchar](255) default NULL, - [profileCanDoMask] [int] default NULL, - [profileWantDoMask] [int] default NULL, - [profileAboutText] [ntext], - [profileFirstText] [ntext], - [profileImage] [varchar](36) default NULL, - [profileFirstImage] [varchar](36) default NULL, - [webLoginKey] [varchar](36) default NULL, - PRIMARY KEY CLUSTERED -( - [UUID] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] -) ON [PRIMARY] - - -CREATE NONCLUSTERED INDEX [usernames] ON [users] -( - [username] ASC, - [lastname] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - - -CREATE TABLE [agents] ( - [UUID] [varchar](36) NOT NULL, - [sessionID] [varchar](36) NOT NULL, - [secureSessionID] [varchar](36) NOT NULL, - [agentIP] [varchar](16) NOT NULL, - [agentPort] [int] NOT NULL, - [agentOnline] [tinyint] NOT NULL, - [loginTime] [int] NOT NULL, - [logoutTime] [int] NOT NULL, - [currentRegion] [varchar](36) NOT NULL, - [currentHandle] [bigint] NOT NULL, - [currentPos] [varchar](64) NOT NULL, - PRIMARY KEY CLUSTERED -( - [UUID] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] -) ON [PRIMARY] - - -CREATE NONCLUSTERED INDEX [session] ON [agents] -( - [sessionID] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX [ssession] ON [agents] -( - [secureSessionID] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - - -CREATE TABLE [dbo].[userfriends]( - [ownerID] [varchar](50) COLLATE Latin1_General_CI_AS NOT NULL, - [friendID] [varchar](50) COLLATE Latin1_General_CI_AS NOT NULL, - [friendPerms] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, - [datetimestamp] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL -) ON [PRIMARY] - -CREATE TABLE [avatarappearance] ( - [Owner] [varchar](36) NOT NULL, - [Serial] int NOT NULL, - [Visual_Params] [image] NOT NULL, - [Texture] [image] NOT NULL, - [Avatar_Height] float NOT NULL, - [Body_Item] [varchar](36) NOT NULL, - [Body_Asset] [varchar](36) NOT NULL, - [Skin_Item] [varchar](36) NOT NULL, - [Skin_Asset] [varchar](36) NOT NULL, - [Hair_Item] [varchar](36) NOT NULL, - [Hair_Asset] [varchar](36) NOT NULL, - [Eyes_Item] [varchar](36) NOT NULL, - [Eyes_Asset] [varchar](36) NOT NULL, - [Shirt_Item] [varchar](36) NOT NULL, - [Shirt_Asset] [varchar](36) NOT NULL, - [Pants_Item] [varchar](36) NOT NULL, - [Pants_Asset] [varchar](36) NOT NULL, - [Shoes_Item] [varchar](36) NOT NULL, - [Shoes_Asset] [varchar](36) NOT NULL, - [Socks_Item] [varchar](36) NOT NULL, - [Socks_Asset] [varchar](36) NOT NULL, - [Jacket_Item] [varchar](36) NOT NULL, - [Jacket_Asset] [varchar](36) NOT NULL, - [Gloves_Item] [varchar](36) NOT NULL, - [Gloves_Asset] [varchar](36) NOT NULL, - [Undershirt_Item] [varchar](36) NOT NULL, - [Undershirt_Asset] [varchar](36) NOT NULL, - [Underpants_Item] [varchar](36) NOT NULL, - [Underpants_Asset] [varchar](36) NOT NULL, - [Skirt_Item] [varchar](36) NOT NULL, - [Skirt_Asset] [varchar](36) NOT NULL, - - PRIMARY KEY CLUSTERED ( - [Owner] - ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] -) ON [PRIMARY] - -:VERSION 2 - -BEGIN TRANSACTION - -ALTER TABLE users ADD homeRegionID varchar(36) NOT NULL default '00000000-0000-0000-0000-000000000000'; -ALTER TABLE users ADD userFlags int NOT NULL default 0; -ALTER TABLE users ADD godLevel int NOT NULL default 0; -ALTER TABLE users ADD customType varchar(32) not null default ''; -ALTER TABLE users ADD partner varchar(36) not null default '00000000-0000-0000-0000-000000000000'; - -COMMIT - - -:VERSION 3 - -BEGIN TRANSACTION - -CREATE TABLE [avatarattachments] ( - [UUID] varchar(36) NOT NULL - , [attachpoint] int NOT NULL - , [item] varchar(36) NOT NULL - , [asset] varchar(36) NOT NULL) - -CREATE NONCLUSTERED INDEX IX_avatarattachments ON dbo.avatarattachments - ( - UUID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - - -COMMIT - - -:VERSION 4 - -BEGIN TRANSACTION - -CREATE TABLE Tmp_userfriends - ( - ownerID varchar(36) NOT NULL, - friendID varchar(36) NOT NULL, - friendPerms int NOT NULL, - datetimestamp int NOT NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM userfriends) - EXEC('INSERT INTO dbo.Tmp_userfriends (ownerID, friendID, friendPerms, datetimestamp) - SELECT CONVERT(varchar(36), ownerID), CONVERT(varchar(36), friendID), CONVERT(int, friendPerms), CONVERT(int, datetimestamp) FROM dbo.userfriends WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.userfriends - -EXECUTE sp_rename N'Tmp_userfriends', N'userfriends', 'OBJECT' - -CREATE NONCLUSTERED INDEX IX_userfriends_ownerID ON userfriends - ( - ownerID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX IX_userfriends_friendID ON userfriends - ( - friendID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 5 - -BEGIN TRANSACTION - - ALTER TABLE users add email varchar(250); - -COMMIT - - -:VERSION 6 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_users - ( - UUID uniqueidentifier NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), - username varchar(32) NOT NULL, - lastname varchar(32) NOT NULL, - passwordHash varchar(32) NOT NULL, - passwordSalt varchar(32) NOT NULL, - homeRegion bigint NULL DEFAULT (NULL), - homeLocationX float(53) NULL DEFAULT (NULL), - homeLocationY float(53) NULL DEFAULT (NULL), - homeLocationZ float(53) NULL DEFAULT (NULL), - homeLookAtX float(53) NULL DEFAULT (NULL), - homeLookAtY float(53) NULL DEFAULT (NULL), - homeLookAtZ float(53) NULL DEFAULT (NULL), - created int NOT NULL, - lastLogin int NOT NULL, - userInventoryURI varchar(255) NULL DEFAULT (NULL), - userAssetURI varchar(255) NULL DEFAULT (NULL), - profileCanDoMask int NULL DEFAULT (NULL), - profileWantDoMask int NULL DEFAULT (NULL), - profileAboutText ntext NULL, - profileFirstText ntext NULL, - profileImage uniqueidentifier NULL DEFAULT (NULL), - profileFirstImage uniqueidentifier NULL DEFAULT (NULL), - webLoginKey uniqueidentifier NULL DEFAULT (NULL), - homeRegionID uniqueidentifier NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), - userFlags int NOT NULL DEFAULT ((0)), - godLevel int NOT NULL DEFAULT ((0)), - customType varchar(32) NOT NULL DEFAULT (''), - partner uniqueidentifier NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), - email varchar(250) NULL - ) ON [PRIMARY] - TEXTIMAGE_ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.users) - EXEC('INSERT INTO dbo.Tmp_users (UUID, username, lastname, passwordHash, passwordSalt, homeRegion, homeLocationX, homeLocationY, homeLocationZ, homeLookAtX, homeLookAtY, homeLookAtZ, created, lastLogin, userInventoryURI, userAssetURI, profileCanDoMask, profileWantDoMask, profileAboutText, profileFirstText, profileImage, profileFirstImage, webLoginKey, homeRegionID, userFlags, godLevel, customType, partner, email) - SELECT CONVERT(uniqueidentifier, UUID), username, lastname, passwordHash, passwordSalt, homeRegion, homeLocationX, homeLocationY, homeLocationZ, homeLookAtX, homeLookAtY, homeLookAtZ, created, lastLogin, userInventoryURI, userAssetURI, profileCanDoMask, profileWantDoMask, profileAboutText, profileFirstText, CONVERT(uniqueidentifier, profileImage), CONVERT(uniqueidentifier, profileFirstImage), CONVERT(uniqueidentifier, webLoginKey), CONVERT(uniqueidentifier, homeRegionID), userFlags, godLevel, customType, CONVERT(uniqueidentifier, partner), email FROM dbo.users WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.users - -EXECUTE sp_rename N'dbo.Tmp_users', N'users', 'OBJECT' - -ALTER TABLE dbo.users ADD CONSTRAINT - PK__users__65A475E737A5467C PRIMARY KEY CLUSTERED - ( - UUID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX usernames ON dbo.users - ( - username, - lastname - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 7 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_agents - ( - UUID uniqueidentifier NOT NULL, - sessionID uniqueidentifier NOT NULL, - secureSessionID uniqueidentifier NOT NULL, - agentIP varchar(16) NOT NULL, - agentPort int NOT NULL, - agentOnline tinyint NOT NULL, - loginTime int NOT NULL, - logoutTime int NOT NULL, - currentRegion uniqueidentifier NOT NULL, - currentHandle bigint NOT NULL, - currentPos varchar(64) NOT NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.agents) - EXEC('INSERT INTO dbo.Tmp_agents (UUID, sessionID, secureSessionID, agentIP, agentPort, agentOnline, loginTime, logoutTime, currentRegion, currentHandle, currentPos) - SELECT CONVERT(uniqueidentifier, UUID), CONVERT(uniqueidentifier, sessionID), CONVERT(uniqueidentifier, secureSessionID), agentIP, agentPort, agentOnline, loginTime, logoutTime, CONVERT(uniqueidentifier, currentRegion), currentHandle, currentPos FROM dbo.agents WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.agents - -EXECUTE sp_rename N'dbo.Tmp_agents', N'agents', 'OBJECT' - -ALTER TABLE dbo.agents ADD CONSTRAINT - PK__agents__65A475E749C3F6B7 PRIMARY KEY CLUSTERED - ( - UUID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX session ON dbo.agents - ( - sessionID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX ssession ON dbo.agents - ( - secureSessionID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 8 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_userfriends - ( - ownerID uniqueidentifier NOT NULL, - friendID uniqueidentifier NOT NULL, - friendPerms int NOT NULL, - datetimestamp int NOT NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.userfriends) - EXEC('INSERT INTO dbo.Tmp_userfriends (ownerID, friendID, friendPerms, datetimestamp) - SELECT CONVERT(uniqueidentifier, ownerID), CONVERT(uniqueidentifier, friendID), friendPerms, datetimestamp FROM dbo.userfriends WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.userfriends - -EXECUTE sp_rename N'dbo.Tmp_userfriends', N'userfriends', 'OBJECT' - -CREATE NONCLUSTERED INDEX IX_userfriends_ownerID ON dbo.userfriends - ( - ownerID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -CREATE NONCLUSTERED INDEX IX_userfriends_friendID ON dbo.userfriends - ( - friendID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 9 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_avatarappearance - ( - Owner uniqueidentifier NOT NULL, - Serial int NOT NULL, - Visual_Params image NOT NULL, - Texture image NOT NULL, - Avatar_Height float(53) NOT NULL, - Body_Item uniqueidentifier NOT NULL, - Body_Asset uniqueidentifier NOT NULL, - Skin_Item uniqueidentifier NOT NULL, - Skin_Asset uniqueidentifier NOT NULL, - Hair_Item uniqueidentifier NOT NULL, - Hair_Asset uniqueidentifier NOT NULL, - Eyes_Item uniqueidentifier NOT NULL, - Eyes_Asset uniqueidentifier NOT NULL, - Shirt_Item uniqueidentifier NOT NULL, - Shirt_Asset uniqueidentifier NOT NULL, - Pants_Item uniqueidentifier NOT NULL, - Pants_Asset uniqueidentifier NOT NULL, - Shoes_Item uniqueidentifier NOT NULL, - Shoes_Asset uniqueidentifier NOT NULL, - Socks_Item uniqueidentifier NOT NULL, - Socks_Asset uniqueidentifier NOT NULL, - Jacket_Item uniqueidentifier NOT NULL, - Jacket_Asset uniqueidentifier NOT NULL, - Gloves_Item uniqueidentifier NOT NULL, - Gloves_Asset uniqueidentifier NOT NULL, - Undershirt_Item uniqueidentifier NOT NULL, - Undershirt_Asset uniqueidentifier NOT NULL, - Underpants_Item uniqueidentifier NOT NULL, - Underpants_Asset uniqueidentifier NOT NULL, - Skirt_Item uniqueidentifier NOT NULL, - Skirt_Asset uniqueidentifier NOT NULL - ) ON [PRIMARY] - TEXTIMAGE_ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.avatarappearance) - EXEC('INSERT INTO dbo.Tmp_avatarappearance (Owner, Serial, Visual_Params, Texture, Avatar_Height, Body_Item, Body_Asset, Skin_Item, Skin_Asset, Hair_Item, Hair_Asset, Eyes_Item, Eyes_Asset, Shirt_Item, Shirt_Asset, Pants_Item, Pants_Asset, Shoes_Item, Shoes_Asset, Socks_Item, Socks_Asset, Jacket_Item, Jacket_Asset, Gloves_Item, Gloves_Asset, Undershirt_Item, Undershirt_Asset, Underpants_Item, Underpants_Asset, Skirt_Item, Skirt_Asset) - SELECT CONVERT(uniqueidentifier, Owner), Serial, Visual_Params, Texture, Avatar_Height, CONVERT(uniqueidentifier, Body_Item), CONVERT(uniqueidentifier, Body_Asset), CONVERT(uniqueidentifier, Skin_Item), CONVERT(uniqueidentifier, Skin_Asset), CONVERT(uniqueidentifier, Hair_Item), CONVERT(uniqueidentifier, Hair_Asset), CONVERT(uniqueidentifier, Eyes_Item), CONVERT(uniqueidentifier, Eyes_Asset), CONVERT(uniqueidentifier, Shirt_Item), CONVERT(uniqueidentifier, Shirt_Asset), CONVERT(uniqueidentifier, Pants_Item), CONVERT(uniqueidentifier, Pants_Asset), CONVERT(uniqueidentifier, Shoes_Item), CONVERT(uniqueidentifier, Shoes_Asset), CONVERT(uniqueidentifier, Socks_Item), CONVERT(uniqueidentifier, Socks_Asset), CONVERT(uniqueidentifier, Jacket_Item), CONVERT(uniqueidentifier, Jacket_Asset), CONVERT(uniqueidentifier, Gloves_Item), CONVERT(uniqueidentifier, Gloves_Asset), CONVERT(uniqueidentifier, Undershirt_Item), CONVERT(uniqueidentifier, Undershirt_Asset), CONVERT(uniqueidentifier, Underpants_Item), CONVERT(uniqueidentifier, Underpants_Asset), CONVERT(uniqueidentifier, Skirt_Item), CONVERT(uniqueidentifier, Skirt_Asset) FROM dbo.avatarappearance WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.avatarappearance - -EXECUTE sp_rename N'dbo.Tmp_avatarappearance', N'avatarappearance', 'OBJECT' - -ALTER TABLE dbo.avatarappearance ADD CONSTRAINT - PK__avatarap__7DD115CC4E88ABD4 PRIMARY KEY CLUSTERED - ( - Owner - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 10 - -BEGIN TRANSACTION - -CREATE TABLE dbo.Tmp_avatarattachments - ( - UUID uniqueidentifier NOT NULL, - attachpoint int NOT NULL, - item uniqueidentifier NOT NULL, - asset uniqueidentifier NOT NULL - ) ON [PRIMARY] - -IF EXISTS(SELECT * FROM dbo.avatarattachments) - EXEC('INSERT INTO dbo.Tmp_avatarattachments (UUID, attachpoint, item, asset) - SELECT CONVERT(uniqueidentifier, UUID), attachpoint, CONVERT(uniqueidentifier, item), CONVERT(uniqueidentifier, asset) FROM dbo.avatarattachments WITH (HOLDLOCK TABLOCKX)') - -DROP TABLE dbo.avatarattachments - -EXECUTE sp_rename N'dbo.Tmp_avatarattachments', N'avatarattachments', 'OBJECT' - -CREATE NONCLUSTERED INDEX IX_avatarattachments ON dbo.avatarattachments - ( - UUID - ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] - -COMMIT - - -:VERSION 11 - -BEGIN TRANSACTION - -ALTER TABLE users ADD scopeID uniqueidentifier not null default '00000000-0000-0000-0000-000000000000' - -COMMIT diff --git a/OpenSim/Data/MySQL/MySQLAgentPreferencesData.cs b/OpenSim/Data/MySQL/MySQLAgentPreferencesData.cs new file mode 100644 index 0000000..ed0ab98 --- /dev/null +++ b/OpenSim/Data/MySQL/MySQLAgentPreferencesData.cs @@ -0,0 +1,56 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using OpenMetaverse; +using OpenSim.Framework; +using MySql.Data.MySqlClient; + +namespace OpenSim.Data.MySQL +{ + public class MySQLAgentPreferencesData : MySQLGenericTableHandler, IAgentPreferencesData + { + public MySQLAgentPreferencesData(string connectionString, string realm) + : base(connectionString, realm, "AgentPrefs") + { + } + + public AgentPreferencesData GetPrefs(UUID agentID) + { + AgentPreferencesData[] ret = Get("PrincipalID", agentID.ToString()); + + if (ret.Length == 0) + return null; + + return ret[0]; + } + } +} + diff --git a/OpenSim/Data/MySQL/MySQLAssetData.cs b/OpenSim/Data/MySQL/MySQLAssetData.cs index 73de64b..5d8da17 100644 --- a/OpenSim/Data/MySQL/MySQLAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLAssetData.cs @@ -45,7 +45,6 @@ namespace OpenSim.Data.MySQL private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private string m_connectionString; - private object m_dbLock = new object(); protected virtual Assembly Assembly { @@ -107,46 +106,46 @@ namespace OpenSim.Data.MySQL override public AssetBase GetAsset(UUID assetID) { AssetBase asset = null; - lock (m_dbLock) + + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + dbcon.Open(); + + using (MySqlCommand cmd = new MySqlCommand( + "SELECT name, description, assetType, local, temporary, asset_flags, CreatorID, data FROM assets WHERE id=?id", + dbcon)) { - dbcon.Open(); + cmd.Parameters.AddWithValue("?id", assetID.ToString()); - using (MySqlCommand cmd = new MySqlCommand( - "SELECT name, description, assetType, local, temporary, asset_flags, CreatorID, data FROM assets WHERE id=?id", - dbcon)) + try { - cmd.Parameters.AddWithValue("?id", assetID.ToString()); - - try + using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { - using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + if (dbReader.Read()) { - if (dbReader.Read()) - { - asset = new AssetBase(assetID, (string)dbReader["name"], (sbyte)dbReader["assetType"], dbReader["CreatorID"].ToString()); - asset.Data = (byte[])dbReader["data"]; - asset.Description = (string)dbReader["description"]; - - string local = dbReader["local"].ToString(); - if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase)) - asset.Local = true; - else - asset.Local = false; - - asset.Temporary = Convert.ToBoolean(dbReader["temporary"]); - asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); - } + asset = new AssetBase(assetID, (string)dbReader["name"], (sbyte)dbReader["assetType"], dbReader["CreatorID"].ToString()); + asset.Data = (byte[])dbReader["data"]; + asset.Description = (string)dbReader["description"]; + + string local = dbReader["local"].ToString(); + if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase)) + asset.Local = true; + else + asset.Local = false; + + asset.Temporary = Convert.ToBoolean(dbReader["temporary"]); + asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); } } - catch (Exception e) - { - m_log.Error("[ASSETS DB]: MySql failure fetching asset " + assetID + ": " + e.Message); - } + } + catch (Exception e) + { + m_log.Error( + string.Format("[ASSETS DB]: MySql failure fetching asset {0}. Exception ", assetID), e); } } } + return asset; } @@ -157,137 +156,134 @@ namespace OpenSim.Data.MySQL /// On failure : Throw an exception and attempt to reconnect to database override public void StoreAsset(AssetBase asset) { - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + dbcon.Open(); + + using (MySqlCommand cmd = + new MySqlCommand( + "replace INTO assets(id, name, description, assetType, local, temporary, create_time, access_time, asset_flags, CreatorID, data)" + + "VALUES(?id, ?name, ?description, ?assetType, ?local, ?temporary, ?create_time, ?access_time, ?asset_flags, ?CreatorID, ?data)", + dbcon)) { - dbcon.Open(); + string assetName = asset.Name; + if (asset.Name.Length > AssetBase.MAX_ASSET_NAME) + { + assetName = asset.Name.Substring(0, AssetBase.MAX_ASSET_NAME); + m_log.WarnFormat( + "[ASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add", + asset.Name, asset.ID, asset.Name.Length, assetName.Length); + } - using (MySqlCommand cmd = - new MySqlCommand( - "replace INTO assets(id, name, description, assetType, local, temporary, create_time, access_time, asset_flags, CreatorID, data)" + - "VALUES(?id, ?name, ?description, ?assetType, ?local, ?temporary, ?create_time, ?access_time, ?asset_flags, ?CreatorID, ?data)", - dbcon)) + string assetDescription = asset.Description; + if (asset.Description.Length > AssetBase.MAX_ASSET_DESC) { - string assetName = asset.Name; - if (asset.Name.Length > 64) - { - assetName = asset.Name.Substring(0, 64); - m_log.Warn("[ASSET DB]: Name field truncated from " + asset.Name.Length + " to " + assetName.Length + " characters on add"); - } - - string assetDescription = asset.Description; - if (asset.Description.Length > 64) - { - assetDescription = asset.Description.Substring(0, 64); - m_log.Warn("[ASSET DB]: Description field truncated from " + asset.Description.Length + " to " + assetDescription.Length + " characters on add"); - } - - try - { - using (cmd) - { - // create unix epoch time - int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); - cmd.Parameters.AddWithValue("?id", asset.ID); - cmd.Parameters.AddWithValue("?name", assetName); - cmd.Parameters.AddWithValue("?description", assetDescription); - cmd.Parameters.AddWithValue("?assetType", asset.Type); - cmd.Parameters.AddWithValue("?local", asset.Local); - cmd.Parameters.AddWithValue("?temporary", asset.Temporary); - cmd.Parameters.AddWithValue("?create_time", now); - cmd.Parameters.AddWithValue("?access_time", now); - cmd.Parameters.AddWithValue("?CreatorID", asset.Metadata.CreatorID); - cmd.Parameters.AddWithValue("?asset_flags", (int)asset.Flags); - cmd.Parameters.AddWithValue("?data", asset.Data); - cmd.ExecuteNonQuery(); - } - } - catch (Exception e) + assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); + m_log.WarnFormat( + "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", + asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); + } + + try + { + using (cmd) { - m_log.ErrorFormat("[ASSET DB]: MySQL failure creating asset {0} with name \"{1}\". Error: {2}", - asset.FullID, asset.Name, e.Message); + // create unix epoch time + int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); + cmd.Parameters.AddWithValue("?id", asset.ID); + cmd.Parameters.AddWithValue("?name", assetName); + cmd.Parameters.AddWithValue("?description", assetDescription); + cmd.Parameters.AddWithValue("?assetType", asset.Type); + cmd.Parameters.AddWithValue("?local", asset.Local); + cmd.Parameters.AddWithValue("?temporary", asset.Temporary); + cmd.Parameters.AddWithValue("?create_time", now); + cmd.Parameters.AddWithValue("?access_time", now); + cmd.Parameters.AddWithValue("?CreatorID", asset.Metadata.CreatorID); + cmd.Parameters.AddWithValue("?asset_flags", (int)asset.Flags); + cmd.Parameters.AddWithValue("?data", asset.Data); + cmd.ExecuteNonQuery(); } } + catch (Exception e) + { + m_log.Error( + string.Format( + "[ASSET DB]: MySQL failure creating asset {0} with name {1}. Exception ", + asset.FullID, asset.Name) + , e); + } } } } private void UpdateAccessTime(AssetBase asset) { - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) - { - dbcon.Open(); + dbcon.Open(); - using (MySqlCommand cmd - = new MySqlCommand("update assets set access_time=?access_time where id=?id", dbcon)) + using (MySqlCommand cmd + = new MySqlCommand("update assets set access_time=?access_time where id=?id", dbcon)) + { + try { - try - { - using (cmd) - { - // create unix epoch time - int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); - cmd.Parameters.AddWithValue("?id", asset.ID); - cmd.Parameters.AddWithValue("?access_time", now); - cmd.ExecuteNonQuery(); - } - } - catch (Exception e) + using (cmd) { - m_log.ErrorFormat( - "[ASSETS DB]: " + - "MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString() - + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name); + // create unix epoch time + int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); + cmd.Parameters.AddWithValue("?id", asset.ID); + cmd.Parameters.AddWithValue("?access_time", now); + cmd.ExecuteNonQuery(); } } + catch (Exception e) + { + m_log.Error( + string.Format( + "[ASSETS DB]: Failure updating access_time for asset {0} with name {1}. Exception ", + asset.FullID, asset.Name), + e); + } } } } /// - /// Check if the asset exists in the database + /// Check if the assets exist in the database. /// - /// The asset UUID - /// true if it exists, false otherwise. - override public bool ExistsAsset(UUID uuid) + /// The assets' IDs + /// For each asset: true if it exists, false otherwise + public override bool[] AssetsExist(UUID[] uuids) { -// m_log.DebugFormat("[ASSETS DB]: Checking for asset {0}", uuid); + if (uuids.Length == 0) + return new bool[0]; - bool assetExists = false; + HashSet exist = new HashSet(); - lock (m_dbLock) + string ids = "'" + string.Join("','", uuids) + "'"; + string sql = string.Format("SELECT id FROM assets WHERE id IN ({0})", ids); + + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(sql, dbcon)) { - dbcon.Open(); - using (MySqlCommand cmd = new MySqlCommand("SELECT id FROM assets WHERE id=?id", dbcon)) + using (MySqlDataReader dbReader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("?id", uuid.ToString()); - - try - { - using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) - { - if (dbReader.Read()) - { -// m_log.DebugFormat("[ASSETS DB]: Found asset {0}", uuid); - assetExists = true; - } - } - } - catch (Exception e) + while (dbReader.Read()) { - m_log.ErrorFormat( - "[ASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString(), uuid); + UUID id = DBGuid.FromDB(dbReader["id"]); + exist.Add(id); } } } } - return assetExists; + bool[] results = new bool[uuids.Length]; + for (int i = 0; i < uuids.Length; i++) + results[i] = exist.Contains(uuids[i]); + + return results; } /// @@ -302,46 +298,47 @@ namespace OpenSim.Data.MySQL { List retList = new List(count); - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + dbcon.Open(); + + using (MySqlCommand cmd + = new MySqlCommand( + "SELECT name,description,assetType,temporary,id,asset_flags,CreatorID FROM assets LIMIT ?start, ?count", + dbcon)) { - dbcon.Open(); + cmd.Parameters.AddWithValue("?start", start); + cmd.Parameters.AddWithValue("?count", count); - using (MySqlCommand cmd - = new MySqlCommand( - "SELECT name,description,assetType,temporary,id,asset_flags,CreatorID FROM assets LIMIT ?start, ?count", - dbcon)) + try { - cmd.Parameters.AddWithValue("?start", start); - cmd.Parameters.AddWithValue("?count", count); - - try + using (MySqlDataReader dbReader = cmd.ExecuteReader()) { - using (MySqlDataReader dbReader = cmd.ExecuteReader()) + while (dbReader.Read()) { - while (dbReader.Read()) - { - AssetMetadata metadata = new AssetMetadata(); - metadata.Name = (string)dbReader["name"]; - metadata.Description = (string)dbReader["description"]; - metadata.Type = (sbyte)dbReader["assetType"]; - metadata.Temporary = Convert.ToBoolean(dbReader["temporary"]); // Not sure if this is correct. - metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); - metadata.FullID = DBGuid.FromDB(dbReader["id"]); - metadata.CreatorID = dbReader["CreatorID"].ToString(); - - // Current SHA1s are not stored/computed. - metadata.SHA1 = new byte[] { }; - - retList.Add(metadata); - } + AssetMetadata metadata = new AssetMetadata(); + metadata.Name = (string)dbReader["name"]; + metadata.Description = (string)dbReader["description"]; + metadata.Type = (sbyte)dbReader["assetType"]; + metadata.Temporary = Convert.ToBoolean(dbReader["temporary"]); // Not sure if this is correct. + metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); + metadata.FullID = DBGuid.FromDB(dbReader["id"]); + metadata.CreatorID = dbReader["CreatorID"].ToString(); + + // Current SHA1s are not stored/computed. + metadata.SHA1 = new byte[] { }; + + retList.Add(metadata); } } - catch (Exception e) - { - m_log.Error("[ASSETS DB]: MySql failure fetching asset set" + Environment.NewLine + e.ToString()); - } + } + catch (Exception e) + { + m_log.Error( + string.Format( + "[ASSETS DB]: MySql failure fetching asset set from {0}, count {1}. Exception ", + start, count), + e); } } } @@ -351,17 +348,14 @@ namespace OpenSim.Data.MySQL public override bool Delete(string id) { - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) - { - dbcon.Open(); + dbcon.Open(); - using (MySqlCommand cmd = new MySqlCommand("delete from assets where id=?id", dbcon)) - { - cmd.Parameters.AddWithValue("?id", id); - cmd.ExecuteNonQuery(); - } + using (MySqlCommand cmd = new MySqlCommand("delete from assets where id=?id", dbcon)) + { + cmd.Parameters.AddWithValue("?id", id); + cmd.ExecuteNonQuery(); } } diff --git a/OpenSim/Data/MySQL/MySQLEstateData.cs b/OpenSim/Data/MySQL/MySQLEstateData.cs index 3dd46cb..fe1487b 100644 --- a/OpenSim/Data/MySQL/MySQLEstateData.cs +++ b/OpenSim/Data/MySQL/MySQLEstateData.cs @@ -43,12 +43,7 @@ namespace OpenSim.Data.MySQL private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private const string m_waitTimeoutSelect = "select @@wait_timeout"; - private string m_connectionString; - private long m_waitTimeout; - private long m_waitTimeoutLeeway = 60 * TimeSpan.TicksPerSecond; -// private long m_lastConnectionUse; private FieldInfo[] m_Fields; private Dictionary m_FieldMap = @@ -81,8 +76,6 @@ namespace OpenSim.Data.MySQL m_log.Debug("Exception: password not found in connection string\n" + e.ToString()); } - GetWaitTimeout(); - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { dbcon.Open(); @@ -108,33 +101,6 @@ namespace OpenSim.Data.MySQL get { return new List(m_FieldMap.Keys).ToArray(); } } - protected void GetWaitTimeout() - { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) - { - dbcon.Open(); - - using (MySqlCommand cmd = new MySqlCommand(m_waitTimeoutSelect, dbcon)) - { - using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) - { - if (dbReader.Read()) - { - m_waitTimeout - = Convert.ToInt32(dbReader["@@wait_timeout"]) * - TimeSpan.TicksPerSecond + m_waitTimeoutLeeway; - } - } - } - -// m_lastConnectionUse = DateTime.Now.Ticks; - - m_log.DebugFormat( - "[REGION DB]: Connection wait timeout {0} seconds", - m_waitTimeout / TimeSpan.TicksPerSecond); - } - } - public EstateSettings LoadEstateSettings(UUID regionID, bool create) { string sql = "select estate_settings." + String.Join(",estate_settings.", FieldList) + @@ -145,7 +111,11 @@ namespace OpenSim.Data.MySQL cmd.CommandText = sql; cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); - return DoLoad(cmd, regionID, create); + EstateSettings e = DoLoad(cmd, regionID, create); + if (!create && e.EstateID == 0) // Not found + return null; + + return e; } } @@ -427,7 +397,10 @@ namespace OpenSim.Data.MySQL cmd.CommandText = sql; cmd.Parameters.AddWithValue("?EstateID", estateID); - return DoLoad(cmd, UUID.Zero, false); + EstateSettings e = DoLoad(cmd, UUID.Zero, false); + if (e.EstateID != estateID) + return null; + return e; } } diff --git a/OpenSim/Data/MySQL/MySQLFSAssetData.cs b/OpenSim/Data/MySQL/MySQLFSAssetData.cs new file mode 100644 index 0000000..19e23b5 --- /dev/null +++ b/OpenSim/Data/MySQL/MySQLFSAssetData.cs @@ -0,0 +1,414 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Data; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using log4net; +using MySql.Data.MySqlClient; +using OpenMetaverse; + +namespace OpenSim.Data.MySQL +{ + public class MySQLFSAssetData : IFSAssetDataPlugin + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected MySqlConnection m_Connection = null; + protected string m_ConnectionString; + protected string m_Table; + protected Object m_connLock = new Object(); + + /// + /// Number of days that must pass before we update the access time on an asset when it has been fetched + /// Config option to change this is "DaysBetweenAccessTimeUpdates" + /// + private int DaysBetweenAccessTimeUpdates = 0; + + protected virtual Assembly Assembly + { + get { return GetType().Assembly; } + } + + public MySQLFSAssetData() + { + } + + #region IPlugin Members + + public string Version { get { return "1.0.0.0"; } } + + // Loads and initialises the MySQL storage plugin and checks for migrations + public void Initialise(string connect, string realm, int UpdateAccessTime) + { + m_ConnectionString = connect; + m_Table = realm; + + DaysBetweenAccessTimeUpdates = UpdateAccessTime; + + try + { + OpenDatabase(); + + Migration m = new Migration(m_Connection, Assembly, "FSAssetStore"); + m.Update(); + } + catch (MySqlException e) + { + m_log.ErrorFormat("[FSASSETS]: Can't connect to database: {0}", e.Message.ToString()); + } + } + + public void Initialise() + { + throw new NotImplementedException(); + } + + public void Dispose() { } + + public string Name + { + get { return "MySQL FSAsset storage engine"; } + } + + #endregion + + private bool OpenDatabase() + { + try + { + m_Connection = new MySqlConnection(m_ConnectionString); + + m_Connection.Open(); + } + catch (MySqlException e) + { + m_log.ErrorFormat("[FSASSETS]: Can't connect to database: {0}", + e.Message.ToString()); + + return false; + } + + return true; + } + + private IDataReader ExecuteReader(MySqlCommand c) + { + IDataReader r = null; + MySqlConnection connection = (MySqlConnection) ((ICloneable)m_Connection).Clone(); + connection.Open(); + c.Connection = connection; + + r = c.ExecuteReader(); + + return r; + } + + private void ExecuteNonQuery(MySqlCommand c) + { + lock (m_connLock) + { + bool errorSeen = false; + + while (true) + { + try + { + c.ExecuteNonQuery(); + } + catch (MySqlException) + { + System.Threading.Thread.Sleep(500); + + m_Connection.Close(); + m_Connection = (MySqlConnection) ((ICloneable)m_Connection).Clone(); + m_Connection.Open(); + c.Connection = m_Connection; + + if (!errorSeen) + { + errorSeen = true; + continue; + } + m_log.ErrorFormat("[FSASSETS] MySQL command: {0}", c.CommandText); + throw; + } + + break; + } + } + } + + #region IFSAssetDataPlugin Members + + public AssetMetadata Get(string id, out string hash) + { + hash = String.Empty; + + MySqlCommand cmd = new MySqlCommand(); + + cmd.CommandText = String.Format("select id, name, description, type, hash, create_time, access_time, asset_flags from {0} where id = ?id", m_Table); + cmd.Parameters.AddWithValue("?id", id); + + IDataReader reader = ExecuteReader(cmd); + + if (!reader.Read()) + { + reader.Close(); + FreeCommand(cmd); + return null; + } + + AssetMetadata meta = new AssetMetadata(); + + hash = reader["hash"].ToString(); + + meta.ID = id; + meta.FullID = new UUID(id); + + meta.Name = reader["name"].ToString(); + meta.Description = reader["description"].ToString(); + meta.Type = (sbyte)Convert.ToInt32(reader["type"]); + meta.ContentType = SLUtil.SLAssetTypeToContentType(meta.Type); + meta.CreationDate = Util.ToDateTime(Convert.ToInt32(reader["create_time"])); + meta.Flags = (AssetFlags)Convert.ToInt32(reader["asset_flags"]); + + int AccessTime = Convert.ToInt32(reader["access_time"]); + + reader.Close(); + + UpdateAccessTime(AccessTime, cmd); + + FreeCommand(cmd); + + return meta; + } + + private void UpdateAccessTime(int AccessTime, MySqlCommand cmd) + { + // Reduce DB work by only updating access time if asset hasn't recently been accessed + // 0 By Default, Config option is "DaysBetweenAccessTimeUpdates" + if (DaysBetweenAccessTimeUpdates > 0 && (DateTime.UtcNow - Utils.UnixTimeToDateTime(AccessTime)).TotalDays < DaysBetweenAccessTimeUpdates) + return; + + cmd.CommandText = String.Format("UPDATE {0} SET `access_time` = UNIX_TIMESTAMP() WHERE `id` = ?id", m_Table); + + cmd.ExecuteNonQuery(); + } + + protected void FreeCommand(MySqlCommand cmd) + { + MySqlConnection c = cmd.Connection; + cmd.Dispose(); + c.Close(); + c.Dispose(); + } + + public bool Store(AssetMetadata meta, string hash) + { + try + { + string oldhash; + AssetMetadata existingAsset = Get(meta.ID, out oldhash); + + MySqlCommand cmd = m_Connection.CreateCommand(); + + cmd.Parameters.AddWithValue("?id", meta.ID); + cmd.Parameters.AddWithValue("?name", meta.Name); + cmd.Parameters.AddWithValue("?description", meta.Description); + cmd.Parameters.AddWithValue("?type", meta.Type.ToString()); + cmd.Parameters.AddWithValue("?hash", hash); + cmd.Parameters.AddWithValue("?asset_flags", meta.Flags); + + if (existingAsset == null) + { + cmd.CommandText = String.Format("insert into {0} (id, name, description, type, hash, asset_flags, create_time, access_time) values ( ?id, ?name, ?description, ?type, ?hash, ?asset_flags, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())", m_Table); + + ExecuteNonQuery(cmd); + + cmd.Dispose(); + + return true; + } + + //cmd.CommandText = String.Format("update {0} set hash = ?hash, access_time = UNIX_TIMESTAMP() where id = ?id", m_Table); + + //ExecuteNonQuery(cmd); + + cmd.Dispose(); + return false; + } + catch(Exception e) + { + m_log.Error("[FSAssets] Failed to store asset with ID " + meta.ID); + m_log.Error(e.ToString()); + return false; + } + } + + /// + /// Check if the assets exist in the database. + /// + /// The asset UUID's + /// For each asset: true if it exists, false otherwise + public bool[] AssetsExist(UUID[] uuids) + { + if (uuids.Length == 0) + return new bool[0]; + + HashSet exists = new HashSet(); + + string ids = "'" + string.Join("','", uuids) + "'"; + string sql = string.Format("select id from {1} where id in ({0})", ids, m_Table); + + using (MySqlCommand cmd = m_Connection.CreateCommand()) + { + cmd.CommandText = sql; + + using (MySqlDataReader dbReader = cmd.ExecuteReader()) + { + while (dbReader.Read()) + { + UUID id = DBGuid.FromDB(dbReader["ID"]); + exists.Add(id); + } + } + } + + bool[] results = new bool[uuids.Length]; + for (int i = 0; i < uuids.Length; i++) + results[i] = exists.Contains(uuids[i]); + return results; + } + + public int Count() + { + MySqlCommand cmd = m_Connection.CreateCommand(); + + cmd.CommandText = String.Format("select count(*) as count from {0}", m_Table); + + IDataReader reader = ExecuteReader(cmd); + + reader.Read(); + + int count = Convert.ToInt32(reader["count"]); + + reader.Close(); + FreeCommand(cmd); + + return count; + } + + public bool Delete(string id) + { + using (MySqlCommand cmd = m_Connection.CreateCommand()) + { + cmd.CommandText = String.Format("delete from {0} where id = ?id", m_Table); + + cmd.Parameters.AddWithValue("?id", id); + + ExecuteNonQuery(cmd); + } + + return true; + } + + public void Import(string conn, string table, int start, int count, bool force, FSStoreDelegate store) + { + MySqlConnection importConn; + + try + { + importConn = new MySqlConnection(conn); + + importConn.Open(); + } + catch (MySqlException e) + { + m_log.ErrorFormat("[FSASSETS]: Can't connect to database: {0}", + e.Message.ToString()); + + return; + } + + int imported = 0; + + MySqlCommand cmd = importConn.CreateCommand(); + + string limit = String.Empty; + if (count != -1) + { + limit = String.Format(" limit {0},{1}", start, count); + } + + cmd.CommandText = String.Format("select * from {0}{1}", table, limit); + + MainConsole.Instance.Output("Querying database"); + IDataReader reader = cmd.ExecuteReader(); + + MainConsole.Instance.Output("Reading data"); + + while (reader.Read()) + { + if ((imported % 100) == 0) + { + MainConsole.Instance.Output(String.Format("{0} assets imported so far", imported)); + } + + AssetBase asset = new AssetBase(); + AssetMetadata meta = new AssetMetadata(); + + meta.ID = reader["id"].ToString(); + meta.FullID = new UUID(meta.ID); + + meta.Name = reader["name"].ToString(); + meta.Description = reader["description"].ToString(); + meta.Type = (sbyte)Convert.ToInt32(reader["assetType"]); + meta.ContentType = SLUtil.SLAssetTypeToContentType(meta.Type); + meta.CreationDate = Util.ToDateTime(Convert.ToInt32(reader["create_time"])); + + asset.Metadata = meta; + asset.Data = (byte[])reader["data"]; + + store(asset, force); + + imported++; + } + + reader.Close(); + cmd.Dispose(); + importConn.Close(); + + MainConsole.Instance.Output(String.Format("Import done, {0} assets imported", imported)); + } + + #endregion + } +} diff --git a/OpenSim/Data/MySQL/MySQLFramework.cs b/OpenSim/Data/MySQL/MySQLFramework.cs index 3fdcf1e..5820a90 100644 --- a/OpenSim/Data/MySQL/MySQLFramework.cs +++ b/OpenSim/Data/MySQL/MySQLFramework.cs @@ -45,38 +45,29 @@ namespace OpenSim.Data.MySQL System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); protected string m_connectionString; - protected object m_dbLock = new object(); protected MySqlFramework(string connectionString) { m_connectionString = connectionString; } - ////////////////////////////////////////////////////////////// - // - // All non queries are funneled through one connection - // to increase performance a little - // protected int ExecuteNonQuery(MySqlCommand cmd) { - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) - { - dbcon.Open(); - cmd.Connection = dbcon; + dbcon.Open(); + cmd.Connection = dbcon; - try - { - return cmd.ExecuteNonQuery(); - } - catch (Exception e) - { - m_log.Error(e.Message, e); - return 0; - } + try + { + return cmd.ExecuteNonQuery(); + } + catch (Exception e) + { + m_log.Error(e.Message, e); + return 0; } } } } -} +} \ No newline at end of file diff --git a/OpenSim/Data/MySQL/MySQLFriendsData.cs b/OpenSim/Data/MySQL/MySQLFriendsData.cs index 3cd6b8f..6ba9fbd 100644 --- a/OpenSim/Data/MySQL/MySQLFriendsData.cs +++ b/OpenSim/Data/MySQL/MySQLFriendsData.cs @@ -47,7 +47,7 @@ namespace OpenSim.Data.MySQL return Delete(principalID.ToString(), friend); } - public bool Delete(string principalID, string friend) + public override bool Delete(string principalID, string friend) { using (MySqlCommand cmd = new MySqlCommand()) { diff --git a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs index 995c6a5..35fa89f 100644 --- a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs +++ b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs @@ -301,5 +301,65 @@ namespace OpenSim.Data.MySQL return ExecuteNonQuery(cmd) > 0; } } + + public long GetCount(string field, string key) + { + return GetCount(new string[] { field }, new string[] { key }); + } + + public long GetCount(string[] fields, string[] keys) + { + if (fields.Length != keys.Length) + return 0; + + List terms = new List(); + + using (MySqlCommand cmd = new MySqlCommand()) + { + for (int i = 0; i < fields.Length; i++) + { + cmd.Parameters.AddWithValue(fields[i], keys[i]); + terms.Add("`" + fields[i] + "` = ?" + fields[i]); + } + + string where = String.Join(" and ", terms.ToArray()); + + string query = String.Format("select count(*) from {0} where {1}", + m_Realm, where); + + cmd.CommandText = query; + + Object result = DoQueryScalar(cmd); + + return Convert.ToInt64(result); + } + } + + public long GetCount(string where) + { + using (MySqlCommand cmd = new MySqlCommand()) + { + string query = String.Format("select count(*) from {0} where {1}", + m_Realm, where); + + cmd.CommandText = query; + + object result = DoQueryScalar(cmd); + + return Convert.ToInt64(result); + } + } + + public object DoQueryScalar(MySqlCommand cmd) + { + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + { + dbcon.Open(); + cmd.Connection = dbcon; + + return cmd.ExecuteScalar(); + } + } + } } \ No newline at end of file diff --git a/OpenSim/Data/MySQL/MySQLGridUserData.cs b/OpenSim/Data/MySQL/MySQLGridUserData.cs index a9ce94d..00560c1 100644 --- a/OpenSim/Data/MySQL/MySQLGridUserData.cs +++ b/OpenSim/Data/MySQL/MySQLGridUserData.cs @@ -46,7 +46,7 @@ namespace OpenSim.Data.MySQL public MySQLGridUserData(string connectionString, string realm) : base(connectionString, realm, "GridUserStore") {} - public GridUserData Get(string userID) + public new GridUserData Get(string userID) { GridUserData[] ret = Get("UserID", userID); @@ -56,6 +56,9 @@ namespace OpenSim.Data.MySQL return ret[0]; } - + public GridUserData[] GetAll(string userID) + { + return base.Get(String.Format("UserID LIKE '{0}%'", userID)); + } } } \ No newline at end of file diff --git a/OpenSim/Data/MySQL/MySQLGroupsData.cs b/OpenSim/Data/MySQL/MySQLGroupsData.cs new file mode 100644 index 0000000..afa499e --- /dev/null +++ b/OpenSim/Data/MySQL/MySQLGroupsData.cs @@ -0,0 +1,484 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +using OpenSim.Framework; +using OpenSim.Data.MySQL; + +using OpenMetaverse; +using MySql.Data.MySqlClient; + +namespace OpenSim.Data.MySQL +{ + public class MySQLGroupsData : IGroupsData + { + private MySqlGroupsGroupsHandler m_Groups; + private MySqlGroupsMembershipHandler m_Membership; + private MySqlGroupsRolesHandler m_Roles; + private MySqlGroupsRoleMembershipHandler m_RoleMembership; + private MySqlGroupsInvitesHandler m_Invites; + private MySqlGroupsNoticesHandler m_Notices; + private MySqlGroupsPrincipalsHandler m_Principals; + + public MySQLGroupsData(string connectionString, string realm) + { + m_Groups = new MySqlGroupsGroupsHandler(connectionString, realm + "_groups", realm + "_Store"); + m_Membership = new MySqlGroupsMembershipHandler(connectionString, realm + "_membership"); + m_Roles = new MySqlGroupsRolesHandler(connectionString, realm + "_roles"); + m_RoleMembership = new MySqlGroupsRoleMembershipHandler(connectionString, realm + "_rolemembership"); + m_Invites = new MySqlGroupsInvitesHandler(connectionString, realm + "_invites"); + m_Notices = new MySqlGroupsNoticesHandler(connectionString, realm + "_notices"); + m_Principals = new MySqlGroupsPrincipalsHandler(connectionString, realm + "_principals"); + } + + #region groups table + public bool StoreGroup(GroupData data) + { + return m_Groups.Store(data); + } + + public GroupData RetrieveGroup(UUID groupID) + { + GroupData[] groups = m_Groups.Get("GroupID", groupID.ToString()); + if (groups.Length > 0) + return groups[0]; + + return null; + } + + public GroupData RetrieveGroup(string name) + { + GroupData[] groups = m_Groups.Get("Name", name); + if (groups.Length > 0) + return groups[0]; + + return null; + } + + public GroupData[] RetrieveGroups(string pattern) + { + if (string.IsNullOrEmpty(pattern)) + pattern = "1"; + else + pattern = string.Format("Name LIKE '%{0}%'", MySqlHelper.EscapeString(pattern)); + + return m_Groups.Get(string.Format("ShowInList=1 AND ({0}) ORDER BY Name LIMIT 100", pattern)); + } + + public bool DeleteGroup(UUID groupID) + { + return m_Groups.Delete("GroupID", groupID.ToString()); + } + + public int GroupsCount() + { + return (int)m_Groups.GetCount("Location=\"\""); + } + + #endregion + + #region membership table + public MembershipData[] RetrieveMembers(UUID groupID) + { + return m_Membership.Get("GroupID", groupID.ToString()); + } + + public MembershipData RetrieveMember(UUID groupID, string pricipalID) + { + MembershipData[] m = m_Membership.Get(new string[] { "GroupID", "PrincipalID" }, + new string[] { groupID.ToString(), pricipalID }); + if (m != null && m.Length > 0) + return m[0]; + + return null; + } + + public MembershipData[] RetrieveMemberships(string pricipalID) + { + return m_Membership.Get("PrincipalID", pricipalID.ToString()); + } + + public bool StoreMember(MembershipData data) + { + return m_Membership.Store(data); + } + + public bool DeleteMember(UUID groupID, string pricipalID) + { + return m_Membership.Delete(new string[] { "GroupID", "PrincipalID" }, + new string[] { groupID.ToString(), pricipalID }); + } + + public int MemberCount(UUID groupID) + { + return (int)m_Membership.GetCount("GroupID", groupID.ToString()); + } + #endregion + + #region roles table + public bool StoreRole(RoleData data) + { + return m_Roles.Store(data); + } + + public RoleData RetrieveRole(UUID groupID, UUID roleID) + { + RoleData[] data = m_Roles.Get(new string[] { "GroupID", "RoleID" }, + new string[] { groupID.ToString(), roleID.ToString() }); + + if (data != null && data.Length > 0) + return data[0]; + + return null; + } + + public RoleData[] RetrieveRoles(UUID groupID) + { + //return m_Roles.RetrieveRoles(groupID); + return m_Roles.Get("GroupID", groupID.ToString()); + } + + public bool DeleteRole(UUID groupID, UUID roleID) + { + return m_Roles.Delete(new string[] { "GroupID", "RoleID" }, + new string[] { groupID.ToString(), roleID.ToString() }); + } + + public int RoleCount(UUID groupID) + { + return (int)m_Roles.GetCount("GroupID", groupID.ToString()); + } + + + #endregion + + #region rolememberhip table + public RoleMembershipData[] RetrieveRolesMembers(UUID groupID) + { + RoleMembershipData[] data = m_RoleMembership.Get("GroupID", groupID.ToString()); + + return data; + } + + public RoleMembershipData[] RetrieveRoleMembers(UUID groupID, UUID roleID) + { + RoleMembershipData[] data = m_RoleMembership.Get(new string[] { "GroupID", "RoleID" }, + new string[] { groupID.ToString(), roleID.ToString() }); + + return data; + } + + public RoleMembershipData[] RetrieveMemberRoles(UUID groupID, string principalID) + { + RoleMembershipData[] data = m_RoleMembership.Get(new string[] { "GroupID", "PrincipalID" }, + new string[] { groupID.ToString(), principalID.ToString() }); + + return data; + } + + public RoleMembershipData RetrieveRoleMember(UUID groupID, UUID roleID, string principalID) + { + RoleMembershipData[] data = m_RoleMembership.Get(new string[] { "GroupID", "RoleID", "PrincipalID" }, + new string[] { groupID.ToString(), roleID.ToString(), principalID.ToString() }); + + if (data != null && data.Length > 0) + return data[0]; + + return null; + } + + public int RoleMemberCount(UUID groupID, UUID roleID) + { + return (int)m_RoleMembership.GetCount(new string[] { "GroupID", "RoleID" }, + new string[] { groupID.ToString(), roleID.ToString() }); + } + + public bool StoreRoleMember(RoleMembershipData data) + { + return m_RoleMembership.Store(data); + } + + public bool DeleteRoleMember(RoleMembershipData data) + { + return m_RoleMembership.Delete(new string[] { "GroupID", "RoleID", "PrincipalID"}, + new string[] { data.GroupID.ToString(), data.RoleID.ToString(), data.PrincipalID }); + } + + public bool DeleteMemberAllRoles(UUID groupID, string principalID) + { + return m_RoleMembership.Delete(new string[] { "GroupID", "PrincipalID" }, + new string[] { groupID.ToString(), principalID }); + } + + #endregion + + #region principals table + public bool StorePrincipal(PrincipalData data) + { + return m_Principals.Store(data); + } + + public PrincipalData RetrievePrincipal(string principalID) + { + PrincipalData[] p = m_Principals.Get("PrincipalID", principalID); + if (p != null && p.Length > 0) + return p[0]; + + return null; + } + + public bool DeletePrincipal(string principalID) + { + return m_Principals.Delete("PrincipalID", principalID); + } + #endregion + + #region invites table + + public bool StoreInvitation(InvitationData data) + { + return m_Invites.Store(data); + } + + public InvitationData RetrieveInvitation(UUID inviteID) + { + InvitationData[] invites = m_Invites.Get("InviteID", inviteID.ToString()); + + if (invites != null && invites.Length > 0) + return invites[0]; + + return null; + } + + public InvitationData RetrieveInvitation(UUID groupID, string principalID) + { + InvitationData[] invites = m_Invites.Get(new string[] { "GroupID", "PrincipalID" }, + new string[] { groupID.ToString(), principalID }); + + if (invites != null && invites.Length > 0) + return invites[0]; + + return null; + } + + public bool DeleteInvite(UUID inviteID) + { + return m_Invites.Delete("InviteID", inviteID.ToString()); + } + + public void DeleteOldInvites() + { + m_Invites.DeleteOld(); + } + + #endregion + + #region notices table + + public bool StoreNotice(NoticeData data) + { + return m_Notices.Store(data); + } + + public NoticeData RetrieveNotice(UUID noticeID) + { + NoticeData[] notices = m_Notices.Get("NoticeID", noticeID.ToString()); + + if (notices != null && notices.Length > 0) + return notices[0]; + + return null; + } + + public NoticeData[] RetrieveNotices(UUID groupID) + { + NoticeData[] notices = m_Notices.Get("GroupID", groupID.ToString()); + + return notices; + } + + public bool DeleteNotice(UUID noticeID) + { + return m_Notices.Delete("NoticeID", noticeID.ToString()); + } + + public void DeleteOldNotices() + { + m_Notices.DeleteOld(); + } + + #endregion + + #region combinations + public MembershipData RetrievePrincipalGroupMembership(string principalID, UUID groupID) + { + // TODO + return null; + } + public MembershipData[] RetrievePrincipalGroupMemberships(string principalID) + { + // TODO + return null; + } + + #endregion + } + + public class MySqlGroupsGroupsHandler : MySQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public MySqlGroupsGroupsHandler(string connectionString, string realm, string store) + : base(connectionString, realm, store) + { + } + + } + + public class MySqlGroupsMembershipHandler : MySQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public MySqlGroupsMembershipHandler(string connectionString, string realm) + : base(connectionString, realm, string.Empty) + { + } + + } + + public class MySqlGroupsRolesHandler : MySQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public MySqlGroupsRolesHandler(string connectionString, string realm) + : base(connectionString, realm, string.Empty) + { + } + + } + + public class MySqlGroupsRoleMembershipHandler : MySQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public MySqlGroupsRoleMembershipHandler(string connectionString, string realm) + : base(connectionString, realm, string.Empty) + { + } + + } + + public class MySqlGroupsInvitesHandler : MySQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public MySqlGroupsInvitesHandler(string connectionString, string realm) + : base(connectionString, realm, string.Empty) + { + } + + public void DeleteOld() + { + uint now = (uint)Util.UnixTimeSinceEpoch(); + + using (MySqlCommand cmd = new MySqlCommand()) + { + cmd.CommandText = String.Format("delete from {0} where TMStamp < ?tstamp", m_Realm); + cmd.Parameters.AddWithValue("?tstamp", now - 14 * 24 * 60 * 60); // > 2 weeks old + + ExecuteNonQuery(cmd); + } + + } + } + + public class MySqlGroupsNoticesHandler : MySQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public MySqlGroupsNoticesHandler(string connectionString, string realm) + : base(connectionString, realm, string.Empty) + { + } + + public void DeleteOld() + { + uint now = (uint)Util.UnixTimeSinceEpoch(); + + using (MySqlCommand cmd = new MySqlCommand()) + { + cmd.CommandText = String.Format("delete from {0} where TMStamp < ?tstamp", m_Realm); + cmd.Parameters.AddWithValue("?tstamp", now - 14 * 24 * 60 * 60); // > 2 weeks old + + ExecuteNonQuery(cmd); + } + + } + } + + public class MySqlGroupsPrincipalsHandler : MySQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public MySqlGroupsPrincipalsHandler(string connectionString, string realm) + : base(connectionString, realm, string.Empty) + { + } + } +} diff --git a/OpenSim/Data/MySQL/MySQLHGTravelData.cs b/OpenSim/Data/MySQL/MySQLHGTravelData.cs new file mode 100644 index 0000000..e81b880 --- /dev/null +++ b/OpenSim/Data/MySQL/MySQLHGTravelData.cs @@ -0,0 +1,80 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Data; +using System.Reflection; +using System.Threading; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using MySql.Data.MySqlClient; + +namespace OpenSim.Data.MySQL +{ + /// + /// A MySQL Interface for user grid data + /// + public class MySQLHGTravelData : MySQLGenericTableHandler, IHGTravelingData + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public MySQLHGTravelData(string connectionString, string realm) : base(connectionString, realm, "HGTravelStore") { } + + public HGTravelingData Get(UUID sessionID) + { + HGTravelingData[] ret = Get("SessionID", sessionID.ToString()); + + if (ret.Length == 0) + return null; + + return ret[0]; + } + + public HGTravelingData[] GetSessions(UUID userID) + { + return base.Get("UserID", userID.ToString()); + } + + public bool Delete(UUID sessionID) + { + return Delete("SessionID", sessionID.ToString()); + } + + public void DeleteOld() + { + using (MySqlCommand cmd = new MySqlCommand()) + { + cmd.CommandText = String.Format("delete from {0} where TMStamp < NOW() - INTERVAL 2 DAY", m_Realm); + + ExecuteNonQuery(cmd); + } + + } + } +} \ No newline at end of file diff --git a/OpenSim/Data/MySQL/MySQLOfflineIMData.cs b/OpenSim/Data/MySQL/MySQLOfflineIMData.cs new file mode 100644 index 0000000..bafd204 --- /dev/null +++ b/OpenSim/Data/MySQL/MySQLOfflineIMData.cs @@ -0,0 +1,59 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +using OpenSim.Framework; +using OpenSim.Data.MySQL; + +using OpenMetaverse; +using MySql.Data.MySqlClient; + +namespace OpenSim.Data.MySQL +{ + public class MySQLOfflineIMData : MySQLGenericTableHandler, IOfflineIMData + { + public MySQLOfflineIMData(string connectionString, string realm) + : base(connectionString, realm, "IM_Store") + { + } + + public void DeleteOld() + { + using (MySqlCommand cmd = new MySqlCommand()) + { + cmd.CommandText = String.Format("delete from {0} where TMStamp < NOW() - INTERVAL 2 WEEK", m_Realm); + + ExecuteNonQuery(cmd); + } + + } + } +} diff --git a/OpenSim/Data/MySQL/MySQLRegionData.cs b/OpenSim/Data/MySQL/MySQLRegionData.cs index a2d4ae4..2ad7590 100644 --- a/OpenSim/Data/MySQL/MySQLRegionData.cs +++ b/OpenSim/Data/MySQL/MySQLRegionData.cs @@ -310,6 +310,11 @@ namespace OpenSim.Data.MySQL return Get((int)RegionFlags.DefaultRegion, scopeID); } + public List GetDefaultHypergridRegions(UUID scopeID) + { + return Get((int)RegionFlags.DefaultHGRegion, scopeID); + } + public List GetFallbackRegions(UUID scopeID, int x, int y) { List regions = Get((int)RegionFlags.FallbackRegion, scopeID); diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index d562783..bb0ab75 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -48,8 +48,18 @@ namespace OpenSim.Data.MySQL public class MySQLSimulationData : ISimulationDataStore { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static string LogHeader = "[REGION DB MYSQL]"; private string m_connectionString; + + /// + /// This lock was being used to serialize database operations when the connection was shared, but this has + /// been unnecessary for a long time after we switched to using MySQL's underlying connection pooling instead. + /// FIXME: However, the locks remain in many places since they are effectively providing a level of + /// transactionality. This should be replaced by more efficient database transactions which would not require + /// unrelated operations to block each other or unrelated operations on the same tables from blocking each + /// other. + /// private object m_dbLock = new object(); protected virtual Assembly Assembly @@ -91,7 +101,7 @@ namespace OpenSim.Data.MySQL } catch (Exception e) { - m_log.Error("[REGION DB]: MySQL error in ExecuteReader: " + e.Message); + m_log.ErrorFormat("{0} MySQL error in ExecuteReader: {1}", LogHeader, e); throw; } @@ -119,8 +129,10 @@ namespace OpenSim.Data.MySQL // Eligibility check // - if ((flags & (uint)PrimFlags.Temporary) != 0) - return; + // PrimFlags.Temporary is not used in OpenSim code and cannot + // be guaranteed to always be clear. Don't check it. +// if ((flags & (uint)PrimFlags.Temporary) != 0) +// return; if ((flags & (uint)PrimFlags.TemporaryOnRez) != 0) return; @@ -135,7 +147,7 @@ namespace OpenSim.Data.MySQL foreach (SceneObjectPart prim in obj.Parts) { cmd.Parameters.Clear(); - + cmd.CommandText = "replace into prims (" + "UUID, CreationDate, " + "Name, Text, Description, " + @@ -171,7 +183,11 @@ namespace OpenSim.Data.MySQL "ParticleSystem, ClickAction, Material, " + "CollisionSound, CollisionSoundVolume, " + "PassTouches, " + - "LinkNumber, MediaURL) values (" + "?UUID, " + + "LinkNumber, MediaURL, AttachedPosX, " + + "AttachedPosY, AttachedPosZ, KeyframeMotion, " + + "PhysicsShapeType, Density, GravityModifier, " + + "Friction, Restitution, DynAttrs " + + ") values (" + "?UUID, " + "?CreationDate, ?Name, ?Text, " + "?Description, ?SitName, ?TouchName, " + "?ObjectFlags, ?OwnerMask, ?NextOwnerMask, " + @@ -202,14 +218,18 @@ namespace OpenSim.Data.MySQL "?SaleType, ?ColorR, ?ColorG, " + "?ColorB, ?ColorA, ?ParticleSystem, " + "?ClickAction, ?Material, ?CollisionSound, " + - "?CollisionSoundVolume, ?PassTouches, ?LinkNumber, ?MediaURL)"; - + "?CollisionSoundVolume, ?PassTouches, " + + "?LinkNumber, ?MediaURL, ?AttachedPosX, " + + "?AttachedPosY, ?AttachedPosZ, ?KeyframeMotion, " + + "?PhysicsShapeType, ?Density, ?GravityModifier, " + + "?Friction, ?Restitution, ?DynAttrs)"; + FillPrimCommand(cmd, prim, obj.UUID, regionUUID); - + ExecuteNonQuery(cmd); - + cmd.Parameters.Clear(); - + cmd.CommandText = "replace into primshapes (" + "UUID, Shape, ScaleX, ScaleY, " + "ScaleZ, PCode, PathBegin, PathEnd, " + @@ -219,7 +239,8 @@ namespace OpenSim.Data.MySQL "PathTaperX, PathTaperY, PathTwist, " + "PathTwistBegin, ProfileBegin, ProfileEnd, " + "ProfileCurve, ProfileHollow, Texture, " + - "ExtraParams, State, Media) values (?UUID, " + + "ExtraParams, State, LastAttachPoint, Media) " + + "values (?UUID, " + "?Shape, ?ScaleX, ?ScaleY, ?ScaleZ, " + "?PCode, ?PathBegin, ?PathEnd, " + "?PathScaleX, ?PathScaleY, " + @@ -230,10 +251,10 @@ namespace OpenSim.Data.MySQL "?PathTwistBegin, ?ProfileBegin, " + "?ProfileEnd, ?ProfileCurve, " + "?ProfileHollow, ?Texture, ?ExtraParams, " + - "?State, ?Media)"; - + "?State, ?LastAttachPoint, ?Media)"; + FillShapeCommand(cmd, prim); - + ExecuteNonQuery(cmd); } } @@ -446,7 +467,9 @@ namespace OpenSim.Data.MySQL foreach (SceneObjectPart prim in prims.Values) { if (prim.ParentUUID == UUID.Zero) + { objects[prim.UUID] = new SceneObjectGroup(prim); + } } // Add all of the children objects to the SOGs @@ -559,10 +582,14 @@ namespace OpenSim.Data.MySQL } } + // Legacy entry point for when terrain was always a 256x256 hieghtmap public void StoreTerrain(double[,] ter, UUID regionID) { - m_log.Info("[REGION DB]: Storing terrain"); + StoreTerrain(new HeightmapTerrainData(ter), regionID); + } + public void StoreTerrain(TerrainData terrData, UUID regionID) + { lock (m_dbLock) { using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) @@ -576,11 +603,18 @@ namespace OpenSim.Data.MySQL ExecuteNonQuery(cmd); - cmd.CommandText = "insert into terrain (RegionUUID, " + - "Revision, Heightfield) values (?RegionUUID, " + - "1, ?Heightfield)"; + int terrainDBRevision; + Array terrainDBblob; + terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob); + + m_log.InfoFormat("{0} Storing terrain. X={1}, Y={2}, rev={3}", + LogHeader, terrData.SizeX, terrData.SizeY, terrainDBRevision); - cmd.Parameters.AddWithValue("Heightfield", SerializeTerrain(ter)); + cmd.CommandText = "insert into terrain (RegionUUID, Revision, Heightfield)" + + "values (?RegionUUID, ?Revision, ?Heightfield)"; + + cmd.Parameters.AddWithValue("Revision", terrainDBRevision); + cmd.Parameters.AddWithValue("Heightfield", terrainDBblob); ExecuteNonQuery(cmd); } @@ -588,9 +622,20 @@ namespace OpenSim.Data.MySQL } } + // Legacy region loading public double[,] LoadTerrain(UUID regionID) { - double[,] terrain = null; + double[,] ret = null; + TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight); + if (terrData != null) + ret = terrData.GetDoubles(); + return ret; + } + + // Returns 'null' if region not found + public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ) + { + TerrainData terrData = null; lock (m_dbLock) { @@ -610,32 +655,15 @@ namespace OpenSim.Data.MySQL while (reader.Read()) { int rev = Convert.ToInt32(reader["Revision"]); - - terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize]; - terrain.Initialize(); - - using (MemoryStream mstr = new MemoryStream((byte[])reader["Heightfield"])) - { - using (BinaryReader br = new BinaryReader(mstr)) - { - for (int x = 0; x < (int)Constants.RegionSize; x++) - { - for (int y = 0; y < (int)Constants.RegionSize; y++) - { - terrain[x, y] = br.ReadDouble(); - } - } - } - - m_log.InfoFormat("[REGION DB]: Loaded terrain revision r{0}", rev); - } + byte[] blob = (byte[])reader["Heightfield"]; + terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob); } } } } } - return terrain; + return terrData; } public void RemoveLandObject(UUID globalID) @@ -676,7 +704,7 @@ namespace OpenSim.Data.MySQL "MusicURL, PassHours, PassPrice, SnapshotUUID, " + "UserLocationX, UserLocationY, UserLocationZ, " + "UserLookAtX, UserLookAtY, UserLookAtZ, " + - "AuthbuyerID, OtherCleanTime, MediaType, MediaDescription, " + + "AuthbuyerID, OtherCleanTime, Dwell, MediaType, MediaDescription, " + "MediaSize, MediaLoop, ObscureMusic, ObscureMedia) values (" + "?UUID, ?RegionUUID, " + "?LocalLandID, ?Bitmap, ?Name, ?Description, " + @@ -687,7 +715,7 @@ namespace OpenSim.Data.MySQL "?MusicURL, ?PassHours, ?PassPrice, ?SnapshotUUID, " + "?UserLocationX, ?UserLocationY, ?UserLocationZ, " + "?UserLookAtX, ?UserLookAtY, ?UserLookAtZ, " + - "?AuthbuyerID, ?OtherCleanTime, ?MediaType, ?MediaDescription, "+ + "?AuthbuyerID, ?OtherCleanTime, ?Dwell, ?MediaType, ?MediaDescription, "+ "CONCAT(?MediaWidth, ',', ?MediaHeight), ?MediaLoop, ?ObscureMusic, ?ObscureMedia)"; FillLandCommand(cmd, parcel.LandData, parcel.RegionUUID); @@ -719,95 +747,92 @@ namespace OpenSim.Data.MySQL RegionLightShareData nWP = new RegionLightShareData(); nWP.OnSave += StoreRegionWindlightSettings; - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + dbcon.Open(); + + string command = "select * from `regionwindlight` where region_id = ?regionID"; + + using (MySqlCommand cmd = new MySqlCommand(command)) { - dbcon.Open(); - - string command = "select * from `regionwindlight` where region_id = ?regionID"; - - using (MySqlCommand cmd = new MySqlCommand(command)) + cmd.Connection = dbcon; + + cmd.Parameters.AddWithValue("?regionID", regionUUID.ToString()); + + IDataReader result = ExecuteReader(cmd); + if (!result.Read()) { - cmd.Connection = dbcon; - - cmd.Parameters.AddWithValue("?regionID", regionUUID.ToString()); - - IDataReader result = ExecuteReader(cmd); - if (!result.Read()) - { - //No result, so store our default windlight profile and return it - nWP.regionID = regionUUID; - StoreRegionWindlightSettings(nWP); - return nWP; - } - else - { - nWP.regionID = DBGuid.FromDB(result["region_id"]); - nWP.waterColor.X = Convert.ToSingle(result["water_color_r"]); - nWP.waterColor.Y = Convert.ToSingle(result["water_color_g"]); - nWP.waterColor.Z = Convert.ToSingle(result["water_color_b"]); - nWP.waterFogDensityExponent = Convert.ToSingle(result["water_fog_density_exponent"]); - nWP.underwaterFogModifier = Convert.ToSingle(result["underwater_fog_modifier"]); - nWP.reflectionWaveletScale.X = Convert.ToSingle(result["reflection_wavelet_scale_1"]); - nWP.reflectionWaveletScale.Y = Convert.ToSingle(result["reflection_wavelet_scale_2"]); - nWP.reflectionWaveletScale.Z = Convert.ToSingle(result["reflection_wavelet_scale_3"]); - nWP.fresnelScale = Convert.ToSingle(result["fresnel_scale"]); - nWP.fresnelOffset = Convert.ToSingle(result["fresnel_offset"]); - nWP.refractScaleAbove = Convert.ToSingle(result["refract_scale_above"]); - nWP.refractScaleBelow = Convert.ToSingle(result["refract_scale_below"]); - nWP.blurMultiplier = Convert.ToSingle(result["blur_multiplier"]); - nWP.bigWaveDirection.X = Convert.ToSingle(result["big_wave_direction_x"]); - nWP.bigWaveDirection.Y = Convert.ToSingle(result["big_wave_direction_y"]); - nWP.littleWaveDirection.X = Convert.ToSingle(result["little_wave_direction_x"]); - nWP.littleWaveDirection.Y = Convert.ToSingle(result["little_wave_direction_y"]); - UUID.TryParse(result["normal_map_texture"].ToString(), out nWP.normalMapTexture); - nWP.horizon.X = Convert.ToSingle(result["horizon_r"]); - nWP.horizon.Y = Convert.ToSingle(result["horizon_g"]); - nWP.horizon.Z = Convert.ToSingle(result["horizon_b"]); - nWP.horizon.W = Convert.ToSingle(result["horizon_i"]); - nWP.hazeHorizon = Convert.ToSingle(result["haze_horizon"]); - nWP.blueDensity.X = Convert.ToSingle(result["blue_density_r"]); - nWP.blueDensity.Y = Convert.ToSingle(result["blue_density_g"]); - nWP.blueDensity.Z = Convert.ToSingle(result["blue_density_b"]); - nWP.blueDensity.W = Convert.ToSingle(result["blue_density_i"]); - nWP.hazeDensity = Convert.ToSingle(result["haze_density"]); - nWP.densityMultiplier = Convert.ToSingle(result["density_multiplier"]); - nWP.distanceMultiplier = Convert.ToSingle(result["distance_multiplier"]); - nWP.maxAltitude = Convert.ToUInt16(result["max_altitude"]); - nWP.sunMoonColor.X = Convert.ToSingle(result["sun_moon_color_r"]); - nWP.sunMoonColor.Y = Convert.ToSingle(result["sun_moon_color_g"]); - nWP.sunMoonColor.Z = Convert.ToSingle(result["sun_moon_color_b"]); - nWP.sunMoonColor.W = Convert.ToSingle(result["sun_moon_color_i"]); - nWP.sunMoonPosition = Convert.ToSingle(result["sun_moon_position"]); - nWP.ambient.X = Convert.ToSingle(result["ambient_r"]); - nWP.ambient.Y = Convert.ToSingle(result["ambient_g"]); - nWP.ambient.Z = Convert.ToSingle(result["ambient_b"]); - nWP.ambient.W = Convert.ToSingle(result["ambient_i"]); - nWP.eastAngle = Convert.ToSingle(result["east_angle"]); - nWP.sunGlowFocus = Convert.ToSingle(result["sun_glow_focus"]); - nWP.sunGlowSize = Convert.ToSingle(result["sun_glow_size"]); - nWP.sceneGamma = Convert.ToSingle(result["scene_gamma"]); - nWP.starBrightness = Convert.ToSingle(result["star_brightness"]); - nWP.cloudColor.X = Convert.ToSingle(result["cloud_color_r"]); - nWP.cloudColor.Y = Convert.ToSingle(result["cloud_color_g"]); - nWP.cloudColor.Z = Convert.ToSingle(result["cloud_color_b"]); - nWP.cloudColor.W = Convert.ToSingle(result["cloud_color_i"]); - nWP.cloudXYDensity.X = Convert.ToSingle(result["cloud_x"]); - nWP.cloudXYDensity.Y = Convert.ToSingle(result["cloud_y"]); - nWP.cloudXYDensity.Z = Convert.ToSingle(result["cloud_density"]); - nWP.cloudCoverage = Convert.ToSingle(result["cloud_coverage"]); - nWP.cloudScale = Convert.ToSingle(result["cloud_scale"]); - nWP.cloudDetailXYDensity.X = Convert.ToSingle(result["cloud_detail_x"]); - nWP.cloudDetailXYDensity.Y = Convert.ToSingle(result["cloud_detail_y"]); - nWP.cloudDetailXYDensity.Z = Convert.ToSingle(result["cloud_detail_density"]); - nWP.cloudScrollX = Convert.ToSingle(result["cloud_scroll_x"]); - nWP.cloudScrollXLock = Convert.ToBoolean(result["cloud_scroll_x_lock"]); - nWP.cloudScrollY = Convert.ToSingle(result["cloud_scroll_y"]); - nWP.cloudScrollYLock = Convert.ToBoolean(result["cloud_scroll_y_lock"]); - nWP.drawClassicClouds = Convert.ToBoolean(result["draw_classic_clouds"]); - nWP.valid = true; - } + //No result, so store our default windlight profile and return it + nWP.regionID = regionUUID; +// StoreRegionWindlightSettings(nWP); + return nWP; + } + else + { + nWP.regionID = DBGuid.FromDB(result["region_id"]); + nWP.waterColor.X = Convert.ToSingle(result["water_color_r"]); + nWP.waterColor.Y = Convert.ToSingle(result["water_color_g"]); + nWP.waterColor.Z = Convert.ToSingle(result["water_color_b"]); + nWP.waterFogDensityExponent = Convert.ToSingle(result["water_fog_density_exponent"]); + nWP.underwaterFogModifier = Convert.ToSingle(result["underwater_fog_modifier"]); + nWP.reflectionWaveletScale.X = Convert.ToSingle(result["reflection_wavelet_scale_1"]); + nWP.reflectionWaveletScale.Y = Convert.ToSingle(result["reflection_wavelet_scale_2"]); + nWP.reflectionWaveletScale.Z = Convert.ToSingle(result["reflection_wavelet_scale_3"]); + nWP.fresnelScale = Convert.ToSingle(result["fresnel_scale"]); + nWP.fresnelOffset = Convert.ToSingle(result["fresnel_offset"]); + nWP.refractScaleAbove = Convert.ToSingle(result["refract_scale_above"]); + nWP.refractScaleBelow = Convert.ToSingle(result["refract_scale_below"]); + nWP.blurMultiplier = Convert.ToSingle(result["blur_multiplier"]); + nWP.bigWaveDirection.X = Convert.ToSingle(result["big_wave_direction_x"]); + nWP.bigWaveDirection.Y = Convert.ToSingle(result["big_wave_direction_y"]); + nWP.littleWaveDirection.X = Convert.ToSingle(result["little_wave_direction_x"]); + nWP.littleWaveDirection.Y = Convert.ToSingle(result["little_wave_direction_y"]); + UUID.TryParse(result["normal_map_texture"].ToString(), out nWP.normalMapTexture); + nWP.horizon.X = Convert.ToSingle(result["horizon_r"]); + nWP.horizon.Y = Convert.ToSingle(result["horizon_g"]); + nWP.horizon.Z = Convert.ToSingle(result["horizon_b"]); + nWP.horizon.W = Convert.ToSingle(result["horizon_i"]); + nWP.hazeHorizon = Convert.ToSingle(result["haze_horizon"]); + nWP.blueDensity.X = Convert.ToSingle(result["blue_density_r"]); + nWP.blueDensity.Y = Convert.ToSingle(result["blue_density_g"]); + nWP.blueDensity.Z = Convert.ToSingle(result["blue_density_b"]); + nWP.blueDensity.W = Convert.ToSingle(result["blue_density_i"]); + nWP.hazeDensity = Convert.ToSingle(result["haze_density"]); + nWP.densityMultiplier = Convert.ToSingle(result["density_multiplier"]); + nWP.distanceMultiplier = Convert.ToSingle(result["distance_multiplier"]); + nWP.maxAltitude = Convert.ToUInt16(result["max_altitude"]); + nWP.sunMoonColor.X = Convert.ToSingle(result["sun_moon_color_r"]); + nWP.sunMoonColor.Y = Convert.ToSingle(result["sun_moon_color_g"]); + nWP.sunMoonColor.Z = Convert.ToSingle(result["sun_moon_color_b"]); + nWP.sunMoonColor.W = Convert.ToSingle(result["sun_moon_color_i"]); + nWP.sunMoonPosition = Convert.ToSingle(result["sun_moon_position"]); + nWP.ambient.X = Convert.ToSingle(result["ambient_r"]); + nWP.ambient.Y = Convert.ToSingle(result["ambient_g"]); + nWP.ambient.Z = Convert.ToSingle(result["ambient_b"]); + nWP.ambient.W = Convert.ToSingle(result["ambient_i"]); + nWP.eastAngle = Convert.ToSingle(result["east_angle"]); + nWP.sunGlowFocus = Convert.ToSingle(result["sun_glow_focus"]); + nWP.sunGlowSize = Convert.ToSingle(result["sun_glow_size"]); + nWP.sceneGamma = Convert.ToSingle(result["scene_gamma"]); + nWP.starBrightness = Convert.ToSingle(result["star_brightness"]); + nWP.cloudColor.X = Convert.ToSingle(result["cloud_color_r"]); + nWP.cloudColor.Y = Convert.ToSingle(result["cloud_color_g"]); + nWP.cloudColor.Z = Convert.ToSingle(result["cloud_color_b"]); + nWP.cloudColor.W = Convert.ToSingle(result["cloud_color_i"]); + nWP.cloudXYDensity.X = Convert.ToSingle(result["cloud_x"]); + nWP.cloudXYDensity.Y = Convert.ToSingle(result["cloud_y"]); + nWP.cloudXYDensity.Z = Convert.ToSingle(result["cloud_density"]); + nWP.cloudCoverage = Convert.ToSingle(result["cloud_coverage"]); + nWP.cloudScale = Convert.ToSingle(result["cloud_scale"]); + nWP.cloudDetailXYDensity.X = Convert.ToSingle(result["cloud_detail_x"]); + nWP.cloudDetailXYDensity.Y = Convert.ToSingle(result["cloud_detail_y"]); + nWP.cloudDetailXYDensity.Z = Convert.ToSingle(result["cloud_detail_density"]); + nWP.cloudScrollX = Convert.ToSingle(result["cloud_scroll_x"]); + nWP.cloudScrollXLock = Convert.ToBoolean(result["cloud_scroll_x_lock"]); + nWP.cloudScrollY = Convert.ToSingle(result["cloud_scroll_y"]); + nWP.cloudScrollYLock = Convert.ToBoolean(result["cloud_scroll_y_lock"]); + nWP.drawClassicClouds = Convert.ToBoolean(result["draw_classic_clouds"]); + nWP.valid = true; } } } @@ -857,124 +882,118 @@ namespace OpenSim.Data.MySQL public void StoreRegionWindlightSettings(RegionLightShareData wl) { - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + dbcon.Open(); + + using (MySqlCommand cmd = dbcon.CreateCommand()) { - dbcon.Open(); - - using (MySqlCommand cmd = dbcon.CreateCommand()) - { - cmd.CommandText = "REPLACE INTO `regionwindlight` (`region_id`, `water_color_r`, `water_color_g`, "; - cmd.CommandText += "`water_color_b`, `water_fog_density_exponent`, `underwater_fog_modifier`, "; - cmd.CommandText += "`reflection_wavelet_scale_1`, `reflection_wavelet_scale_2`, `reflection_wavelet_scale_3`, "; - cmd.CommandText += "`fresnel_scale`, `fresnel_offset`, `refract_scale_above`, `refract_scale_below`, "; - cmd.CommandText += "`blur_multiplier`, `big_wave_direction_x`, `big_wave_direction_y`, `little_wave_direction_x`, "; - cmd.CommandText += "`little_wave_direction_y`, `normal_map_texture`, `horizon_r`, `horizon_g`, `horizon_b`, "; - cmd.CommandText += "`horizon_i`, `haze_horizon`, `blue_density_r`, `blue_density_g`, `blue_density_b`, "; - cmd.CommandText += "`blue_density_i`, `haze_density`, `density_multiplier`, `distance_multiplier`, `max_altitude`, "; - cmd.CommandText += "`sun_moon_color_r`, `sun_moon_color_g`, `sun_moon_color_b`, `sun_moon_color_i`, `sun_moon_position`, "; - cmd.CommandText += "`ambient_r`, `ambient_g`, `ambient_b`, `ambient_i`, `east_angle`, `sun_glow_focus`, `sun_glow_size`, "; - cmd.CommandText += "`scene_gamma`, `star_brightness`, `cloud_color_r`, `cloud_color_g`, `cloud_color_b`, `cloud_color_i`, "; - cmd.CommandText += "`cloud_x`, `cloud_y`, `cloud_density`, `cloud_coverage`, `cloud_scale`, `cloud_detail_x`, "; - cmd.CommandText += "`cloud_detail_y`, `cloud_detail_density`, `cloud_scroll_x`, `cloud_scroll_x_lock`, `cloud_scroll_y`, "; - cmd.CommandText += "`cloud_scroll_y_lock`, `draw_classic_clouds`) VALUES (?region_id, ?water_color_r, "; - cmd.CommandText += "?water_color_g, ?water_color_b, ?water_fog_density_exponent, ?underwater_fog_modifier, ?reflection_wavelet_scale_1, "; - cmd.CommandText += "?reflection_wavelet_scale_2, ?reflection_wavelet_scale_3, ?fresnel_scale, ?fresnel_offset, ?refract_scale_above, "; - cmd.CommandText += "?refract_scale_below, ?blur_multiplier, ?big_wave_direction_x, ?big_wave_direction_y, ?little_wave_direction_x, "; - cmd.CommandText += "?little_wave_direction_y, ?normal_map_texture, ?horizon_r, ?horizon_g, ?horizon_b, ?horizon_i, ?haze_horizon, "; - cmd.CommandText += "?blue_density_r, ?blue_density_g, ?blue_density_b, ?blue_density_i, ?haze_density, ?density_multiplier, "; - cmd.CommandText += "?distance_multiplier, ?max_altitude, ?sun_moon_color_r, ?sun_moon_color_g, ?sun_moon_color_b, "; - cmd.CommandText += "?sun_moon_color_i, ?sun_moon_position, ?ambient_r, ?ambient_g, ?ambient_b, ?ambient_i, ?east_angle, "; - cmd.CommandText += "?sun_glow_focus, ?sun_glow_size, ?scene_gamma, ?star_brightness, ?cloud_color_r, ?cloud_color_g, "; - cmd.CommandText += "?cloud_color_b, ?cloud_color_i, ?cloud_x, ?cloud_y, ?cloud_density, ?cloud_coverage, ?cloud_scale, "; - cmd.CommandText += "?cloud_detail_x, ?cloud_detail_y, ?cloud_detail_density, ?cloud_scroll_x, ?cloud_scroll_x_lock, "; - cmd.CommandText += "?cloud_scroll_y, ?cloud_scroll_y_lock, ?draw_classic_clouds)"; - - cmd.Parameters.AddWithValue("region_id", wl.regionID); - cmd.Parameters.AddWithValue("water_color_r", wl.waterColor.X); - cmd.Parameters.AddWithValue("water_color_g", wl.waterColor.Y); - cmd.Parameters.AddWithValue("water_color_b", wl.waterColor.Z); - cmd.Parameters.AddWithValue("water_fog_density_exponent", wl.waterFogDensityExponent); - cmd.Parameters.AddWithValue("underwater_fog_modifier", wl.underwaterFogModifier); - cmd.Parameters.AddWithValue("reflection_wavelet_scale_1", wl.reflectionWaveletScale.X); - cmd.Parameters.AddWithValue("reflection_wavelet_scale_2", wl.reflectionWaveletScale.Y); - cmd.Parameters.AddWithValue("reflection_wavelet_scale_3", wl.reflectionWaveletScale.Z); - cmd.Parameters.AddWithValue("fresnel_scale", wl.fresnelScale); - cmd.Parameters.AddWithValue("fresnel_offset", wl.fresnelOffset); - cmd.Parameters.AddWithValue("refract_scale_above", wl.refractScaleAbove); - cmd.Parameters.AddWithValue("refract_scale_below", wl.refractScaleBelow); - cmd.Parameters.AddWithValue("blur_multiplier", wl.blurMultiplier); - cmd.Parameters.AddWithValue("big_wave_direction_x", wl.bigWaveDirection.X); - cmd.Parameters.AddWithValue("big_wave_direction_y", wl.bigWaveDirection.Y); - cmd.Parameters.AddWithValue("little_wave_direction_x", wl.littleWaveDirection.X); - cmd.Parameters.AddWithValue("little_wave_direction_y", wl.littleWaveDirection.Y); - cmd.Parameters.AddWithValue("normal_map_texture", wl.normalMapTexture); - cmd.Parameters.AddWithValue("horizon_r", wl.horizon.X); - cmd.Parameters.AddWithValue("horizon_g", wl.horizon.Y); - cmd.Parameters.AddWithValue("horizon_b", wl.horizon.Z); - cmd.Parameters.AddWithValue("horizon_i", wl.horizon.W); - cmd.Parameters.AddWithValue("haze_horizon", wl.hazeHorizon); - cmd.Parameters.AddWithValue("blue_density_r", wl.blueDensity.X); - cmd.Parameters.AddWithValue("blue_density_g", wl.blueDensity.Y); - cmd.Parameters.AddWithValue("blue_density_b", wl.blueDensity.Z); - cmd.Parameters.AddWithValue("blue_density_i", wl.blueDensity.W); - cmd.Parameters.AddWithValue("haze_density", wl.hazeDensity); - cmd.Parameters.AddWithValue("density_multiplier", wl.densityMultiplier); - cmd.Parameters.AddWithValue("distance_multiplier", wl.distanceMultiplier); - cmd.Parameters.AddWithValue("max_altitude", wl.maxAltitude); - cmd.Parameters.AddWithValue("sun_moon_color_r", wl.sunMoonColor.X); - cmd.Parameters.AddWithValue("sun_moon_color_g", wl.sunMoonColor.Y); - cmd.Parameters.AddWithValue("sun_moon_color_b", wl.sunMoonColor.Z); - cmd.Parameters.AddWithValue("sun_moon_color_i", wl.sunMoonColor.W); - cmd.Parameters.AddWithValue("sun_moon_position", wl.sunMoonPosition); - cmd.Parameters.AddWithValue("ambient_r", wl.ambient.X); - cmd.Parameters.AddWithValue("ambient_g", wl.ambient.Y); - cmd.Parameters.AddWithValue("ambient_b", wl.ambient.Z); - cmd.Parameters.AddWithValue("ambient_i", wl.ambient.W); - cmd.Parameters.AddWithValue("east_angle", wl.eastAngle); - cmd.Parameters.AddWithValue("sun_glow_focus", wl.sunGlowFocus); - cmd.Parameters.AddWithValue("sun_glow_size", wl.sunGlowSize); - cmd.Parameters.AddWithValue("scene_gamma", wl.sceneGamma); - cmd.Parameters.AddWithValue("star_brightness", wl.starBrightness); - cmd.Parameters.AddWithValue("cloud_color_r", wl.cloudColor.X); - cmd.Parameters.AddWithValue("cloud_color_g", wl.cloudColor.Y); - cmd.Parameters.AddWithValue("cloud_color_b", wl.cloudColor.Z); - cmd.Parameters.AddWithValue("cloud_color_i", wl.cloudColor.W); - cmd.Parameters.AddWithValue("cloud_x", wl.cloudXYDensity.X); - cmd.Parameters.AddWithValue("cloud_y", wl.cloudXYDensity.Y); - cmd.Parameters.AddWithValue("cloud_density", wl.cloudXYDensity.Z); - cmd.Parameters.AddWithValue("cloud_coverage", wl.cloudCoverage); - cmd.Parameters.AddWithValue("cloud_scale", wl.cloudScale); - cmd.Parameters.AddWithValue("cloud_detail_x", wl.cloudDetailXYDensity.X); - cmd.Parameters.AddWithValue("cloud_detail_y", wl.cloudDetailXYDensity.Y); - cmd.Parameters.AddWithValue("cloud_detail_density", wl.cloudDetailXYDensity.Z); - cmd.Parameters.AddWithValue("cloud_scroll_x", wl.cloudScrollX); - cmd.Parameters.AddWithValue("cloud_scroll_x_lock", wl.cloudScrollXLock); - cmd.Parameters.AddWithValue("cloud_scroll_y", wl.cloudScrollY); - cmd.Parameters.AddWithValue("cloud_scroll_y_lock", wl.cloudScrollYLock); - cmd.Parameters.AddWithValue("draw_classic_clouds", wl.drawClassicClouds); - - ExecuteNonQuery(cmd); - } + cmd.CommandText = "REPLACE INTO `regionwindlight` (`region_id`, `water_color_r`, `water_color_g`, "; + cmd.CommandText += "`water_color_b`, `water_fog_density_exponent`, `underwater_fog_modifier`, "; + cmd.CommandText += "`reflection_wavelet_scale_1`, `reflection_wavelet_scale_2`, `reflection_wavelet_scale_3`, "; + cmd.CommandText += "`fresnel_scale`, `fresnel_offset`, `refract_scale_above`, `refract_scale_below`, "; + cmd.CommandText += "`blur_multiplier`, `big_wave_direction_x`, `big_wave_direction_y`, `little_wave_direction_x`, "; + cmd.CommandText += "`little_wave_direction_y`, `normal_map_texture`, `horizon_r`, `horizon_g`, `horizon_b`, "; + cmd.CommandText += "`horizon_i`, `haze_horizon`, `blue_density_r`, `blue_density_g`, `blue_density_b`, "; + cmd.CommandText += "`blue_density_i`, `haze_density`, `density_multiplier`, `distance_multiplier`, `max_altitude`, "; + cmd.CommandText += "`sun_moon_color_r`, `sun_moon_color_g`, `sun_moon_color_b`, `sun_moon_color_i`, `sun_moon_position`, "; + cmd.CommandText += "`ambient_r`, `ambient_g`, `ambient_b`, `ambient_i`, `east_angle`, `sun_glow_focus`, `sun_glow_size`, "; + cmd.CommandText += "`scene_gamma`, `star_brightness`, `cloud_color_r`, `cloud_color_g`, `cloud_color_b`, `cloud_color_i`, "; + cmd.CommandText += "`cloud_x`, `cloud_y`, `cloud_density`, `cloud_coverage`, `cloud_scale`, `cloud_detail_x`, "; + cmd.CommandText += "`cloud_detail_y`, `cloud_detail_density`, `cloud_scroll_x`, `cloud_scroll_x_lock`, `cloud_scroll_y`, "; + cmd.CommandText += "`cloud_scroll_y_lock`, `draw_classic_clouds`) VALUES (?region_id, ?water_color_r, "; + cmd.CommandText += "?water_color_g, ?water_color_b, ?water_fog_density_exponent, ?underwater_fog_modifier, ?reflection_wavelet_scale_1, "; + cmd.CommandText += "?reflection_wavelet_scale_2, ?reflection_wavelet_scale_3, ?fresnel_scale, ?fresnel_offset, ?refract_scale_above, "; + cmd.CommandText += "?refract_scale_below, ?blur_multiplier, ?big_wave_direction_x, ?big_wave_direction_y, ?little_wave_direction_x, "; + cmd.CommandText += "?little_wave_direction_y, ?normal_map_texture, ?horizon_r, ?horizon_g, ?horizon_b, ?horizon_i, ?haze_horizon, "; + cmd.CommandText += "?blue_density_r, ?blue_density_g, ?blue_density_b, ?blue_density_i, ?haze_density, ?density_multiplier, "; + cmd.CommandText += "?distance_multiplier, ?max_altitude, ?sun_moon_color_r, ?sun_moon_color_g, ?sun_moon_color_b, "; + cmd.CommandText += "?sun_moon_color_i, ?sun_moon_position, ?ambient_r, ?ambient_g, ?ambient_b, ?ambient_i, ?east_angle, "; + cmd.CommandText += "?sun_glow_focus, ?sun_glow_size, ?scene_gamma, ?star_brightness, ?cloud_color_r, ?cloud_color_g, "; + cmd.CommandText += "?cloud_color_b, ?cloud_color_i, ?cloud_x, ?cloud_y, ?cloud_density, ?cloud_coverage, ?cloud_scale, "; + cmd.CommandText += "?cloud_detail_x, ?cloud_detail_y, ?cloud_detail_density, ?cloud_scroll_x, ?cloud_scroll_x_lock, "; + cmd.CommandText += "?cloud_scroll_y, ?cloud_scroll_y_lock, ?draw_classic_clouds)"; + + cmd.Parameters.AddWithValue("region_id", wl.regionID); + cmd.Parameters.AddWithValue("water_color_r", wl.waterColor.X); + cmd.Parameters.AddWithValue("water_color_g", wl.waterColor.Y); + cmd.Parameters.AddWithValue("water_color_b", wl.waterColor.Z); + cmd.Parameters.AddWithValue("water_fog_density_exponent", wl.waterFogDensityExponent); + cmd.Parameters.AddWithValue("underwater_fog_modifier", wl.underwaterFogModifier); + cmd.Parameters.AddWithValue("reflection_wavelet_scale_1", wl.reflectionWaveletScale.X); + cmd.Parameters.AddWithValue("reflection_wavelet_scale_2", wl.reflectionWaveletScale.Y); + cmd.Parameters.AddWithValue("reflection_wavelet_scale_3", wl.reflectionWaveletScale.Z); + cmd.Parameters.AddWithValue("fresnel_scale", wl.fresnelScale); + cmd.Parameters.AddWithValue("fresnel_offset", wl.fresnelOffset); + cmd.Parameters.AddWithValue("refract_scale_above", wl.refractScaleAbove); + cmd.Parameters.AddWithValue("refract_scale_below", wl.refractScaleBelow); + cmd.Parameters.AddWithValue("blur_multiplier", wl.blurMultiplier); + cmd.Parameters.AddWithValue("big_wave_direction_x", wl.bigWaveDirection.X); + cmd.Parameters.AddWithValue("big_wave_direction_y", wl.bigWaveDirection.Y); + cmd.Parameters.AddWithValue("little_wave_direction_x", wl.littleWaveDirection.X); + cmd.Parameters.AddWithValue("little_wave_direction_y", wl.littleWaveDirection.Y); + cmd.Parameters.AddWithValue("normal_map_texture", wl.normalMapTexture); + cmd.Parameters.AddWithValue("horizon_r", wl.horizon.X); + cmd.Parameters.AddWithValue("horizon_g", wl.horizon.Y); + cmd.Parameters.AddWithValue("horizon_b", wl.horizon.Z); + cmd.Parameters.AddWithValue("horizon_i", wl.horizon.W); + cmd.Parameters.AddWithValue("haze_horizon", wl.hazeHorizon); + cmd.Parameters.AddWithValue("blue_density_r", wl.blueDensity.X); + cmd.Parameters.AddWithValue("blue_density_g", wl.blueDensity.Y); + cmd.Parameters.AddWithValue("blue_density_b", wl.blueDensity.Z); + cmd.Parameters.AddWithValue("blue_density_i", wl.blueDensity.W); + cmd.Parameters.AddWithValue("haze_density", wl.hazeDensity); + cmd.Parameters.AddWithValue("density_multiplier", wl.densityMultiplier); + cmd.Parameters.AddWithValue("distance_multiplier", wl.distanceMultiplier); + cmd.Parameters.AddWithValue("max_altitude", wl.maxAltitude); + cmd.Parameters.AddWithValue("sun_moon_color_r", wl.sunMoonColor.X); + cmd.Parameters.AddWithValue("sun_moon_color_g", wl.sunMoonColor.Y); + cmd.Parameters.AddWithValue("sun_moon_color_b", wl.sunMoonColor.Z); + cmd.Parameters.AddWithValue("sun_moon_color_i", wl.sunMoonColor.W); + cmd.Parameters.AddWithValue("sun_moon_position", wl.sunMoonPosition); + cmd.Parameters.AddWithValue("ambient_r", wl.ambient.X); + cmd.Parameters.AddWithValue("ambient_g", wl.ambient.Y); + cmd.Parameters.AddWithValue("ambient_b", wl.ambient.Z); + cmd.Parameters.AddWithValue("ambient_i", wl.ambient.W); + cmd.Parameters.AddWithValue("east_angle", wl.eastAngle); + cmd.Parameters.AddWithValue("sun_glow_focus", wl.sunGlowFocus); + cmd.Parameters.AddWithValue("sun_glow_size", wl.sunGlowSize); + cmd.Parameters.AddWithValue("scene_gamma", wl.sceneGamma); + cmd.Parameters.AddWithValue("star_brightness", wl.starBrightness); + cmd.Parameters.AddWithValue("cloud_color_r", wl.cloudColor.X); + cmd.Parameters.AddWithValue("cloud_color_g", wl.cloudColor.Y); + cmd.Parameters.AddWithValue("cloud_color_b", wl.cloudColor.Z); + cmd.Parameters.AddWithValue("cloud_color_i", wl.cloudColor.W); + cmd.Parameters.AddWithValue("cloud_x", wl.cloudXYDensity.X); + cmd.Parameters.AddWithValue("cloud_y", wl.cloudXYDensity.Y); + cmd.Parameters.AddWithValue("cloud_density", wl.cloudXYDensity.Z); + cmd.Parameters.AddWithValue("cloud_coverage", wl.cloudCoverage); + cmd.Parameters.AddWithValue("cloud_scale", wl.cloudScale); + cmd.Parameters.AddWithValue("cloud_detail_x", wl.cloudDetailXYDensity.X); + cmd.Parameters.AddWithValue("cloud_detail_y", wl.cloudDetailXYDensity.Y); + cmd.Parameters.AddWithValue("cloud_detail_density", wl.cloudDetailXYDensity.Z); + cmd.Parameters.AddWithValue("cloud_scroll_x", wl.cloudScrollX); + cmd.Parameters.AddWithValue("cloud_scroll_x_lock", wl.cloudScrollXLock); + cmd.Parameters.AddWithValue("cloud_scroll_y", wl.cloudScrollY); + cmd.Parameters.AddWithValue("cloud_scroll_y_lock", wl.cloudScrollYLock); + cmd.Parameters.AddWithValue("draw_classic_clouds", wl.drawClassicClouds); + + ExecuteNonQuery(cmd); } } } public void RemoveRegionWindlightSettings(UUID regionID) { - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + dbcon.Open(); + + using (MySqlCommand cmd = dbcon.CreateCommand()) { - dbcon.Open(); - - using (MySqlCommand cmd = dbcon.CreateCommand()) - { - cmd.CommandText = "delete from `regionwindlight` where `region_id`=?regionID"; - cmd.Parameters.AddWithValue("?regionID", regionID.ToString()); - ExecuteNonQuery(cmd); - } + cmd.CommandText = "delete from `regionwindlight` where `region_id`=?regionID"; + cmd.Parameters.AddWithValue("?regionID", regionID.ToString()); + ExecuteNonQuery(cmd); } } } @@ -982,29 +1001,26 @@ namespace OpenSim.Data.MySQL #region RegionEnvironmentSettings public string LoadRegionEnvironmentSettings(UUID regionUUID) { - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + dbcon.Open(); + + string command = "select * from `regionenvironment` where region_id = ?region_id"; + + using (MySqlCommand cmd = new MySqlCommand(command)) { - dbcon.Open(); - - string command = "select * from `regionenvironment` where region_id = ?region_id"; - - using (MySqlCommand cmd = new MySqlCommand(command)) + cmd.Connection = dbcon; + + cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString()); + + IDataReader result = ExecuteReader(cmd); + if (!result.Read()) { - cmd.Connection = dbcon; - - cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString()); - - IDataReader result = ExecuteReader(cmd); - if (!result.Read()) - { - return String.Empty; - } - else - { - return Convert.ToString(result["llsd_settings"]); - } + return String.Empty; + } + else + { + return Convert.ToString(result["llsd_settings"]); } } } @@ -1012,39 +1028,33 @@ namespace OpenSim.Data.MySQL public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) { - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + dbcon.Open(); + + using (MySqlCommand cmd = dbcon.CreateCommand()) { - dbcon.Open(); - - using (MySqlCommand cmd = dbcon.CreateCommand()) - { - cmd.CommandText = "REPLACE INTO `regionenvironment` (`region_id`, `llsd_settings`) VALUES (?region_id, ?llsd_settings)"; - - cmd.Parameters.AddWithValue("region_id", regionUUID); - cmd.Parameters.AddWithValue("llsd_settings", settings); - - ExecuteNonQuery(cmd); - } + cmd.CommandText = "REPLACE INTO `regionenvironment` (`region_id`, `llsd_settings`) VALUES (?region_id, ?llsd_settings)"; + + cmd.Parameters.AddWithValue("region_id", regionUUID); + cmd.Parameters.AddWithValue("llsd_settings", settings); + + ExecuteNonQuery(cmd); } } } public void RemoveRegionEnvironmentSettings(UUID regionUUID) { - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + dbcon.Open(); + + using (MySqlCommand cmd = dbcon.CreateCommand()) { - dbcon.Open(); - - using (MySqlCommand cmd = dbcon.CreateCommand()) - { - cmd.CommandText = "delete from `regionenvironment` where region_id = ?region_id"; - cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString()); - ExecuteNonQuery(cmd); - } + cmd.CommandText = "delete from `regionenvironment` where region_id = ?region_id"; + cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString()); + ExecuteNonQuery(cmd); } } } @@ -1052,56 +1062,55 @@ namespace OpenSim.Data.MySQL public void StoreRegionSettings(RegionSettings rs) { - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) - { - dbcon.Open(); - - using (MySqlCommand cmd = dbcon.CreateCommand()) - { - cmd.CommandText = "replace into regionsettings (regionUUID, " + - "block_terraform, block_fly, allow_damage, " + - "restrict_pushing, allow_land_resell, " + - "allow_land_join_divide, block_show_in_search, " + - "agent_limit, object_bonus, maturity, " + - "disable_scripts, disable_collisions, " + - "disable_physics, terrain_texture_1, " + - "terrain_texture_2, terrain_texture_3, " + - "terrain_texture_4, elevation_1_nw, " + - "elevation_2_nw, elevation_1_ne, " + - "elevation_2_ne, elevation_1_se, " + - "elevation_2_se, elevation_1_sw, " + - "elevation_2_sw, water_height, " + - "terrain_raise_limit, terrain_lower_limit, " + - "use_estate_sun, fixed_sun, sun_position, " + - "covenant, covenant_datetime, Sandbox, sunvectorx, sunvectory, " + - "sunvectorz, loaded_creation_datetime, " + - "loaded_creation_id, map_tile_ID, " + - "TelehubObject, parcel_tile_ID) " + - "values (?RegionUUID, ?BlockTerraform, " + - "?BlockFly, ?AllowDamage, ?RestrictPushing, " + - "?AllowLandResell, ?AllowLandJoinDivide, " + - "?BlockShowInSearch, ?AgentLimit, ?ObjectBonus, " + - "?Maturity, ?DisableScripts, ?DisableCollisions, " + - "?DisablePhysics, ?TerrainTexture1, " + - "?TerrainTexture2, ?TerrainTexture3, " + - "?TerrainTexture4, ?Elevation1NW, ?Elevation2NW, " + - "?Elevation1NE, ?Elevation2NE, ?Elevation1SE, " + - "?Elevation2SE, ?Elevation1SW, ?Elevation2SW, " + - "?WaterHeight, ?TerrainRaiseLimit, " + - "?TerrainLowerLimit, ?UseEstateSun, ?FixedSun, " + - "?SunPosition, ?Covenant, ?CovenantChangedDateTime, ?Sandbox, " + - "?SunVectorX, ?SunVectorY, ?SunVectorZ, " + - "?LoadedCreationDateTime, ?LoadedCreationID, " + - "?TerrainImageID, ?TelehubObject, ?ParcelImageID) "; - - FillRegionSettingsCommand(cmd, rs); + dbcon.Open(); - ExecuteNonQuery(cmd); - } + using (MySqlCommand cmd = dbcon.CreateCommand()) + { + cmd.CommandText = "replace into regionsettings (regionUUID, " + + "block_terraform, block_fly, allow_damage, " + + "restrict_pushing, allow_land_resell, " + + "allow_land_join_divide, block_show_in_search, " + + "agent_limit, object_bonus, maturity, " + + "disable_scripts, disable_collisions, " + + "disable_physics, terrain_texture_1, " + + "terrain_texture_2, terrain_texture_3, " + + "terrain_texture_4, elevation_1_nw, " + + "elevation_2_nw, elevation_1_ne, " + + "elevation_2_ne, elevation_1_se, " + + "elevation_2_se, elevation_1_sw, " + + "elevation_2_sw, water_height, " + + "terrain_raise_limit, terrain_lower_limit, " + + "use_estate_sun, fixed_sun, sun_position, " + + "covenant, covenant_datetime, Sandbox, sunvectorx, sunvectory, " + + "sunvectorz, loaded_creation_datetime, " + + "loaded_creation_id, map_tile_ID, " + + "TelehubObject, parcel_tile_ID) " + + "values (?RegionUUID, ?BlockTerraform, " + + "?BlockFly, ?AllowDamage, ?RestrictPushing, " + + "?AllowLandResell, ?AllowLandJoinDivide, " + + "?BlockShowInSearch, ?AgentLimit, ?ObjectBonus, " + + "?Maturity, ?DisableScripts, ?DisableCollisions, " + + "?DisablePhysics, ?TerrainTexture1, " + + "?TerrainTexture2, ?TerrainTexture3, " + + "?TerrainTexture4, ?Elevation1NW, ?Elevation2NW, " + + "?Elevation1NE, ?Elevation2NE, ?Elevation1SE, " + + "?Elevation2SE, ?Elevation1SW, ?Elevation2SW, " + + "?WaterHeight, ?TerrainRaiseLimit, " + + "?TerrainLowerLimit, ?UseEstateSun, ?FixedSun, " + + "?SunPosition, ?Covenant, ?CovenantChangedDateTime, ?Sandbox, " + + "?SunVectorX, ?SunVectorY, ?SunVectorZ, " + + "?LoadedCreationDateTime, ?LoadedCreationID, " + + "?TerrainImageID, " + + "?TelehubObject, ?ParcelImageID)"; + + FillRegionSettingsCommand(cmd, rs); + + ExecuteNonQuery(cmd); } } + SaveSpawnPoints(rs); } @@ -1292,6 +1301,39 @@ namespace OpenSim.Data.MySQL if (!(row["MediaURL"] is System.DBNull)) prim.MediaUrl = (string)row["MediaURL"]; + if (!(row["AttachedPosX"] is System.DBNull)) + { + prim.AttachedPos = new Vector3( + (float)(double)row["AttachedPosX"], + (float)(double)row["AttachedPosY"], + (float)(double)row["AttachedPosZ"] + ); + } + + if (!(row["DynAttrs"] is System.DBNull)) + prim.DynAttrs = DAMap.FromXml((string)row["DynAttrs"]); + else + prim.DynAttrs = new DAMap(); + + if (!(row["KeyframeMotion"] is DBNull)) + { + Byte[] data = (byte[])row["KeyframeMotion"]; + if (data.Length > 0) + prim.KeyframeMotion = KeyframeMotion.FromData(null, data); + else + prim.KeyframeMotion = null; + } + else + { + prim.KeyframeMotion = null; + } + + prim.PhysicsShapeType = (byte)Convert.ToInt32(row["PhysicsShapeType"].ToString()); + prim.Density = (float)(double)row["Density"]; + prim.GravityModifier = (float)(double)row["GravityModifier"]; + prim.Friction = (float)(double)row["Friction"]; + prim.Restitution = (float)(double)row["Restitution"]; + return prim; } @@ -1431,6 +1473,7 @@ namespace OpenSim.Data.MySQL UUID.TryParse((string)row["AuthBuyerID"], out authedbuyer); UUID.TryParse((string)row["SnapshotUUID"], out snapshotID); newData.OtherCleanTime = Convert.ToInt32(row["OtherCleanTime"]); + newData.Dwell = Convert.ToSingle(row["Dwell"]); newData.AuthBuyerID = authedbuyer; newData.SnapshotID = snapshotID; @@ -1478,30 +1521,6 @@ namespace OpenSim.Data.MySQL } /// - /// - /// - /// - /// - private static Array SerializeTerrain(double[,] val) - { - MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize) *sizeof (double)); - BinaryWriter bw = new BinaryWriter(str); - - // TODO: COMPATIBILITY - Add byte-order conversions - for (int x = 0; x < (int)Constants.RegionSize; x++) - for (int y = 0; y < (int)Constants.RegionSize; y++) - { - double height = val[x, y]; - if (height == 0.0) - height = double.Epsilon; - - bw.Write(height); - } - - return str.ToArray(); - } - - /// /// Fill the prim command with prim values /// /// @@ -1637,6 +1656,28 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("LinkNumber", prim.LinkNum); cmd.Parameters.AddWithValue("MediaURL", prim.MediaUrl); + if (prim.AttachedPos != null) + { + cmd.Parameters.AddWithValue("AttachedPosX", (double)prim.AttachedPos.X); + cmd.Parameters.AddWithValue("AttachedPosY", (double)prim.AttachedPos.Y); + cmd.Parameters.AddWithValue("AttachedPosZ", (double)prim.AttachedPos.Z); + } + + if (prim.KeyframeMotion != null) + cmd.Parameters.AddWithValue("KeyframeMotion", prim.KeyframeMotion.Serialize()); + else + cmd.Parameters.AddWithValue("KeyframeMotion", new Byte[0]); + + if (prim.DynAttrs.CountNamespaces > 0) + cmd.Parameters.AddWithValue("DynAttrs", prim.DynAttrs.ToXml()); + else + cmd.Parameters.AddWithValue("DynAttrs", null); + + cmd.Parameters.AddWithValue("PhysicsShapeType", prim.PhysicsShapeType); + cmd.Parameters.AddWithValue("Density", (double)prim.Density); + cmd.Parameters.AddWithValue("GravityModifier", (double)prim.GravityModifier); + cmd.Parameters.AddWithValue("Friction", (double)prim.Friction); + cmd.Parameters.AddWithValue("Restitution", (double)prim.Restitution); } /// @@ -1715,6 +1756,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("LoadedCreationDateTime", settings.LoadedCreationDateTime); cmd.Parameters.AddWithValue("LoadedCreationID", settings.LoadedCreationID); cmd.Parameters.AddWithValue("TerrainImageID", settings.TerrainImageID); + cmd.Parameters.AddWithValue("ParcelImageID", settings.ParcelImageID); cmd.Parameters.AddWithValue("TelehubObject", settings.TelehubObject); } @@ -1763,6 +1805,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("UserLookAtZ", land.UserLookAt.Z); cmd.Parameters.AddWithValue("AuthBuyerID", land.AuthBuyerID); cmd.Parameters.AddWithValue("OtherCleanTime", land.OtherCleanTime); + cmd.Parameters.AddWithValue("Dwell", land.Dwell); cmd.Parameters.AddWithValue("MediaDescription", land.MediaDescription); cmd.Parameters.AddWithValue("MediaType", land.MediaType); cmd.Parameters.AddWithValue("MediaWidth", land.MediaWidth); @@ -1770,7 +1813,6 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("MediaLoop", land.MediaLoop); cmd.Parameters.AddWithValue("ObscureMusic", land.ObscureMusic); cmd.Parameters.AddWithValue("ObscureMedia", land.ObscureMedia); - } /// @@ -1826,6 +1868,7 @@ namespace OpenSim.Data.MySQL s.ExtraParams = (byte[])row["ExtraParams"]; s.State = (byte)(int)row["State"]; + s.LastAttachPoint = (byte)(int)row["LastAttachPoint"]; if (!(row["Media"] is System.DBNull)) s.Media = PrimitiveBaseShape.MediaList.FromXml((string)row["Media"]); @@ -1872,6 +1915,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("Texture", s.TextureEntry); cmd.Parameters.AddWithValue("ExtraParams", s.ExtraParams); cmd.Parameters.AddWithValue("State", s.State); + cmd.Parameters.AddWithValue("LastAttachPoint", s.LastAttachPoint); cmd.Parameters.AddWithValue("Media", null == s.Media ? null : s.Media.ToXml()); } @@ -1988,41 +2032,35 @@ namespace OpenSim.Data.MySQL public void SaveExtra(UUID regionID, string name, string val) { - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) - { - dbcon.Open(); + dbcon.Open(); - using (MySqlCommand cmd = dbcon.CreateCommand()) - { - cmd.CommandText = "replace into regionextra values (?RegionID, ?Name, ?value)"; - cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); - cmd.Parameters.AddWithValue("?Name", name); - cmd.Parameters.AddWithValue("?value", val); + using (MySqlCommand cmd = dbcon.CreateCommand()) + { + cmd.CommandText = "replace into regionextra values (?RegionID, ?Name, ?value)"; + cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); + cmd.Parameters.AddWithValue("?Name", name); + cmd.Parameters.AddWithValue("?value", val); - cmd.ExecuteNonQuery(); - } + cmd.ExecuteNonQuery(); } } } public void RemoveExtra(UUID regionID, string name) { - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) - { - dbcon.Open(); + dbcon.Open(); - using (MySqlCommand cmd = dbcon.CreateCommand()) - { - cmd.CommandText = "delete from regionextra where RegionID=?RegionID and Name=?Name"; - cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); - cmd.Parameters.AddWithValue("?Name", name); + using (MySqlCommand cmd = dbcon.CreateCommand()) + { + cmd.CommandText = "delete from regionextra where RegionID=?RegionID and Name=?Name"; + cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); + cmd.Parameters.AddWithValue("?Name", name); - cmd.ExecuteNonQuery(); - } + cmd.ExecuteNonQuery(); } } } @@ -2031,22 +2069,19 @@ namespace OpenSim.Data.MySQL { Dictionary ret = new Dictionary(); - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) - { - dbcon.Open(); + dbcon.Open(); - using (MySqlCommand cmd = dbcon.CreateCommand()) + using (MySqlCommand cmd = dbcon.CreateCommand()) + { + cmd.CommandText = "select * from regionextra where RegionID=?RegionID"; + cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); + using (IDataReader r = cmd.ExecuteReader()) { - cmd.CommandText = "select * from regionextra where RegionID=?RegionID"; - cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); - using (IDataReader r = cmd.ExecuteReader()) + while (r.Read()) { - while (r.Read()) - { - ret[r["Name"].ToString()] = r["value"].ToString(); - } + ret[r["Name"].ToString()] = r["value"].ToString(); } } } diff --git a/OpenSim/Data/MySQL/MySQLUserProfilesData.cs b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs new file mode 100644 index 0000000..b35595d --- /dev/null +++ b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs @@ -0,0 +1,1086 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Data; +using System.Reflection; +using OpenSim.Data; +using OpenSim.Framework; +using MySql.Data.MySqlClient; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using log4net; + +namespace OpenSim.Data.MySQL +{ + public class UserProfilesData: IProfilesData + { + static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + #region Properites + string ConnectionString + { + get; set; + } + + protected virtual Assembly Assembly + { + get { return GetType().Assembly; } + } + + #endregion Properties + + #region class Member Functions + public UserProfilesData(string connectionString) + { + ConnectionString = connectionString; + Init(); + } + + void Init() + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + + Migration m = new Migration(dbcon, Assembly, "UserProfiles"); + m.Update(); + } + } + #endregion Member Functions + + #region Classifieds Queries + /// + /// Gets the classified records. + /// + /// + /// Array of classified records + /// + /// + /// Creator identifier. + /// + public OSDArray GetClassifiedRecords(UUID creatorId) + { + OSDArray data = new OSDArray(); + + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + string query = "SELECT classifieduuid, name FROM classifieds WHERE creatoruuid = ?Id"; + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?Id", creatorId); + using( MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.Default)) + { + if(reader.HasRows) + { + while (reader.Read()) + { + OSDMap n = new OSDMap(); + UUID Id = UUID.Zero; + + string Name = null; + try + { + UUID.TryParse(Convert.ToString( reader["classifieduuid"]), out Id); + Name = Convert.ToString(reader["name"]); + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": UserAccount exception {0}", e.Message); + } + n.Add("classifieduuid", OSD.FromUUID(Id)); + n.Add("name", OSD.FromString(Name)); + data.Add(n); + } + } + } + } + } + return data; + } + + public bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result) + { + string query = string.Empty; + + + query += "INSERT INTO classifieds ("; + query += "`classifieduuid`,"; + query += "`creatoruuid`,"; + query += "`creationdate`,"; + query += "`expirationdate`,"; + query += "`category`,"; + query += "`name`,"; + query += "`description`,"; + query += "`parceluuid`,"; + query += "`parentestate`,"; + query += "`snapshotuuid`,"; + query += "`simname`,"; + query += "`posglobal`,"; + query += "`parcelname`,"; + query += "`classifiedflags`,"; + query += "`priceforlisting`) "; + query += "VALUES ("; + query += "?ClassifiedId,"; + query += "?CreatorId,"; + query += "?CreatedDate,"; + query += "?ExpirationDate,"; + query += "?Category,"; + query += "?Name,"; + query += "?Description,"; + query += "?ParcelId,"; + query += "?ParentEstate,"; + query += "?SnapshotId,"; + query += "?SimName,"; + query += "?GlobalPos,"; + query += "?ParcelName,"; + query += "?Flags,"; + query += "?ListingPrice ) "; + query += "ON DUPLICATE KEY UPDATE "; + query += "category=?Category, "; + query += "expirationdate=?ExpirationDate, "; + query += "name=?Name, "; + query += "description=?Description, "; + query += "parentestate=?ParentEstate, "; + query += "posglobal=?GlobalPos, "; + query += "parcelname=?ParcelName, "; + query += "classifiedflags=?Flags, "; + query += "priceforlisting=?ListingPrice, "; + query += "snapshotuuid=?SnapshotId"; + + if(string.IsNullOrEmpty(ad.ParcelName)) + ad.ParcelName = "Unknown"; + if(ad.ParcelId == null) + ad.ParcelId = UUID.Zero; + if(string.IsNullOrEmpty(ad.Description)) + ad.Description = "No Description"; + + DateTime epoch = new DateTime(1970, 1, 1); + DateTime now = DateTime.Now; + TimeSpan epochnow = now - epoch; + TimeSpan duration; + DateTime expiration; + TimeSpan epochexp; + + if(ad.Flags == 2) + { + duration = new TimeSpan(7,0,0,0); + expiration = now.Add(duration); + epochexp = expiration - epoch; + } + else + { + duration = new TimeSpan(365,0,0,0); + expiration = now.Add(duration); + epochexp = expiration - epoch; + } + ad.CreationDate = (int)epochnow.TotalSeconds; + ad.ExpirationDate = (int)epochexp.TotalSeconds; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?ClassifiedId", ad.ClassifiedId.ToString()); + cmd.Parameters.AddWithValue("?CreatorId", ad.CreatorId.ToString()); + cmd.Parameters.AddWithValue("?CreatedDate", ad.CreationDate.ToString()); + cmd.Parameters.AddWithValue("?ExpirationDate", ad.ExpirationDate.ToString()); + cmd.Parameters.AddWithValue("?Category", ad.Category.ToString()); + cmd.Parameters.AddWithValue("?Name", ad.Name.ToString()); + cmd.Parameters.AddWithValue("?Description", ad.Description.ToString()); + cmd.Parameters.AddWithValue("?ParcelId", ad.ParcelId.ToString()); + cmd.Parameters.AddWithValue("?ParentEstate", ad.ParentEstate.ToString()); + cmd.Parameters.AddWithValue("?SnapshotId", ad.SnapshotId.ToString ()); + cmd.Parameters.AddWithValue("?SimName", ad.SimName.ToString()); + cmd.Parameters.AddWithValue("?GlobalPos", ad.GlobalPos.ToString()); + cmd.Parameters.AddWithValue("?ParcelName", ad.ParcelName.ToString()); + cmd.Parameters.AddWithValue("?Flags", ad.Flags.ToString()); + cmd.Parameters.AddWithValue("?ListingPrice", ad.Price.ToString ()); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": ClassifiedesUpdate exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + + public bool DeleteClassifiedRecord(UUID recordId) + { + string query = string.Empty; + + query += "DELETE FROM classifieds WHERE "; + query += "classifieduuid = ?recordId"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?recordId", recordId.ToString()); + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": DeleteClassifiedRecord exception {0}", e.Message); + return false; + } + return true; + } + + public bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result) + { + string query = string.Empty; + + query += "SELECT * FROM classifieds WHERE "; + query += "classifieduuid = ?AdId"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?AdId", ad.ClassifiedId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if(reader.Read ()) + { + ad.CreatorId = new UUID(reader.GetGuid("creatoruuid")); + ad.ParcelId = new UUID(reader.GetGuid("parceluuid")); + ad.SnapshotId = new UUID(reader.GetGuid("snapshotuuid")); + ad.CreationDate = Convert.ToInt32(reader["creationdate"]); + ad.ExpirationDate = Convert.ToInt32(reader["expirationdate"]); + ad.ParentEstate = Convert.ToInt32(reader["parentestate"]); + ad.Flags = (byte)reader.GetUInt32("classifiedflags"); + ad.Category = reader.GetInt32("category"); + ad.Price = reader.GetInt16("priceforlisting"); + ad.Name = reader.GetString("name"); + ad.Description = reader.GetString("description"); + ad.SimName = reader.GetString("simname"); + ad.GlobalPos = reader.GetString("posglobal"); + ad.ParcelName = reader.GetString("parcelname"); + + } + } + } + dbcon.Close(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": GetPickInfo exception {0}", e.Message); + } + return true; + } + #endregion Classifieds Queries + + #region Picks Queries + public OSDArray GetAvatarPicks(UUID avatarId) + { + string query = string.Empty; + + query += "SELECT `pickuuid`,`name` FROM userpicks WHERE "; + query += "creatoruuid = ?Id"; + OSDArray data = new OSDArray(); + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?Id", avatarId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if(reader.HasRows) + { + while (reader.Read()) + { + OSDMap record = new OSDMap(); + + record.Add("pickuuid",OSD.FromString((string)reader["pickuuid"])); + record.Add("name",OSD.FromString((string)reader["name"])); + data.Add(record); + } + } + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": GetAvatarPicks exception {0}", e.Message); + } + return data; + } + + public UserProfilePick GetPickInfo(UUID avatarId, UUID pickId) + { + string query = string.Empty; + UserProfilePick pick = new UserProfilePick(); + + query += "SELECT * FROM userpicks WHERE "; + query += "creatoruuid = ?CreatorId AND "; + query += "pickuuid = ?PickId"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?CreatorId", avatarId.ToString()); + cmd.Parameters.AddWithValue("?PickId", pickId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if(reader.HasRows) + { + reader.Read(); + + string description = (string)reader["description"]; + + if (string.IsNullOrEmpty(description)) + description = "No description given."; + + UUID.TryParse((string)reader["pickuuid"], out pick.PickId); + UUID.TryParse((string)reader["creatoruuid"], out pick.CreatorId); + UUID.TryParse((string)reader["parceluuid"], out pick.ParcelId); + UUID.TryParse((string)reader["snapshotuuid"], out pick.SnapshotId); + pick.GlobalPos = (string)reader["posglobal"]; + pick.Gatekeeper = (string)reader["gatekeeper"]; + bool.TryParse((string)reader["toppick"], out pick.TopPick); + bool.TryParse((string)reader["enabled"], out pick.Enabled); + pick.Name = (string)reader["name"]; + pick.Desc = description; + pick.ParcelName = (string)reader["user"]; + pick.OriginalName = (string)reader["originalname"]; + pick.SimName = (string)reader["simname"]; + pick.SortOrder = (int)reader["sortorder"]; + } + } + } + dbcon.Close(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": GetPickInfo exception {0}", e.Message); + } + return pick; + } + + public bool UpdatePicksRecord(UserProfilePick pick) + { + string query = string.Empty; + + query += "INSERT INTO userpicks VALUES ("; + query += "?PickId,"; + query += "?CreatorId,"; + query += "?TopPick,"; + query += "?ParcelId,"; + query += "?Name,"; + query += "?Desc,"; + query += "?SnapshotId,"; + query += "?User,"; + query += "?Original,"; + query += "?SimName,"; + query += "?GlobalPos,"; + query += "?SortOrder,"; + query += "?Enabled,"; + query += "?Gatekeeper)"; + query += "ON DUPLICATE KEY UPDATE "; + query += "parceluuid=?ParcelId,"; + query += "name=?Name,"; + query += "description=?Desc,"; + query += "user=?User,"; + query += "simname=?SimName,"; + query += "snapshotuuid=?SnapshotId,"; + query += "pickuuid=?PickId,"; + query += "posglobal=?GlobalPos,"; + query += "gatekeeper=?Gatekeeper"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?PickId", pick.PickId.ToString()); + cmd.Parameters.AddWithValue("?CreatorId", pick.CreatorId.ToString()); + cmd.Parameters.AddWithValue("?TopPick", pick.TopPick.ToString()); + cmd.Parameters.AddWithValue("?ParcelId", pick.ParcelId.ToString()); + cmd.Parameters.AddWithValue("?Name", pick.Name.ToString()); + cmd.Parameters.AddWithValue("?Desc", pick.Desc.ToString()); + cmd.Parameters.AddWithValue("?SnapshotId", pick.SnapshotId.ToString()); + cmd.Parameters.AddWithValue("?User", pick.ParcelName.ToString()); + cmd.Parameters.AddWithValue("?Original", pick.OriginalName.ToString()); + cmd.Parameters.AddWithValue("?SimName",pick.SimName.ToString()); + cmd.Parameters.AddWithValue("?GlobalPos", pick.GlobalPos); + cmd.Parameters.AddWithValue("?Gatekeeper",pick.Gatekeeper); + cmd.Parameters.AddWithValue("?SortOrder", pick.SortOrder.ToString ()); + cmd.Parameters.AddWithValue("?Enabled", pick.Enabled.ToString()); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": UpdateAvatarNotes exception {0}", e.Message); + return false; + } + return true; + } + + public bool DeletePicksRecord(UUID pickId) + { + string query = string.Empty; + + query += "DELETE FROM userpicks WHERE "; + query += "pickuuid = ?PickId"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?PickId", pickId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": DeleteUserPickRecord exception {0}", e.Message); + return false; + } + return true; + } + #endregion Picks Queries + + #region Avatar Notes Queries + public bool GetAvatarNotes(ref UserProfileNotes notes) + { // WIP + string query = string.Empty; + + query += "SELECT `notes` FROM usernotes WHERE "; + query += "useruuid = ?Id AND "; + query += "targetuuid = ?TargetId"; + OSDArray data = new OSDArray(); + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?Id", notes.UserId.ToString()); + cmd.Parameters.AddWithValue("?TargetId", notes.TargetId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.HasRows) + { + reader.Read(); + notes.Notes = OSD.FromString((string)reader["notes"]); + } + else + { + notes.Notes = OSD.FromString(""); + } + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": GetAvatarNotes exception {0}", e.Message); + } + return true; + } + + public bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result) + { + string query = string.Empty; + bool remove; + + if(string.IsNullOrEmpty(note.Notes)) + { + remove = true; + query += "DELETE FROM usernotes WHERE "; + query += "useruuid=?UserId AND "; + query += "targetuuid=?TargetId"; + } + else + { + remove = false; + query += "INSERT INTO usernotes VALUES ( "; + query += "?UserId,"; + query += "?TargetId,"; + query += "?Notes )"; + query += "ON DUPLICATE KEY "; + query += "UPDATE "; + query += "notes=?Notes"; + } + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + if(!remove) + cmd.Parameters.AddWithValue("?Notes", note.Notes); + cmd.Parameters.AddWithValue("?TargetId", note.TargetId.ToString ()); + cmd.Parameters.AddWithValue("?UserId", note.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": UpdateAvatarNotes exception {0}", e.Message); + return false; + } + return true; + + } + #endregion Avatar Notes Queries + + #region Avatar Properties + public bool GetAvatarProperties(ref UserProfileProperties props, ref string result) + { + string query = string.Empty; + + query += "SELECT * FROM userprofile WHERE "; + query += "useruuid = ?Id"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?Id", props.UserId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.HasRows) + { + reader.Read(); + props.WebUrl = (string)reader["profileURL"]; + UUID.TryParse((string)reader["profileImage"], out props.ImageId); + props.AboutText = (string)reader["profileAboutText"]; + UUID.TryParse((string)reader["profileFirstImage"], out props.FirstLifeImageId); + props.FirstLifeText = (string)reader["profileFirstText"]; + UUID.TryParse((string)reader["profilePartner"], out props.PartnerId); + props.WantToMask = (int)reader["profileWantToMask"]; + props.WantToText = (string)reader["profileWantToText"]; + props.SkillsMask = (int)reader["profileSkillsMask"]; + props.SkillsText = (string)reader["profileSkillsText"]; + props.Language = (string)reader["profileLanguages"]; + } + else + { + props.WebUrl = string.Empty; + props.ImageId = UUID.Zero; + props.AboutText = string.Empty; + props.FirstLifeImageId = UUID.Zero; + props.FirstLifeText = string.Empty; + props.PartnerId = UUID.Zero; + props.WantToMask = 0; + props.WantToText = string.Empty; + props.SkillsMask = 0; + props.SkillsText = string.Empty; + props.Language = string.Empty; + props.PublishProfile = false; + props.PublishMature = false; + + query = "INSERT INTO userprofile ("; + query += "useruuid, "; + query += "profilePartner, "; + query += "profileAllowPublish, "; + query += "profileMaturePublish, "; + query += "profileURL, "; + query += "profileWantToMask, "; + query += "profileWantToText, "; + query += "profileSkillsMask, "; + query += "profileSkillsText, "; + query += "profileLanguages, "; + query += "profileImage, "; + query += "profileAboutText, "; + query += "profileFirstImage, "; + query += "profileFirstText) VALUES ("; + query += "?userId, "; + query += "?profilePartner, "; + query += "?profileAllowPublish, "; + query += "?profileMaturePublish, "; + query += "?profileURL, "; + query += "?profileWantToMask, "; + query += "?profileWantToText, "; + query += "?profileSkillsMask, "; + query += "?profileSkillsText, "; + query += "?profileLanguages, "; + query += "?profileImage, "; + query += "?profileAboutText, "; + query += "?profileFirstImage, "; + query += "?profileFirstText)"; + + dbcon.Close(); + dbcon.Open(); + + using (MySqlCommand put = new MySqlCommand(query, dbcon)) + { + put.Parameters.AddWithValue("?userId", props.UserId.ToString()); + put.Parameters.AddWithValue("?profilePartner", props.PartnerId.ToString()); + put.Parameters.AddWithValue("?profileAllowPublish", props.PublishProfile); + put.Parameters.AddWithValue("?profileMaturePublish", props.PublishMature); + put.Parameters.AddWithValue("?profileURL", props.WebUrl); + put.Parameters.AddWithValue("?profileWantToMask", props.WantToMask); + put.Parameters.AddWithValue("?profileWantToText", props.WantToText); + put.Parameters.AddWithValue("?profileSkillsMask", props.SkillsMask); + put.Parameters.AddWithValue("?profileSkillsText", props.SkillsText); + put.Parameters.AddWithValue("?profileLanguages", props.Language); + put.Parameters.AddWithValue("?profileImage", props.ImageId.ToString()); + put.Parameters.AddWithValue("?profileAboutText", props.AboutText); + put.Parameters.AddWithValue("?profileFirstImage", props.FirstLifeImageId.ToString()); + put.Parameters.AddWithValue("?profileFirstText", props.FirstLifeText); + + put.ExecuteNonQuery(); + } + } + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": Requst properties exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + + public bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result) + { + string query = string.Empty; + + query += "UPDATE userprofile SET "; + query += "profileURL=?profileURL, "; + query += "profileImage=?image, "; + query += "profileAboutText=?abouttext,"; + query += "profileFirstImage=?firstlifeimage,"; + query += "profileFirstText=?firstlifetext "; + query += "WHERE useruuid=?uuid"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?profileURL", props.WebUrl); + cmd.Parameters.AddWithValue("?image", props.ImageId.ToString()); + cmd.Parameters.AddWithValue("?abouttext", props.AboutText); + cmd.Parameters.AddWithValue("?firstlifeimage", props.FirstLifeImageId.ToString()); + cmd.Parameters.AddWithValue("?firstlifetext", props.FirstLifeText); + cmd.Parameters.AddWithValue("?uuid", props.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": AgentPropertiesUpdate exception {0}", e.Message); + + return false; + } + return true; + } + #endregion Avatar Properties + + #region Avatar Interests + public bool UpdateAvatarInterests(UserProfileProperties up, ref string result) + { + string query = string.Empty; + + query += "UPDATE userprofile SET "; + query += "profileWantToMask=?WantMask, "; + query += "profileWantToText=?WantText,"; + query += "profileSkillsMask=?SkillsMask,"; + query += "profileSkillsText=?SkillsText, "; + query += "profileLanguages=?Languages "; + query += "WHERE useruuid=?uuid"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?WantMask", up.WantToMask); + cmd.Parameters.AddWithValue("?WantText", up.WantToText); + cmd.Parameters.AddWithValue("?SkillsMask", up.SkillsMask); + cmd.Parameters.AddWithValue("?SkillsText", up.SkillsText); + cmd.Parameters.AddWithValue("?Languages", up.Language); + cmd.Parameters.AddWithValue("?uuid", up.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": AgentInterestsUpdate exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + #endregion Avatar Interests + + public OSDArray GetUserImageAssets(UUID avatarId) + { + OSDArray data = new OSDArray(); + string query = "SELECT `snapshotuuid` FROM {0} WHERE `creatoruuid` = ?Id"; + + // Get classified image assets + + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + + using (MySqlCommand cmd = new MySqlCommand(string.Format (query,"`classifieds`"), dbcon)) + { + cmd.Parameters.AddWithValue("?Id", avatarId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.HasRows) + { + while (reader.Read()) + { + data.Add(new OSDString((string)reader["snapshotuuid"].ToString ())); + } + } + } + } + + dbcon.Close(); + dbcon.Open(); + + using (MySqlCommand cmd = new MySqlCommand(string.Format (query,"`userpicks`"), dbcon)) + { + cmd.Parameters.AddWithValue("?Id", avatarId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.HasRows) + { + while (reader.Read()) + { + data.Add(new OSDString((string)reader["snapshotuuid"].ToString ())); + } + } + } + } + + dbcon.Close(); + dbcon.Open(); + + query = "SELECT `profileImage`, `profileFirstImage` FROM `userprofile` WHERE `useruuid` = ?Id"; + + using (MySqlCommand cmd = new MySqlCommand(string.Format (query,"`userpicks`"), dbcon)) + { + cmd.Parameters.AddWithValue("?Id", avatarId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.HasRows) + { + while (reader.Read()) + { + data.Add(new OSDString((string)reader["profileImage"].ToString ())); + data.Add(new OSDString((string)reader["profileFirstImage"].ToString ())); + } + } + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": GetAvatarNotes exception {0}", e.Message); + } + return data; + } + + #region User Preferences + public bool GetUserPreferences(ref UserPreferences pref, ref string result) + { + string query = string.Empty; + + query += "SELECT imviaemail,visible,email FROM "; + query += "usersettings WHERE "; + query += "useruuid = ?Id"; + + OSDArray data = new OSDArray(); + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?Id", pref.UserId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if(reader.HasRows) + { + reader.Read(); + bool.TryParse((string)reader["imviaemail"], out pref.IMViaEmail); + bool.TryParse((string)reader["visible"], out pref.Visible); + pref.EMail = (string)reader["email"]; + } + else + { + dbcon.Close(); + dbcon.Open(); + + query = "INSERT INTO usersettings VALUES "; + query += "(?uuid,'false','false', ?Email)"; + + using (MySqlCommand put = new MySqlCommand(query, dbcon)) + { + + put.Parameters.AddWithValue("?Email", pref.EMail); + put.Parameters.AddWithValue("?uuid", pref.UserId.ToString()); + + put.ExecuteNonQuery(); + } + } + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": Get preferences exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + + public bool UpdateUserPreferences(ref UserPreferences pref, ref string result) + { + string query = string.Empty; + + query += "UPDATE usersettings SET "; + query += "imviaemail=?ImViaEmail, "; + query += "visible=?Visible, "; + query += "email=?EMail "; + query += "WHERE useruuid=?uuid"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?ImViaEmail", pref.IMViaEmail.ToString().ToLower()); + cmd.Parameters.AddWithValue("?Visible", pref.Visible.ToString().ToLower()); + cmd.Parameters.AddWithValue("?uuid", pref.UserId.ToString()); + cmd.Parameters.AddWithValue("?EMail", pref.EMail.ToString().ToLower()); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": UserPreferencesUpdate exception {0} {1}", e.Message, e.InnerException); + result = e.Message; + return false; + } + return true; + } + #endregion User Preferences + + #region Integration + public bool GetUserAppData(ref UserAppData props, ref string result) + { + string query = string.Empty; + + query += "SELECT * FROM `userdata` WHERE "; + query += "UserId = ?Id AND "; + query += "TagId = ?TagId"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?Id", props.UserId.ToString()); + cmd.Parameters.AddWithValue ("?TagId", props.TagId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.HasRows) + { + reader.Read(); + props.DataKey = (string)reader["DataKey"]; + props.DataVal = (string)reader["DataVal"]; + } + else + { + query += "INSERT INTO userdata VALUES ( "; + query += "?UserId,"; + query += "?TagId,"; + query += "?DataKey,"; + query += "?DataVal) "; + + using (MySqlCommand put = new MySqlCommand(query, dbcon)) + { + put.Parameters.AddWithValue("?UserId", props.UserId.ToString()); + put.Parameters.AddWithValue("?TagId", props.TagId.ToString()); + put.Parameters.AddWithValue("?DataKey", props.DataKey.ToString()); + put.Parameters.AddWithValue("?DataVal", props.DataVal.ToString()); + + put.ExecuteNonQuery(); + } + } + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": Requst application data exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + + public bool SetUserAppData(UserAppData props, ref string result) + { + string query = string.Empty; + + query += "UPDATE userdata SET "; + query += "TagId = ?TagId, "; + query += "DataKey = ?DataKey, "; + query += "DataVal = ?DataVal WHERE "; + query += "UserId = ?UserId AND "; + query += "TagId = ?TagId"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?UserId", props.UserId.ToString()); + cmd.Parameters.AddWithValue("?TagId", props.TagId.ToString()); + cmd.Parameters.AddWithValue("?DataKey", props.DataKey.ToString()); + cmd.Parameters.AddWithValue("?DataVal", props.DataKey.ToString()); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": SetUserData exception {0}", e.Message); + return false; + } + return true; + } + #endregion Integration + } +} \ No newline at end of file diff --git a/OpenSim/Data/MySQL/MySQLXAssetData.cs b/OpenSim/Data/MySQL/MySQLXAssetData.cs index e6ac22e..af7e876 100644 --- a/OpenSim/Data/MySQL/MySQLXAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLXAssetData.cs @@ -50,9 +50,13 @@ namespace OpenSim.Data.MySQL get { return GetType().Assembly; } } + /// + /// Number of days that must pass before we update the access time on an asset when it has been fetched. + /// + private const int DaysBetweenAccessTimeUpdates = 30; + private bool m_enableCompression = false; private string m_connectionString; - private object m_dbLock = new object(); /// /// We can reuse this for all hashing since all methods are single-threaded through m_dbBLock @@ -126,58 +130,58 @@ namespace OpenSim.Data.MySQL // m_log.DebugFormat("[MYSQL XASSET DATA]: Looking for asset {0}", assetID); AssetBase asset = null; - lock (m_dbLock) + + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + dbcon.Open(); + + using (MySqlCommand cmd = new MySqlCommand( + "SELECT Name, Description, AccessTime, AssetType, Local, Temporary, AssetFlags, CreatorID, Data FROM XAssetsMeta JOIN XAssetsData ON XAssetsMeta.Hash = XAssetsData.Hash WHERE ID=?ID", + dbcon)) { - dbcon.Open(); + cmd.Parameters.AddWithValue("?ID", assetID.ToString()); - using (MySqlCommand cmd = new MySqlCommand( - "SELECT name, description, asset_type, local, temporary, asset_flags, creator_id, data FROM xassetsmeta JOIN xassetsdata ON xassetsmeta.hash = xassetsdata.hash WHERE id=?id", - dbcon)) + try { - cmd.Parameters.AddWithValue("?id", assetID.ToString()); - - try + using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) { - using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + if (dbReader.Read()) { - if (dbReader.Read()) - { - asset = new AssetBase(assetID, (string)dbReader["name"], (sbyte)dbReader["asset_type"], dbReader["creator_id"].ToString()); - asset.Data = (byte[])dbReader["data"]; - asset.Description = (string)dbReader["description"]; + asset = new AssetBase(assetID, (string)dbReader["Name"], (sbyte)dbReader["AssetType"], dbReader["CreatorID"].ToString()); + asset.Data = (byte[])dbReader["Data"]; + asset.Description = (string)dbReader["Description"]; - string local = dbReader["local"].ToString(); - if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase)) - asset.Local = true; - else - asset.Local = false; + string local = dbReader["Local"].ToString(); + if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase)) + asset.Local = true; + else + asset.Local = false; - asset.Temporary = Convert.ToBoolean(dbReader["temporary"]); - asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); + asset.Temporary = Convert.ToBoolean(dbReader["Temporary"]); + asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]); - if (m_enableCompression) + if (m_enableCompression) + { + using (GZipStream decompressionStream = new GZipStream(new MemoryStream(asset.Data), CompressionMode.Decompress)) { - using (GZipStream decompressionStream = new GZipStream(new MemoryStream(asset.Data), CompressionMode.Decompress)) - { - MemoryStream outputStream = new MemoryStream(); - WebUtil.CopyStream(decompressionStream, outputStream, int.MaxValue); - // int compressedLength = asset.Data.Length; - asset.Data = outputStream.ToArray(); - - // m_log.DebugFormat( - // "[XASSET DB]: Decompressed {0} {1} to {2} bytes from {3}", - // asset.ID, asset.Name, asset.Data.Length, compressedLength); - } + MemoryStream outputStream = new MemoryStream(); + WebUtil.CopyStream(decompressionStream, outputStream, int.MaxValue); +// int compressedLength = asset.Data.Length; + asset.Data = outputStream.ToArray(); + +// m_log.DebugFormat( +// "[XASSET DB]: Decompressed {0} {1} to {2} bytes from {3}", +// asset.ID, asset.Name, asset.Data.Length, compressedLength); } } + + UpdateAccessTime(asset.Metadata, (int)dbReader["AccessTime"]); } } - catch (Exception e) - { - m_log.Error("[MYSQL XASSET DATA]: MySql failure fetching asset " + assetID + ": " + e.Message); - } + } + catch (Exception e) + { + m_log.Error(string.Format("[MYSQL XASSET DATA]: Failure fetching asset {0}", assetID), e); } } } @@ -192,148 +196,156 @@ namespace OpenSim.Data.MySQL /// On failure : Throw an exception and attempt to reconnect to database public void StoreAsset(AssetBase asset) { - lock (m_dbLock) +// m_log.DebugFormat("[XASSETS DB]: Storing asset {0} {1}", asset.Name, asset.ID); + + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + dbcon.Open(); + + using (MySqlTransaction transaction = dbcon.BeginTransaction()) { - dbcon.Open(); + string assetName = asset.Name; + if (asset.Name.Length > AssetBase.MAX_ASSET_NAME) + { + assetName = asset.Name.Substring(0, AssetBase.MAX_ASSET_NAME); + m_log.WarnFormat( + "[XASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add", + asset.Name, asset.ID, asset.Name.Length, assetName.Length); + } - using (MySqlTransaction transaction = dbcon.BeginTransaction()) + string assetDescription = asset.Description; + if (asset.Description.Length > AssetBase.MAX_ASSET_DESC) { - string assetName = asset.Name; - if (asset.Name.Length > 64) - { - assetName = asset.Name.Substring(0, 64); - m_log.Warn("[XASSET DB]: Name field truncated from " + asset.Name.Length + " to " + assetName.Length + " characters on add"); - } - - string assetDescription = asset.Description; - if (asset.Description.Length > 64) - { - assetDescription = asset.Description.Substring(0, 64); - m_log.Warn("[XASSET DB]: Description field truncated from " + asset.Description.Length + " to " + assetDescription.Length + " characters on add"); - } + assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); + m_log.WarnFormat( + "[XASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", + asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); + } - if (m_enableCompression) - { - MemoryStream outputStream = new MemoryStream(); + if (m_enableCompression) + { + MemoryStream outputStream = new MemoryStream(); - using (GZipStream compressionStream = new GZipStream(outputStream, CompressionMode.Compress, false)) - { - // Console.WriteLine(WebUtil.CopyTo(new MemoryStream(asset.Data), compressionStream, int.MaxValue)); - // We have to close the compression stream in order to make sure it writes everything out to the underlying memory output stream. - compressionStream.Close(); - byte[] compressedData = outputStream.ToArray(); - asset.Data = compressedData; - } + using (GZipStream compressionStream = new GZipStream(outputStream, CompressionMode.Compress, false)) + { +// Console.WriteLine(WebUtil.CopyTo(new MemoryStream(asset.Data), compressionStream, int.MaxValue)); + // We have to close the compression stream in order to make sure it writes everything out to the underlying memory output stream. + compressionStream.Close(); + byte[] compressedData = outputStream.ToArray(); + asset.Data = compressedData; } + } - byte[] hash = hasher.ComputeHash(asset.Data); + byte[] hash = hasher.ComputeHash(asset.Data); // m_log.DebugFormat( // "[XASSET DB]: Compressed data size for {0} {1}, hash {2} is {3}", // asset.ID, asset.Name, hash, compressedData.Length); + try + { + using (MySqlCommand cmd = + new MySqlCommand( + "replace INTO XAssetsMeta(ID, Hash, Name, Description, AssetType, Local, Temporary, CreateTime, AccessTime, AssetFlags, CreatorID)" + + "VALUES(?ID, ?Hash, ?Name, ?Description, ?AssetType, ?Local, ?Temporary, ?CreateTime, ?AccessTime, ?AssetFlags, ?CreatorID)", + dbcon)) + { + // create unix epoch time + int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); + cmd.Parameters.AddWithValue("?ID", asset.ID); + cmd.Parameters.AddWithValue("?Hash", hash); + cmd.Parameters.AddWithValue("?Name", assetName); + cmd.Parameters.AddWithValue("?Description", assetDescription); + cmd.Parameters.AddWithValue("?AssetType", asset.Type); + cmd.Parameters.AddWithValue("?Local", asset.Local); + cmd.Parameters.AddWithValue("?Temporary", asset.Temporary); + cmd.Parameters.AddWithValue("?CreateTime", now); + cmd.Parameters.AddWithValue("?AccessTime", now); + cmd.Parameters.AddWithValue("?CreatorID", asset.Metadata.CreatorID); + cmd.Parameters.AddWithValue("?AssetFlags", (int)asset.Flags); + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[ASSET DB]: MySQL failure creating asset metadata {0} with name \"{1}\". Error: {2}", + asset.FullID, asset.Name, e.Message); + + transaction.Rollback(); + + return; + } + + if (!ExistsData(dbcon, transaction, hash)) + { try { using (MySqlCommand cmd = new MySqlCommand( - "replace INTO xassetsmeta(id, hash, name, description, asset_type, local, temporary, create_time, access_time, asset_flags, creator_id)" + - "VALUES(?id, ?hash, ?name, ?description, ?asset_type, ?local, ?temporary, ?create_time, ?access_time, ?asset_flags, ?creator_id)", + "INSERT INTO XAssetsData(Hash, Data) VALUES(?Hash, ?Data)", dbcon)) { - // create unix epoch time - int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); - cmd.Parameters.AddWithValue("?id", asset.ID); - cmd.Parameters.AddWithValue("?hash", hash); - cmd.Parameters.AddWithValue("?name", assetName); - cmd.Parameters.AddWithValue("?description", assetDescription); - cmd.Parameters.AddWithValue("?asset_type", asset.Type); - cmd.Parameters.AddWithValue("?local", asset.Local); - cmd.Parameters.AddWithValue("?temporary", asset.Temporary); - cmd.Parameters.AddWithValue("?create_time", now); - cmd.Parameters.AddWithValue("?access_time", now); - cmd.Parameters.AddWithValue("?creator_id", asset.Metadata.CreatorID); - cmd.Parameters.AddWithValue("?asset_flags", (int)asset.Flags); + cmd.Parameters.AddWithValue("?Hash", hash); + cmd.Parameters.AddWithValue("?Data", asset.Data); cmd.ExecuteNonQuery(); } } catch (Exception e) { - m_log.ErrorFormat("[ASSET DB]: MySQL failure creating asset metadata {0} with name \"{1}\". Error: {2}", + m_log.ErrorFormat("[XASSET DB]: MySQL failure creating asset data {0} with name \"{1}\". Error: {2}", asset.FullID, asset.Name, e.Message); transaction.Rollback(); return; } - - if (!ExistsData(dbcon, transaction, hash)) - { - try - { - using (MySqlCommand cmd = - new MySqlCommand( - "INSERT INTO xassetsdata(hash, data) VALUES(?hash, ?data)", - dbcon)) - { - cmd.Parameters.AddWithValue("?hash", hash); - cmd.Parameters.AddWithValue("?data", asset.Data); - cmd.ExecuteNonQuery(); - } - } - catch (Exception e) - { - m_log.ErrorFormat("[XASSET DB]: MySQL failure creating asset data {0} with name \"{1}\". Error: {2}", - asset.FullID, asset.Name, e.Message); - - transaction.Rollback(); - - return; - } - } - - transaction.Commit(); } + + transaction.Commit(); } } } -// private void UpdateAccessTime(AssetBase asset) -// { -// lock (m_dbLock) -// { -// using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) -// { -// dbcon.Open(); -// MySqlCommand cmd = -// new MySqlCommand("update assets set access_time=?access_time where id=?id", -// dbcon); -// -// // need to ensure we dispose -// try -// { -// using (cmd) -// { -// // create unix epoch time -// int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); -// cmd.Parameters.AddWithValue("?id", asset.ID); -// cmd.Parameters.AddWithValue("?access_time", now); -// cmd.ExecuteNonQuery(); -// cmd.Dispose(); -// } -// } -// catch (Exception e) -// { -// m_log.ErrorFormat( -// "[ASSETS DB]: " + -// "MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString() -// + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name); -// } -// } -// } -// -// } + /// + /// Updates the access time of the asset if it was accessed above a given threshhold amount of time. + /// + /// + /// This gives us some insight into assets which haven't ben accessed for a long period. This is only done + /// over the threshold time to avoid excessive database writes as assets are fetched. + /// + /// + /// + private void UpdateAccessTime(AssetMetadata assetMetadata, int accessTime) + { + DateTime now = DateTime.UtcNow; + + if ((now - Utils.UnixTimeToDateTime(accessTime)).TotalDays < DaysBetweenAccessTimeUpdates) + return; + + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + { + dbcon.Open(); + MySqlCommand cmd = + new MySqlCommand("update XAssetsMeta set AccessTime=?AccessTime where ID=?ID", dbcon); + + try + { + using (cmd) + { + // create unix epoch time + cmd.Parameters.AddWithValue("?ID", assetMetadata.ID); + cmd.Parameters.AddWithValue("?AccessTime", (int)Utils.DateTimeToUnixTime(now)); + cmd.ExecuteNonQuery(); + } + } + catch (Exception) + { + m_log.ErrorFormat( + "[XASSET MYSQL DB]: Failure updating access_time for asset {0} with name {1}", + assetMetadata.ID, assetMetadata.Name); + } + } + } /// /// We assume we already have the m_dbLock. @@ -349,9 +361,9 @@ namespace OpenSim.Data.MySQL bool exists = false; - using (MySqlCommand cmd = new MySqlCommand("SELECT hash FROM xassetsdata WHERE hash=?hash", dbcon)) + using (MySqlCommand cmd = new MySqlCommand("SELECT Hash FROM XAssetsData WHERE Hash=?Hash", dbcon)) { - cmd.Parameters.AddWithValue("?hash", hash); + cmd.Parameters.AddWithValue("?Hash", hash); try { @@ -376,48 +388,43 @@ namespace OpenSim.Data.MySQL } /// - /// Check if the asset exists in the database + /// Check if the assets exist in the database. /// - /// The asset UUID - /// true if it exists, false otherwise. - public bool ExistsAsset(UUID uuid) + /// The asset UUID's + /// For each asset: true if it exists, false otherwise + public bool[] AssetsExist(UUID[] uuids) { -// m_log.DebugFormat("[ASSETS DB]: Checking for asset {0}", uuid); + if (uuids.Length == 0) + return new bool[0]; + + HashSet exists = new HashSet(); - bool assetExists = false; + string ids = "'" + string.Join("','", uuids) + "'"; + string sql = string.Format("SELECT ID FROM assets WHERE ID IN ({0})", ids); - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(sql, dbcon)) { - dbcon.Open(); - using (MySqlCommand cmd = new MySqlCommand("SELECT id FROM xassetsmeta WHERE id=?id", dbcon)) + using (MySqlDataReader dbReader = cmd.ExecuteReader()) { - cmd.Parameters.AddWithValue("?id", uuid.ToString()); - - try - { - using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) - { - if (dbReader.Read()) - { -// m_log.DebugFormat("[ASSETS DB]: Found asset {0}", uuid); - assetExists = true; - } - } - } - catch (Exception e) + while (dbReader.Read()) { - m_log.ErrorFormat( - "[XASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString(), uuid); + UUID id = DBGuid.FromDB(dbReader["ID"]); + exists.Add(id); } } } } - return assetExists; + bool[] results = new bool[uuids.Length]; + for (int i = 0; i < uuids.Length; i++) + results[i] = exists.Contains(uuids[i]); + return results; } + /// /// Returns a list of AssetMetadata objects. The list is a subset of /// the entire data set offset by containing @@ -430,41 +437,40 @@ namespace OpenSim.Data.MySQL { List retList = new List(count); - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) - { - dbcon.Open(); - MySqlCommand cmd = new MySqlCommand("SELECT name,description,asset_type,temporary,id,asset_flags,creator_id FROM xassetsmeta LIMIT ?start, ?count", dbcon); - cmd.Parameters.AddWithValue("?start", start); - cmd.Parameters.AddWithValue("?count", count); + dbcon.Open(); + MySqlCommand cmd = new MySqlCommand("SELECT Name, Description, AccessTime, AssetType, Temporary, ID, AssetFlags, CreatorID FROM XAssetsMeta LIMIT ?start, ?count", dbcon); + cmd.Parameters.AddWithValue("?start", start); + cmd.Parameters.AddWithValue("?count", count); - try + try + { + using (MySqlDataReader dbReader = cmd.ExecuteReader()) { - using (MySqlDataReader dbReader = cmd.ExecuteReader()) + while (dbReader.Read()) { - while (dbReader.Read()) - { - AssetMetadata metadata = new AssetMetadata(); - metadata.Name = (string)dbReader["name"]; - metadata.Description = (string)dbReader["description"]; - metadata.Type = (sbyte)dbReader["asset_type"]; - metadata.Temporary = Convert.ToBoolean(dbReader["temporary"]); // Not sure if this is correct. - metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); - metadata.FullID = DBGuid.FromDB(dbReader["id"]); - metadata.CreatorID = dbReader["creator_id"].ToString(); - - // We'll ignore this for now - it appears unused! + AssetMetadata metadata = new AssetMetadata(); + metadata.Name = (string)dbReader["Name"]; + metadata.Description = (string)dbReader["Description"]; + metadata.Type = (sbyte)dbReader["AssetType"]; + metadata.Temporary = Convert.ToBoolean(dbReader["Temporary"]); // Not sure if this is correct. + metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]); + metadata.FullID = DBGuid.FromDB(dbReader["ID"]); + metadata.CreatorID = dbReader["CreatorID"].ToString(); + + // We'll ignore this for now - it appears unused! // metadata.SHA1 = dbReader["hash"]); - retList.Add(metadata); - } + UpdateAccessTime(metadata, (int)dbReader["AccessTime"]); + + retList.Add(metadata); } } - catch (Exception e) - { - m_log.Error("[XASSETS DB]: MySql failure fetching asset set" + Environment.NewLine + e.ToString()); - } + } + catch (Exception e) + { + m_log.Error("[XASSETS DB]: MySql failure fetching asset set" + Environment.NewLine + e.ToString()); } } @@ -475,21 +481,18 @@ namespace OpenSim.Data.MySQL { // m_log.DebugFormat("[XASSETS DB]: Deleting asset {0}", id); - lock (m_dbLock) + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { - using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) - { - dbcon.Open(); - - using (MySqlCommand cmd = new MySqlCommand("delete from xassetsmeta where id=?id", dbcon)) - { - cmd.Parameters.AddWithValue("?id", id); - cmd.ExecuteNonQuery(); - } + dbcon.Open(); - // TODO: How do we deal with data from deleted assets? Probably not easily reapable unless we - // keep a reference count (?) + using (MySqlCommand cmd = new MySqlCommand("delete from XAssetsMeta where ID=?ID", dbcon)) + { + cmd.Parameters.AddWithValue("?ID", id); + cmd.ExecuteNonQuery(); } + + // TODO: How do we deal with data from deleted assets? Probably not easily reapable unless we + // keep a reference count (?) } return true; diff --git a/OpenSim/Data/MySQL/Properties/AssemblyInfo.cs b/OpenSim/Data/MySQL/Properties/AssemblyInfo.cs index ab3fe36..b46d175 100644 --- a/OpenSim/Data/MySQL/Properties/AssemblyInfo.cs +++ b/OpenSim/Data/MySQL/Properties/AssemblyInfo.cs @@ -61,5 +61,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly : AssemblyVersion("0.7.5.*")] -[assembly : AssemblyFileVersion("0.6.5.0")] +[assembly : AssemblyVersion("0.8.2.*")] + diff --git a/OpenSim/Data/MySQL/Resources/AgentPrefs.migrations b/OpenSim/Data/MySQL/Resources/AgentPrefs.migrations new file mode 100644 index 0000000..e496f72 --- /dev/null +++ b/OpenSim/Data/MySQL/Resources/AgentPrefs.migrations @@ -0,0 +1,18 @@ +:VERSION 1 # ------------------------- + +BEGIN; + +CREATE TABLE `AgentPrefs` ( + `PrincipalID` CHAR(36) NOT NULL, + `AccessPrefs` CHAR(2) NOT NULL DEFAULT 'M', + `HoverHeight` DOUBLE(30, 27) NOT NULL DEFAULT 0, + `Language` CHAR(5) NOT NULL DEFAULT 'en-us', + `LanguageIsPublic` BOOLEAN NOT NULL DEFAULT 1, + `PermEveryone` INT(6) NOT NULL DEFAULT 0, + `PermGroup` INT(6) NOT NULL DEFAULT 0, + `PermNextOwner` INT(6) NOT NULL DEFAULT 532480, + UNIQUE KEY `PrincipalID` (`PrincipalID`), + PRIMARY KEY(`PrincipalID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +COMMIT; diff --git a/OpenSim/Data/MySQL/Resources/AssetStore.migrations b/OpenSim/Data/MySQL/Resources/AssetStore.migrations index f7211c2..661d825 100644 --- a/OpenSim/Data/MySQL/Resources/AssetStore.migrations +++ b/OpenSim/Data/MySQL/Resources/AssetStore.migrations @@ -13,7 +13,7 @@ CREATE TABLE `assets` ( `temporary` tinyint(1) NOT NULL, `data` longblob NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Rev. 1'; +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Rev. 1'; COMMIT; @@ -75,3 +75,7 @@ ALTER TABLE assets ADD COLUMN asset_flags INTEGER NOT NULL DEFAULT 0; ALTER TABLE assets ADD COLUMN CreatorID varchar(128) NOT NULL DEFAULT ''; +:VERSION 9 + +BEGIN; +COMMIT; diff --git a/OpenSim/Data/MySQL/Resources/AuthStore.migrations b/OpenSim/Data/MySQL/Resources/AuthStore.migrations index 9450940..023c786 100644 --- a/OpenSim/Data/MySQL/Resources/AuthStore.migrations +++ b/OpenSim/Data/MySQL/Resources/AuthStore.migrations @@ -8,7 +8,7 @@ CREATE TABLE `auth` ( `passwordSalt` char(32) NOT NULL default '', `webLoginKey` varchar(255) NOT NULL default '', PRIMARY KEY (`UUID`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; CREATE TABLE `tokens` ( `UUID` char(36) NOT NULL, @@ -18,7 +18,7 @@ CREATE TABLE `tokens` ( KEY `UUID` (`UUID`), KEY `token` (`token`), KEY `validity` (`validity`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; commit; diff --git a/OpenSim/Data/MySQL/Resources/EstateStore.migrations b/OpenSim/Data/MySQL/Resources/EstateStore.migrations index 6ef92ee..2d1c2b5 100644 --- a/OpenSim/Data/MySQL/Resources/EstateStore.migrations +++ b/OpenSim/Data/MySQL/Resources/EstateStore.migrations @@ -10,19 +10,19 @@ CREATE TABLE IF NOT EXISTS `estate_managers` ( `EstateID` int(10) unsigned NOT NULL, `uuid` char(36) NOT NULL, KEY `EstateID` (`EstateID`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; CREATE TABLE IF NOT EXISTS `estate_groups` ( `EstateID` int(10) unsigned NOT NULL, `uuid` char(36) NOT NULL, KEY `EstateID` (`EstateID`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; CREATE TABLE IF NOT EXISTS `estate_users` ( `EstateID` int(10) unsigned NOT NULL, `uuid` char(36) NOT NULL, KEY `EstateID` (`EstateID`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; CREATE TABLE IF NOT EXISTS `estateban` ( `EstateID` int(10) unsigned NOT NULL, @@ -31,7 +31,7 @@ CREATE TABLE IF NOT EXISTS `estateban` ( `bannedIpHostMask` varchar(16) NOT NULL, `bannedNameMask` varchar(64) default NULL, KEY `estateban_EstateID` (`EstateID`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; CREATE TABLE IF NOT EXISTS `estate_settings` ( `EstateID` int(10) unsigned NOT NULL auto_increment, @@ -60,14 +60,14 @@ CREATE TABLE IF NOT EXISTS `estate_settings` ( `DenyMinors` tinyint not null, PRIMARY KEY (`EstateID`) -) ENGINE=MyISAM AUTO_INCREMENT=100; +) ENGINE=InnoDB AUTO_INCREMENT=100; CREATE TABLE IF NOT EXISTS `estate_map` ( `RegionID` char(36) NOT NULL default '00000000-0000-0000-0000-000000000000', `EstateID` int(11) NOT NULL, PRIMARY KEY (`RegionID`), KEY `EstateID` (`EstateID`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; COMMIT; @@ -77,5 +77,11 @@ BEGIN; ALTER TABLE estate_settings AUTO_INCREMENT = 100; COMMIT; +:VERSION 33 #--------------------- +BEGIN; +ALTER TABLE estate_settings ADD COLUMN `AllowLandmark` tinyint(4) NOT NULL default '1'; +ALTER TABLE estate_settings ADD COLUMN `AllowParcelChanges` tinyint(4) NOT NULL default '1'; +ALTER TABLE estate_settings ADD COLUMN `AllowSetHome` tinyint(4) NOT NULL default '1'; +COMMIT; diff --git a/OpenSim/Data/MySQL/Resources/FSAssetStore.migrations b/OpenSim/Data/MySQL/Resources/FSAssetStore.migrations new file mode 100644 index 0000000..87d08c6 --- /dev/null +++ b/OpenSim/Data/MySQL/Resources/FSAssetStore.migrations @@ -0,0 +1,18 @@ +# ----------------- +:VERSION 1 + +BEGIN; + +CREATE TABLE `fsassets` ( + `id` char(36) NOT NULL, + `name` varchar(64) NOT NULL DEFAULT '', + `description` varchar(64) NOT NULL DEFAULT '', + `type` int(11) NOT NULL, + `hash` char(80) NOT NULL, + `create_time` int(11) NOT NULL DEFAULT '0', + `access_time` int(11) NOT NULL DEFAULT '0', + `asset_flags` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +COMMIT; \ No newline at end of file diff --git a/OpenSim/Data/MySQL/Resources/FriendsStore.migrations b/OpenSim/Data/MySQL/Resources/FriendsStore.migrations index 55d82ec..5faf956 100644 --- a/OpenSim/Data/MySQL/Resources/FriendsStore.migrations +++ b/OpenSim/Data/MySQL/Resources/FriendsStore.migrations @@ -9,7 +9,7 @@ CREATE TABLE `Friends` ( `Offered` VARCHAR(32) NOT NULL DEFAULT 0, PRIMARY KEY(`PrincipalID`, `Friend`), KEY(`PrincipalID`) -); +) ENGINE=InnoDB; COMMIT; diff --git a/OpenSim/Data/MySQL/Resources/GridStore.migrations b/OpenSim/Data/MySQL/Resources/GridStore.migrations index b010c63..b8d287a 100644 --- a/OpenSim/Data/MySQL/Resources/GridStore.migrations +++ b/OpenSim/Data/MySQL/Resources/GridStore.migrations @@ -1,5 +1,7 @@ :VERSION 1 +BEGIN; + CREATE TABLE `regions` ( `uuid` varchar(36) NOT NULL, `regionHandle` bigint(20) unsigned NOT NULL, @@ -31,7 +33,9 @@ CREATE TABLE `regions` ( KEY `regionName` (`regionName`), KEY `regionHandle` (`regionHandle`), KEY `overrideHandles` (`eastOverrideHandle`,`westOverrideHandle`,`southOverrideHandle`,`northOverrideHandle`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Rev. 3'; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +COMMIT; :VERSION 2 diff --git a/OpenSim/Data/MySQL/Resources/GridUserStore.migrations b/OpenSim/Data/MySQL/Resources/GridUserStore.migrations index e2be27e..d08e096 100644 --- a/OpenSim/Data/MySQL/Resources/GridUserStore.migrations +++ b/OpenSim/Data/MySQL/Resources/GridUserStore.migrations @@ -14,7 +14,7 @@ CREATE TABLE `GridUser` ( `Login` CHAR(16) NOT NULL DEFAULT '0', `Logout` CHAR(16) NOT NULL DEFAULT '0', PRIMARY KEY (`UserID`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; COMMIT; diff --git a/OpenSim/Data/MySQL/Resources/HGTravelStore.migrations b/OpenSim/Data/MySQL/Resources/HGTravelStore.migrations new file mode 100644 index 0000000..b4e4422 --- /dev/null +++ b/OpenSim/Data/MySQL/Resources/HGTravelStore.migrations @@ -0,0 +1,18 @@ +:VERSION 1 # -------------------------- + +BEGIN; + +CREATE TABLE `hg_traveling_data` ( + `SessionID` VARCHAR(36) NOT NULL, + `UserID` VARCHAR(36) NOT NULL, + `GridExternalName` VARCHAR(255) NOT NULL DEFAULT '', + `ServiceToken` VARCHAR(255) NOT NULL DEFAULT '', + `ClientIPAddress` VARCHAR(16) NOT NULL DEFAULT '', + `MyIPAddress` VARCHAR(16) NOT NULL DEFAULT '', + `TMStamp` timestamp NOT NULL, + PRIMARY KEY (`SessionID`), + KEY (`UserID`) +) ENGINE=InnoDB; + +COMMIT; + diff --git a/OpenSim/Data/MySQL/Resources/IM_Store.migrations b/OpenSim/Data/MySQL/Resources/IM_Store.migrations new file mode 100644 index 0000000..79ead98 --- /dev/null +++ b/OpenSim/Data/MySQL/Resources/IM_Store.migrations @@ -0,0 +1,42 @@ +:VERSION 1 # -------------------------- + +BEGIN; + +CREATE TABLE `im_offline` ( + `ID` MEDIUMINT NOT NULL AUTO_INCREMENT, + `PrincipalID` char(36) NOT NULL default '', + `Message` text NOT NULL, + `TMStamp` timestamp NOT NULL, + PRIMARY KEY (`ID`), + KEY `PrincipalID` (`PrincipalID`) +) ENGINE=MyISAM; + +COMMIT; + +:VERSION 2 # -------------------------- + +BEGIN; + +INSERT INTO `im_offline` SELECT * from `diva_im_offline`; +DROP TABLE `diva_im_offline`; +DELETE FROM `migrations` WHERE name='diva_im_Store'; + +COMMIT; + +:VERSION 3 # -------------------------- + +BEGIN; + +ALTER TABLE `im_offline` + ADD `FromID` char(36) NOT NULL default '' AFTER `PrincipalID`, + ADD KEY `FromID` (`FromID`); + +COMMIT; + +:VERSION 4 # -------------------------- + +BEGIN; + +ALTER TABLE im_offline CONVERT TO CHARACTER SET utf8; + +COMMIT; diff --git a/OpenSim/Data/MySQL/Resources/InventoryStore.migrations b/OpenSim/Data/MySQL/Resources/InventoryStore.migrations index ca2fe11..993a5a0 100644 --- a/OpenSim/Data/MySQL/Resources/InventoryStore.migrations +++ b/OpenSim/Data/MySQL/Resources/InventoryStore.migrations @@ -11,7 +11,7 @@ CREATE TABLE `inventoryfolders` ( PRIMARY KEY (`folderID`), KEY `owner` (`agentID`), KEY `parent` (`parentFolderID`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `inventoryitems` ( `inventoryID` varchar(36) NOT NULL default '', @@ -36,7 +36,7 @@ CREATE TABLE `inventoryitems` ( PRIMARY KEY (`inventoryID`), KEY `owner` (`avatarID`), KEY `folder` (`parentFolderID`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; COMMIT; diff --git a/OpenSim/Data/MySQL/Resources/LogStore.migrations b/OpenSim/Data/MySQL/Resources/LogStore.migrations index b572411..9ac26ac 100644 --- a/OpenSim/Data/MySQL/Resources/LogStore.migrations +++ b/OpenSim/Data/MySQL/Resources/LogStore.migrations @@ -10,4 +10,4 @@ CREATE TABLE `logs` ( `priority` int(11) default NULL, `message` text, PRIMARY KEY (`logID`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/OpenSim/Data/MySQL/Resources/Presence.migrations b/OpenSim/Data/MySQL/Resources/Presence.migrations index 5dc96d2..c4e40fa 100644 --- a/OpenSim/Data/MySQL/Resources/Presence.migrations +++ b/OpenSim/Data/MySQL/Resources/Presence.migrations @@ -1,4 +1,4 @@ -:VERSION 1 # -------------------------- +:VERSION 1 # -------------------------- BEGIN; @@ -7,7 +7,7 @@ CREATE TABLE `Presence` ( `RegionID` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', `SessionID` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', `SecureSessionID` CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' -) ENGINE=MyISAM; +) ENGINE=InnoDB; CREATE UNIQUE INDEX SessionID ON Presence(SessionID); CREATE INDEX UserID ON Presence(UserID); @@ -21,3 +21,11 @@ BEGIN; ALTER TABLE `Presence` ADD COLUMN LastSeen timestamp; COMMIT; + +:VERSION 3 # -------------------------- + +BEGIN; + +CREATE INDEX RegionID ON Presence(RegionID); + +COMMIT; diff --git a/OpenSim/Data/MySQL/Resources/RegionStore.migrations b/OpenSim/Data/MySQL/Resources/RegionStore.migrations index 071f64e..ac31380 100644 --- a/OpenSim/Data/MySQL/Resources/RegionStore.migrations +++ b/OpenSim/Data/MySQL/Resources/RegionStore.migrations @@ -146,7 +146,7 @@ CREATE TABLE `land` ( `UserLookAtZ` float default NULL, `AuthbuyerID` varchar(36) NOT NULL default '00000000-0000-0000-0000-000000000000', PRIMARY KEY (`UUID`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `landaccesslist` ( `LandUUID` varchar(255) default NULL, @@ -168,7 +168,7 @@ COMMIT; :VERSION 3 #--------------------- BEGIN; - CREATE TABLE regionban (regionUUID VARCHAR(36) NOT NULL, bannedUUID VARCHAR(36) NOT NULL, bannedIp VARCHAR(16) NOT NULL, bannedIpHostMask VARCHAR(16) NOT NULL) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Rev. 1'; + CREATE TABLE regionban (regionUUID VARCHAR(36) NOT NULL, bannedUUID VARCHAR(36) NOT NULL, bannedIp VARCHAR(16) NOT NULL, bannedIpHostMask VARCHAR(16) NOT NULL) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='Rev. 1'; COMMIT; :VERSION 4 #--------------------- @@ -226,13 +226,13 @@ COMMIT; BEGIN; -alter table landaccesslist ENGINE = MyISAM; -alter table migrations ENGINE = MyISAM; -alter table primitems ENGINE = MyISAM; -alter table prims ENGINE = MyISAM; -alter table primshapes ENGINE = MyISAM; -alter table regionsettings ENGINE = MyISAM; -alter table terrain ENGINE = MyISAM; +alter table landaccesslist ENGINE = InnoDB; +alter table migrations ENGINE = InnoDB; +alter table primitems ENGINE = InnoDB; +alter table prims ENGINE = InnoDB; +alter table primshapes ENGINE = InnoDB; +alter table regionsettings ENGINE = InnoDB; +alter table terrain ENGINE = InnoDB; COMMIT; @@ -384,7 +384,7 @@ CREATE TABLE `regionsettings` ( `covenant` char(36) default NULL, `Sandbox` tinyint(4) NOT NULL, PRIMARY KEY (`regionUUID`) -) ENGINE=MyISAM; +) ENGINE=InnoDB; commit; @@ -852,7 +852,7 @@ CREATE TABLE IF NOT EXISTS `spawn_points` ( `Pitch` float NOT NULL, `Distance` float NOT NULL, KEY `RegionID` (`RegionID`) -) ENGINE=MyISAM; +) ENGINE=Innodb; ALTER TABLE `regionsettings` ADD COLUMN `TelehubObject` varchar(36) NOT NULL; COMMIT; @@ -891,7 +891,7 @@ CREATE TABLE `regionenvironment` ( `region_id` varchar(36) NOT NULL, `llsd_settings` TEXT NOT NULL, PRIMARY KEY (`region_id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; COMMIT; @@ -902,3 +902,49 @@ BEGIN; CREATE TABLE `regionextra` (`RegionID` char(36) not null, `Name` varchar(32) not null, `value` text, primary key(`RegionID`, `Name`)); COMMIT; + +:VERSION 46 #---------------- Dynamic attributes + +BEGIN; + +ALTER TABLE prims ADD COLUMN DynAttrs TEXT; + +COMMIT; + +:VERSION 47 #---------------- Extra physics params + +BEGIN; + +ALTER TABLE prims ADD COLUMN `PhysicsShapeType` tinyint(4) NOT NULL default '0'; +ALTER TABLE prims ADD COLUMN `Density` double NOT NULL default '1000'; +ALTER TABLE prims ADD COLUMN `GravityModifier` double NOT NULL default '1'; +ALTER TABLE prims ADD COLUMN `Friction` double NOT NULL default '0.6'; +ALTER TABLE prims ADD COLUMN `Restitution` double NOT NULL default '0.5'; + +COMMIT; + +:VERSION 48 #---------------- Keyframes + +BEGIN; + +ALTER TABLE prims ADD COLUMN `KeyframeMotion` blob; + +COMMIT; + +:VERSION 49 #--------------------- Save attachment info + +BEGIN; +ALTER TABLE prims ADD COLUMN AttachedPosX double default 0; +ALTER TABLE prims ADD COLUMN AttachedPosY double default 0; +ALTER TABLE prims ADD COLUMN AttachedPosZ double default 0; +ALTER TABLE primshapes ADD COLUMN LastAttachPoint int(4) not null default '0'; +COMMIT; + +:VERSION 50 #---- Change LandFlags to unsigned + +BEGIN; + +ALTER TABLE land CHANGE COLUMN LandFlags LandFlags int unsigned default null; + +COMMIT; + diff --git a/OpenSim/Data/MySQL/Resources/UserAccount.migrations b/OpenSim/Data/MySQL/Resources/UserAccount.migrations index 97e5e4f..84011e6 100644 --- a/OpenSim/Data/MySQL/Resources/UserAccount.migrations +++ b/OpenSim/Data/MySQL/Resources/UserAccount.migrations @@ -10,7 +10,7 @@ CREATE TABLE `UserAccounts` ( `Email` VARCHAR(64), `ServiceURLs` TEXT, `Created` INT(11) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; COMMIT; diff --git a/OpenSim/Data/MySQL/Resources/UserProfiles.migrations b/OpenSim/Data/MySQL/Resources/UserProfiles.migrations new file mode 100644 index 0000000..87e99fa --- /dev/null +++ b/OpenSim/Data/MySQL/Resources/UserProfiles.migrations @@ -0,0 +1,98 @@ +:VERSION 1 # ------------------------------- + +begin; + +CREATE TABLE IF NOT EXISTS `classifieds` ( + `classifieduuid` char(36) NOT NULL, + `creatoruuid` char(36) NOT NULL, + `creationdate` int(20) NOT NULL, + `expirationdate` int(20) NOT NULL, + `category` varchar(20) NOT NULL, + `name` varchar(255) NOT NULL, + `description` text NOT NULL, + `parceluuid` char(36) NOT NULL, + `parentestate` int(11) NOT NULL, + `snapshotuuid` char(36) NOT NULL, + `simname` varchar(255) NOT NULL, + `posglobal` varchar(255) NOT NULL, + `parcelname` varchar(255) NOT NULL, + `classifiedflags` int(8) NOT NULL, + `priceforlisting` int(5) NOT NULL, + PRIMARY KEY (`classifieduuid`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + + +CREATE TABLE IF NOT EXISTS `usernotes` ( + `useruuid` varchar(36) NOT NULL, + `targetuuid` varchar(36) NOT NULL, + `notes` text NOT NULL, + UNIQUE KEY `useruuid` (`useruuid`,`targetuuid`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +CREATE TABLE IF NOT EXISTS `userpicks` ( + `pickuuid` varchar(36) NOT NULL, + `creatoruuid` varchar(36) NOT NULL, + `toppick` enum('true','false') NOT NULL, + `parceluuid` varchar(36) NOT NULL, + `name` varchar(255) NOT NULL, + `description` text NOT NULL, + `snapshotuuid` varchar(36) NOT NULL, + `user` varchar(255) NOT NULL, + `originalname` varchar(255) NOT NULL, + `simname` varchar(255) NOT NULL, + `posglobal` varchar(255) NOT NULL, + `sortorder` int(2) NOT NULL, + `enabled` enum('true','false') NOT NULL, + PRIMARY KEY (`pickuuid`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +CREATE TABLE IF NOT EXISTS `userprofile` ( + `useruuid` varchar(36) NOT NULL, + `profilePartner` varchar(36) NOT NULL, + `profileAllowPublish` binary(1) NOT NULL, + `profileMaturePublish` binary(1) NOT NULL, + `profileURL` varchar(255) NOT NULL, + `profileWantToMask` int(3) NOT NULL, + `profileWantToText` text NOT NULL, + `profileSkillsMask` int(3) NOT NULL, + `profileSkillsText` text NOT NULL, + `profileLanguages` text NOT NULL, + `profileImage` varchar(36) NOT NULL, + `profileAboutText` text NOT NULL, + `profileFirstImage` varchar(36) NOT NULL, + `profileFirstText` text NOT NULL, + PRIMARY KEY (`useruuid`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +commit; + +:VERSION 2 # ------------------------------- + +begin; +CREATE TABLE IF NOT EXISTS `userdata` ( + `UserId` char(36) NOT NULL, + `TagId` varchar(64) NOT NULL, + `DataKey` varchar(255), + `DataVal` varchar(255), + PRIMARY KEY (`UserId`,`TagId`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +commit; + +:VERSION 3 # ------------------------------- +begin; +CREATE TABLE IF NOT EXISTS `usersettings` ( + `useruuid` varchar(36) NOT NULL, + `imviaemail` enum('true','false') NOT NULL, + `visible` enum('true','false') NOT NULL, + `email` varchar(254) NOT NULL, + PRIMARY KEY (`useruuid`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +commit; + +:VERSION 4 # ------------------------------- +begin; +ALTER TABLE userpicks ADD COLUMN gatekeeper varchar(255); +commit; diff --git a/OpenSim/Data/MySQL/Resources/UserStore.migrations b/OpenSim/Data/MySQL/Resources/UserStore.migrations index 9129075..f054611 100644 --- a/OpenSim/Data/MySQL/Resources/UserStore.migrations +++ b/OpenSim/Data/MySQL/Resources/UserStore.migrations @@ -21,7 +21,7 @@ CREATE TABLE `agents` ( PRIMARY KEY (`UUID`), UNIQUE KEY `session` (`sessionID`), UNIQUE KEY `ssession` (`secureSessionID`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- Create schema avatar_appearance -- @@ -59,7 +59,7 @@ CREATE TABLE `avatarappearance` ( Skirt_Item char(36) NOT NULL, Skirt_Asset char(36) NOT NULL, PRIMARY KEY (`Owner`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- @@ -71,7 +71,7 @@ CREATE TABLE `userfriends` ( `friendPerms` INT NOT NULL, `datetimestamp` INT NOT NULL, UNIQUE KEY (`ownerID`, `friendID`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for users -- ---------------------------- @@ -101,7 +101,7 @@ CREATE TABLE `users` ( `webLoginKey` varchar(36) default NULL, PRIMARY KEY (`UUID`), UNIQUE KEY `usernames` (`username`,`lastname`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records @@ -138,7 +138,7 @@ COMMIT; BEGIN; -CREATE TABLE `avatarattachments` (`UUID` char(36) NOT NULL, `attachpoint` int(11) NOT NULL, `item` char(36) NOT NULL, `asset` char(36) NOT NULL) ENGINE=MyISAM; +CREATE TABLE `avatarattachments` (`UUID` char(36) NOT NULL, `attachpoint` int(11) NOT NULL, `item` char(36) NOT NULL, `asset` char(36) NOT NULL) ENGINE=InnoDB; COMMIT; diff --git a/OpenSim/Data/MySQL/Resources/XAssetStore.migrations b/OpenSim/Data/MySQL/Resources/XAssetStore.migrations index bb58c39..9459e3e 100644 --- a/OpenSim/Data/MySQL/Resources/XAssetStore.migrations +++ b/OpenSim/Data/MySQL/Resources/XAssetStore.migrations @@ -3,25 +3,30 @@ BEGIN; -CREATE TABLE `xassetsmeta` ( - `id` char(36) NOT NULL, - `hash` binary(32) NOT NULL, - `name` varchar(64) NOT NULL, - `description` varchar(64) NOT NULL, - `asset_type` tinyint(4) NOT NULL, - `local` tinyint(1) NOT NULL, - `temporary` tinyint(1) NOT NULL, - `create_time` int(11) NOT NULL, - `access_time` int(11) NOT NULL, - `asset_flags` int(11) NOT NULL, - `creator_id` varchar(128) NOT NULL, +CREATE TABLE `XAssetsMeta` ( + `ID` char(36) NOT NULL, + `Hash` binary(32) NOT NULL, + `Name` varchar(64) NOT NULL, + `Description` varchar(64) NOT NULL, + `AssetType` tinyint(4) NOT NULL, + `Local` tinyint(1) NOT NULL, + `Temporary` tinyint(1) NOT NULL, + `CreateTime` int(11) NOT NULL, + `AccessTime` int(11) NOT NULL, + `AssetFlags` int(11) NOT NULL, + `CreatorID` varchar(128) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Version 1'; +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1'; -CREATE TABLE `xassetsdata` ( - `hash` binary(32) NOT NULL, - `data` longblob NOT NULL, +CREATE TABLE `XAssetsData` ( + `Hash` binary(32) NOT NULL, + `Data` longblob NOT NULL, PRIMARY KEY (`hash`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Version 1'; +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1'; -COMMIT; \ No newline at end of file +COMMIT; + +:VERSION 2 + +BEGIN; +COMMIT; 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 @@ +:VERSION 1 # -------------------------- + +BEGIN; + +CREATE TABLE `os_groups_groups` ( + `GroupID` char(36) NOT NULL default '', + `Location` varchar(255) NOT NULL default '', + `Name` varchar(255) NOT NULL default '', + `Charter` text NOT NULL, + `InsigniaID` char(36) NOT NULL default '', + `FounderID` char(36) NOT NULL default '', + `MembershipFee` int(11) NOT NULL default '0', + `OpenEnrollment` varchar(255) NOT NULL default '', + `ShowInList` int(4) NOT NULL default '0', + `AllowPublish` int(4) NOT NULL default '0', + `MaturePublish` int(4) NOT NULL default '0', + `OwnerRoleID` char(36) NOT NULL default '', + PRIMARY KEY (`GroupID`), + UNIQUE KEY `Name` (`Name`), + FULLTEXT KEY `Name_2` (`Name`) +) ENGINE=MyISAM; + + +CREATE TABLE `os_groups_membership` ( + `GroupID`char(36) NOT NULL default '', + `PrincipalID` VARCHAR(255) NOT NULL default '', + `SelectedRoleID` char(36) NOT NULL default '', + `Contribution` int(11) NOT NULL default '0', + `ListInProfile` int(4) NOT NULL default '1', + `AcceptNotices` int(4) NOT NULL default '1', + `AccessToken` char(36) NOT NULL default '', + PRIMARY KEY (`GroupID`,`PrincipalID`), + KEY `PrincipalID` (`PrincipalID`) +) ENGINE=MyISAM; + + +CREATE TABLE `os_groups_roles` ( + `GroupID` char(36) NOT NULL default '', + `RoleID` char(36) NOT NULL default '', + `Name` varchar(255) NOT NULL default '', + `Description` varchar(255) NOT NULL default '', + `Title` varchar(255) NOT NULL default '', + `Powers` bigint(20) unsigned NOT NULL default '0', + PRIMARY KEY (`GroupID`,`RoleID`), + KEY `GroupID` (`GroupID`) +) ENGINE=MyISAM; + + +CREATE TABLE `os_groups_rolemembership` ( + `GroupID` char(36) NOT NULL default '', + `RoleID` char(36) NOT NULL default '', + `PrincipalID` VARCHAR(255) NOT NULL default '', + PRIMARY KEY (`GroupID`,`RoleID`,`PrincipalID`), + KEY `PrincipalID` (`PrincipalID`) +) ENGINE=MyISAM; + + +CREATE TABLE `os_groups_invites` ( + `InviteID` char(36) NOT NULL default '', + `GroupID` char(36) NOT NULL default '', + `RoleID` char(36) NOT NULL default '', + `PrincipalID` VARCHAR(255) NOT NULL default '', + `TMStamp` timestamp NOT NULL, + PRIMARY KEY (`InviteID`), + UNIQUE KEY `PrincipalGroup` (`GroupID`,`PrincipalID`) +) ENGINE=MyISAM; + + +CREATE TABLE `os_groups_notices` ( + `GroupID` char(36) NOT NULL default '', + `NoticeID` char(36) NOT NULL default '', + `TMStamp` int(10) unsigned NOT NULL default '0', + `FromName` varchar(255) NOT NULL default '', + `Subject` varchar(255) NOT NULL default '', + `Message` text NOT NULL, + `HasAttachment` int(4) NOT NULL default '0', + `AttachmentType` int(4) NOT NULL default '0', + `AttachmentName` varchar(128) NOT NULL default '', + `AttachmentItemID` char(36) NOT NULL default '', + `AttachmentOwnerID` varchar(255) NOT NULL default '', + PRIMARY KEY (`NoticeID`), + KEY `GroupID` (`GroupID`), + KEY `TMStamp` (`TMStamp`) +) ENGINE=MyISAM; + +CREATE TABLE `os_groups_principals` ( + `PrincipalID` VARCHAR(255) NOT NULL default '', + `ActiveGroupID` char(36) NOT NULL default '', + PRIMARY KEY (`PrincipalID`) +) ENGINE=MyISAM; + +COMMIT; + +:VERSION 2 # -------------------------- + +BEGIN; + +INSERT INTO `os_groups_groups` SELECT * from `diva_groups_groups`; +DROP TABLE `diva_groups_groups`; +INSERT INTO `os_groups_membership` SELECT * from `diva_groups_membership`; +DROP TABLE `diva_groups_membership`; +INSERT INTO `os_groups_roles` SELECT * from `diva_groups_roles`; +DROP TABLE `diva_groups_roles`; +INSERT INTO `os_groups_rolemembership` SELECT * from `diva_groups_rolemembership`; +DROP TABLE `diva_groups_rolemembership`; +INSERT INTO `os_groups_invites` SELECT * from `diva_groups_invites`; +DROP TABLE `diva_groups_invites`; +INSERT INTO `os_groups_notices` SELECT * from `diva_groups_notices`; +DROP TABLE `diva_groups_notices`; +INSERT INTO `os_groups_principals` SELECT * from `diva_groups_principals`; +DROP TABLE `diva_groups_principals`; + +DELETE FROM `migrations` WHERE name='diva_im_Store'; + +COMMIT; \ No newline at end of file diff --git a/OpenSim/Data/Null/NullEstateData.cs b/OpenSim/Data/Null/NullEstateData.cs index d64136d..57592f1 100755 --- a/OpenSim/Data/Null/NullEstateData.cs +++ b/OpenSim/Data/Null/NullEstateData.cs @@ -42,6 +42,22 @@ namespace OpenSim.Data.Null // private string m_connectionString; +// private Dictionary m_knownEstates = new Dictionary(); + private EstateSettings m_estate = null; + + private EstateSettings GetEstate() + { + if (m_estate == null) + { + // This fools the initialization caller into thinking an estate was fetched (a check in OpenSimBase). + // The estate info is pretty empty so don't try banning anyone. + m_estate = new EstateSettings(); + m_estate.EstateID = 1; + m_estate.OnSave += StoreEstateSettings; + } + return m_estate; + } + protected virtual Assembly Assembly { get { return GetType().Assembly; } @@ -68,21 +84,18 @@ namespace OpenSim.Data.Null public EstateSettings LoadEstateSettings(UUID regionID, bool create) { - // This fools the initialization caller into thinking an estate was fetched (a check in OpenSimBase). - // The estate info is pretty empty so don't try banning anyone. - EstateSettings oneEstate = new EstateSettings(); - oneEstate.EstateID = 1; - return oneEstate; + return GetEstate(); } public void StoreEstateSettings(EstateSettings es) { + m_estate = es; return; } public EstateSettings LoadEstateSettings(int estateID) { - return new EstateSettings(); + return GetEstate(); } public EstateSettings CreateNewEstate() @@ -93,13 +106,14 @@ namespace OpenSim.Data.Null public List LoadEstateSettingsAll() { List allEstateSettings = new List(); - allEstateSettings.Add(new EstateSettings()); + allEstateSettings.Add(GetEstate()); return allEstateSettings; } public List GetEstatesAll() { List result = new List(); + result.Add((int)GetEstate().EstateID); return result; } diff --git a/OpenSim/Data/Null/NullPresenceData.cs b/OpenSim/Data/Null/NullPresenceData.cs index b85b95e..aff0b0b 100644 --- a/OpenSim/Data/Null/NullPresenceData.cs +++ b/OpenSim/Data/Null/NullPresenceData.cs @@ -40,7 +40,7 @@ namespace OpenSim.Data.Null { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static NullPresenceData Instance; + public static NullPresenceData Instance; Dictionary m_presenceData = new Dictionary(); diff --git a/OpenSim/Data/Null/NullRegionData.cs b/OpenSim/Data/Null/NullRegionData.cs index f707d98..d28cd99 100644 --- a/OpenSim/Data/Null/NullRegionData.cs +++ b/OpenSim/Data/Null/NullRegionData.cs @@ -239,6 +239,11 @@ namespace OpenSim.Data.Null return Get((int)RegionFlags.DefaultRegion, scopeID); } + public List GetDefaultHypergridRegions(UUID scopeID) + { + return Get((int)RegionFlags.DefaultHGRegion, scopeID); + } + public List GetFallbackRegions(UUID scopeID, int x, int y) { List regions = Get((int)RegionFlags.FallbackRegion, scopeID); diff --git a/OpenSim/Data/Null/NullSimulationData.cs b/OpenSim/Data/Null/NullSimulationData.cs index 4979cf6..deeaced 100644 --- a/OpenSim/Data/Null/NullSimulationData.cs +++ b/OpenSim/Data/Null/NullSimulationData.cs @@ -77,20 +77,34 @@ namespace OpenSim.Data.Null } #region Environment Settings + + private Dictionary EnvironmentSettings = new Dictionary(); + public string LoadRegionEnvironmentSettings(UUID regionUUID) { - //This connector doesn't support the Environment module yet + lock (EnvironmentSettings) + { + if (EnvironmentSettings.ContainsKey(regionUUID)) + return EnvironmentSettings[regionUUID]; + } return string.Empty; } public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) { - //This connector doesn't support the Environment module yet + lock (EnvironmentSettings) + { + EnvironmentSettings[regionUUID] = settings; + } } public void RemoveRegionEnvironmentSettings(UUID regionUUID) { - //This connector doesn't support the Environment module yet + lock (EnvironmentSettings) + { + if (EnvironmentSettings.ContainsKey(regionUUID)) + EnvironmentSettings.Remove(regionUUID); + } } #endregion @@ -118,18 +132,36 @@ namespace OpenSim.Data.Null return new List(); } - Dictionary m_terrains = new Dictionary(); - public void StoreTerrain(double[,] ter, UUID regionID) + Dictionary m_terrains = new Dictionary(); + public void StoreTerrain(TerrainData ter, UUID regionID) { if (m_terrains.ContainsKey(regionID)) m_terrains.Remove(regionID); m_terrains.Add(regionID, ter); } + // Legacy. Just don't do this. + public void StoreTerrain(double[,] ter, UUID regionID) + { + TerrainData terrData = new HeightmapTerrainData(ter); + StoreTerrain(terrData, regionID); + } + + // Legacy. Just don't do this. + // Returns 'null' if region not found public double[,] LoadTerrain(UUID regionID) { if (m_terrains.ContainsKey(regionID)) { + return m_terrains[regionID].GetDoubles(); + } + return null; + } + + public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ) + { + if (m_terrains.ContainsKey(regionID)) + { return m_terrains[regionID]; } return null; diff --git a/OpenSim/Data/Null/NullXGroupData.cs b/OpenSim/Data/Null/NullXGroupData.cs index 7a86b9f..3fa9451 100644 --- a/OpenSim/Data/Null/NullXGroupData.cs +++ b/OpenSim/Data/Null/NullXGroupData.cs @@ -38,7 +38,7 @@ using OpenSim.Data; namespace OpenSim.Data.Null { - public class NullXGroupData : NullGenericDataHandler, IXGroupData + public class NullXGroupData : IXGroupData { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -56,35 +56,31 @@ namespace OpenSim.Data.Null return true; } - public XGroup[] GetGroups(string field, string val) + public XGroup GetGroup(UUID groupID) { - return GetGroups(new string[] { field }, new string[] { val }); - } + XGroup group = null; - public XGroup[] GetGroups(string[] fields, string[] vals) - { lock (m_groups) - { - List origGroups = Get(fields, vals, m_groups.Values.ToList()); + m_groups.TryGetValue(groupID, out group); - return origGroups.Select(g => g.Clone()).ToArray(); - } + return group; } - public bool DeleteGroups(string field, string val) + public Dictionary GetGroups() { - return DeleteGroups(new string[] { field }, new string[] { val }); + Dictionary groupsClone = new Dictionary(); + + lock (m_groups) + foreach (XGroup group in m_groups.Values) + groupsClone[group.groupID] = group.Clone(); + + return groupsClone; } - public bool DeleteGroups(string[] fields, string[] vals) + public bool DeleteGroup(UUID groupID) { lock (m_groups) - { - XGroup[] groupsToDelete = GetGroups(fields, vals); - Array.ForEach(groupsToDelete, g => m_groups.Remove(g.groupID)); - } - - return true; + return m_groups.Remove(groupID); } } } \ No newline at end of file diff --git a/OpenSim/Data/Null/Properties/AssemblyInfo.cs b/OpenSim/Data/Null/Properties/AssemblyInfo.cs index 43b0bb3..a827bd0 100644 --- a/OpenSim/Data/Null/Properties/AssemblyInfo.cs +++ b/OpenSim/Data/Null/Properties/AssemblyInfo.cs @@ -61,5 +61,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly : AssemblyVersion("0.7.5.*")] -[assembly : AssemblyFileVersion("0.6.5.0")] +[assembly : AssemblyVersion("0.8.2.*")] + diff --git a/OpenSim/Data/PGSQL/PGSQLAgentPreferencesData.cs b/OpenSim/Data/PGSQL/PGSQLAgentPreferencesData.cs new file mode 100644 index 0000000..20612fe --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLAgentPreferencesData.cs @@ -0,0 +1,64 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using OpenMetaverse; +using OpenSim.Framework; +using Npgsql; + +namespace OpenSim.Data.PGSQL +{ + public class PGSQLAgentPreferencesData : PGSQLGenericTableHandler, IAgentPreferencesData + { + public PGSQLAgentPreferencesData(string connectionString, string realm) + : base(connectionString, realm, "AgentPrefs") + { + } + + public AgentPreferencesData GetPrefs(UUID agentID) + { + // Until someone sends in a table that works + return null; + //AgentPreferencesData[] ret = Get("PrincipalID", agentID.ToString()); + + //if (ret.Length == 0) + // return null; + + //return ret[0]; + } + + public override bool Store(AgentPreferencesData row) + { + // Until someone sends in a table that works + return false; + } + + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLAssetData.cs b/OpenSim/Data/PGSQL/PGSQLAssetData.cs new file mode 100644 index 0000000..5d8b0a2 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLAssetData.cs @@ -0,0 +1,316 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Data; +using System.Reflection; +using System.Collections.Generic; +using OpenMetaverse; +using log4net; +using OpenSim.Framework; +using Npgsql; +using NpgsqlTypes; + +namespace OpenSim.Data.PGSQL +{ + /// + /// A PGSQL Interface for the Asset server + /// + public class PGSQLAssetData : AssetDataBase + { + private const string _migrationStore = "AssetStore"; + + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private long m_ticksToEpoch; + /// + /// Database manager + /// + private PGSQLManager m_database; + private string m_connectionString; + + protected virtual Assembly Assembly + { + get { return GetType().Assembly; } + } + + #region IPlugin Members + + override public void Dispose() { } + + /// + /// Initialises asset interface + /// + // [Obsolete("Cannot be default-initialized!")] + override public void Initialise() + { + m_log.Info("[PGSQLAssetData]: " + Name + " cannot be default-initialized!"); + throw new PluginNotInitialisedException(Name); + } + + /// + /// Initialises asset interface + /// + /// + /// a string instead of file, if someone writes the support + /// + /// connect string + override public void Initialise(string connectionString) + { + m_ticksToEpoch = new System.DateTime(1970, 1, 1).Ticks; + + m_database = new PGSQLManager(connectionString); + m_connectionString = connectionString; + + //New migration to check for DB changes + m_database.CheckMigration(_migrationStore); + } + + /// + /// Database provider version. + /// + override public string Version + { + get { return m_database.getVersion(); } + } + + /// + /// The name of this DB provider. + /// + override public string Name + { + get { return "PGSQL Asset storage engine"; } + } + + #endregion + + #region IAssetDataPlugin Members + + /// + /// Fetch Asset from m_database + /// + /// the asset UUID + /// + override public AssetBase GetAsset(UUID assetID) + { + string sql = "SELECT * FROM assets WHERE id = :id"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("id", assetID)); + conn.Open(); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + AssetBase asset = new AssetBase( + DBGuid.FromDB(reader["id"]), + (string)reader["name"], + Convert.ToSByte(reader["assetType"]), + reader["creatorid"].ToString() + ); + // Region Main + asset.Description = (string)reader["description"]; + asset.Local = Convert.ToBoolean(reader["local"]); + asset.Temporary = Convert.ToBoolean(reader["temporary"]); + asset.Flags = (AssetFlags)(Convert.ToInt32(reader["asset_flags"])); + asset.Data = (byte[])reader["data"]; + return asset; + } + return null; // throw new Exception("No rows to return"); + } + } + } + + /// + /// Create asset in m_database + /// + /// the asset + override public void StoreAsset(AssetBase asset) + { + + string sql = + @"UPDATE assets set name = :name, description = :description, " + "\"assetType\" " + @" = :assetType, + local = :local, temporary = :temporary, creatorid = :creatorid, data = :data + WHERE id=:id; + + INSERT INTO assets + (id, name, description, " + "\"assetType\" " + @", local, + temporary, create_time, access_time, creatorid, asset_flags, data) + Select :id, :name, :description, :assetType, :local, + :temporary, :create_time, :access_time, :creatorid, :asset_flags, :data + Where not EXISTS(SELECT * FROM assets WHERE id=:id) + "; + + string assetName = asset.Name; + if (asset.Name.Length > AssetBase.MAX_ASSET_NAME) + { + assetName = asset.Name.Substring(0, AssetBase.MAX_ASSET_NAME); + m_log.WarnFormat( + "[ASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add", + asset.Name, asset.ID, asset.Name.Length, assetName.Length); + } + + string assetDescription = asset.Description; + if (asset.Description.Length > AssetBase.MAX_ASSET_DESC) + { + assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); + m_log.WarnFormat( + "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", + asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); + } + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand command = new NpgsqlCommand(sql, conn)) + { + int now = (int)((System.DateTime.Now.Ticks - m_ticksToEpoch) / 10000000); + command.Parameters.Add(m_database.CreateParameter("id", asset.FullID)); + command.Parameters.Add(m_database.CreateParameter("name", assetName)); + command.Parameters.Add(m_database.CreateParameter("description", assetDescription)); + command.Parameters.Add(m_database.CreateParameter("assetType", asset.Type)); + command.Parameters.Add(m_database.CreateParameter("local", asset.Local)); + command.Parameters.Add(m_database.CreateParameter("temporary", asset.Temporary)); + command.Parameters.Add(m_database.CreateParameter("access_time", now)); + command.Parameters.Add(m_database.CreateParameter("create_time", now)); + command.Parameters.Add(m_database.CreateParameter("asset_flags", (int)asset.Flags)); + command.Parameters.Add(m_database.CreateParameter("creatorid", asset.Metadata.CreatorID)); + command.Parameters.Add(m_database.CreateParameter("data", asset.Data)); + conn.Open(); + try + { + command.ExecuteNonQuery(); + } + catch(Exception e) + { + m_log.Error("[ASSET DB]: Error storing item :" + e.Message + " sql "+sql); + } + } + } + + +// Commented out since currently unused - this probably should be called in GetAsset() +// private void UpdateAccessTime(AssetBase asset) +// { +// using (AutoClosingSqlCommand cmd = m_database.Query("UPDATE assets SET access_time = :access_time WHERE id=:id")) +// { +// int now = (int)((System.DateTime.Now.Ticks - m_ticksToEpoch) / 10000000); +// cmd.Parameters.AddWithValue(":id", asset.FullID.ToString()); +// cmd.Parameters.AddWithValue(":access_time", now); +// try +// { +// cmd.ExecuteNonQuery(); +// } +// catch (Exception e) +// { +// m_log.Error(e.ToString()); +// } +// } +// } + + /// + /// Check if the assets exist in the database. + /// + /// The assets' IDs + /// For each asset: true if it exists, false otherwise + public override bool[] AssetsExist(UUID[] uuids) + { + if (uuids.Length == 0) + return new bool[0]; + + HashSet exist = new HashSet(); + + string ids = "'" + string.Join("','", uuids) + "'"; + string sql = string.Format("SELECT id FROM assets WHERE id IN ({0})", ids); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + conn.Open(); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + UUID id = DBGuid.FromDB(reader["id"]); + exist.Add(id); + } + } + } + + bool[] results = new bool[uuids.Length]; + for (int i = 0; i < uuids.Length; i++) + results[i] = exist.Contains(uuids[i]); + return results; + } + + /// + /// Returns a list of AssetMetadata objects. The list is a subset of + /// the entire data set offset by containing + /// elements. + /// + /// The number of results to discard from the total data set. + /// The number of rows the returned list should contain. + /// A list of AssetMetadata objects. + public override List FetchAssetMetadataSet(int start, int count) + { + List retList = new List(count); + string sql = @" SELECT id, name, description, " + "\"assetType\"" + @", temporary, creatorid + FROM assets + order by id + limit :stop + offset :start;"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("start", start)); + cmd.Parameters.Add(m_database.CreateParameter("stop", start + count - 1)); + conn.Open(); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + AssetMetadata metadata = new AssetMetadata(); + metadata.FullID = DBGuid.FromDB(reader["id"]); + metadata.Name = (string)reader["name"]; + metadata.Description = (string)reader["description"]; + metadata.Type = Convert.ToSByte(reader["assetType"]); + metadata.Temporary = Convert.ToBoolean(reader["temporary"]); + metadata.CreatorID = (string)reader["creatorid"]; + retList.Add(metadata); + } + } + } + + return retList; + } + + public override bool Delete(string id) + { + return false; + } + #endregion + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLAuthenticationData.cs b/OpenSim/Data/PGSQL/PGSQLAuthenticationData.cs new file mode 100644 index 0000000..d174112 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLAuthenticationData.cs @@ -0,0 +1,254 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using OpenMetaverse; +using OpenSim.Framework; +using System.Reflection; +using System.Text; +using System.Data; +using Npgsql; +using NpgsqlTypes; + +namespace OpenSim.Data.PGSQL +{ + public class PGSQLAuthenticationData : IAuthenticationData + { + private string m_Realm; + private List m_ColumnNames = null; + private int m_LastExpire = 0; + private string m_ConnectionString; + private PGSQLManager m_database; + + protected virtual Assembly Assembly + { + get { return GetType().Assembly; } + } + + public PGSQLAuthenticationData(string connectionString, string realm) + { + m_Realm = realm; + m_ConnectionString = connectionString; + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + { + conn.Open(); + Migration m = new Migration(conn, GetType().Assembly, "AuthStore"); + m_database = new PGSQLManager(m_ConnectionString); + m.Update(); + } + } + + public AuthenticationData Get(UUID principalID) + { + AuthenticationData ret = new AuthenticationData(); + ret.Data = new Dictionary(); + + string sql = string.Format("select * from {0} where uuid = :principalID", m_Realm); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("principalID", principalID)); + conn.Open(); + using (NpgsqlDataReader result = cmd.ExecuteReader()) + { + if (result.Read()) + { + ret.PrincipalID = principalID; + + if (m_ColumnNames == null) + { + m_ColumnNames = new List(); + + DataTable schemaTable = result.GetSchemaTable(); + foreach (DataRow row in schemaTable.Rows) + m_ColumnNames.Add(row["ColumnName"].ToString()); + } + + foreach (string s in m_ColumnNames) + { + if (s == "UUID"||s == "uuid") + continue; + + ret.Data[s] = result[s].ToString(); + } + return ret; + } + } + } + return null; + } + + public bool Store(AuthenticationData data) + { + if (data.Data.ContainsKey("UUID")) + data.Data.Remove("UUID"); + if (data.Data.ContainsKey("uuid")) + data.Data.Remove("uuid"); + + /* + Dictionary oAuth = new Dictionary(); + + foreach (KeyValuePair oDado in data.Data) + { + if (oDado.Key != oDado.Key.ToLower()) + { + oAuth.Add(oDado.Key.ToLower(), oDado.Value); + } + } + foreach (KeyValuePair oDado in data.Data) + { + if (!oAuth.ContainsKey(oDado.Key.ToLower())) { + oAuth.Add(oDado.Key.ToLower(), oDado.Value); + } + } + */ + string[] fields = new List(data.Data.Keys).ToArray(); + StringBuilder updateBuilder = new StringBuilder(); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + updateBuilder.AppendFormat("update {0} set ", m_Realm); + + bool first = true; + foreach (string field in fields) + { + if (!first) + updateBuilder.Append(", "); + updateBuilder.AppendFormat("\"{0}\" = :{0}",field); + + first = false; + + cmd.Parameters.Add(m_database.CreateParameter("" + field, data.Data[field])); + } + + updateBuilder.Append(" where uuid = :principalID"); + + cmd.CommandText = updateBuilder.ToString(); + cmd.Connection = conn; + cmd.Parameters.Add(m_database.CreateParameter("principalID", data.PrincipalID)); + + conn.Open(); + if (cmd.ExecuteNonQuery() < 1) + { + StringBuilder insertBuilder = new StringBuilder(); + + insertBuilder.AppendFormat("insert into {0} (uuid, \"", m_Realm); + insertBuilder.Append(String.Join("\", \"", fields)); + insertBuilder.Append("\") values (:principalID, :"); + insertBuilder.Append(String.Join(", :", fields)); + insertBuilder.Append(")"); + + cmd.CommandText = insertBuilder.ToString(); + + if (cmd.ExecuteNonQuery() < 1) + { + return false; + } + } + } + return true; + } + + public bool SetDataItem(UUID principalID, string item, string value) + { + string sql = string.Format("update {0} set {1} = :{1} where uuid = :UUID", m_Realm, item); + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("" + item, value)); + conn.Open(); + if (cmd.ExecuteNonQuery() > 0) + return true; + } + return false; + } + + public bool SetToken(UUID principalID, string token, int lifetime) + { + if (System.Environment.TickCount - m_LastExpire > 30000) + DoExpire(); + + string sql = "insert into tokens (uuid, token, validity) values (:principalID, :token, :lifetime)"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("principalID", principalID)); + cmd.Parameters.Add(m_database.CreateParameter("token", token)); + cmd.Parameters.Add(m_database.CreateParameter("lifetime", DateTime.Now.AddMinutes(lifetime))); + conn.Open(); + + if (cmd.ExecuteNonQuery() > 0) + { + return true; + } + } + return false; + } + + public bool CheckToken(UUID principalID, string token, int lifetime) + { + if (System.Environment.TickCount - m_LastExpire > 30000) + DoExpire(); + + DateTime validDate = DateTime.Now.AddMinutes(lifetime); + string sql = "update tokens set validity = :validDate where uuid = :principalID and token = :token and validity > (CURRENT_DATE + CURRENT_TIME)"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("principalID", principalID)); + cmd.Parameters.Add(m_database.CreateParameter("token", token)); + cmd.Parameters.Add(m_database.CreateParameter("validDate", validDate)); + conn.Open(); + + if (cmd.ExecuteNonQuery() > 0) + { + return true; + } + } + return false; + } + + private void DoExpire() + { + DateTime currentDateTime = DateTime.Now; + string sql = "delete from tokens where validity < :currentDateTime"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + conn.Open(); + cmd.Parameters.Add(m_database.CreateParameter("currentDateTime", currentDateTime)); + cmd.ExecuteNonQuery(); + } + m_LastExpire = System.Environment.TickCount; + } + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLAvatarData.cs b/OpenSim/Data/PGSQL/PGSQLAvatarData.cs new file mode 100644 index 0000000..d9c4905 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLAvatarData.cs @@ -0,0 +1,72 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using Npgsql; +using NpgsqlTypes; + + +namespace OpenSim.Data.PGSQL +{ + /// + /// A PGSQL Interface for Avatar Storage + /// + public class PGSQLAvatarData : PGSQLGenericTableHandler, + IAvatarData + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public PGSQLAvatarData(string connectionString, string realm) : + base(connectionString, realm, "Avatar") + { + } + + public bool Delete(UUID principalID, string name) + { + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + + cmd.CommandText = String.Format("DELETE FROM {0} where \"PrincipalID\" = :PrincipalID and \"Name\" = :Name", m_Realm); + cmd.Parameters.Add(m_database.CreateParameter("PrincipalID", principalID)); + cmd.Parameters.Add(m_database.CreateParameter("Name", name)); + cmd.Connection = conn; + conn.Open(); + if (cmd.ExecuteNonQuery() > 0) + return true; + + return false; + } + } + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLEstateData.cs b/OpenSim/Data/PGSQL/PGSQLEstateData.cs new file mode 100644 index 0000000..b5ca235 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLEstateData.cs @@ -0,0 +1,602 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using System.Data; +using Npgsql; +using NpgsqlTypes; + +namespace OpenSim.Data.PGSQL +{ + public class PGSQLEstateStore : IEstateDataStore + { + private const string _migrationStore = "EstateStore"; + + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private PGSQLManager _Database; + private string m_connectionString; + private FieldInfo[] _Fields; + private Dictionary _FieldMap = new Dictionary(); + + #region Public methods + + public PGSQLEstateStore() + { + } + + public PGSQLEstateStore(string connectionString) + { + Initialise(connectionString); + } + + protected virtual Assembly Assembly + { + get { return GetType().Assembly; } + } + + /// + /// Initialises the estatedata class. + /// + /// connectionString. + public void Initialise(string connectionString) + { + if (!string.IsNullOrEmpty(connectionString)) + { + m_connectionString = connectionString; + _Database = new PGSQLManager(connectionString); + } + + //Migration settings + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + conn.Open(); + Migration m = new Migration(conn, GetType().Assembly, "EstateStore"); + m.Update(); + } + + //Interesting way to get parameters! Maybe implement that also with other types + Type t = typeof(EstateSettings); + _Fields = t.GetFields(BindingFlags.NonPublic | + BindingFlags.Instance | + BindingFlags.DeclaredOnly); + + foreach (FieldInfo f in _Fields) + { + if (f.Name.Substring(0, 2) == "m_") + _FieldMap[f.Name.Substring(2)] = f; + } + } + + /// + /// Loads the estate settings. + /// + /// region ID. + /// + public EstateSettings LoadEstateSettings(UUID regionID, bool create) + { + EstateSettings es = new EstateSettings(); + + string sql = "select estate_settings.\"" + String.Join("\",estate_settings.\"", FieldList) + + "\" from estate_map left join estate_settings on estate_map.\"EstateID\" = estate_settings.\"EstateID\" " + + " where estate_settings.\"EstateID\" is not null and \"RegionID\" = :RegionID"; + + bool insertEstate = false; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("RegionID", regionID)); + conn.Open(); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + foreach (string name in FieldList) + { + FieldInfo f = _FieldMap[name]; + object v = reader[name]; + if (f.FieldType == typeof(bool)) + { + f.SetValue(es, v); + } + else if (f.FieldType == typeof(UUID)) + { + UUID estUUID = UUID.Zero; + + UUID.TryParse(v.ToString(), out estUUID); + + f.SetValue(es, estUUID); + } + else if (f.FieldType == typeof(string)) + { + f.SetValue(es, v.ToString()); + } + else if (f.FieldType == typeof(UInt32)) + { + f.SetValue(es, Convert.ToUInt32(v)); + } + else if (f.FieldType == typeof(Single)) + { + f.SetValue(es, Convert.ToSingle(v)); + } + else + f.SetValue(es, v); + } + } + else + { + insertEstate = true; + } + } + } + + if (insertEstate && create) + { + DoCreate(es); + LinkRegion(regionID, (int)es.EstateID); + } + + LoadBanList(es); + + es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers"); + es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users"); + es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups"); + + //Set event + es.OnSave += StoreEstateSettings; + return es; + } + + public EstateSettings CreateNewEstate() + { + EstateSettings es = new EstateSettings(); + es.OnSave += StoreEstateSettings; + + DoCreate(es); + + LoadBanList(es); + + es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers"); + es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users"); + es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups"); + + return es; + } + + private void DoCreate(EstateSettings es) + { + List names = new List(FieldList); + + names.Remove("EstateID"); + + string sql = string.Format("insert into estate_settings (\"{0}\") values ( :{1} )", String.Join("\",\"", names.ToArray()), String.Join(", :", names.ToArray())); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand insertCommand = new NpgsqlCommand(sql, conn)) + { + insertCommand.CommandText = sql; + + foreach (string name in names) + { + insertCommand.Parameters.Add(_Database.CreateParameter("" + name, _FieldMap[name].GetValue(es))); + } + //NpgsqlParameter idParameter = new NpgsqlParameter("ID", SqlDbType.Int); + //idParameter.Direction = ParameterDirection.Output; + //insertCommand.Parameters.Add(idParameter); + conn.Open(); + + es.EstateID = 100; + + if (insertCommand.ExecuteNonQuery() > 0) + { + insertCommand.CommandText = "Select cast(lastval() as int) as ID ;"; + + using (NpgsqlDataReader result = insertCommand.ExecuteReader()) + { + if (result.Read()) + { + es.EstateID = (uint)result.GetInt32(0); + } + } + } + + } + + //TODO check if this is needed?? + es.Save(); + } + + /// + /// Stores the estate settings. + /// + /// estate settings + public void StoreEstateSettings(EstateSettings es) + { + List names = new List(FieldList); + + names.Remove("EstateID"); + + string sql = string.Format("UPDATE estate_settings SET "); + foreach (string name in names) + { + sql += "\"" + name + "\" = :" + name + ", "; + } + sql = sql.Remove(sql.LastIndexOf(",")); + sql += " WHERE \"EstateID\" = :EstateID"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + foreach (string name in names) + { + cmd.Parameters.Add(_Database.CreateParameter("" + name, _FieldMap[name].GetValue(es))); + } + + cmd.Parameters.Add(_Database.CreateParameter("EstateID", es.EstateID)); + conn.Open(); + cmd.ExecuteNonQuery(); + } + + SaveBanList(es); + SaveUUIDList(es.EstateID, "estate_managers", es.EstateManagers); + SaveUUIDList(es.EstateID, "estate_users", es.EstateAccess); + SaveUUIDList(es.EstateID, "estate_groups", es.EstateGroups); + } + + #endregion + + #region Private methods + + private string[] FieldList + { + get { return new List(_FieldMap.Keys).ToArray(); } + } + + private void LoadBanList(EstateSettings es) + { + es.ClearBans(); + + string sql = "select \"bannedUUID\" from estateban where \"EstateID\" = :EstateID"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + NpgsqlParameter idParameter = new NpgsqlParameter("EstateID", DbType.Int32); + idParameter.Value = es.EstateID; + cmd.Parameters.Add(idParameter); + conn.Open(); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + EstateBan eb = new EstateBan(); + + eb.BannedUserID = new UUID((Guid)reader["bannedUUID"]); //uuid; + eb.BannedHostAddress = "0.0.0.0"; + eb.BannedHostIPMask = "0.0.0.0"; + es.AddBan(eb); + } + } + } + } + + private UUID[] LoadUUIDList(uint estateID, string table) + { + List uuids = new List(); + + string sql = string.Format("select uuid from {0} where \"EstateID\" = :EstateID", table); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("EstateID", estateID)); + conn.Open(); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + uuids.Add(new UUID((Guid)reader["uuid"])); //uuid); + } + } + } + + return uuids.ToArray(); + } + + private void SaveBanList(EstateSettings es) + { + //Delete first + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + conn.Open(); + using (NpgsqlCommand cmd = conn.CreateCommand()) + { + cmd.CommandText = "delete from estateban where \"EstateID\" = :EstateID"; + cmd.Parameters.AddWithValue("EstateID", (int)es.EstateID); + cmd.ExecuteNonQuery(); + + //Insert after + cmd.CommandText = "insert into estateban (\"EstateID\", \"bannedUUID\",\"bannedIp\", \"bannedIpHostMask\", \"bannedNameMask\") values ( :EstateID, :bannedUUID, '','','' )"; + cmd.Parameters.AddWithValue("bannedUUID", Guid.Empty); + foreach (EstateBan b in es.EstateBans) + { + cmd.Parameters["bannedUUID"].Value = b.BannedUserID.Guid; + cmd.ExecuteNonQuery(); + } + } + } + } + + private void SaveUUIDList(uint estateID, string table, UUID[] data) + { + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + conn.Open(); + using (NpgsqlCommand cmd = conn.CreateCommand()) + { + cmd.Parameters.AddWithValue("EstateID", (int)estateID); + cmd.CommandText = string.Format("delete from {0} where \"EstateID\" = :EstateID", table); + cmd.ExecuteNonQuery(); + + cmd.CommandText = string.Format("insert into {0} (\"EstateID\", uuid) values ( :EstateID, :uuid )", table); + cmd.Parameters.AddWithValue("uuid", Guid.Empty); + foreach (UUID uuid in data) + { + cmd.Parameters["uuid"].Value = uuid.Guid; //.ToString(); //TODO check if this works + cmd.ExecuteNonQuery(); + } + } + } + } + + public EstateSettings LoadEstateSettings(int estateID) + { + EstateSettings es = new EstateSettings(); + string sql = "select estate_settings.\"" + String.Join("\",estate_settings.\"", FieldList) + "\" from estate_settings where \"EstateID\" = :EstateID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + conn.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.AddWithValue("EstateID", (int)estateID); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + foreach (string name in FieldList) + { + FieldInfo f = _FieldMap[name]; + object v = reader[name]; + if (f.FieldType == typeof(bool)) + { + f.SetValue(es, Convert.ToInt32(v) != 0); + } + else if (f.FieldType == typeof(UUID)) + { + f.SetValue(es, new UUID((Guid)v)); // uuid); + } + else if (f.FieldType == typeof(string)) + { + f.SetValue(es, v.ToString()); + } + else if (f.FieldType == typeof(UInt32)) + { + f.SetValue(es, Convert.ToUInt32(v)); + } + else if (f.FieldType == typeof(Single)) + { + f.SetValue(es, Convert.ToSingle(v)); + } + else + f.SetValue(es, v); + } + } + + } + } + } + LoadBanList(es); + + es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers"); + es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users"); + es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups"); + + //Set event + es.OnSave += StoreEstateSettings; + return es; + + } + + public List LoadEstateSettingsAll() + { + List allEstateSettings = new List(); + + List allEstateIds = GetEstatesAll(); + + foreach (int estateId in allEstateIds) + allEstateSettings.Add(LoadEstateSettings(estateId)); + + return allEstateSettings; + } + + public List GetEstates(string search) + { + List result = new List(); + string sql = "select \"EstateID\" from estate_settings where lower(\"EstateName\") = lower(:EstateName)"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + conn.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.AddWithValue("EstateName", search); + + using (IDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + result.Add(Convert.ToInt32(reader["EstateID"])); + } + reader.Close(); + } + } + } + + return result; + } + + public List GetEstatesAll() + { + List result = new List(); + string sql = "select \"EstateID\" from estate_settings"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + conn.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + using (IDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + result.Add(Convert.ToInt32(reader["EstateID"])); + } + reader.Close(); + } + } + } + + return result; + } + + public List GetEstatesByOwner(UUID ownerID) + { + List result = new List(); + string sql = "select \"EstateID\" from estate_settings where \"EstateOwner\" = :EstateOwner"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + conn.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.AddWithValue("EstateOwner", ownerID); + + using (IDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + result.Add(Convert.ToInt32(reader["EstateID"])); + } + reader.Close(); + } + } + } + + return result; + } + + public bool LinkRegion(UUID regionID, int estateID) + { + string deleteSQL = "delete from estate_map where \"RegionID\" = :RegionID"; + string insertSQL = "insert into estate_map values (:RegionID, :EstateID)"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + conn.Open(); + + NpgsqlTransaction transaction = conn.BeginTransaction(); + + try + { + using (NpgsqlCommand cmd = new NpgsqlCommand(deleteSQL, conn)) + { + cmd.Transaction = transaction; + cmd.Parameters.AddWithValue("RegionID", regionID.Guid); + + cmd.ExecuteNonQuery(); + } + + using (NpgsqlCommand cmd = new NpgsqlCommand(insertSQL, conn)) + { + cmd.Transaction = transaction; + cmd.Parameters.AddWithValue("RegionID", regionID.Guid); + cmd.Parameters.AddWithValue("EstateID", estateID); + + int ret = cmd.ExecuteNonQuery(); + + if (ret != 0) + transaction.Commit(); + else + transaction.Rollback(); + + return (ret != 0); + } + } + catch (Exception ex) + { + m_log.Error("[REGION DB]: LinkRegion failed: " + ex.Message); + transaction.Rollback(); + } + } + return false; + } + + public List GetRegions(int estateID) + { + List result = new List(); + string sql = "select \"RegionID\" from estate_map where \"EstateID\" = :EstateID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + conn.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.AddWithValue("EstateID", estateID); + + using (IDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + result.Add(DBGuid.FromDB(reader["RegionID"])); + } + reader.Close(); + } + } + } + + return result; + } + + public bool DeleteEstate(int estateID) + { + // TODO: Implementation! + return false; + } + #endregion + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLFramework.cs b/OpenSim/Data/PGSQL/PGSQLFramework.cs new file mode 100644 index 0000000..1028e4e --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLFramework.cs @@ -0,0 +1,111 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Reflection; +using OpenMetaverse; +using OpenSim.Framework; +using Npgsql; + +namespace OpenSim.Data.PGSQL +{ + /// + /// A database interface class to a user profile storage system + /// + public class PGSqlFramework + { + private static readonly log4net.ILog m_log = + log4net.LogManager.GetLogger( + System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + protected string m_connectionString; + protected object m_dbLock = new object(); + + protected PGSqlFramework(string connectionString) + { + m_connectionString = connectionString; + InitializeMonoSecurity(); + } + + public void InitializeMonoSecurity() + { + if (!Util.IsPlatformMono) + { + + if (AppDomain.CurrentDomain.GetData("MonoSecurityPostgresAdded") == null) + { + AppDomain.CurrentDomain.SetData("MonoSecurityPostgresAdded", "true"); + + AppDomain currentDomain = AppDomain.CurrentDomain; + currentDomain.AssemblyResolve += new ResolveEventHandler(ResolveEventHandlerMonoSec); + } + } + } + + private System.Reflection.Assembly ResolveEventHandlerMonoSec(object sender, ResolveEventArgs args) + { + Assembly MyAssembly = null; + + if (args.Name.Substring(0, args.Name.IndexOf(",")) == "Mono.Security") + { + MyAssembly = Assembly.LoadFrom("lib/NET/Mono.Security.dll"); + } + + //Return the loaded assembly. + return MyAssembly; + } + ////////////////////////////////////////////////////////////// + // + // All non queries are funneled through one connection + // to increase performance a little + // + protected int ExecuteNonQuery(NpgsqlCommand cmd) + { + lock (m_dbLock) + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString)) + { + dbcon.Open(); + cmd.Connection = dbcon; + + try + { + return cmd.ExecuteNonQuery(); + } + catch (Exception e) + { + m_log.Error(e.Message, e); + return 0; + } + } + } + } + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLFriendsData.cs b/OpenSim/Data/PGSQL/PGSQLFriendsData.cs new file mode 100644 index 0000000..a841353 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLFriendsData.cs @@ -0,0 +1,116 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using OpenMetaverse; +using OpenSim.Framework; +using System.Reflection; +using System.Text; +using Npgsql; + +namespace OpenSim.Data.PGSQL +{ + public class PGSQLFriendsData : PGSQLGenericTableHandler, IFriendsData + { + public PGSQLFriendsData(string connectionString, string realm) + : base(connectionString, realm, "FriendsStore") + { + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + { + conn.Open(); + Migration m = new Migration(conn, GetType().Assembly, "FriendsStore"); + m.Update(); + } + } + + + public override bool Delete(string principalID, string friend) + { + UUID princUUID = UUID.Zero; + + bool ret = UUID.TryParse(principalID, out princUUID); + + if (ret) + return Delete(princUUID, friend); + else + return false; + } + + public bool Delete(UUID principalID, string friend) + { + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + cmd.CommandText = String.Format("delete from {0} where \"PrincipalID\" = :PrincipalID and \"Friend\" = :Friend", m_Realm); + cmd.Parameters.Add(m_database.CreateParameter("PrincipalID", principalID.ToString())); + cmd.Parameters.Add(m_database.CreateParameter("Friend", friend)); + cmd.Connection = conn; + conn.Open(); + cmd.ExecuteNonQuery(); + + return true; + } + } + + public FriendsData[] GetFriends(string principalID) + { + UUID princUUID = UUID.Zero; + + bool ret = UUID.TryParse(principalID, out princUUID); + + if (ret) + return GetFriends(princUUID); + else + return new FriendsData[0]; + } + + public FriendsData[] GetFriends(UUID principalID) + { + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + + cmd.CommandText = String.Format("select a.*,case when b.\"Flags\" is null then '-1' else b.\"Flags\" end as \"TheirFlags\" from {0} as a " + + " left join {0} as b on a.\"PrincipalID\" = b.\"Friend\" and a.\"Friend\" = b.\"PrincipalID\" " + + " where a.\"PrincipalID\" = :PrincipalID", m_Realm); + cmd.Parameters.Add(m_database.CreateParameter("PrincipalID", principalID.ToString())); + cmd.Connection = conn; + conn.Open(); + return DoQuery(cmd); + } + } + + public FriendsData[] GetFriends(Guid principalID) + { + return GetFriends(principalID); + } + + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLGenericTableHandler.cs b/OpenSim/Data/PGSQL/PGSQLGenericTableHandler.cs new file mode 100644 index 0000000..826c6fc --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLGenericTableHandler.cs @@ -0,0 +1,537 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Data; +using System.Reflection; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using System.Text; +using Npgsql; + +namespace OpenSim.Data.PGSQL +{ + public class PGSQLGenericTableHandler : PGSqlFramework where T : class, new() + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected string m_ConnectionString; + protected PGSQLManager m_database; //used for parameter type translation + protected Dictionary m_Fields = + new Dictionary(); + + protected Dictionary m_FieldTypes = new Dictionary(); + + protected List m_ColumnNames = null; + protected string m_Realm; + protected FieldInfo m_DataField = null; + + protected virtual Assembly Assembly + { + get { return GetType().Assembly; } + } + + public PGSQLGenericTableHandler(string connectionString, + string realm, string storeName) + : base(connectionString) + { + m_Realm = realm; + + m_ConnectionString = connectionString; + + if (storeName != String.Empty) + { + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + { + conn.Open(); + Migration m = new Migration(conn, GetType().Assembly, storeName); + m.Update(); + } + + } + m_database = new PGSQLManager(m_ConnectionString); + + Type t = typeof(T); + FieldInfo[] fields = t.GetFields(BindingFlags.Public | + BindingFlags.Instance | + BindingFlags.DeclaredOnly); + + LoadFieldTypes(); + + if (fields.Length == 0) + return; + + foreach (FieldInfo f in fields) + { + if (f.Name != "Data") + m_Fields[f.Name] = f; + else + m_DataField = f; + } + + } + + private void LoadFieldTypes() + { + m_FieldTypes = new Dictionary(); + + string query = string.Format(@"select column_name,data_type + from INFORMATION_SCHEMA.COLUMNS + where table_name = lower('{0}'); + + ", m_Realm); + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(query, conn)) + { + conn.Open(); + using (NpgsqlDataReader rdr = cmd.ExecuteReader()) + { + while (rdr.Read()) + { + // query produces 0 to many rows of single column, so always add the first item in each row + m_FieldTypes.Add((string)rdr[0], (string)rdr[1]); + } + } + } + } + + private void CheckColumnNames(NpgsqlDataReader reader) + { + if (m_ColumnNames != null) + return; + + m_ColumnNames = new List(); + + DataTable schemaTable = reader.GetSchemaTable(); + + foreach (DataRow row in schemaTable.Rows) + { + if (row["ColumnName"] != null && + (!m_Fields.ContainsKey(row["ColumnName"].ToString()))) + m_ColumnNames.Add(row["ColumnName"].ToString()); + + } + } + + // TODO GET CONSTRAINTS FROM POSTGRESQL + private List GetConstraints() + { + List constraints = new List(); + string query = string.Format(@"SELECT kcu.column_name + FROM information_schema.table_constraints tc + LEFT JOIN information_schema.key_column_usage kcu + ON tc.constraint_catalog = kcu.constraint_catalog + AND tc.constraint_schema = kcu.constraint_schema + AND tc.constraint_name = kcu.constraint_name + + LEFT JOIN information_schema.referential_constraints rc + ON tc.constraint_catalog = rc.constraint_catalog + AND tc.constraint_schema = rc.constraint_schema + AND tc.constraint_name = rc.constraint_name + + LEFT JOIN information_schema.constraint_column_usage ccu + ON rc.unique_constraint_catalog = ccu.constraint_catalog + AND rc.unique_constraint_schema = ccu.constraint_schema + AND rc.unique_constraint_name = ccu.constraint_name + + where tc.table_name = lower('{0}') + and lower(tc.constraint_type) in ('primary key') + and kcu.column_name is not null + ;", m_Realm); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(query, conn)) + { + conn.Open(); + using (NpgsqlDataReader rdr = cmd.ExecuteReader()) + { + while (rdr.Read()) + { + // query produces 0 to many rows of single column, so always add the first item in each row + constraints.Add((string)rdr[0]); + } + } + return constraints; + } + } + + public virtual T[] Get(string field, string key) + { + return Get(new string[] { field }, new string[] { key }); + } + + public virtual T[] Get(string[] fields, string[] keys) + { + if (fields.Length != keys.Length) + return new T[0]; + + List terms = new List(); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + + for (int i = 0; i < fields.Length; i++) + { + if ( m_FieldTypes.ContainsKey(fields[i]) ) + cmd.Parameters.Add(m_database.CreateParameter(fields[i], keys[i], m_FieldTypes[fields[i]])); + else + cmd.Parameters.Add(m_database.CreateParameter(fields[i], keys[i])); + + terms.Add(" \"" + fields[i] + "\" = :" + fields[i]); + } + + string where = String.Join(" AND ", terms.ToArray()); + + string query = String.Format("SELECT * FROM {0} WHERE {1}", + m_Realm, where); + + cmd.Connection = conn; + cmd.CommandText = query; + conn.Open(); + return DoQuery(cmd); + } + } + + protected T[] DoQuery(NpgsqlCommand cmd) + { + List result = new List(); + if (cmd.Connection == null) + { + cmd.Connection = new NpgsqlConnection(m_connectionString); + } + if (cmd.Connection.State == ConnectionState.Closed) + { + cmd.Connection.Open(); + } + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + if (reader == null) + return new T[0]; + + CheckColumnNames(reader); + + while (reader.Read()) + { + T row = new T(); + + foreach (string name in m_Fields.Keys) + { + if (m_Fields[name].GetValue(row) is bool) + { + int v = Convert.ToInt32(reader[name]); + m_Fields[name].SetValue(row, v != 0 ? true : false); + } + else if (m_Fields[name].GetValue(row) is UUID) + { + UUID uuid = UUID.Zero; + + UUID.TryParse(reader[name].ToString(), out uuid); + m_Fields[name].SetValue(row, uuid); + } + else if (m_Fields[name].GetValue(row) is int) + { + int v = Convert.ToInt32(reader[name]); + m_Fields[name].SetValue(row, v); + } + else + { + m_Fields[name].SetValue(row, reader[name]); + } + } + + if (m_DataField != null) + { + Dictionary data = + new Dictionary(); + + foreach (string col in m_ColumnNames) + { + data[col] = reader[col].ToString(); + + if (data[col] == null) + data[col] = String.Empty; + } + + m_DataField.SetValue(row, data); + } + + result.Add(row); + } + return result.ToArray(); + } + } + + public virtual T[] Get(string where) + { + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + + string query = String.Format("SELECT * FROM {0} WHERE {1}", + m_Realm, where); + cmd.Connection = conn; + cmd.CommandText = query; + //m_log.WarnFormat("[PGSQLGenericTable]: SELECT {0} WHERE {1}", m_Realm, where); + + conn.Open(); + return DoQuery(cmd); + } + } + + public virtual T[] Get(string where, NpgsqlParameter parameter) + { + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + + string query = String.Format("SELECT * FROM {0} WHERE {1}", + m_Realm, where); + cmd.Connection = conn; + cmd.CommandText = query; + //m_log.WarnFormat("[PGSQLGenericTable]: SELECT {0} WHERE {1}", m_Realm, where); + + cmd.Parameters.Add(parameter); + + conn.Open(); + return DoQuery(cmd); + } + } + + public virtual bool Store(T row) + { + List constraintFields = GetConstraints(); + List> constraints = new List>(); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + + StringBuilder query = new StringBuilder(); + List names = new List(); + List values = new List(); + + foreach (FieldInfo fi in m_Fields.Values) + { + names.Add(fi.Name); + values.Add(":" + fi.Name); + // Temporarily return more information about what field is unexpectedly null for + // http://opensimulator.org/mantis/view.php?id=5403. This might be due to a bug in the + // InventoryTransferModule or we may be required to substitute a DBNull here. + if (fi.GetValue(row) == null) + throw new NullReferenceException( + string.Format( + "[PGSQL GENERIC TABLE HANDLER]: Trying to store field {0} for {1} which is unexpectedly null", + fi.Name, row)); + + if (constraintFields.Count > 0 && constraintFields.Contains(fi.Name)) + { + constraints.Add(new KeyValuePair(fi.Name, fi.GetValue(row).ToString() )); + } + if (m_FieldTypes.ContainsKey(fi.Name)) + cmd.Parameters.Add(m_database.CreateParameter(fi.Name, fi.GetValue(row), m_FieldTypes[fi.Name])); + else + cmd.Parameters.Add(m_database.CreateParameter(fi.Name, fi.GetValue(row))); + } + + if (m_DataField != null) + { + Dictionary data = + (Dictionary)m_DataField.GetValue(row); + + foreach (KeyValuePair kvp in data) + { + if (constraintFields.Count > 0 && constraintFields.Contains(kvp.Key)) + { + constraints.Add(new KeyValuePair(kvp.Key, kvp.Key)); + } + names.Add(kvp.Key); + values.Add(":" + kvp.Key); + + if (m_FieldTypes.ContainsKey(kvp.Key)) + cmd.Parameters.Add(m_database.CreateParameter("" + kvp.Key, kvp.Value, m_FieldTypes[kvp.Key])); + else + cmd.Parameters.Add(m_database.CreateParameter("" + kvp.Key, kvp.Value)); + } + + } + + query.AppendFormat("UPDATE {0} SET ", m_Realm); + int i = 0; + for (i = 0; i < names.Count - 1; i++) + { + query.AppendFormat("\"{0}\" = {1}, ", names[i], values[i]); + } + query.AppendFormat("\"{0}\" = {1} ", names[i], values[i]); + if (constraints.Count > 0) + { + List terms = new List(); + for (int j = 0; j < constraints.Count; j++) + { + terms.Add(String.Format(" \"{0}\" = :{0}", constraints[j].Key)); + } + string where = String.Join(" AND ", terms.ToArray()); + query.AppendFormat(" WHERE {0} ", where); + + } + cmd.Connection = conn; + cmd.CommandText = query.ToString(); + + conn.Open(); + if (cmd.ExecuteNonQuery() > 0) + { + //m_log.WarnFormat("[PGSQLGenericTable]: Updating {0}", m_Realm); + return true; + } + else + { + // assume record has not yet been inserted + + query = new StringBuilder(); + query.AppendFormat("INSERT INTO {0} (\"", m_Realm); + query.Append(String.Join("\",\"", names.ToArray())); + query.Append("\") values (" + String.Join(",", values.ToArray()) + ")"); + cmd.Connection = conn; + cmd.CommandText = query.ToString(); + + // m_log.WarnFormat("[PGSQLGenericTable]: Inserting into {0} sql {1}", m_Realm, cmd.CommandText); + + if (conn.State != ConnectionState.Open) + conn.Open(); + if (cmd.ExecuteNonQuery() > 0) + return true; + } + + return false; + } + } + + public virtual bool Delete(string field, string key) + { + return Delete(new string[] { field }, new string[] { key }); + } + + public virtual bool Delete(string[] fields, string[] keys) + { + if (fields.Length != keys.Length) + return false; + + List terms = new List(); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + for (int i = 0; i < fields.Length; i++) + { + if (m_FieldTypes.ContainsKey(fields[i])) + cmd.Parameters.Add(m_database.CreateParameter(fields[i], keys[i], m_FieldTypes[fields[i]])); + else + cmd.Parameters.Add(m_database.CreateParameter(fields[i], keys[i])); + + terms.Add(" \"" + fields[i] + "\" = :" + fields[i]); + } + + string where = String.Join(" AND ", terms.ToArray()); + + string query = String.Format("DELETE FROM {0} WHERE {1}", m_Realm, where); + + cmd.Connection = conn; + cmd.CommandText = query; + conn.Open(); + + if (cmd.ExecuteNonQuery() > 0) + { + //m_log.Warn("[PGSQLGenericTable]: " + deleteCommand); + return true; + } + return false; + } + } + public long GetCount(string field, string key) + { + return GetCount(new string[] { field }, new string[] { key }); + } + + public long GetCount(string[] fields, string[] keys) + { + if (fields.Length != keys.Length) + return 0; + + List terms = new List(); + + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + for (int i = 0; i < fields.Length; i++) + { + cmd.Parameters.AddWithValue(fields[i], keys[i]); + terms.Add("\"" + fields[i] + "\" = :" + fields[i]); + } + + string where = String.Join(" and ", terms.ToArray()); + + string query = String.Format("select count(*) from {0} where {1}", + m_Realm, where); + + cmd.CommandText = query; + + Object result = DoQueryScalar(cmd); + + return Convert.ToInt64(result); + } + } + + public long GetCount(string where) + { + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + string query = String.Format("select count(*) from {0} where {1}", + m_Realm, where); + + cmd.CommandText = query; + + object result = DoQueryScalar(cmd); + + return Convert.ToInt64(result); + } + } + + public object DoQueryScalar(NpgsqlCommand cmd) + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(m_ConnectionString)) + { + dbcon.Open(); + cmd.Connection = dbcon; + + return cmd.ExecuteScalar(); + } + } + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLGridUserData.cs b/OpenSim/Data/PGSQL/PGSQLGridUserData.cs new file mode 100644 index 0000000..89319f3 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLGridUserData.cs @@ -0,0 +1,68 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Data; +using System.Reflection; +using System.Threading; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; + +namespace OpenSim.Data.PGSQL +{ + /// + /// A PGSQL Interface for Avatar Storage + /// + public class PGSQLGridUserData : PGSQLGenericTableHandler, + IGridUserData + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public PGSQLGridUserData(string connectionString, string realm) : + base(connectionString, realm, "GridUserStore") + { + } + + public new GridUserData Get(string userID) + { + GridUserData[] ret = Get("UserID", userID); + + if (ret.Length == 0) + return null; + + return ret[0]; + } + + public GridUserData[] GetAll(string userID) + { + return base.Get(String.Format("\"UserID\" LIKE '{0}%'", userID)); + } + + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLGroupsData.cs b/OpenSim/Data/PGSQL/PGSQLGroupsData.cs new file mode 100755 index 0000000..e257e7c --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLGroupsData.cs @@ -0,0 +1,485 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using OpenSim.Framework; +using OpenMetaverse; +using log4net; +using Npgsql; + +namespace OpenSim.Data.PGSQL +{ + public class PGSQLGroupsData : IGroupsData + { + private PGSqlGroupsGroupsHandler m_Groups; + private PGSqlGroupsMembershipHandler m_Membership; + private PGSqlGroupsRolesHandler m_Roles; + private PGSqlGroupsRoleMembershipHandler m_RoleMembership; + private PGSqlGroupsInvitesHandler m_Invites; + private PGSqlGroupsNoticesHandler m_Notices; + private PGSqlGroupsPrincipalsHandler m_Principals; + + public PGSQLGroupsData(string connectionString, string realm) + { + m_Groups = new PGSqlGroupsGroupsHandler(connectionString, realm + "_groups", realm + "_Store"); + m_Membership = new PGSqlGroupsMembershipHandler(connectionString, realm + "_membership"); + m_Roles = new PGSqlGroupsRolesHandler(connectionString, realm + "_roles"); + m_RoleMembership = new PGSqlGroupsRoleMembershipHandler(connectionString, realm + "_rolemembership"); + m_Invites = new PGSqlGroupsInvitesHandler(connectionString, realm + "_invites"); + m_Notices = new PGSqlGroupsNoticesHandler(connectionString, realm + "_notices"); + m_Principals = new PGSqlGroupsPrincipalsHandler(connectionString, realm + "_principals"); + } + + #region groups table + public bool StoreGroup(GroupData data) + { + return m_Groups.Store(data); + } + + public GroupData RetrieveGroup(UUID groupID) + { + GroupData[] groups = m_Groups.Get("GroupID", groupID.ToString()); + if (groups.Length > 0) + return groups[0]; + + return null; + } + + public GroupData RetrieveGroup(string name) + { + GroupData[] groups = m_Groups.Get("Name", name); + if (groups.Length > 0) + return groups[0]; + + return null; + } + + public GroupData[] RetrieveGroups(string pattern) + { + + if (string.IsNullOrEmpty(pattern)) // True for where clause + { + pattern = " 1 ORDER BY lower(\"Name\") LIMIT 100"; + + return m_Groups.Get(pattern); + } + else + { + pattern = " \"ShowInList\" = 1 AND lower(\"Name\") LIKE lower('%" + pattern + "%') ORDER BY lower(\"Name\") LIMIT 100"; + + return m_Groups.Get(pattern, new NpgsqlParameter("pattern", pattern)); + } + } + + public bool DeleteGroup(UUID groupID) + { + return m_Groups.Delete("GroupID", groupID.ToString()); + } + + public int GroupsCount() + { + return (int)m_Groups.GetCount(" \"Location\" = \"\""); + } + + #endregion + + #region membership table + public MembershipData[] RetrieveMembers(UUID groupID) + { + return m_Membership.Get("GroupID", groupID.ToString()); + } + + public MembershipData RetrieveMember(UUID groupID, string pricipalID) + { + MembershipData[] m = m_Membership.Get(new string[] { "GroupID", "PrincipalID" }, + new string[] { groupID.ToString(), pricipalID }); + if (m != null && m.Length > 0) + return m[0]; + + return null; + } + + public MembershipData[] RetrieveMemberships(string pricipalID) + { + return m_Membership.Get("PrincipalID", pricipalID.ToString()); + } + + public bool StoreMember(MembershipData data) + { + return m_Membership.Store(data); + } + + public bool DeleteMember(UUID groupID, string pricipalID) + { + return m_Membership.Delete(new string[] { "GroupID", "PrincipalID" }, + new string[] { groupID.ToString(), pricipalID }); + } + + public int MemberCount(UUID groupID) + { + return (int)m_Membership.GetCount("GroupID", groupID.ToString()); + } + #endregion + + #region roles table + public bool StoreRole(RoleData data) + { + return m_Roles.Store(data); + } + + public RoleData RetrieveRole(UUID groupID, UUID roleID) + { + RoleData[] data = m_Roles.Get(new string[] { "GroupID", "RoleID" }, + new string[] { groupID.ToString(), roleID.ToString() }); + + if (data != null && data.Length > 0) + return data[0]; + + return null; + } + + public RoleData[] RetrieveRoles(UUID groupID) + { + //return m_Roles.RetrieveRoles(groupID); + return m_Roles.Get("GroupID", groupID.ToString()); + } + + public bool DeleteRole(UUID groupID, UUID roleID) + { + return m_Roles.Delete(new string[] { "GroupID", "RoleID" }, + new string[] { groupID.ToString(), roleID.ToString() }); + } + + public int RoleCount(UUID groupID) + { + return (int)m_Roles.GetCount("GroupID", groupID.ToString()); + } + + + #endregion + + #region rolememberhip table + public RoleMembershipData[] RetrieveRolesMembers(UUID groupID) + { + RoleMembershipData[] data = m_RoleMembership.Get("GroupID", groupID.ToString()); + + return data; + } + + public RoleMembershipData[] RetrieveRoleMembers(UUID groupID, UUID roleID) + { + RoleMembershipData[] data = m_RoleMembership.Get(new string[] { "GroupID", "RoleID" }, + new string[] { groupID.ToString(), roleID.ToString() }); + + return data; + } + + public RoleMembershipData[] RetrieveMemberRoles(UUID groupID, string principalID) + { + RoleMembershipData[] data = m_RoleMembership.Get(new string[] { "GroupID", "PrincipalID" }, + new string[] { groupID.ToString(), principalID.ToString() }); + + return data; + } + + public RoleMembershipData RetrieveRoleMember(UUID groupID, UUID roleID, string principalID) + { + RoleMembershipData[] data = m_RoleMembership.Get(new string[] { "GroupID", "RoleID", "PrincipalID" }, + new string[] { groupID.ToString(), roleID.ToString(), principalID.ToString() }); + + if (data != null && data.Length > 0) + return data[0]; + + return null; + } + + public int RoleMemberCount(UUID groupID, UUID roleID) + { + return (int)m_RoleMembership.GetCount(new string[] { "GroupID", "RoleID" }, + new string[] { groupID.ToString(), roleID.ToString() }); + } + + public bool StoreRoleMember(RoleMembershipData data) + { + return m_RoleMembership.Store(data); + } + + public bool DeleteRoleMember(RoleMembershipData data) + { + return m_RoleMembership.Delete(new string[] { "GroupID", "RoleID", "PrincipalID"}, + new string[] { data.GroupID.ToString(), data.RoleID.ToString(), data.PrincipalID }); + } + + public bool DeleteMemberAllRoles(UUID groupID, string principalID) + { + return m_RoleMembership.Delete(new string[] { "GroupID", "PrincipalID" }, + new string[] { groupID.ToString(), principalID }); + } + + #endregion + + #region principals table + public bool StorePrincipal(PrincipalData data) + { + return m_Principals.Store(data); + } + + public PrincipalData RetrievePrincipal(string principalID) + { + PrincipalData[] p = m_Principals.Get("PrincipalID", principalID); + if (p != null && p.Length > 0) + return p[0]; + + return null; + } + + public bool DeletePrincipal(string principalID) + { + return m_Principals.Delete("PrincipalID", principalID); + } + #endregion + + #region invites table + + public bool StoreInvitation(InvitationData data) + { + return m_Invites.Store(data); + } + + public InvitationData RetrieveInvitation(UUID inviteID) + { + InvitationData[] invites = m_Invites.Get("InviteID", inviteID.ToString()); + + if (invites != null && invites.Length > 0) + return invites[0]; + + return null; + } + + public InvitationData RetrieveInvitation(UUID groupID, string principalID) + { + InvitationData[] invites = m_Invites.Get(new string[] { "GroupID", "PrincipalID" }, + new string[] { groupID.ToString(), principalID }); + + if (invites != null && invites.Length > 0) + return invites[0]; + + return null; + } + + public bool DeleteInvite(UUID inviteID) + { + return m_Invites.Delete("InviteID", inviteID.ToString()); + } + + public void DeleteOldInvites() + { + m_Invites.DeleteOld(); + } + + #endregion + + #region notices table + + public bool StoreNotice(NoticeData data) + { + return m_Notices.Store(data); + } + + public NoticeData RetrieveNotice(UUID noticeID) + { + NoticeData[] notices = m_Notices.Get("NoticeID", noticeID.ToString()); + + if (notices != null && notices.Length > 0) + return notices[0]; + + return null; + } + + public NoticeData[] RetrieveNotices(UUID groupID) + { + NoticeData[] notices = m_Notices.Get("GroupID", groupID.ToString()); + + return notices; + } + + public bool DeleteNotice(UUID noticeID) + { + return m_Notices.Delete("NoticeID", noticeID.ToString()); + } + + public void DeleteOldNotices() + { + m_Notices.DeleteOld(); + } + + #endregion + + #region combinations + public MembershipData RetrievePrincipalGroupMembership(string principalID, UUID groupID) + { + // TODO + return null; + } + public MembershipData[] RetrievePrincipalGroupMemberships(string principalID) + { + // TODO + return null; + } + + #endregion + } + + public class PGSqlGroupsGroupsHandler : PGSQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public PGSqlGroupsGroupsHandler(string connectionString, string realm, string store) + : base(connectionString, realm, store) + { + } + + } + + public class PGSqlGroupsMembershipHandler : PGSQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public PGSqlGroupsMembershipHandler(string connectionString, string realm) + : base(connectionString, realm, string.Empty) + { + } + + } + + public class PGSqlGroupsRolesHandler : PGSQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public PGSqlGroupsRolesHandler(string connectionString, string realm) + : base(connectionString, realm, string.Empty) + { + } + + } + + public class PGSqlGroupsRoleMembershipHandler : PGSQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public PGSqlGroupsRoleMembershipHandler(string connectionString, string realm) + : base(connectionString, realm, string.Empty) + { + } + + } + + public class PGSqlGroupsInvitesHandler : PGSQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public PGSqlGroupsInvitesHandler(string connectionString, string realm) + : base(connectionString, realm, string.Empty) + { + } + + public void DeleteOld() + { + + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + cmd.CommandText = String.Format("delete from {0} where \"TMStamp\" < CURRENT_DATE - INTERVAL '2 week'", m_Realm); + + ExecuteNonQuery(cmd); + } + + } + } + + public class PGSqlGroupsNoticesHandler : PGSQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public PGSqlGroupsNoticesHandler(string connectionString, string realm) + : base(connectionString, realm, string.Empty) + { + } + + public void DeleteOld() + { + + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + cmd.CommandText = String.Format("delete from {0} where \"TMStamp\" < CURRENT_DATE - INTERVAL '2 week'", m_Realm); + + ExecuteNonQuery(cmd); + } + + } + } + + public class PGSqlGroupsPrincipalsHandler : PGSQLGenericTableHandler + { + protected override Assembly Assembly + { + // WARNING! Moving migrations to this assembly!!! + get { return GetType().Assembly; } + } + + public PGSqlGroupsPrincipalsHandler(string connectionString, string realm) + : base(connectionString, realm, string.Empty) + { + } + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLHGTravelData.cs b/OpenSim/Data/PGSQL/PGSQLHGTravelData.cs new file mode 100644 index 0000000..c71b15f --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLHGTravelData.cs @@ -0,0 +1,80 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Data; +using System.Reflection; +using System.Threading; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using Npgsql; + +namespace OpenSim.Data.PGSQL +{ + /// + /// A PGSQL Interface for user grid data + /// + public class PGSQLHGTravelData : PGSQLGenericTableHandler, IHGTravelingData + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public PGSQLHGTravelData(string connectionString, string realm) : base(connectionString, realm, "HGTravelStore") { } + + public HGTravelingData Get(UUID sessionID) + { + HGTravelingData[] ret = Get("SessionID", sessionID.ToString()); + + if (ret.Length == 0) + return null; + + return ret[0]; + } + + public HGTravelingData[] GetSessions(UUID userID) + { + return base.Get("UserID", userID.ToString()); + } + + public bool Delete(UUID sessionID) + { + return Delete("SessionID", sessionID.ToString()); + } + + public void DeleteOld() + { + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + cmd.CommandText = String.Format(@"delete from {0} where ""TMStamp"" < CURRENT_DATE - INTERVAL '2 day'", m_Realm); + + ExecuteNonQuery(cmd); + } + + } + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLInventoryData.cs b/OpenSim/Data/PGSQL/PGSQLInventoryData.cs new file mode 100644 index 0000000..c999433 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLInventoryData.cs @@ -0,0 +1,831 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Data; +using System.Reflection; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using Npgsql; + +namespace OpenSim.Data.PGSQL +{ + /// + /// A PGSQL interface for the inventory server + /// + public class PGSQLInventoryData : IInventoryDataPlugin + { + private const string _migrationStore = "InventoryStore"; + + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// The database manager + /// + private PGSQLManager database; + private string m_connectionString; + + #region IPlugin members + + [Obsolete("Cannot be default-initialized!")] + public void Initialise() + { + m_log.Info("[PGSQLInventoryData]: " + Name + " cannot be default-initialized!"); + throw new PluginNotInitialisedException(Name); + } + + /// + /// Loads and initialises the PGSQL inventory storage interface + /// + /// connect string + /// use PGSQL_connection.ini + public void Initialise(string connectionString) + { + m_connectionString = connectionString; + database = new PGSQLManager(connectionString); + + //New migrations check of store + database.CheckMigration(_migrationStore); + } + + /// + /// The name of this DB provider + /// + /// A string containing the name of the DB provider + public string Name + { + get { return "PGSQL Inventory Data Interface"; } + } + + /// + /// Closes this DB provider + /// + public void Dispose() + { + database = null; + } + + /// + /// Returns the version of this DB provider + /// + /// A string containing the DB provider + public string Version + { + get { return database.getVersion(); } + } + + #endregion + + #region Folder methods + + /// + /// Returns a list of the root folders within a users inventory + /// + /// The user whos inventory is to be searched + /// A list of folder objects + public List getUserRootFolders(UUID user) + { + if (user == UUID.Zero) + return new List(); + + return getInventoryFolders(UUID.Zero, user); + } + + /// + /// see InventoryItemBase.getUserRootFolder + /// + /// the User UUID + /// + public InventoryFolderBase getUserRootFolder(UUID user) + { + List items = getUserRootFolders(user); + + InventoryFolderBase rootFolder = null; + + // There should only ever be one root folder for a user. However, if there's more + // than one we'll simply use the first one rather than failing. It would be even + // nicer to print some message to this effect, but this feels like it's too low a + // to put such a message out, and it's too minor right now to spare the time to + // suitably refactor. + if (items.Count > 0) + { + rootFolder = items[0]; + } + + return rootFolder; + } + + /// + /// Returns a list of folders in a users inventory contained within the specified folder + /// + /// The folder to search + /// A list of inventory folders + public List getInventoryFolders(UUID parentID) + { + return getInventoryFolders(parentID, UUID.Zero); + } + + /// + /// Returns a specified inventory folder + /// + /// The folder to return + /// A folder class + public InventoryFolderBase getInventoryFolder(UUID folderID) + { + string sql = "SELECT * FROM inventoryfolders WHERE \"folderID\" = :folderID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(database.CreateParameter("folderID", folderID)); + conn.Open(); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + return readInventoryFolder(reader); + } + } + } + m_log.InfoFormat("[INVENTORY DB] : Found no inventory folder with ID : {0}", folderID); + return null; + } + + /// + /// Returns all child folders in the hierarchy from the parent folder and down. + /// Does not return the parent folder itself. + /// + /// The folder to get subfolders for + /// A list of inventory folders + public List getFolderHierarchy(UUID parentID) + { + //Note maybe change this to use a Dataset that loading in all folders of a user and then go throw it that way. + //Note this is changed so it opens only one connection to the database and not everytime it wants to get data. + + /* NOTE: the implementation below is very inefficient (makes a separate request to get subfolders for + * every found folder, recursively). Inventory code for other DBs has been already rewritten to get ALL + * inventory for a specific user at once. + * + * Meanwhile, one little thing is corrected: getFolderHierarchy(UUID.Zero) doesn't make sense and should never + * be used, so check for that and return an empty list. + */ + + List folders = new List(); + + if (parentID == UUID.Zero) + return folders; + + string sql = "SELECT * FROM inventoryfolders WHERE \"parentFolderID\" = :parentID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(database.CreateParameter("parentID", parentID)); + conn.Open(); + folders.AddRange(getInventoryFolders(cmd)); + + List tempFolders = new List(); + + foreach (InventoryFolderBase folderBase in folders) + { + tempFolders.AddRange(getFolderHierarchy(folderBase.ID, cmd)); + } + if (tempFolders.Count > 0) + { + folders.AddRange(tempFolders); + } + } + return folders; + } + + /// + /// Creates a new inventory folder + /// + /// Folder to create + public void addInventoryFolder(InventoryFolderBase folder) + { + string sql = "INSERT INTO inventoryfolders (\"folderID\", \"agentID\", \"parentFolderID\", \"folderName\", type, version) " + + " VALUES (:folderID, :agentID, :parentFolderID, :folderName, :type, :version);"; + + string folderName = folder.Name; + if (folderName.Length > 64) + { + folderName = folderName.Substring(0, 64); + m_log.Warn("[INVENTORY DB]: Name field truncated from " + folder.Name.Length.ToString() + " to " + folderName.Length + " characters on add"); + } + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(database.CreateParameter("folderID", folder.ID)); + cmd.Parameters.Add(database.CreateParameter("agentID", folder.Owner)); + cmd.Parameters.Add(database.CreateParameter("parentFolderID", folder.ParentID)); + cmd.Parameters.Add(database.CreateParameter("folderName", folderName)); + cmd.Parameters.Add(database.CreateParameter("type", folder.Type)); + cmd.Parameters.Add(database.CreateParameter("version", folder.Version)); + conn.Open(); + try + { + cmd.ExecuteNonQuery(); + } + catch (Exception e) + { + m_log.ErrorFormat("[INVENTORY DB]: Error : {0}", e.Message); + } + } + } + + /// + /// Updates an inventory folder + /// + /// Folder to update + public void updateInventoryFolder(InventoryFolderBase folder) + { + string sql = @"UPDATE inventoryfolders SET ""agentID"" = :agentID, + ""parentFolderID"" = :parentFolderID, + ""folderName"" = :folderName, + type = :type, + version = :version + WHERE folderID = :folderID"; + + string folderName = folder.Name; + if (folderName.Length > 64) + { + folderName = folderName.Substring(0, 64); + m_log.Warn("[INVENTORY DB]: Name field truncated from " + folder.Name.Length.ToString() + " to " + folderName.Length + " characters on update"); + } + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(database.CreateParameter("folderID", folder.ID)); + cmd.Parameters.Add(database.CreateParameter("agentID", folder.Owner)); + cmd.Parameters.Add(database.CreateParameter("parentFolderID", folder.ParentID)); + cmd.Parameters.Add(database.CreateParameter("folderName", folderName)); + cmd.Parameters.Add(database.CreateParameter("type", folder.Type)); + cmd.Parameters.Add(database.CreateParameter("version", folder.Version)); + conn.Open(); + try + { + cmd.ExecuteNonQuery(); + } + catch (Exception e) + { + m_log.ErrorFormat("[INVENTORY DB]: Error : {0}", e.Message); + } + } + } + + /// + /// Updates an inventory folder + /// + /// Folder to update + public void moveInventoryFolder(InventoryFolderBase folder) + { + string sql = @"UPDATE inventoryfolders SET ""parentFolderID"" = :parentFolderID WHERE ""folderID"" = :folderID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(database.CreateParameter("parentFolderID", folder.ParentID)); + cmd.Parameters.Add(database.CreateParameter("folderID", folder.ID)); + conn.Open(); + try + { + cmd.ExecuteNonQuery(); + } + catch (Exception e) + { + m_log.ErrorFormat("[INVENTORY DB]: Error : {0}", e.Message); + } + } + } + + /// + /// Delete an inventory folder + /// + /// Id of folder to delete + public void deleteInventoryFolder(UUID folderID) + { + string sql = @"SELECT * FROM inventoryfolders WHERE ""parentFolderID"" = :parentID"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + List subFolders; + cmd.Parameters.Add(database.CreateParameter("parentID", UUID.Zero)); + conn.Open(); + subFolders = getFolderHierarchy(folderID, cmd); + + + //Delete all sub-folders + foreach (InventoryFolderBase f in subFolders) + { + DeleteOneFolder(f.ID, conn); + DeleteItemsInFolder(f.ID, conn); + } + + //Delete the actual row + DeleteOneFolder(folderID, conn); + DeleteItemsInFolder(folderID, conn); + } + } + + #endregion + + #region Item Methods + + /// + /// Returns a list of items in a specified folder + /// + /// The folder to search + /// A list containing inventory items + public List getInventoryInFolder(UUID folderID) + { + string sql = @"SELECT * FROM inventoryitems WHERE ""parentFolderID"" = :parentFolderID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(database.CreateParameter("parentFolderID", folderID)); + conn.Open(); + List items = new List(); + + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + items.Add(readInventoryItem(reader)); + } + } + return items; + } + } + + /// + /// Returns a specified inventory item + /// + /// The item ID + /// An inventory item + public InventoryItemBase getInventoryItem(UUID itemID) + { + string sql = @"SELECT * FROM inventoryitems WHERE ""inventoryID"" = :inventoryID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(database.CreateParameter("inventoryID", itemID)); + conn.Open(); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + return readInventoryItem(reader); + } + } + } + + m_log.InfoFormat("[INVENTORY DB]: Found no inventory item with ID : {0}", itemID); + return null; + } + + /// + /// Adds a specified item to the database + /// + /// The inventory item + public void addInventoryItem(InventoryItemBase item) + { + if (getInventoryItem(item.ID) != null) + { + updateInventoryItem(item); + return; + } + + string sql = @"INSERT INTO inventoryitems + (""inventoryID"", ""assetID"", ""assetType"", ""parentFolderID"", ""avatarID"", ""inventoryName"", + ""inventoryDescription"", ""inventoryNextPermissions"", ""inventoryCurrentPermissions"", + ""invType"", ""creatorID"", ""inventoryBasePermissions"", ""inventoryEveryOnePermissions"", ""inventoryGroupPermissions"", + ""salePrice"", ""SaleType"", ""creationDate"", ""groupID"", ""groupOwned"", flags) + VALUES + (:inventoryID, :assetID, :assetType, :parentFolderID, :avatarID, :inventoryName, :inventoryDescription, + :inventoryNextPermissions, :inventoryCurrentPermissions, :invType, :creatorID, + :inventoryBasePermissions, :inventoryEveryOnePermissions, :inventoryGroupPermissions, :SalePrice, :SaleType, + :creationDate, :groupID, :groupOwned, :flags)"; + + string itemName = item.Name; + if (item.Name.Length > 64) + { + itemName = item.Name.Substring(0, 64); + m_log.Warn("[INVENTORY DB]: Name field truncated from " + item.Name.Length.ToString() + " to " + itemName.Length.ToString() + " characters"); + } + + string itemDesc = item.Description; + if (item.Description.Length > 128) + { + itemDesc = item.Description.Substring(0, 128); + m_log.Warn("[INVENTORY DB]: Description field truncated from " + item.Description.Length.ToString() + " to " + itemDesc.Length.ToString() + " characters"); + } + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand command = new NpgsqlCommand(sql, conn)) + { + command.Parameters.Add(database.CreateParameter("inventoryID", item.ID)); + command.Parameters.Add(database.CreateParameter("assetID", item.AssetID)); + command.Parameters.Add(database.CreateParameter("assetType", item.AssetType)); + command.Parameters.Add(database.CreateParameter("parentFolderID", item.Folder)); + command.Parameters.Add(database.CreateParameter("avatarID", item.Owner)); + command.Parameters.Add(database.CreateParameter("inventoryName", itemName)); + command.Parameters.Add(database.CreateParameter("inventoryDescription", itemDesc)); + command.Parameters.Add(database.CreateParameter("inventoryNextPermissions", item.NextPermissions)); + command.Parameters.Add(database.CreateParameter("inventoryCurrentPermissions", item.CurrentPermissions)); + command.Parameters.Add(database.CreateParameter("invType", item.InvType)); + command.Parameters.Add(database.CreateParameter("creatorID", item.CreatorId)); + command.Parameters.Add(database.CreateParameter("inventoryBasePermissions", item.BasePermissions)); + command.Parameters.Add(database.CreateParameter("inventoryEveryOnePermissions", item.EveryOnePermissions)); + command.Parameters.Add(database.CreateParameter("inventoryGroupPermissions", item.GroupPermissions)); + command.Parameters.Add(database.CreateParameter("SalePrice", item.SalePrice)); + command.Parameters.Add(database.CreateParameter("SaleType", item.SaleType)); + command.Parameters.Add(database.CreateParameter("creationDate", item.CreationDate)); + command.Parameters.Add(database.CreateParameter("groupID", item.GroupID)); + command.Parameters.Add(database.CreateParameter("groupOwned", item.GroupOwned)); + command.Parameters.Add(database.CreateParameter("flags", item.Flags)); + conn.Open(); + try + { + command.ExecuteNonQuery(); + } + catch (Exception e) + { + m_log.Error("[INVENTORY DB]: Error inserting item :" + e.Message); + } + } + + sql = @"UPDATE inventoryfolders SET version = version + 1 WHERE ""folderID"" = @folderID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand command = new NpgsqlCommand(sql, conn)) + { + command.Parameters.Add(database.CreateParameter("folderID", item.Folder.ToString())); + conn.Open(); + try + { + command.ExecuteNonQuery(); + } + catch (Exception e) + { + m_log.Error("[INVENTORY DB] Error updating inventory folder for new item :" + e.Message); + } + } + } + + /// + /// Updates the specified inventory item + /// + /// Inventory item to update + public void updateInventoryItem(InventoryItemBase item) + { + string sql = @"UPDATE inventoryitems SET ""assetID"" = :assetID, + ""assetType"" = :assetType, + ""parentFolderID"" = :parentFolderID, + ""avatarID"" = :avatarID, + ""inventoryName"" = :inventoryName, + ""inventoryDescription"" = :inventoryDescription, + ""inventoryNextPermissions"" = :inventoryNextPermissions, + ""inventoryCurrentPermissions"" = :inventoryCurrentPermissions, + ""invType"" = :invType, + ""creatorID"" = :creatorID, + ""inventoryBasePermissions"" = :inventoryBasePermissions, + ""inventoryEveryOnePermissions"" = :inventoryEveryOnePermissions, + ""inventoryGroupPermissions"" = :inventoryGroupPermissions, + ""salePrice"" = :SalePrice, + ""saleType"" = :SaleType, + ""creationDate"" = :creationDate, + ""groupID"" = :groupID, + ""groupOwned"" = :groupOwned, + flags = :flags + WHERE ""inventoryID"" = :inventoryID"; + + string itemName = item.Name; + if (item.Name.Length > 64) + { + itemName = item.Name.Substring(0, 64); + m_log.Warn("[INVENTORY DB]: Name field truncated from " + item.Name.Length.ToString() + " to " + itemName.Length.ToString() + " characters on update"); + } + + string itemDesc = item.Description; + if (item.Description.Length > 128) + { + itemDesc = item.Description.Substring(0, 128); + m_log.Warn("[INVENTORY DB]: Description field truncated from " + item.Description.Length.ToString() + " to " + itemDesc.Length.ToString() + " characters on update"); + } + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand command = new NpgsqlCommand(sql, conn)) + { + command.Parameters.Add(database.CreateParameter("inventoryID", item.ID)); + command.Parameters.Add(database.CreateParameter("assetID", item.AssetID)); + command.Parameters.Add(database.CreateParameter("assetType", item.AssetType)); + command.Parameters.Add(database.CreateParameter("parentFolderID", item.Folder)); + command.Parameters.Add(database.CreateParameter("avatarID", item.Owner)); + command.Parameters.Add(database.CreateParameter("inventoryName", itemName)); + command.Parameters.Add(database.CreateParameter("inventoryDescription", itemDesc)); + command.Parameters.Add(database.CreateParameter("inventoryNextPermissions", item.NextPermissions)); + command.Parameters.Add(database.CreateParameter("inventoryCurrentPermissions", item.CurrentPermissions)); + command.Parameters.Add(database.CreateParameter("invType", item.InvType)); + command.Parameters.Add(database.CreateParameter("creatorID", item.CreatorId)); + command.Parameters.Add(database.CreateParameter("inventoryBasePermissions", item.BasePermissions)); + command.Parameters.Add(database.CreateParameter("inventoryEveryOnePermissions", item.EveryOnePermissions)); + command.Parameters.Add(database.CreateParameter("inventoryGroupPermissions", item.GroupPermissions)); + command.Parameters.Add(database.CreateParameter("SalePrice", item.SalePrice)); + command.Parameters.Add(database.CreateParameter("SaleType", item.SaleType)); + command.Parameters.Add(database.CreateParameter("creationDate", item.CreationDate)); + command.Parameters.Add(database.CreateParameter("groupID", item.GroupID)); + command.Parameters.Add(database.CreateParameter("groupOwned", item.GroupOwned)); + command.Parameters.Add(database.CreateParameter("flags", item.Flags)); + conn.Open(); + try + { + command.ExecuteNonQuery(); + } + catch (Exception e) + { + m_log.Error("[INVENTORY DB]: Error updating item :" + e.Message); + } + } + } + + // See IInventoryDataPlugin + + /// + /// Delete an item in inventory database + /// + /// the item UUID + public void deleteInventoryItem(UUID itemID) + { + string sql = @"DELETE FROM inventoryitems WHERE ""inventoryID""=:inventoryID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(database.CreateParameter("inventoryID", itemID)); + try + { + conn.Open(); + cmd.ExecuteNonQuery(); + } + catch (Exception e) + { + m_log.Error("[INVENTORY DB]: Error deleting item :" + e.Message); + } + } + } + + public InventoryItemBase queryInventoryItem(UUID itemID) + { + return getInventoryItem(itemID); + } + + public InventoryFolderBase queryInventoryFolder(UUID folderID) + { + return getInventoryFolder(folderID); + } + + /// + /// Returns all activated gesture-items in the inventory of the specified avatar. + /// + /// The of the avatar + /// + /// The list of gestures (s) + /// + public List fetchActiveGestures(UUID avatarID) + { + string sql = @"SELECT * FROM inventoryitems WHERE ""avatarID"" = :uuid AND ""assetType"" = :assetType and flags = 1"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(database.CreateParameter("uuid", avatarID)); + cmd.Parameters.Add(database.CreateParameter("assetType", (int)AssetType.Gesture)); + conn.Open(); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + List gestureList = new List(); + while (reader.Read()) + { + gestureList.Add(readInventoryItem(reader)); + } + return gestureList; + } + } + } + + #endregion + + #region Private methods + + /// + /// Delete an item in inventory database + /// + /// the item ID + /// connection to the database + private void DeleteItemsInFolder(UUID folderID, NpgsqlConnection connection) + { + using (NpgsqlCommand command = new NpgsqlCommand(@"DELETE FROM inventoryitems WHERE ""folderID""=:folderID", connection)) + { + command.Parameters.Add(database.CreateParameter("folderID", folderID)); + + try + { + command.ExecuteNonQuery(); + } + catch (Exception e) + { + m_log.Error("[INVENTORY DB] Error deleting item :" + e.Message); + } + } + } + + /// + /// Gets the folder hierarchy in a loop. + /// + /// parent ID. + /// SQL command/connection to database + /// + private static List getFolderHierarchy(UUID parentID, NpgsqlCommand command) + { + command.Parameters["parentID"].Value = parentID.Guid; //.ToString(); + + List folders = getInventoryFolders(command); + + if (folders.Count > 0) + { + List tempFolders = new List(); + + foreach (InventoryFolderBase folderBase in folders) + { + tempFolders.AddRange(getFolderHierarchy(folderBase.ID, command)); + } + + if (tempFolders.Count > 0) + { + folders.AddRange(tempFolders); + } + } + return folders; + } + + /// + /// Gets the inventory folders. + /// + /// parentID, use UUID.Zero to get root + /// user id, use UUID.Zero, if you want all folders from a parentID. + /// + private List getInventoryFolders(UUID parentID, UUID user) + { + string sql = @"SELECT * FROM inventoryfolders WHERE ""parentFolderID"" = :parentID AND ""agentID"" = :uuid"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand command = new NpgsqlCommand(sql, conn)) + { + if (user == UUID.Zero) + { + command.Parameters.Add(database.CreateParameter("uuid", "%")); + } + else + { + command.Parameters.Add(database.CreateParameter("uuid", user)); + } + command.Parameters.Add(database.CreateParameter("parentID", parentID)); + conn.Open(); + return getInventoryFolders(command); + } + } + + /// + /// Gets the inventory folders. + /// + /// SQLcommand. + /// + private static List getInventoryFolders(NpgsqlCommand command) + { + using (NpgsqlDataReader reader = command.ExecuteReader()) + { + + List items = new List(); + while (reader.Read()) + { + items.Add(readInventoryFolder(reader)); + } + return items; + } + } + + /// + /// Reads a list of inventory folders returned by a query. + /// + /// A PGSQL Data Reader + /// A List containing inventory folders + protected static InventoryFolderBase readInventoryFolder(NpgsqlDataReader reader) + { + try + { + InventoryFolderBase folder = new InventoryFolderBase(); + folder.Owner = DBGuid.FromDB(reader["agentID"]); + folder.ParentID = DBGuid.FromDB(reader["parentFolderID"]); + folder.ID = DBGuid.FromDB(reader["folderID"]); + folder.Name = (string)reader["folderName"]; + folder.Type = (short)reader["type"]; + folder.Version = Convert.ToUInt16(reader["version"]); + + return folder; + } + catch (Exception e) + { + m_log.Error("[INVENTORY DB] Error reading inventory folder :" + e.Message); + } + + return null; + } + + /// + /// Reads a one item from an SQL result + /// + /// The SQL Result + /// the item read + private static InventoryItemBase readInventoryItem(IDataRecord reader) + { + try + { + InventoryItemBase item = new InventoryItemBase(); + + item.ID = DBGuid.FromDB(reader["inventoryID"]); + item.AssetID = DBGuid.FromDB(reader["assetID"]); + item.AssetType = Convert.ToInt32(reader["assetType"].ToString()); + item.Folder = DBGuid.FromDB(reader["parentFolderID"]); + item.Owner = DBGuid.FromDB(reader["avatarID"]); + item.Name = reader["inventoryName"].ToString(); + item.Description = reader["inventoryDescription"].ToString(); + item.NextPermissions = Convert.ToUInt32(reader["inventoryNextPermissions"]); + item.CurrentPermissions = Convert.ToUInt32(reader["inventoryCurrentPermissions"]); + item.InvType = Convert.ToInt32(reader["invType"].ToString()); + item.CreatorId = reader["creatorID"].ToString(); + item.BasePermissions = Convert.ToUInt32(reader["inventoryBasePermissions"]); + item.EveryOnePermissions = Convert.ToUInt32(reader["inventoryEveryOnePermissions"]); + item.GroupPermissions = Convert.ToUInt32(reader["inventoryGroupPermissions"]); + item.SalePrice = Convert.ToInt32(reader["salePrice"]); + item.SaleType = Convert.ToByte(reader["saleType"]); + item.CreationDate = Convert.ToInt32(reader["creationDate"]); + item.GroupID = DBGuid.FromDB(reader["groupID"]); + item.GroupOwned = Convert.ToBoolean(reader["groupOwned"]); + item.Flags = Convert.ToUInt32(reader["flags"]); + + return item; + } + catch (NpgsqlException e) + { + m_log.Error("[INVENTORY DB]: Error reading inventory item :" + e.Message); + } + + return null; + } + + /// + /// Delete a folder in inventory databasae + /// + /// the folder UUID + /// connection to database + private void DeleteOneFolder(UUID folderID, NpgsqlConnection connection) + { + try + { + using (NpgsqlCommand command = new NpgsqlCommand(@"DELETE FROM inventoryfolders WHERE ""folderID""=:folderID and type=-1", connection)) + { + command.Parameters.Add(database.CreateParameter("folderID", folderID)); + + command.ExecuteNonQuery(); + } + } + catch (NpgsqlException e) + { + m_log.Error("[INVENTORY DB]: Error deleting folder :" + e.Message); + } + } + + #endregion + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLManager.cs b/OpenSim/Data/PGSQL/PGSQLManager.cs new file mode 100644 index 0000000..46f835a --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLManager.cs @@ -0,0 +1,354 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Reflection; +using OpenSim.Framework; +using log4net; +using OpenMetaverse; +using Npgsql; +using NpgsqlTypes; + +namespace OpenSim.Data.PGSQL +{ + /// + /// A management class for the MS SQL Storage Engine + /// + public class PGSQLManager + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Connection string for ADO.net + /// + private readonly string connectionString; + + /// + /// Initialize the manager and set the connectionstring + /// + /// + public PGSQLManager(string connection) + { + connectionString = connection; + InitializeMonoSecurity(); + } + + public void InitializeMonoSecurity() + { + if (!Util.IsPlatformMono) + { + if (AppDomain.CurrentDomain.GetData("MonoSecurityPostgresAdded") == null) + { + AppDomain.CurrentDomain.SetData("MonoSecurityPostgresAdded", "true"); + + AppDomain currentDomain = AppDomain.CurrentDomain; + currentDomain.AssemblyResolve += new ResolveEventHandler(ResolveEventHandlerMonoSec); + } + } + } + + private System.Reflection.Assembly ResolveEventHandlerMonoSec(object sender, ResolveEventArgs args) + { + Assembly MyAssembly = null; + + if (args.Name.Substring(0, args.Name.IndexOf(",")) == "Mono.Security") + { + MyAssembly = Assembly.LoadFrom("lib/NET/Mono.Security.dll"); + } + + //Return the loaded assembly. + return MyAssembly; + } + + /// + /// Type conversion to a SQLDbType functions + /// + /// + /// + internal NpgsqlDbType DbtypeFromType(Type type) + { + if (type == typeof(string)) + { + return NpgsqlDbType.Varchar; + } + if (type == typeof(double)) + { + return NpgsqlDbType.Double; + } + if (type == typeof(Single)) + { + return NpgsqlDbType.Double; + } + if (type == typeof(int)) + { + return NpgsqlDbType.Integer; + } + if (type == typeof(bool)) + { + return NpgsqlDbType.Boolean; + } + if (type == typeof(UUID)) + { + return NpgsqlDbType.Uuid; + } + if (type == typeof(byte)) + { + return NpgsqlDbType.Smallint; + } + if (type == typeof(sbyte)) + { + return NpgsqlDbType.Integer; + } + if (type == typeof(Byte[])) + { + return NpgsqlDbType.Bytea; + } + if (type == typeof(uint) || type == typeof(ushort)) + { + return NpgsqlDbType.Integer; + } + if (type == typeof(ulong)) + { + return NpgsqlDbType.Bigint; + } + if (type == typeof(DateTime)) + { + return NpgsqlDbType.Timestamp; + } + + return NpgsqlDbType.Varchar; + } + + internal NpgsqlDbType DbtypeFromString(Type type, string PGFieldType) + { + if (PGFieldType == "") + { + return DbtypeFromType(type); + } + + if (PGFieldType == "character varying") + { + return NpgsqlDbType.Varchar; + } + if (PGFieldType == "double precision") + { + return NpgsqlDbType.Double; + } + if (PGFieldType == "integer") + { + return NpgsqlDbType.Integer; + } + if (PGFieldType == "smallint") + { + return NpgsqlDbType.Smallint; + } + if (PGFieldType == "boolean") + { + return NpgsqlDbType.Boolean; + } + if (PGFieldType == "uuid") + { + return NpgsqlDbType.Uuid; + } + if (PGFieldType == "bytea") + { + return NpgsqlDbType.Bytea; + } + + return DbtypeFromType(type); + } + + /// + /// Creates value for parameter. + /// + /// The value. + /// + private static object CreateParameterValue(object value) + { + Type valueType = value.GetType(); + + if (valueType == typeof(UUID)) //TODO check if this works + { + return ((UUID) value).Guid; + } + if (valueType == typeof(UUID)) + { + return ((UUID)value).Guid; + } + if (valueType == typeof(bool)) + { + return (bool)value; + } + if (valueType == typeof(Byte[])) + { + return value; + } + if (valueType == typeof(int)) + { + return value; + } + return value; + } + + /// + /// Create value for parameter based on PGSQL Schema + /// + /// + /// + /// + internal static object CreateParameterValue(object value, string PGFieldType) + { + if (PGFieldType == "uuid") + { + UUID uidout; + UUID.TryParse(value.ToString(), out uidout); + return uidout; + } + if (PGFieldType == "integer") + { + int intout; + int.TryParse(value.ToString(), out intout); + return intout; + } + if (PGFieldType == "boolean") + { + return (value.ToString() == "true"); + } + if (PGFieldType == "timestamp with time zone") + { + return (DateTime)value; + } + if (PGFieldType == "timestamp without time zone") + { + return (DateTime)value; + } + if (PGFieldType == "double precision") + { + return (Double)value; + } + return CreateParameterValue(value); + } + + /// + /// Create a parameter for a command + /// + /// Name of the parameter. + /// parameter object. + /// + internal NpgsqlParameter CreateParameter(string parameterName, object parameterObject) + { + return CreateParameter(parameterName, parameterObject, false); + } + + /// + /// Creates the parameter for a command. + /// + /// Name of the parameter. + /// parameter object. + /// if set to true parameter is a output parameter + /// + internal NpgsqlParameter CreateParameter(string parameterName, object parameterObject, bool parameterOut) + { + //Tweak so we dont always have to add : sign + if (parameterName.StartsWith(":")) parameterName = parameterName.Replace(":",""); + + //HACK if object is null, it is turned into a string, there are no nullable type till now + if (parameterObject == null) parameterObject = ""; + + NpgsqlParameter parameter = new NpgsqlParameter(parameterName, DbtypeFromType(parameterObject.GetType())); + + if (parameterOut) + { + parameter.Direction = ParameterDirection.Output; + } + else + { + parameter.Direction = ParameterDirection.Input; + parameter.Value = CreateParameterValue(parameterObject); + } + + return parameter; + } + + /// + /// Create a parameter with PGSQL schema type + /// + /// + /// + /// + /// + internal NpgsqlParameter CreateParameter(string parameterName, object parameterObject, string PGFieldType) + { + //Tweak so we dont always have to add : sign + if (parameterName.StartsWith(":")) parameterName = parameterName.Replace(":", ""); + + //HACK if object is null, it is turned into a string, there are no nullable type till now + if (parameterObject == null) parameterObject = ""; + + NpgsqlParameter parameter = new NpgsqlParameter(parameterName, DbtypeFromString(parameterObject.GetType(), PGFieldType)); + + parameter.Direction = ParameterDirection.Input; + parameter.Value = CreateParameterValue(parameterObject, PGFieldType); + + return parameter; + } + + /// + /// Checks if we need to do some migrations to the database + /// + /// migrationStore. + public void CheckMigration(string migrationStore) + { + using (NpgsqlConnection connection = new NpgsqlConnection(connectionString)) + { + connection.Open(); + Assembly assem = GetType().Assembly; + PGSQLMigration migration = new PGSQLMigration(connection, assem, migrationStore); + + migration.Update(); + } + } + + /// + /// Returns the version of this DB provider + /// + /// A string containing the DB provider + public string getVersion() + { + Module module = GetType().Module; + // string dllName = module.Assembly.ManifestModule.Name; + Version dllVersion = module.Assembly.GetName().Version; + + return + string.Format("{0}.{1}.{2}.{3}", dllVersion.Major, dllVersion.Minor, dllVersion.Build, + dllVersion.Revision); + } + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLMigration.cs b/OpenSim/Data/PGSQL/PGSQLMigration.cs new file mode 100644 index 0000000..709fde0 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLMigration.cs @@ -0,0 +1,102 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using Npgsql; +using System; +using System.Data; +using System.Data.Common; +using System.Reflection; + +namespace OpenSim.Data.PGSQL +{ + public class PGSQLMigration : Migration + { + public PGSQLMigration(NpgsqlConnection conn, Assembly assem, string type) + : base(conn, assem, type) + { + } + + public PGSQLMigration(NpgsqlConnection conn, Assembly assem, string subtype, string type) + : base(conn, assem, subtype, type) + { + } + + protected override int FindVersion(DbConnection conn, string type) + { + int version = 0; + NpgsqlConnection lcConn = (NpgsqlConnection)conn; + + using (NpgsqlCommand cmd = lcConn.CreateCommand()) + { + try + { + cmd.CommandText = "select version from migrations where name = '" + type + "' " + + " order by version desc limit 1"; //Must be + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + version = Convert.ToInt32(reader["version"]); + } + reader.Close(); + } + } + catch + { + // Return -1 to indicate table does not exist + return -1; + } + } + return version; + } + + protected override void ExecuteScript(DbConnection conn, string[] script) + { + if (!(conn is NpgsqlConnection)) + { + base.ExecuteScript(conn, script); + return; + } + + foreach (string sql in script) + { + try + { + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, (NpgsqlConnection)conn)) + { + cmd.ExecuteNonQuery(); + } + } + catch (Exception) + { + throw new Exception(sql); + + } + } + } + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLOfflineIMData.cs b/OpenSim/Data/PGSQL/PGSQLOfflineIMData.cs new file mode 100644 index 0000000..82e5ed8 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLOfflineIMData.cs @@ -0,0 +1,56 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using OpenSim.Framework; +using OpenMetaverse; +using Npgsql; + +namespace OpenSim.Data.PGSQL +{ + public class PGSQLOfflineIMData : PGSQLGenericTableHandler, IOfflineIMData + { + public PGSQLOfflineIMData(string connectionString, string realm) + : base(connectionString, realm, "IM_Store") + { + } + + public void DeleteOld() + { + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + cmd.CommandText = String.Format("delete from {0} where \"TMStamp\" < CURRENT_DATE - INTERVAL '2 week'", m_Realm); + + ExecuteNonQuery(cmd); + } + + } + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLPresenceData.cs b/OpenSim/Data/PGSQL/PGSQLPresenceData.cs new file mode 100755 index 0000000..0376585 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLPresenceData.cs @@ -0,0 +1,116 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Data; +using System.Reflection; +using System.Threading; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using Npgsql; + +namespace OpenSim.Data.PGSQL +{ + /// + /// A PGSQL Interface for the Presence Server + /// + public class PGSQLPresenceData : PGSQLGenericTableHandler, + IPresenceData + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public PGSQLPresenceData(string connectionString, string realm) : + base(connectionString, realm, "Presence") + { + } + + public PresenceData Get(UUID sessionID) + { + PresenceData[] ret = Get("SessionID", sessionID.ToString()); + + if (ret.Length == 0) + return null; + + return ret[0]; + } + + public void LogoutRegionAgents(UUID regionID) + { + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + + cmd.CommandText = String.Format("DELETE FROM {0} WHERE \"RegionID\" = :regionID", m_Realm); + + cmd.Parameters.Add(m_database.CreateParameter("RegionID", regionID)); + cmd.Connection = conn; + conn.Open(); + cmd.ExecuteNonQuery(); + } + } + + public bool ReportAgent(UUID sessionID, UUID regionID) + { + PresenceData[] pd = Get("SessionID", sessionID.ToString()); + if (pd.Length == 0) + return false; + + if (regionID == UUID.Zero) + return false; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + + cmd.CommandText = String.Format("UPDATE {0} SET \"RegionID\" = :regionID, \"LastSeen\" = now() WHERE \"SessionID\" = :sessionID", m_Realm); + + cmd.Parameters.Add(m_database.CreateParameter("SessionID", sessionID)); + cmd.Parameters.Add(m_database.CreateParameter("RegionID", regionID)); + cmd.Connection = conn; + conn.Open(); + if (cmd.ExecuteNonQuery() == 0) + return false; + } + return true; + } + + public bool VerifyAgent(UUID agentId, UUID secureSessionID) + { + PresenceData[] ret = Get("SecureSessionID", secureSessionID.ToString()); + + if (ret.Length == 0) + return false; + + if(ret[0].UserID != agentId.ToString()) + return false; + + return true; + } + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLRegionData.cs b/OpenSim/Data/PGSQL/PGSQLRegionData.cs new file mode 100644 index 0000000..b3076f0 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLRegionData.cs @@ -0,0 +1,392 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Data; +using System.Drawing; +using System.IO; +using System.Reflection; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using RegionFlags = OpenSim.Framework.RegionFlags; +using Npgsql; + +namespace OpenSim.Data.PGSQL +{ + /// + /// A PGSQL Interface for the Region Server. + /// + public class PGSQLRegionData : IRegionData + { + private string m_Realm; + private List m_ColumnNames = null; + private string m_ConnectionString; + private PGSQLManager m_database; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected Dictionary m_FieldTypes = new Dictionary(); + + protected virtual Assembly Assembly + { + get { return GetType().Assembly; } + } + + public PGSQLRegionData(string connectionString, string realm) + { + m_Realm = realm; + m_ConnectionString = connectionString; + m_database = new PGSQLManager(connectionString); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + { + conn.Open(); + Migration m = new Migration(conn, GetType().Assembly, "GridStore"); + m.Update(); + } + LoadFieldTypes(); + } + + private void LoadFieldTypes() + { + m_FieldTypes = new Dictionary(); + + string query = string.Format(@"select column_name,data_type + from INFORMATION_SCHEMA.COLUMNS + where table_name = lower('{0}'); + + ", m_Realm); + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(query, conn)) + { + conn.Open(); + using (NpgsqlDataReader rdr = cmd.ExecuteReader()) + { + while (rdr.Read()) + { + // query produces 0 to many rows of single column, so always add the first item in each row + m_FieldTypes.Add((string)rdr[0], (string)rdr[1]); + } + } + } + } + + public List Get(string regionName, UUID scopeID) + { + string sql = "select * from "+m_Realm+" where lower(\"regionName\") like lower(:regionName) "; + if (scopeID != UUID.Zero) + sql += " and \"ScopeID\" = :scopeID"; + sql += " order by lower(\"regionName\")"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("regionName", regionName)); + if (scopeID != UUID.Zero) + cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID)); + conn.Open(); + return RunCommand(cmd); + } + } + + public RegionData Get(int posX, int posY, UUID scopeID) + { + string sql = "select * from "+m_Realm+" where \"locX\" = :posX and \"locY\" = :posY"; + if (scopeID != UUID.Zero) + sql += " and \"ScopeID\" = :scopeID"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("posX", posX)); + cmd.Parameters.Add(m_database.CreateParameter("posY", posY)); + if (scopeID != UUID.Zero) + cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID)); + conn.Open(); + List ret = RunCommand(cmd); + if (ret.Count == 0) + return null; + + return ret[0]; + } + } + + public RegionData Get(UUID regionID, UUID scopeID) + { + string sql = "select * from "+m_Realm+" where uuid = :regionID"; + if (scopeID != UUID.Zero) + sql += " and \"ScopeID\" = :scopeID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("regionID", regionID)); + if (scopeID != UUID.Zero) + cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID)); + conn.Open(); + List ret = RunCommand(cmd); + if (ret.Count == 0) + return null; + + return ret[0]; + } + } + + public List Get(int startX, int startY, int endX, int endY, UUID scopeID) + { + string sql = "select * from "+m_Realm+" where \"locX\" between :startX and :endX and \"locY\" between :startY and :endY"; + if (scopeID != UUID.Zero) + sql += " and \"ScopeID\" = :scopeID"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("startX", startX)); + cmd.Parameters.Add(m_database.CreateParameter("startY", startY)); + cmd.Parameters.Add(m_database.CreateParameter("endX", endX)); + cmd.Parameters.Add(m_database.CreateParameter("endY", endY)); + cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID)); + conn.Open(); + return RunCommand(cmd); + } + } + + public List RunCommand(NpgsqlCommand cmd) + { + List retList = new List(); + + NpgsqlDataReader result = cmd.ExecuteReader(); + + while (result.Read()) + { + RegionData ret = new RegionData(); + ret.Data = new Dictionary(); + + UUID regionID; + UUID.TryParse(result["uuid"].ToString(), out regionID); + ret.RegionID = regionID; + UUID scope; + UUID.TryParse(result["ScopeID"].ToString(), out scope); + ret.ScopeID = scope; + ret.RegionName = result["regionName"].ToString(); + ret.posX = Convert.ToInt32(result["locX"]); + ret.posY = Convert.ToInt32(result["locY"]); + ret.sizeX = Convert.ToInt32(result["sizeX"]); + ret.sizeY = Convert.ToInt32(result["sizeY"]); + + if (m_ColumnNames == null) + { + m_ColumnNames = new List(); + + DataTable schemaTable = result.GetSchemaTable(); + foreach (DataRow row in schemaTable.Rows) + m_ColumnNames.Add(row["ColumnName"].ToString()); + } + + foreach (string s in m_ColumnNames) + { + if (s == "uuid") + continue; + if (s == "ScopeID") + continue; + if (s == "regionName") + continue; + if (s == "locX") + continue; + if (s == "locY") + continue; + + ret.Data[s] = result[s].ToString(); + } + + retList.Add(ret); + } + return retList; + } + + public bool Store(RegionData data) + { + if (data.Data.ContainsKey("uuid")) + data.Data.Remove("uuid"); + if (data.Data.ContainsKey("ScopeID")) + data.Data.Remove("ScopeID"); + if (data.Data.ContainsKey("regionName")) + data.Data.Remove("regionName"); + if (data.Data.ContainsKey("posX")) + data.Data.Remove("posX"); + if (data.Data.ContainsKey("posY")) + data.Data.Remove("posY"); + if (data.Data.ContainsKey("sizeX")) + data.Data.Remove("sizeX"); + if (data.Data.ContainsKey("sizeY")) + data.Data.Remove("sizeY"); + if (data.Data.ContainsKey("locX")) + data.Data.Remove("locX"); + if (data.Data.ContainsKey("locY")) + data.Data.Remove("locY"); + + string[] fields = new List(data.Data.Keys).ToArray(); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + + string update = "update " + m_Realm + " set \"locX\"=:posX, \"locY\"=:posY, \"sizeX\"=:sizeX, \"sizeY\"=:sizeY "; + + foreach (string field in fields) + { + + update += ", "; + update += " \"" + field + "\" = :" + field; + + if (m_FieldTypes.ContainsKey(field)) + cmd.Parameters.Add(m_database.CreateParameter(field, data.Data[field], m_FieldTypes[field])); + else + cmd.Parameters.Add(m_database.CreateParameter(field, data.Data[field])); + } + + update += " where uuid = :regionID"; + + if (data.ScopeID != UUID.Zero) + update += " and \"ScopeID\" = :scopeID"; + + cmd.CommandText = update; + cmd.Connection = conn; + cmd.Parameters.Add(m_database.CreateParameter("regionID", data.RegionID)); + cmd.Parameters.Add(m_database.CreateParameter("regionName", data.RegionName)); + cmd.Parameters.Add(m_database.CreateParameter("scopeID", data.ScopeID)); + cmd.Parameters.Add(m_database.CreateParameter("posX", data.posX)); + cmd.Parameters.Add(m_database.CreateParameter("posY", data.posY)); + cmd.Parameters.Add(m_database.CreateParameter("sizeX", data.sizeX)); + cmd.Parameters.Add(m_database.CreateParameter("sizeY", data.sizeY)); + conn.Open(); + try + { + if (cmd.ExecuteNonQuery() < 1) + { + string insert = "insert into " + m_Realm + " (uuid, \"ScopeID\", \"locX\", \"locY\", \"sizeX\", \"sizeY\", \"regionName\", \"" + + String.Join("\", \"", fields) + + "\") values (:regionID, :scopeID, :posX, :posY, :sizeX, :sizeY, :regionName, :" + String.Join(", :", fields) + ")"; + + cmd.CommandText = insert; + + try + { + if (cmd.ExecuteNonQuery() < 1) + { + return false; + } + } + catch (Exception ex) + { + m_log.Warn("[PGSQL Grid]: Error inserting into Regions table: " + ex.Message + ", INSERT sql: " + insert); + } + } + } + catch (Exception ex) + { + m_log.Warn("[PGSQL Grid]: Error updating Regions table: " + ex.Message + ", UPDATE sql: " + update); + } + } + + return true; + } + + public bool SetDataItem(UUID regionID, string item, string value) + { + string sql = "update " + m_Realm + + " set \"" + item + "\" = :" + item + " where uuid = :UUID"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("" + item, value)); + cmd.Parameters.Add(m_database.CreateParameter("UUID", regionID)); + conn.Open(); + if (cmd.ExecuteNonQuery() > 0) + return true; + } + return false; + } + + public bool Delete(UUID regionID) + { + string sql = "delete from " + m_Realm + + " where uuid = :UUID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("UUID", regionID)); + conn.Open(); + if (cmd.ExecuteNonQuery() > 0) + return true; + } + return false; + } + + public List GetDefaultRegions(UUID scopeID) + { + return Get((int)RegionFlags.DefaultRegion, scopeID); + } + + public List GetDefaultHypergridRegions(UUID scopeID) + { + return Get((int)RegionFlags.DefaultHGRegion, scopeID); + } + + public List GetFallbackRegions(UUID scopeID, int x, int y) + { + List regions = Get((int)RegionFlags.FallbackRegion, scopeID); + RegionDataDistanceCompare distanceComparer = new RegionDataDistanceCompare(x, y); + regions.Sort(distanceComparer); + + return regions; + } + + public List GetHyperlinks(UUID scopeID) + { + return Get((int)RegionFlags.Hyperlink, scopeID); + } + + private List Get(int regionFlags, UUID scopeID) + { + string sql = "SELECT * FROM " + m_Realm + " WHERE (\"flags\" & " + regionFlags.ToString() + ") <> 0"; + if (scopeID != UUID.Zero) + sql += " AND \"ScopeID\" = :scopeID"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID)); + conn.Open(); + return RunCommand(cmd); + } + } + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLSimulationData.cs b/OpenSim/Data/PGSQL/PGSQLSimulationData.cs new file mode 100644 index 0000000..77d87d4 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLSimulationData.cs @@ -0,0 +1,2243 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Data; +using System.Drawing; +using System.IO; +using System.Reflection; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using Npgsql; + +namespace OpenSim.Data.PGSQL +{ + /// + /// A PGSQL Interface for the Region Server. + /// + public class PGSQLSimulationData : ISimulationDataStore + { + private const string _migrationStore = "RegionStore"; + private const string LogHeader = "[REGION DB PGSQL]"; + + // private static FileSystemDataStore Instance = new FileSystemDataStore(); + private static readonly ILog _Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// The database manager + /// + private PGSQLManager _Database; + private string m_connectionString; + protected virtual Assembly Assembly + { + get { return GetType().Assembly; } + } + + public PGSQLSimulationData() + { + } + + public PGSQLSimulationData(string connectionString) + { + Initialise(connectionString); + } + + /// + /// Initialises the region datastore + /// + /// The connection string. + public void Initialise(string connectionString) + { + m_connectionString = connectionString; + _Database = new PGSQLManager(connectionString); + + using (NpgsqlConnection conn = new NpgsqlConnection(connectionString)) + { + conn.Open(); + //New Migration settings + Migration m = new Migration(conn, Assembly, "RegionStore"); + m.Update(); + } + } + + /// + /// Dispose the database + /// + public void Dispose() { } + + #region SceneObjectGroup region for loading and Store of the scene. + + /// + /// Loads the objects present in the region. + /// + /// The region UUID. + /// + public List LoadObjects(UUID regionUUID) + { + UUID lastGroupID = UUID.Zero; + + Dictionary prims = new Dictionary(); + Dictionary objects = new Dictionary(); + SceneObjectGroup grp = null; + + string sql = @"SELECT *, + CASE WHEN prims.""UUID"" = prims.""SceneGroupID"" THEN 0 ELSE 1 END as sort + FROM prims + LEFT JOIN primshapes ON prims.""UUID"" = primshapes.""UUID"" + WHERE ""RegionUUID"" = :RegionUUID + ORDER BY ""SceneGroupID"" asc, sort asc, ""LinkNumber"" asc"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand command = new NpgsqlCommand(sql, conn)) + { + command.Parameters.Add(_Database.CreateParameter("regionUUID", regionUUID)); + conn.Open(); + using (NpgsqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + SceneObjectPart sceneObjectPart = BuildPrim(reader); + if (reader["Shape"] is DBNull) + sceneObjectPart.Shape = PrimitiveBaseShape.Default; + else + sceneObjectPart.Shape = BuildShape(reader); + + prims[sceneObjectPart.UUID] = sceneObjectPart; + + UUID groupID = new UUID((Guid)reader["SceneGroupID"]); + + if (groupID != lastGroupID) // New SOG + { + if (grp != null) + objects[grp.UUID] = grp; + + lastGroupID = groupID; + + // There sometimes exist OpenSim bugs that 'orphan groups' so that none of the prims are + // recorded as the root prim (for which the UUID must equal the persisted group UUID). In + // this case, force the UUID to be the same as the group UUID so that at least these can be + // deleted (we need to change the UUID so that any other prims in the linkset can also be + // deleted). + if (sceneObjectPart.UUID != groupID && groupID != UUID.Zero) + { + _Log.WarnFormat( + "[REGION DB]: Found root prim {0} {1} at {2} where group was actually {3}. Forcing UUID to group UUID", + sceneObjectPart.Name, sceneObjectPart.UUID, sceneObjectPart.GroupPosition, groupID); + + sceneObjectPart.UUID = groupID; + } + + grp = new SceneObjectGroup(sceneObjectPart); + } + else + { + // Black magic to preserve link numbers + // Why is this needed, fix this in AddPart method. + int link = sceneObjectPart.LinkNum; + + grp.AddPart(sceneObjectPart); + + if (link != 0) + sceneObjectPart.LinkNum = link; + } + } + } + } + + if (grp != null) + objects[grp.UUID] = grp; + + // Instead of attempting to LoadItems on every prim, + // most of which probably have no items... get a + // list from DB of all prims which have items and + // LoadItems only on those + List primsWithInventory = new List(); + string qry = "select distinct \"primID\" from primitems"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand command = new NpgsqlCommand(qry, conn)) + { + conn.Open(); + using (NpgsqlDataReader itemReader = command.ExecuteReader()) + { + while (itemReader.Read()) + { + if (!(itemReader["primID"] is DBNull)) + { + UUID primID = new UUID(itemReader["primID"].ToString()); + if (prims.ContainsKey(primID)) + { + primsWithInventory.Add(prims[primID]); + } + } + } + } + } + + LoadItems(primsWithInventory); + + _Log.DebugFormat("[REGION DB]: Loaded {0} objects using {1} prims", objects.Count, prims.Count); + + return new List(objects.Values); + } + + /// + /// Load in the prim's persisted inventory. + /// + /// all prims with inventory on a region + private void LoadItems(List allPrimsWithInventory) + { + string sql = @"SELECT * FROM primitems WHERE ""primID"" = :PrimID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand command = new NpgsqlCommand(sql, conn)) + { + conn.Open(); + foreach (SceneObjectPart objectPart in allPrimsWithInventory) + { + command.Parameters.Clear(); + command.Parameters.Add(_Database.CreateParameter("PrimID", objectPart.UUID)); + + List inventory = new List(); + + using (NpgsqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + TaskInventoryItem item = BuildItem(reader); + + item.ParentID = objectPart.UUID; // Values in database are + // often wrong + inventory.Add(item); + } + } + + objectPart.Inventory.RestoreInventoryItems(inventory); + } + } + } + + /// + /// Stores all object's details apart from inventory + /// + /// + /// + public void StoreObject(SceneObjectGroup obj, UUID regionUUID) + { + uint flags = obj.RootPart.GetEffectiveObjectFlags(); + // Eligibility check + // + if ((flags & (uint)PrimFlags.Temporary) != 0) + return; + if ((flags & (uint)PrimFlags.TemporaryOnRez) != 0) + return; + + //_Log.DebugFormat("[PGSQL]: Adding/Changing SceneObjectGroup: {0} to region: {1}, object has {2} prims.", obj.UUID, regionUUID, obj.Parts.Length); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + conn.Open(); + NpgsqlTransaction transaction = conn.BeginTransaction(); + + try + { + foreach (SceneObjectPart sceneObjectPart in obj.Parts) + { + //Update prim + using (NpgsqlCommand sqlCommand = conn.CreateCommand()) + { + sqlCommand.Transaction = transaction; + try + { + StoreSceneObjectPrim(sceneObjectPart, sqlCommand, obj.UUID, regionUUID); + } + catch (NpgsqlException sqlEx) + { + _Log.ErrorFormat("[REGION DB]: Store SceneObjectPrim SQL error: {0} at line {1}", sqlEx.Message, sqlEx.Line); + throw; + } + } + + //Update primshapes + using (NpgsqlCommand sqlCommand = conn.CreateCommand()) + { + sqlCommand.Transaction = transaction; + try + { + StoreSceneObjectPrimShapes(sceneObjectPart, sqlCommand, obj.UUID, regionUUID); + } + catch (NpgsqlException sqlEx) + { + _Log.ErrorFormat("[REGION DB]: Store SceneObjectPrimShapes SQL error: {0} at line {1}", sqlEx.Message, sqlEx.Line); + throw; + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + _Log.ErrorFormat("[REGION DB]: Store SceneObjectGroup error: {0}, Rolling back...", ex.Message); + try + { + transaction.Rollback(); + } + catch (Exception ex2) + { + //Show error + _Log.InfoFormat("[REGION DB]: Rollback of SceneObjectGroup store transaction failed with error: {0}", ex2.Message); + + } + } + } + } + + /// + /// Stores the prim of the sceneobjectpart. + /// + /// The sceneobjectpart or prim. + /// The SQL command with the transaction. + /// The scenegroup UUID. + /// The region UUID. + private void StoreSceneObjectPrim(SceneObjectPart sceneObjectPart, NpgsqlCommand sqlCommand, UUID sceneGroupID, UUID regionUUID) + { + //Big query to update or insert a new prim. + + string queryPrims = @" + UPDATE prims SET + ""CreationDate"" = :CreationDate, ""Name"" = :Name, ""Text"" = :Text, ""Description"" = :Description, ""SitName"" = :SitName, + ""TouchName"" = :TouchName, ""ObjectFlags"" = :ObjectFlags, ""OwnerMask"" = :OwnerMask, ""NextOwnerMask"" = :NextOwnerMask, ""GroupMask"" = :GroupMask, + ""EveryoneMask"" = :EveryoneMask, ""BaseMask"" = :BaseMask, ""PositionX"" = :PositionX, ""PositionY"" = :PositionY, ""PositionZ"" = :PositionZ, + ""GroupPositionX"" = :GroupPositionX, ""GroupPositionY"" = :GroupPositionY, ""GroupPositionZ"" = :GroupPositionZ, ""VelocityX"" = :VelocityX, + ""VelocityY"" = :VelocityY, ""VelocityZ"" = :VelocityZ, ""AngularVelocityX"" = :AngularVelocityX, ""AngularVelocityY"" = :AngularVelocityY, + ""AngularVelocityZ"" = :AngularVelocityZ, ""AccelerationX"" = :AccelerationX, ""AccelerationY"" = :AccelerationY, + ""AccelerationZ"" = :AccelerationZ, ""RotationX"" = :RotationX, ""RotationY"" = :RotationY, ""RotationZ"" = :RotationZ, ""RotationW"" = :RotationW, + ""SitTargetOffsetX"" = :SitTargetOffsetX, ""SitTargetOffsetY"" = :SitTargetOffsetY, ""SitTargetOffsetZ"" = :SitTargetOffsetZ, + ""SitTargetOrientW"" = :SitTargetOrientW, ""SitTargetOrientX"" = :SitTargetOrientX, ""SitTargetOrientY"" = :SitTargetOrientY, + ""SitTargetOrientZ"" = :SitTargetOrientZ, ""RegionUUID"" = :RegionUUID, ""CreatorID"" = :CreatorID, ""OwnerID"" = :OwnerID, ""GroupID"" = :GroupID, + ""LastOwnerID"" = :LastOwnerID, ""SceneGroupID"" = :SceneGroupID, ""PayPrice"" = :PayPrice, ""PayButton1"" = :PayButton1, ""PayButton2"" = :PayButton2, + ""PayButton3"" = :PayButton3, ""PayButton4"" = :PayButton4, ""LoopedSound"" = :LoopedSound, ""LoopedSoundGain"" = :LoopedSoundGain, + ""TextureAnimation"" = :TextureAnimation, ""OmegaX"" = :OmegaX, ""OmegaY"" = :OmegaY, ""OmegaZ"" = :OmegaZ, ""CameraEyeOffsetX"" = :CameraEyeOffsetX, + ""CameraEyeOffsetY"" = :CameraEyeOffsetY, ""CameraEyeOffsetZ"" = :CameraEyeOffsetZ, ""CameraAtOffsetX"" = :CameraAtOffsetX, + ""CameraAtOffsetY"" = :CameraAtOffsetY, ""CameraAtOffsetZ"" = :CameraAtOffsetZ, ""ForceMouselook"" = :ForceMouselook, + ""ScriptAccessPin"" = :ScriptAccessPin, ""AllowedDrop"" = :AllowedDrop, ""DieAtEdge"" = :DieAtEdge, ""SalePrice"" = :SalePrice, + ""SaleType"" = :SaleType, ""ColorR"" = :ColorR, ""ColorG"" = :ColorG, ""ColorB"" = :ColorB, ""ColorA"" = :ColorA, ""ParticleSystem"" = :ParticleSystem, + ""ClickAction"" = :ClickAction, ""Material"" = :Material, ""CollisionSound"" = :CollisionSound, ""CollisionSoundVolume"" = :CollisionSoundVolume, ""PassTouches"" = :PassTouches, + ""LinkNumber"" = :LinkNumber, ""MediaURL"" = :MediaURL, ""DynAttrs"" = :DynAttrs, + ""PhysicsShapeType"" = :PhysicsShapeType, ""Density"" = :Density, ""GravityModifier"" = :GravityModifier, ""Friction"" = :Friction, ""Restitution"" = :Restitution + WHERE ""UUID"" = :UUID ; + + INSERT INTO + prims ( + ""UUID"", ""CreationDate"", ""Name"", ""Text"", ""Description"", ""SitName"", ""TouchName"", ""ObjectFlags"", ""OwnerMask"", ""NextOwnerMask"", ""GroupMask"", + ""EveryoneMask"", ""BaseMask"", ""PositionX"", ""PositionY"", ""PositionZ"", ""GroupPositionX"", ""GroupPositionY"", ""GroupPositionZ"", ""VelocityX"", + ""VelocityY"", ""VelocityZ"", ""AngularVelocityX"", ""AngularVelocityY"", ""AngularVelocityZ"", ""AccelerationX"", ""AccelerationY"", ""AccelerationZ"", + ""RotationX"", ""RotationY"", ""RotationZ"", ""RotationW"", ""SitTargetOffsetX"", ""SitTargetOffsetY"", ""SitTargetOffsetZ"", ""SitTargetOrientW"", + ""SitTargetOrientX"", ""SitTargetOrientY"", ""SitTargetOrientZ"", ""RegionUUID"", ""CreatorID"", ""OwnerID"", ""GroupID"", ""LastOwnerID"", ""SceneGroupID"", + ""PayPrice"", ""PayButton1"", ""PayButton2"", ""PayButton3"", ""PayButton4"", ""LoopedSound"", ""LoopedSoundGain"", ""TextureAnimation"", ""OmegaX"", + ""OmegaY"", ""OmegaZ"", ""CameraEyeOffsetX"", ""CameraEyeOffsetY"", ""CameraEyeOffsetZ"", ""CameraAtOffsetX"", ""CameraAtOffsetY"", ""CameraAtOffsetZ"", + ""ForceMouselook"", ""ScriptAccessPin"", ""AllowedDrop"", ""DieAtEdge"", ""SalePrice"", ""SaleType"", ""ColorR"", ""ColorG"", ""ColorB"", ""ColorA"", + ""ParticleSystem"", ""ClickAction"", ""Material"", ""CollisionSound"", ""CollisionSoundVolume"", ""PassTouches"", ""LinkNumber"", ""MediaURL"", ""DynAttrs"", + ""PhysicsShapeType"", ""Density"", ""GravityModifier"", ""Friction"", ""Restitution"" + ) Select + :UUID, :CreationDate, :Name, :Text, :Description, :SitName, :TouchName, :ObjectFlags, :OwnerMask, :NextOwnerMask, :GroupMask, + :EveryoneMask, :BaseMask, :PositionX, :PositionY, :PositionZ, :GroupPositionX, :GroupPositionY, :GroupPositionZ, :VelocityX, + :VelocityY, :VelocityZ, :AngularVelocityX, :AngularVelocityY, :AngularVelocityZ, :AccelerationX, :AccelerationY, :AccelerationZ, + :RotationX, :RotationY, :RotationZ, :RotationW, :SitTargetOffsetX, :SitTargetOffsetY, :SitTargetOffsetZ, :SitTargetOrientW, + :SitTargetOrientX, :SitTargetOrientY, :SitTargetOrientZ, :RegionUUID, :CreatorID, :OwnerID, :GroupID, :LastOwnerID, :SceneGroupID, + :PayPrice, :PayButton1, :PayButton2, :PayButton3, :PayButton4, :LoopedSound, :LoopedSoundGain, :TextureAnimation, :OmegaX, + :OmegaY, :OmegaZ, :CameraEyeOffsetX, :CameraEyeOffsetY, :CameraEyeOffsetZ, :CameraAtOffsetX, :CameraAtOffsetY, :CameraAtOffsetZ, + :ForceMouselook, :ScriptAccessPin, :AllowedDrop, :DieAtEdge, :SalePrice, :SaleType, :ColorR, :ColorG, :ColorB, :ColorA, + :ParticleSystem, :ClickAction, :Material, :CollisionSound, :CollisionSoundVolume, :PassTouches, :LinkNumber, :MediaURL, :DynAttrs, + :PhysicsShapeType, :Density, :GravityModifier, :Friction, :Restitution + where not EXISTS (SELECT ""UUID"" FROM prims WHERE ""UUID"" = :UUID); + "; + + //Set commandtext. + sqlCommand.CommandText = queryPrims; + //Add parameters + sqlCommand.Parameters.AddRange(CreatePrimParameters(sceneObjectPart, sceneGroupID, regionUUID)); + + //Execute the query. If it fails then error is trapped in calling function + sqlCommand.ExecuteNonQuery(); + } + + /// + /// Stores the scene object prim shapes. + /// + /// The sceneobjectpart containing prim shape. + /// The SQL command with the transaction. + /// The scenegroup UUID. + /// The region UUID. + private void StoreSceneObjectPrimShapes(SceneObjectPart sceneObjectPart, NpgsqlCommand sqlCommand, UUID sceneGroupID, UUID regionUUID) + { + //Big query to or insert or update primshapes + + string queryPrimShapes = @" + UPDATE primshapes SET + ""Shape"" = :Shape, ""ScaleX"" = :ScaleX, ""ScaleY"" = :ScaleY, ""ScaleZ"" = :ScaleZ, ""PCode"" = :PCode, ""PathBegin"" = :PathBegin, + ""PathEnd"" = :PathEnd, ""PathScaleX"" = :PathScaleX, ""PathScaleY"" = :PathScaleY, ""PathShearX"" = :PathShearX, ""PathShearY"" = :PathShearY, + ""PathSkew"" = :PathSkew, ""PathCurve"" = :PathCurve, ""PathRadiusOffset"" = :PathRadiusOffset, ""PathRevolutions"" = :PathRevolutions, + ""PathTaperX"" = :PathTaperX, ""PathTaperY"" = :PathTaperY, ""PathTwist"" = :PathTwist, ""PathTwistBegin"" = :PathTwistBegin, + ""ProfileBegin"" = :ProfileBegin, ""ProfileEnd"" = :ProfileEnd, ""ProfileCurve"" = :ProfileCurve, ""ProfileHollow"" = :ProfileHollow, + ""Texture"" = :Texture, ""ExtraParams"" = :ExtraParams, ""State"" = :State, ""Media"" = :Media + WHERE ""UUID"" = :UUID ; + + INSERT INTO + primshapes ( + ""UUID"", ""Shape"", ""ScaleX"", ""ScaleY"", ""ScaleZ"", ""PCode"", ""PathBegin"", ""PathEnd"", ""PathScaleX"", ""PathScaleY"", ""PathShearX"", ""PathShearY"", + ""PathSkew"", ""PathCurve"", ""PathRadiusOffset"", ""PathRevolutions"", ""PathTaperX"", ""PathTaperY"", ""PathTwist"", ""PathTwistBegin"", ""ProfileBegin"", + ""ProfileEnd"", ""ProfileCurve"", ""ProfileHollow"", ""Texture"", ""ExtraParams"", ""State"", ""Media"" + ) + Select + :UUID, :Shape, :ScaleX, :ScaleY, :ScaleZ, :PCode, :PathBegin, :PathEnd, :PathScaleX, :PathScaleY, :PathShearX, :PathShearY, + :PathSkew, :PathCurve, :PathRadiusOffset, :PathRevolutions, :PathTaperX, :PathTaperY, :PathTwist, :PathTwistBegin, :ProfileBegin, + :ProfileEnd, :ProfileCurve, :ProfileHollow, :Texture, :ExtraParams, :State, :Media + where not EXISTS (SELECT ""UUID"" FROM primshapes WHERE ""UUID"" = :UUID); + "; + + //Set commandtext. + sqlCommand.CommandText = queryPrimShapes; + + //Add parameters + sqlCommand.Parameters.AddRange(CreatePrimShapeParameters(sceneObjectPart, sceneGroupID, regionUUID)); + + //Execute the query. If it fails then error is trapped in calling function + sqlCommand.ExecuteNonQuery(); + + } + + /// + /// Removes a object from the database. + /// Meaning removing it from tables Prims, PrimShapes and PrimItems + /// + /// id of scenegroup + /// regionUUID (is this used anyway + public void RemoveObject(UUID objectID, UUID regionUUID) + { + //_Log.InfoFormat("[PGSQL]: Removing obj: {0} from region: {1}", objectID, regionUUID); + + //Remove from prims and primsitem table + string sqlPrims = @"DELETE FROM PRIMS WHERE ""SceneGroupID"" = :objectID"; + string sqlPrimItems = @"DELETE FROM PRIMITEMS WHERE ""primID"" in (SELECT ""UUID"" FROM PRIMS WHERE ""SceneGroupID"" = :objectID)"; + string sqlPrimShapes = @"DELETE FROM PRIMSHAPES WHERE ""UUID"" in (SELECT ""UUID"" FROM PRIMS WHERE ""SceneGroupID"" = :objectID)"; + + lock (_Database) + { + //Using the non transaction mode. + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + cmd.Connection = conn; + cmd.CommandText = sqlPrimShapes; + conn.Open(); + cmd.Parameters.Add(_Database.CreateParameter("objectID", objectID)); + cmd.ExecuteNonQuery(); + + cmd.CommandText = sqlPrimItems; + cmd.ExecuteNonQuery(); + + cmd.CommandText = sqlPrims; + cmd.ExecuteNonQuery(); + } + } + } + + /// + /// Store the inventory of a prim. Warning deletes everything first and then adds all again. + /// + /// + /// + public void StorePrimInventory(UUID primID, ICollection items) + { + //_Log.InfoFormat("[REGION DB: Persisting Prim Inventory with prim ID {0}", primID); + + //Statement from PGSQL section! + // For now, we're just going to crudely remove all the previous inventory items + // no matter whether they have changed or not, and replace them with the current set. + + //Delete everything from PrimID + //TODO add index on PrimID in DB, if not already exist + + string sql = @"delete from primitems where ""primID"" = :primID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("primID", primID)); + conn.Open(); + cmd.ExecuteNonQuery(); + } + + sql = + @"INSERT INTO primitems ( + ""itemID"",""primID"",""assetID"",""parentFolderID"",""invType"",""assetType"",""name"",""description"",""creationDate"",""creatorID"",""ownerID"",""lastOwnerID"",""groupID"", + ""nextPermissions"",""currentPermissions"",""basePermissions"",""everyonePermissions"",""groupPermissions"",""flags"") + VALUES (:itemID,:primID,:assetID,:parentFolderID,:invType,:assetType,:name,:description,:creationDate,:creatorID,:ownerID, + :lastOwnerID,:groupID,:nextPermissions,:currentPermissions,:basePermissions,:everyonePermissions,:groupPermissions,:flags)"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + conn.Open(); + foreach (TaskInventoryItem taskItem in items) + { + cmd.Parameters.AddRange(CreatePrimInventoryParameters(taskItem)); + cmd.ExecuteNonQuery(); + cmd.Parameters.Clear(); + } + } + } + + #endregion + + /// + /// Loads the terrain map. + /// + /// regionID. + /// + public double[,] LoadTerrain(UUID regionID) + { + double[,] ret = null; + TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight); + if (terrData != null) + ret = terrData.GetDoubles(); + return ret; + } + + // Returns 'null' if region not found + public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ) + { + TerrainData terrData = null; + + string sql = @"select ""RegionUUID"", ""Revision"", ""Heightfield"" from terrain + where ""RegionUUID"" = :RegionUUID order by ""Revision"" desc limit 1; "; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + // PGSqlParameter param = new PGSqlParameter(); + cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID)); + conn.Open(); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + int rev; + if (reader.Read()) + { + rev = Convert.ToInt32(reader["Revision"]); + byte[] blob = (byte[])reader["Heightfield"]; + terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob); + } + else + { + _Log.Info("[REGION DB]: No terrain found for region"); + return null; + } + _Log.Info("[REGION DB]: Loaded terrain revision r" + rev); + } + } + } + + return terrData; + } + + // Legacy entry point for when terrain was always a 256x256 heightmap + public void StoreTerrain(double[,] terrain, UUID regionID) + { + StoreTerrain(new HeightmapTerrainData(terrain), regionID); + } + + /// + /// Stores the terrain map to DB. + /// + /// terrain map data. + /// regionID. + public void StoreTerrain(TerrainData terrData, UUID regionID) + { + //Delete old terrain map + string sql = @"delete from terrain where ""RegionUUID""=:RegionUUID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID)); + conn.Open(); + cmd.ExecuteNonQuery(); + + _Log.InfoFormat("{0} Deleted terrain revision id = {1}", LogHeader, regionID); + } + } + + int terrainDBRevision; + Array terrainDBblob; + terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob); + + sql = @"insert into terrain(""RegionUUID"", ""Revision"", ""Heightfield"") values(:RegionUUID, :Revision, :Heightfield)"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID)); + cmd.Parameters.Add(_Database.CreateParameter("Revision", terrainDBRevision)); + cmd.Parameters.Add(_Database.CreateParameter("Heightfield", terrainDBblob)); + conn.Open(); + cmd.ExecuteNonQuery(); + + _Log.InfoFormat("{0} Stored terrain id = {1}, terrainSize = <{2},{3}>", + LogHeader, regionID, terrData.SizeX, terrData.SizeY); + } + } + + } + + /// + /// Loads all the land objects of a region. + /// + /// The region UUID. + /// + public List LoadLandObjects(UUID regionUUID) + { + List LandDataForRegion = new List(); + + string sql = @"select * from land where ""RegionUUID"" = :RegionUUID"; + + //Retrieve all land data from region + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionUUID)); + conn.Open(); + using (NpgsqlDataReader readerLandData = cmd.ExecuteReader()) + { + while (readerLandData.Read()) + { + LandDataForRegion.Add(BuildLandData(readerLandData)); + } + } + } + + //Retrieve all accesslist data for all landdata + foreach (LandData LandData in LandDataForRegion) + { + sql = @"select * from landaccesslist where ""LandUUID"" = :LandUUID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("LandUUID", LandData.GlobalID)); + conn.Open(); + using (NpgsqlDataReader readerAccessList = cmd.ExecuteReader()) + { + while (readerAccessList.Read()) + { + LandData.ParcelAccessList.Add(BuildLandAccessData(readerAccessList)); + } + } + } + } + + //Return data + return LandDataForRegion; + } + + /// + /// Stores land object with landaccess list. + /// + /// parcel data. + public void StoreLandObject(ILandObject parcel) + { + //As this is only one record in land table I just delete all and then add a new record. + //As the delete landaccess is already in the pgsql code + + //Delete old values + RemoveLandObject(parcel.LandData.GlobalID); + + //Insert new values + string sql = @"INSERT INTO land + (""UUID"",""RegionUUID"",""LocalLandID"",""Bitmap"",""Name"",""Description"",""OwnerUUID"",""IsGroupOwned"",""Area"",""AuctionID"",""Category"",""ClaimDate"",""ClaimPrice"", + ""GroupUUID"",""SalePrice"",""LandStatus"",""LandFlags"",""LandingType"",""MediaAutoScale"",""MediaTextureUUID"",""MediaURL"",""MusicURL"",""PassHours"",""PassPrice"", + ""SnapshotUUID"",""UserLocationX"",""UserLocationY"",""UserLocationZ"",""UserLookAtX"",""UserLookAtY"",""UserLookAtZ"",""AuthbuyerID"",""OtherCleanTime"") + VALUES + (:UUID,:RegionUUID,:LocalLandID,:Bitmap,:Name,:Description,:OwnerUUID,:IsGroupOwned,:Area,:AuctionID,:Category,:ClaimDate,:ClaimPrice, + :GroupUUID,:SalePrice,:LandStatus,:LandFlags,:LandingType,:MediaAutoScale,:MediaTextureUUID,:MediaURL,:MusicURL,:PassHours,:PassPrice, + :SnapshotUUID,:UserLocationX,:UserLocationY,:UserLocationZ,:UserLookAtX,:UserLookAtY,:UserLookAtZ,:AuthbuyerID,:OtherCleanTime)"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.AddRange(CreateLandParameters(parcel.LandData, parcel.RegionUUID)); + conn.Open(); + cmd.ExecuteNonQuery(); + } + + sql = @"INSERT INTO landaccesslist (""LandUUID"",""AccessUUID"",""LandFlags"",""Expires"") VALUES (:LandUUID,:AccessUUID,:Flags,:Expires)"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + conn.Open(); + foreach (LandAccessEntry parcelAccessEntry in parcel.LandData.ParcelAccessList) + { + cmd.Parameters.AddRange(CreateLandAccessParameters(parcelAccessEntry, parcel.RegionUUID)); + + cmd.ExecuteNonQuery(); + cmd.Parameters.Clear(); + } + } + } + + /// + /// Removes a land object from DB. + /// + /// UUID of landobject + public void RemoveLandObject(UUID globalID) + { + string sql = @"delete from land where ""UUID""=:UUID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("UUID", globalID)); + conn.Open(); + cmd.ExecuteNonQuery(); + } + sql = @"delete from landaccesslist where ""LandUUID""=:UUID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("UUID", globalID)); + conn.Open(); + cmd.ExecuteNonQuery(); + } + } + public RegionLightShareData LoadRegionWindlightSettings(UUID regionUUID) + { + RegionLightShareData nWP = new RegionLightShareData(); + nWP.OnSave += StoreRegionWindlightSettings; + + string sql = @"select * from regionwindlight where ""region_id"" = :regionID"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("regionID", regionUUID.ToString() )); + conn.Open(); + using (NpgsqlDataReader result = cmd.ExecuteReader()) + { + if (!result.Read()) + { + //No result, so store our default windlight profile and return it + nWP.regionID = regionUUID; + StoreRegionWindlightSettings(nWP); + return nWP; + } + else + { + nWP.regionID = DBGuid.FromDB(result["region_id"]); + nWP.waterColor.X = Convert.ToSingle(result["water_color_r"]); + nWP.waterColor.Y = Convert.ToSingle(result["water_color_g"]); + nWP.waterColor.Z = Convert.ToSingle(result["water_color_b"]); + nWP.waterFogDensityExponent = Convert.ToSingle(result["water_fog_density_exponent"]); + nWP.underwaterFogModifier = Convert.ToSingle(result["underwater_fog_modifier"]); + nWP.reflectionWaveletScale.X = Convert.ToSingle(result["reflection_wavelet_scale_1"]); + nWP.reflectionWaveletScale.Y = Convert.ToSingle(result["reflection_wavelet_scale_2"]); + nWP.reflectionWaveletScale.Z = Convert.ToSingle(result["reflection_wavelet_scale_3"]); + nWP.fresnelScale = Convert.ToSingle(result["fresnel_scale"]); + nWP.fresnelOffset = Convert.ToSingle(result["fresnel_offset"]); + nWP.refractScaleAbove = Convert.ToSingle(result["refract_scale_above"]); + nWP.refractScaleBelow = Convert.ToSingle(result["refract_scale_below"]); + nWP.blurMultiplier = Convert.ToSingle(result["blur_multiplier"]); + nWP.bigWaveDirection.X = Convert.ToSingle(result["big_wave_direction_x"]); + nWP.bigWaveDirection.Y = Convert.ToSingle(result["big_wave_direction_y"]); + nWP.littleWaveDirection.X = Convert.ToSingle(result["little_wave_direction_x"]); + nWP.littleWaveDirection.Y = Convert.ToSingle(result["little_wave_direction_y"]); + UUID.TryParse(result["normal_map_texture"].ToString(), out nWP.normalMapTexture); + nWP.horizon.X = Convert.ToSingle(result["horizon_r"]); + nWP.horizon.Y = Convert.ToSingle(result["horizon_g"]); + nWP.horizon.Z = Convert.ToSingle(result["horizon_b"]); + nWP.horizon.W = Convert.ToSingle(result["horizon_i"]); + nWP.hazeHorizon = Convert.ToSingle(result["haze_horizon"]); + nWP.blueDensity.X = Convert.ToSingle(result["blue_density_r"]); + nWP.blueDensity.Y = Convert.ToSingle(result["blue_density_g"]); + nWP.blueDensity.Z = Convert.ToSingle(result["blue_density_b"]); + nWP.blueDensity.W = Convert.ToSingle(result["blue_density_i"]); + nWP.hazeDensity = Convert.ToSingle(result["haze_density"]); + nWP.densityMultiplier = Convert.ToSingle(result["density_multiplier"]); + nWP.distanceMultiplier = Convert.ToSingle(result["distance_multiplier"]); + nWP.maxAltitude = Convert.ToUInt16(result["max_altitude"]); + nWP.sunMoonColor.X = Convert.ToSingle(result["sun_moon_color_r"]); + nWP.sunMoonColor.Y = Convert.ToSingle(result["sun_moon_color_g"]); + nWP.sunMoonColor.Z = Convert.ToSingle(result["sun_moon_color_b"]); + nWP.sunMoonColor.W = Convert.ToSingle(result["sun_moon_color_i"]); + nWP.sunMoonPosition = Convert.ToSingle(result["sun_moon_position"]); + nWP.ambient.X = Convert.ToSingle(result["ambient_r"]); + nWP.ambient.Y = Convert.ToSingle(result["ambient_g"]); + nWP.ambient.Z = Convert.ToSingle(result["ambient_b"]); + nWP.ambient.W = Convert.ToSingle(result["ambient_i"]); + nWP.eastAngle = Convert.ToSingle(result["east_angle"]); + nWP.sunGlowFocus = Convert.ToSingle(result["sun_glow_focus"]); + nWP.sunGlowSize = Convert.ToSingle(result["sun_glow_size"]); + nWP.sceneGamma = Convert.ToSingle(result["scene_gamma"]); + nWP.starBrightness = Convert.ToSingle(result["star_brightness"]); + nWP.cloudColor.X = Convert.ToSingle(result["cloud_color_r"]); + nWP.cloudColor.Y = Convert.ToSingle(result["cloud_color_g"]); + nWP.cloudColor.Z = Convert.ToSingle(result["cloud_color_b"]); + nWP.cloudColor.W = Convert.ToSingle(result["cloud_color_i"]); + nWP.cloudXYDensity.X = Convert.ToSingle(result["cloud_x"]); + nWP.cloudXYDensity.Y = Convert.ToSingle(result["cloud_y"]); + nWP.cloudXYDensity.Z = Convert.ToSingle(result["cloud_density"]); + nWP.cloudCoverage = Convert.ToSingle(result["cloud_coverage"]); + nWP.cloudScale = Convert.ToSingle(result["cloud_scale"]); + nWP.cloudDetailXYDensity.X = Convert.ToSingle(result["cloud_detail_x"]); + nWP.cloudDetailXYDensity.Y = Convert.ToSingle(result["cloud_detail_y"]); + nWP.cloudDetailXYDensity.Z = Convert.ToSingle(result["cloud_detail_density"]); + nWP.cloudScrollX = Convert.ToSingle(result["cloud_scroll_x"]); + nWP.cloudScrollXLock = Convert.ToBoolean(result["cloud_scroll_x_lock"]); + nWP.cloudScrollY = Convert.ToSingle(result["cloud_scroll_y"]); + nWP.cloudScrollYLock = Convert.ToBoolean(result["cloud_scroll_y_lock"]); + nWP.drawClassicClouds = Convert.ToBoolean(result["draw_classic_clouds"]); + nWP.valid = true; + } + } + } + return nWP; + } + + public void RemoveRegionWindlightSettings(UUID regionID) + { + string sql = @"delete from regionwindlight where ""region_id"" = :region_id"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + conn.Open(); + cmd.Parameters.Add(_Database.CreateParameter("region_id", regionID.ToString())); + cmd.ExecuteNonQuery(); + } + } + + public void StoreRegionWindlightSettings(RegionLightShareData wl) + { + string sql = @"select region_id from regionwindlight where ""region_id"" = :region_id limit 1;"; + bool exists = false; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + conn.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("region_id", wl.regionID.ToString() )); + NpgsqlDataReader dr = cmd.ExecuteReader(); + exists = dr.Read(); + } + } + if (exists) + { + RemoveRegionWindlightSettings(wl.regionID); + } + + // sql insert + sql = @"INSERT INTO regionwindlight + (region_id + ,water_color_r + ,water_color_g + ,water_color_b + ,water_fog_density_exponent + ,underwater_fog_modifier + ,reflection_wavelet_scale_1 + ,reflection_wavelet_scale_2 + ,reflection_wavelet_scale_3 + ,fresnel_scale + ,fresnel_offset + ,refract_scale_above + ,refract_scale_below + ,blur_multiplier + ,big_wave_direction_x + ,big_wave_direction_y + ,little_wave_direction_x + ,little_wave_direction_y + ,normal_map_texture + ,horizon_r + ,horizon_g + ,horizon_b + ,horizon_i + ,haze_horizon + ,blue_density_r + ,blue_density_g + ,blue_density_b + ,blue_density_i + ,haze_density + ,density_multiplier + ,distance_multiplier + ,max_altitude + ,sun_moon_color_r + ,sun_moon_color_g + ,sun_moon_color_b + ,sun_moon_color_i + ,sun_moon_position + ,ambient_r + ,ambient_g + ,ambient_b + ,ambient_i + ,east_angle + ,sun_glow_focus + ,sun_glow_size + ,scene_gamma + ,star_brightness + ,cloud_color_r + ,cloud_color_g + ,cloud_color_b + ,cloud_color_i + ,cloud_x + ,cloud_y + ,cloud_density + ,cloud_coverage + ,cloud_scale + ,cloud_detail_x + ,cloud_detail_y + ,cloud_detail_density + ,cloud_scroll_x + ,cloud_scroll_x_lock + ,cloud_scroll_y + ,cloud_scroll_y_lock + ,draw_classic_clouds) + VALUES + (:region_id + ,:water_color_r + ,:water_color_g + ,:water_color_b + ,:water_fog_density_exponent + ,:underwater_fog_modifier + ,:reflection_wavelet_scale_1 + ,:reflection_wavelet_scale_2 + ,:reflection_wavelet_scale_3 + ,:fresnel_scale + ,:fresnel_offset + ,:refract_scale_above + ,:refract_scale_below + ,:blur_multiplier + ,:big_wave_direction_x + ,:big_wave_direction_y + ,:little_wave_direction_x + ,:little_wave_direction_y + ,:normal_map_texture + ,:horizon_r + ,:horizon_g + ,:horizon_b + ,:horizon_i + ,:haze_horizon + ,:blue_density_r + ,:blue_density_g + ,:blue_density_b + ,:blue_density_i + ,:haze_density + ,:density_multiplier + ,:distance_multiplier + ,:max_altitude + ,:sun_moon_color_r + ,:sun_moon_color_g + ,:sun_moon_color_b + ,:sun_moon_color_i + ,:sun_moon_position + ,:ambient_r + ,:ambient_g + ,:ambient_b + ,:ambient_i + ,:east_angle + ,:sun_glow_focus + ,:sun_glow_size + ,:scene_gamma + ,:star_brightness + ,:cloud_color_r + ,:cloud_color_g + ,:cloud_color_b + ,:cloud_color_i + ,:cloud_x + ,:cloud_y + ,:cloud_density + ,:cloud_coverage + ,:cloud_scale + ,:cloud_detail_x + ,:cloud_detail_y + ,:cloud_detail_density + ,:cloud_scroll_x + ,:cloud_scroll_x_lock + ,:cloud_scroll_y + ,:cloud_scroll_y_lock + ,:draw_classic_clouds);"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + conn.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("region_id", wl.regionID.ToString())); + cmd.Parameters.Add(_Database.CreateParameter("water_color_r", wl.waterColor.X)); + cmd.Parameters.Add(_Database.CreateParameter("water_color_g", wl.waterColor.Y)); + cmd.Parameters.Add(_Database.CreateParameter("water_color_b", wl.waterColor.Z)); + cmd.Parameters.Add(_Database.CreateParameter("water_fog_density_exponent", wl.waterFogDensityExponent)); + cmd.Parameters.Add(_Database.CreateParameter("underwater_fog_modifier", wl.underwaterFogModifier)); + cmd.Parameters.Add(_Database.CreateParameter("reflection_wavelet_scale_1", wl.reflectionWaveletScale.X)); + cmd.Parameters.Add(_Database.CreateParameter("reflection_wavelet_scale_2", wl.reflectionWaveletScale.Y)); + cmd.Parameters.Add(_Database.CreateParameter("reflection_wavelet_scale_3", wl.reflectionWaveletScale.Z)); + cmd.Parameters.Add(_Database.CreateParameter("fresnel_scale", wl.fresnelScale)); + cmd.Parameters.Add(_Database.CreateParameter("fresnel_offset", wl.fresnelOffset)); + cmd.Parameters.Add(_Database.CreateParameter("refract_scale_above", wl.refractScaleAbove)); + cmd.Parameters.Add(_Database.CreateParameter("refract_scale_below", wl.refractScaleBelow)); + cmd.Parameters.Add(_Database.CreateParameter("blur_multiplier", wl.blurMultiplier)); + cmd.Parameters.Add(_Database.CreateParameter("big_wave_direction_x", wl.bigWaveDirection.X)); + cmd.Parameters.Add(_Database.CreateParameter("big_wave_direction_y", wl.bigWaveDirection.Y)); + cmd.Parameters.Add(_Database.CreateParameter("little_wave_direction_x", wl.littleWaveDirection.X)); + cmd.Parameters.Add(_Database.CreateParameter("little_wave_direction_y", wl.littleWaveDirection.Y)); + cmd.Parameters.Add(_Database.CreateParameter("normal_map_texture", wl.normalMapTexture.ToString())); + cmd.Parameters.Add(_Database.CreateParameter("horizon_r", wl.horizon.X)); + cmd.Parameters.Add(_Database.CreateParameter("horizon_g", wl.horizon.Y)); + cmd.Parameters.Add(_Database.CreateParameter("horizon_b", wl.horizon.Z)); + cmd.Parameters.Add(_Database.CreateParameter("horizon_i", wl.horizon.W)); + cmd.Parameters.Add(_Database.CreateParameter("haze_horizon", wl.hazeHorizon)); + cmd.Parameters.Add(_Database.CreateParameter("blue_density_r", wl.blueDensity.X)); + cmd.Parameters.Add(_Database.CreateParameter("blue_density_g", wl.blueDensity.Y)); + cmd.Parameters.Add(_Database.CreateParameter("blue_density_b", wl.blueDensity.Z)); + cmd.Parameters.Add(_Database.CreateParameter("blue_density_i", wl.blueDensity.W)); + cmd.Parameters.Add(_Database.CreateParameter("haze_density", wl.hazeDensity)); + cmd.Parameters.Add(_Database.CreateParameter("density_multiplier", wl.densityMultiplier)); + cmd.Parameters.Add(_Database.CreateParameter("distance_multiplier", wl.distanceMultiplier)); + cmd.Parameters.Add(_Database.CreateParameter("max_altitude", wl.maxAltitude)); + cmd.Parameters.Add(_Database.CreateParameter("sun_moon_color_r", wl.sunMoonColor.X)); + cmd.Parameters.Add(_Database.CreateParameter("sun_moon_color_g", wl.sunMoonColor.Y)); + cmd.Parameters.Add(_Database.CreateParameter("sun_moon_color_b", wl.sunMoonColor.Z)); + cmd.Parameters.Add(_Database.CreateParameter("sun_moon_color_i", wl.sunMoonColor.W)); + cmd.Parameters.Add(_Database.CreateParameter("sun_moon_position", wl.sunMoonPosition)); + cmd.Parameters.Add(_Database.CreateParameter("ambient_r", wl.ambient.X)); + cmd.Parameters.Add(_Database.CreateParameter("ambient_g", wl.ambient.Y)); + cmd.Parameters.Add(_Database.CreateParameter("ambient_b", wl.ambient.Z)); + cmd.Parameters.Add(_Database.CreateParameter("ambient_i", wl.ambient.W)); + cmd.Parameters.Add(_Database.CreateParameter("east_angle", wl.eastAngle)); + cmd.Parameters.Add(_Database.CreateParameter("sun_glow_focus", wl.sunGlowFocus)); + cmd.Parameters.Add(_Database.CreateParameter("sun_glow_size", wl.sunGlowSize)); + cmd.Parameters.Add(_Database.CreateParameter("scene_gamma", wl.sceneGamma)); + cmd.Parameters.Add(_Database.CreateParameter("star_brightness", wl.starBrightness)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_color_r", wl.cloudColor.X)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_color_g", wl.cloudColor.Y)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_color_b", wl.cloudColor.Z)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_color_i", wl.cloudColor.W)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_x", wl.cloudXYDensity.X)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_y", wl.cloudXYDensity.Y)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_density", wl.cloudXYDensity.Z)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_coverage", wl.cloudCoverage)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_scale", wl.cloudScale)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_detail_x", wl.cloudDetailXYDensity.X)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_detail_y", wl.cloudDetailXYDensity.Y)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_detail_density", wl.cloudDetailXYDensity.Z)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_scroll_x", wl.cloudScrollX)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_scroll_x_lock", wl.cloudScrollXLock)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_scroll_y", wl.cloudScrollY)); + cmd.Parameters.Add(_Database.CreateParameter("cloud_scroll_y_lock", wl.cloudScrollYLock)); + cmd.Parameters.Add(_Database.CreateParameter("draw_classic_clouds", wl.drawClassicClouds)); + + cmd.ExecuteNonQuery(); + } + } + #region update + // } + // else + // { + // // sql update + // sql = @"UPDATE [OpenSim].[dbo].[regionwindlight] + // SET [region_id] = @region_id + // ,[water_color_r] = @water_color_r + // ,[water_color_g] = @water_color_g + // ,[water_color_b] = @water_color_b + // ,[water_fog_density_exponent] = @water_fog_density_exponent + // ,[underwater_fog_modifier] = @underwater_fog_modifier + // ,[reflection_wavelet_scale_1] = @reflection_wavelet_scale_1 + // ,[reflection_wavelet_scale_2] = @reflection_wavelet_scale_2 + // ,[reflection_wavelet_scale_3] = @reflection_wavelet_scale_3 + // ,[fresnel_scale] = @fresnel_scale + // ,[fresnel_offset] = @fresnel_offset + // ,[refract_scale_above] = @refract_scale_above + // ,[refract_scale_below] = @refract_scale_below + // ,[blur_multiplier] = @blur_multiplier + // ,[big_wave_direction_x] = @big_wave_direction_x + // ,[big_wave_direction_y] = @big_wave_direction_y + // ,[little_wave_direction_x] = @little_wave_direction_x + // ,[little_wave_direction_y] = @little_wave_direction_y + // ,[normal_map_texture] = @normal_map_texture + // ,[horizon_r] = @horizon_r + // ,[horizon_g] = @horizon_g + // ,[horizon_b] = @horizon_b + // ,[horizon_i] = @horizon_i + // ,[haze_horizon] = @haze_horizon + // ,[blue_density_r] = @blue_density_r + // ,[blue_density_g] = @blue_density_g + // ,[blue_density_b] = @blue_density_b + // ,[blue_density_i] = @blue_density_i + // ,[haze_density] = @haze_density + // ,[density_multiplier] = @density_multiplier + // ,[distance_multiplier] = @distance_multiplier + // ,[max_altitude] = @max_altitude + // ,[sun_moon_color_r] = @sun_moon_color_r + // ,[sun_moon_color_g] = @sun_moon_color_g + // ,[sun_moon_color_b] = @sun_moon_color_b + // ,[sun_moon_color_i] = @sun_moon_color_i + // ,[sun_moon_position] = @sun_moon_position + // ,[ambient_r] = @ambient_r + // ,[ambient_g] = @ambient_g + // ,[ambient_b] = @ambient_b + // ,[ambient_i] = @ambient_i + // ,[east_angle] = @east_angle + // ,[sun_glow_focus] = @sun_glow_focus + // ,[sun_glow_size] = @sun_glow_size + // ,[scene_gamma] = @scene_gamma + // ,[star_brightness] = @star_brightness + // ,[cloud_color_r] = @cloud_color_r + // ,[cloud_color_g] = @cloud_color_g + // ,[cloud_color_b] = @cloud_color_b + // ,[cloud_color_i] = @cloud_color_i + // ,[cloud_x] = @cloud_x + // ,[cloud_y] = @cloud_y + // ,[cloud_density] = @cloud_density + // ,[cloud_coverage] = @cloud_coverage + // ,[cloud_scale] = @cloud_scale + // ,[cloud_detail_x] = @cloud_detail_x + // ,[cloud_detail_y] = @cloud_detail_y + // ,[cloud_detail_density] = @cloud_detail_density + // ,[cloud_scroll_x] = @cloud_scroll_x + // ,[cloud_scroll_x_lock] = @cloud_scroll_x_lock + // ,[cloud_scroll_y] = @cloud_scroll_y + // ,[cloud_scroll_y_lock] = @cloud_scroll_y_lock + // ,[draw_classic_clouds] = @draw_classic_clouds + // WHERE region_id = @region_id"; + // using (SqlConnection conn = new SqlConnection(m_connectionString)) + // { + // conn.Open(); + // using (SqlCommand cmd = new SqlCommand(sql, conn)) + // { + // cmd.Parameters.AddWithValue("region_id", wl.regionID); + // cmd.Parameters.AddWithValue("water_color_r", wl.waterColor.X); + // cmd.Parameters.AddWithValue("water_color_g", wl.waterColor.Y); + // cmd.Parameters.AddWithValue("water_color_b", wl.waterColor.Z); + // cmd.Parameters.AddWithValue("water_fog_density_exponent", wl.waterFogDensityExponent); + // cmd.Parameters.AddWithValue("underwater_fog_modifier", wl.underwaterFogModifier); + // cmd.Parameters.AddWithValue("reflection_wavelet_scale_1", wl.reflectionWaveletScale.X); + // cmd.Parameters.AddWithValue("reflection_wavelet_scale_2", wl.reflectionWaveletScale.Y); + // cmd.Parameters.AddWithValue("reflection_wavelet_scale_3", wl.reflectionWaveletScale.Z); + // cmd.Parameters.AddWithValue("fresnel_scale", wl.fresnelScale); + // cmd.Parameters.AddWithValue("fresnel_offset", wl.fresnelOffset); + // cmd.Parameters.AddWithValue("refract_scale_above", wl.refractScaleAbove); + // cmd.Parameters.AddWithValue("refract_scale_below", wl.refractScaleBelow); + // cmd.Parameters.AddWithValue("blur_multiplier", wl.blurMultiplier); + // cmd.Parameters.AddWithValue("big_wave_direction_x", wl.bigWaveDirection.X); + // cmd.Parameters.AddWithValue("big_wave_direction_y", wl.bigWaveDirection.Y); + // cmd.Parameters.AddWithValue("little_wave_direction_x", wl.littleWaveDirection.X); + // cmd.Parameters.AddWithValue("little_wave_direction_y", wl.littleWaveDirection.Y); + // cmd.Parameters.AddWithValue("normal_map_texture", wl.normalMapTexture); + // cmd.Parameters.AddWithValue("horizon_r", wl.horizon.X); + // cmd.Parameters.AddWithValue("horizon_g", wl.horizon.Y); + // cmd.Parameters.AddWithValue("horizon_b", wl.horizon.Z); + // cmd.Parameters.AddWithValue("horizon_i", wl.horizon.W); + // cmd.Parameters.AddWithValue("haze_horizon", wl.hazeHorizon); + // cmd.Parameters.AddWithValue("blue_density_r", wl.blueDensity.X); + // cmd.Parameters.AddWithValue("blue_density_g", wl.blueDensity.Y); + // cmd.Parameters.AddWithValue("blue_density_b", wl.blueDensity.Z); + // cmd.Parameters.AddWithValue("blue_density_i", wl.blueDensity.W); + // cmd.Parameters.AddWithValue("haze_density", wl.hazeDensity); + // cmd.Parameters.AddWithValue("density_multiplier", wl.densityMultiplier); + // cmd.Parameters.AddWithValue("distance_multiplier", wl.distanceMultiplier); + // cmd.Parameters.AddWithValue("max_altitude", wl.maxAltitude); + // cmd.Parameters.AddWithValue("sun_moon_color_r", wl.sunMoonColor.X); + // cmd.Parameters.AddWithValue("sun_moon_color_g", wl.sunMoonColor.Y); + // cmd.Parameters.AddWithValue("sun_moon_color_b", wl.sunMoonColor.Z); + // cmd.Parameters.AddWithValue("sun_moon_color_i", wl.sunMoonColor.W); + // cmd.Parameters.AddWithValue("sun_moon_position", wl.sunMoonPosition); + // cmd.Parameters.AddWithValue("ambient_r", wl.ambient.X); + // cmd.Parameters.AddWithValue("ambient_g", wl.ambient.Y); + // cmd.Parameters.AddWithValue("ambient_b", wl.ambient.Z); + // cmd.Parameters.AddWithValue("ambient_i", wl.ambient.W); + // cmd.Parameters.AddWithValue("east_angle", wl.eastAngle); + // cmd.Parameters.AddWithValue("sun_glow_focus", wl.sunGlowFocus); + // cmd.Parameters.AddWithValue("sun_glow_size", wl.sunGlowSize); + // cmd.Parameters.AddWithValue("scene_gamma", wl.sceneGamma); + // cmd.Parameters.AddWithValue("star_brightness", wl.starBrightness); + // cmd.Parameters.AddWithValue("cloud_color_r", wl.cloudColor.X); + // cmd.Parameters.AddWithValue("cloud_color_g", wl.cloudColor.Y); + // cmd.Parameters.AddWithValue("cloud_color_b", wl.cloudColor.Z); + // cmd.Parameters.AddWithValue("cloud_color_i", wl.cloudColor.W); + // cmd.Parameters.AddWithValue("cloud_x", wl.cloudXYDensity.X); + // cmd.Parameters.AddWithValue("cloud_y", wl.cloudXYDensity.Y); + // cmd.Parameters.AddWithValue("cloud_density", wl.cloudXYDensity.Z); + // cmd.Parameters.AddWithValue("cloud_coverage", wl.cloudCoverage); + // cmd.Parameters.AddWithValue("cloud_scale", wl.cloudScale); + // cmd.Parameters.AddWithValue("cloud_detail_x", wl.cloudDetailXYDensity.X); + // cmd.Parameters.AddWithValue("cloud_detail_y", wl.cloudDetailXYDensity.Y); + // cmd.Parameters.AddWithValue("cloud_detail_density", wl.cloudDetailXYDensity.Z); + // cmd.Parameters.AddWithValue("cloud_scroll_x", wl.cloudScrollX); + // cmd.Parameters.AddWithValue("cloud_scroll_x_lock", wl.cloudScrollXLock); + // cmd.Parameters.AddWithValue("cloud_scroll_y", wl.cloudScrollY); + // cmd.Parameters.AddWithValue("cloud_scroll_y_lock", wl.cloudScrollYLock); + // cmd.Parameters.AddWithValue("draw_classic_clouds", wl.drawClassicClouds); + + // cmd.ExecuteNonQuery(); + // } + // } + // } + #endregion + } + + #region Environment Settings + public string LoadRegionEnvironmentSettings(UUID regionUUID) + { + string sql = "select * from regionenvironment where region_id = :region_id"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("region_id", regionUUID)); + conn.Open(); + using (NpgsqlDataReader result = cmd.ExecuteReader()) + { + if (!result.Read()) + { + return String.Empty; + } + else + { + return Convert.ToString(result["llsd_settings"]); + } + } + } + } + + public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) + { + { + string sql = "DELETE FROM regionenvironment WHERE region_id = :region_id ;"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("region_id", regionUUID)); + conn.Open(); + cmd.ExecuteNonQuery(); + } + + sql = "INSERT INTO regionenvironment (region_id, llsd_settings) VALUES (:region_id, :llsd_settings) ;"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("region_id", regionUUID)); + cmd.Parameters.Add(_Database.CreateParameter("llsd_settings", settings)); + + conn.Open(); + cmd.ExecuteNonQuery(); + } + } + } + + public void RemoveRegionEnvironmentSettings(UUID regionUUID) + { + string sql = "delete from regionenvironment where region_id = :region_id ;"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("region_id", regionUUID)); + + conn.Open(); + cmd.ExecuteNonQuery(); + } + } + #endregion + + /// + /// Loads the settings of a region. + /// + /// The region UUID. + /// + public RegionSettings LoadRegionSettings(UUID regionUUID) + { + string sql = @"select * from regionsettings where ""regionUUID"" = :regionUUID"; + RegionSettings regionSettings; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("regionUUID", regionUUID)); + conn.Open(); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + regionSettings = BuildRegionSettings(reader); + regionSettings.OnSave += StoreRegionSettings; + + return regionSettings; + } + } + } + + //If we reach this point then there are new region settings for that region + regionSettings = new RegionSettings(); + regionSettings.RegionUUID = regionUUID; + regionSettings.OnSave += StoreRegionSettings; + + //Store new values + StoreNewRegionSettings(regionSettings); + + LoadSpawnPoints(regionSettings); + + return regionSettings; + } + + /// + /// Store region settings, need to check if the check is really necesary. If we can make something for creating new region. + /// + /// region settings. + public void StoreRegionSettings(RegionSettings regionSettings) + { + //Little check if regionUUID already exist in DB + string regionUUID; + string sql = @"SELECT ""regionUUID"" FROM regionsettings WHERE ""regionUUID"" = :regionUUID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("regionUUID", regionSettings.RegionUUID)); + conn.Open(); + regionUUID = cmd.ExecuteScalar().ToString(); + } + + if (string.IsNullOrEmpty(regionUUID)) + { + StoreNewRegionSettings(regionSettings); + } + else + { + //This method only updates region settings!!! First call LoadRegionSettings to create new region settings in DB + sql = + @"UPDATE regionsettings SET block_terraform = :block_terraform ,block_fly = :block_fly ,allow_damage = :allow_damage +,restrict_pushing = :restrict_pushing ,allow_land_resell = :allow_land_resell ,allow_land_join_divide = :allow_land_join_divide +,block_show_in_search = :block_show_in_search ,agent_limit = :agent_limit ,object_bonus = :object_bonus ,maturity = :maturity +,disable_scripts = :disable_scripts ,disable_collisions = :disable_collisions ,disable_physics = :disable_physics +,terrain_texture_1 = :terrain_texture_1 ,terrain_texture_2 = :terrain_texture_2 ,terrain_texture_3 = :terrain_texture_3 +,terrain_texture_4 = :terrain_texture_4 ,elevation_1_nw = :elevation_1_nw ,elevation_2_nw = :elevation_2_nw +,elevation_1_ne = :elevation_1_ne ,elevation_2_ne = :elevation_2_ne ,elevation_1_se = :elevation_1_se ,elevation_2_se = :elevation_2_se +,elevation_1_sw = :elevation_1_sw ,elevation_2_sw = :elevation_2_sw ,water_height = :water_height ,terrain_raise_limit = :terrain_raise_limit +,terrain_lower_limit = :terrain_lower_limit ,use_estate_sun = :use_estate_sun ,fixed_sun = :fixed_sun ,sun_position = :sun_position +,covenant = :covenant ,covenant_datetime = :covenant_datetime, sunvectorx = :sunvectorx, sunvectory = :sunvectory, sunvectorz = :sunvectorz, +""Sandbox"" = :Sandbox, loaded_creation_datetime = :loaded_creation_datetime, loaded_creation_id = :loaded_creation_id, ""map_tile_ID"" = :TerrainImageID, +""TelehubObject"" = :telehubobject, ""parcel_tile_ID"" = :ParcelImageID + WHERE ""regionUUID"" = :regionUUID"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.AddRange(CreateRegionSettingParameters(regionSettings)); + conn.Open(); + cmd.ExecuteNonQuery(); + } + } + SaveSpawnPoints(regionSettings); + } + + public void Shutdown() + { + //Not used?? + } + + #region Private Methods + + /// + /// Stores new regionsettings. + /// + /// The region settings. + private void StoreNewRegionSettings(RegionSettings regionSettings) + { + string sql = @"INSERT INTO regionsettings + (""regionUUID"",block_terraform,block_fly,allow_damage,restrict_pushing,allow_land_resell,allow_land_join_divide, + block_show_in_search,agent_limit,object_bonus,maturity,disable_scripts,disable_collisions,disable_physics, + terrain_texture_1,terrain_texture_2,terrain_texture_3,terrain_texture_4,elevation_1_nw,elevation_2_nw,elevation_1_ne, + elevation_2_ne,elevation_1_se,elevation_2_se,elevation_1_sw,elevation_2_sw,water_height,terrain_raise_limit, + terrain_lower_limit,use_estate_sun,fixed_sun,sun_position,covenant,covenant_datetime,sunvectorx, sunvectory, sunvectorz, + ""Sandbox"", loaded_creation_datetime, loaded_creation_id + ) + VALUES + (:regionUUID,:block_terraform,:block_fly,:allow_damage,:restrict_pushing,:allow_land_resell,:allow_land_join_divide, + :block_show_in_search,:agent_limit,:object_bonus,:maturity,:disable_scripts,:disable_collisions,:disable_physics, + :terrain_texture_1,:terrain_texture_2,:terrain_texture_3,:terrain_texture_4,:elevation_1_nw,:elevation_2_nw,:elevation_1_ne, + :elevation_2_ne,:elevation_1_se,:elevation_2_se,:elevation_1_sw,:elevation_2_sw,:water_height,:terrain_raise_limit, + :terrain_lower_limit,:use_estate_sun,:fixed_sun,:sun_position,:covenant, :covenant_datetime, :sunvectorx,:sunvectory, + :sunvectorz, :Sandbox, :loaded_creation_datetime, :loaded_creation_id )"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.AddRange(CreateRegionSettingParameters(regionSettings)); + conn.Open(); + cmd.ExecuteNonQuery(); + } + } + + #region Private DataRecord conversion methods + + /// + /// Builds the region settings from a datarecod. + /// + /// datarecord with regionsettings. + /// + private static RegionSettings BuildRegionSettings(IDataRecord row) + { + //TODO change this is some more generic code so we doesnt have to change it every time a new field is added? + RegionSettings newSettings = new RegionSettings(); + + newSettings.RegionUUID = new UUID((Guid)row["regionUUID"]); + newSettings.BlockTerraform = Convert.ToBoolean(row["block_terraform"]); + newSettings.AllowDamage = Convert.ToBoolean(row["allow_damage"]); + newSettings.BlockFly = Convert.ToBoolean(row["block_fly"]); + newSettings.RestrictPushing = Convert.ToBoolean(row["restrict_pushing"]); + newSettings.AllowLandResell = Convert.ToBoolean(row["allow_land_resell"]); + newSettings.AllowLandJoinDivide = Convert.ToBoolean(row["allow_land_join_divide"]); + newSettings.BlockShowInSearch = Convert.ToBoolean(row["block_show_in_search"]); + newSettings.AgentLimit = Convert.ToInt32(row["agent_limit"]); + newSettings.ObjectBonus = Convert.ToDouble(row["object_bonus"]); + newSettings.Maturity = Convert.ToInt32(row["maturity"]); + newSettings.DisableScripts = Convert.ToBoolean(row["disable_scripts"]); + newSettings.DisableCollisions = Convert.ToBoolean(row["disable_collisions"]); + newSettings.DisablePhysics = Convert.ToBoolean(row["disable_physics"]); + newSettings.TerrainTexture1 = new UUID((Guid)row["terrain_texture_1"]); + newSettings.TerrainTexture2 = new UUID((Guid)row["terrain_texture_2"]); + newSettings.TerrainTexture3 = new UUID((Guid)row["terrain_texture_3"]); + newSettings.TerrainTexture4 = new UUID((Guid)row["terrain_texture_4"]); + newSettings.Elevation1NW = Convert.ToDouble(row["elevation_1_nw"]); + newSettings.Elevation2NW = Convert.ToDouble(row["elevation_2_nw"]); + newSettings.Elevation1NE = Convert.ToDouble(row["elevation_1_ne"]); + newSettings.Elevation2NE = Convert.ToDouble(row["elevation_2_ne"]); + newSettings.Elevation1SE = Convert.ToDouble(row["elevation_1_se"]); + newSettings.Elevation2SE = Convert.ToDouble(row["elevation_2_se"]); + newSettings.Elevation1SW = Convert.ToDouble(row["elevation_1_sw"]); + newSettings.Elevation2SW = Convert.ToDouble(row["elevation_2_sw"]); + newSettings.WaterHeight = Convert.ToDouble(row["water_height"]); + newSettings.TerrainRaiseLimit = Convert.ToDouble(row["terrain_raise_limit"]); + newSettings.TerrainLowerLimit = Convert.ToDouble(row["terrain_lower_limit"]); + newSettings.UseEstateSun = Convert.ToBoolean(row["use_estate_sun"]); + newSettings.Sandbox = Convert.ToBoolean(row["Sandbox"]); + newSettings.FixedSun = Convert.ToBoolean(row["fixed_sun"]); + newSettings.SunPosition = Convert.ToDouble(row["sun_position"]); + newSettings.SunVector = new Vector3( + Convert.ToSingle(row["sunvectorx"]), + Convert.ToSingle(row["sunvectory"]), + Convert.ToSingle(row["sunvectorz"]) + ); + newSettings.Covenant = new UUID((Guid)row["covenant"]); + newSettings.CovenantChangedDateTime = Convert.ToInt32(row["covenant_datetime"]); + newSettings.LoadedCreationDateTime = Convert.ToInt32(row["loaded_creation_datetime"]); + + if (row["loaded_creation_id"] is DBNull) + newSettings.LoadedCreationID = ""; + else + newSettings.LoadedCreationID = (String)row["loaded_creation_id"]; + + newSettings.TerrainImageID = new UUID((string)row["map_tile_ID"]); + newSettings.ParcelImageID = new UUID((Guid)row["parcel_tile_ID"]); + newSettings.TelehubObject = new UUID((Guid)row["TelehubObject"]); + + return newSettings; + } + + /// + /// Builds the land data from a datarecord. + /// + /// datarecord with land data + /// + private static LandData BuildLandData(IDataRecord row) + { + LandData newData = new LandData(); + + newData.GlobalID = new UUID((Guid)row["UUID"]); + newData.LocalID = Convert.ToInt32(row["LocalLandID"]); + + // Bitmap is a byte[512] + newData.Bitmap = (Byte[])row["Bitmap"]; + + newData.Name = (string)row["Name"]; + newData.Description = (string)row["Description"]; + newData.OwnerID = new UUID((Guid)row["OwnerUUID"]); + newData.IsGroupOwned = Convert.ToBoolean(row["IsGroupOwned"]); + newData.Area = Convert.ToInt32(row["Area"]); + newData.AuctionID = Convert.ToUInt32(row["AuctionID"]); //Unemplemented + newData.Category = (ParcelCategory)Convert.ToInt32(row["Category"]); + //Enum libsecondlife.Parcel.ParcelCategory + newData.ClaimDate = Convert.ToInt32(row["ClaimDate"]); + newData.ClaimPrice = Convert.ToInt32(row["ClaimPrice"]); + newData.GroupID = new UUID((Guid)row["GroupUUID"]); + newData.SalePrice = Convert.ToInt32(row["SalePrice"]); + newData.Status = (ParcelStatus)Convert.ToInt32(row["LandStatus"]); + //Enum. libsecondlife.Parcel.ParcelStatus + newData.Flags = Convert.ToUInt32(row["LandFlags"]); + newData.LandingType = Convert.ToByte(row["LandingType"]); + newData.MediaAutoScale = Convert.ToByte(row["MediaAutoScale"]); + newData.MediaID = new UUID((Guid)row["MediaTextureUUID"]); + newData.MediaURL = (string)row["MediaURL"]; + newData.MusicURL = (string)row["MusicURL"]; + newData.PassHours = Convert.ToSingle(row["PassHours"]); + newData.PassPrice = Convert.ToInt32(row["PassPrice"]); + + // UUID authedbuyer; + // UUID snapshotID; + // + // if (UUID.TryParse((string)row["AuthBuyerID"], out authedbuyer)) + // newData.AuthBuyerID = authedbuyer; + // + // if (UUID.TryParse((string)row["SnapshotUUID"], out snapshotID)) + // newData.SnapshotID = snapshotID; + newData.AuthBuyerID = new UUID((Guid)row["AuthBuyerID"]); + newData.SnapshotID = new UUID((Guid)row["SnapshotUUID"]); + + newData.OtherCleanTime = Convert.ToInt32(row["OtherCleanTime"]); + + try + { + newData.UserLocation = + new Vector3(Convert.ToSingle(row["UserLocationX"]), Convert.ToSingle(row["UserLocationY"]), + Convert.ToSingle(row["UserLocationZ"])); + newData.UserLookAt = + new Vector3(Convert.ToSingle(row["UserLookAtX"]), Convert.ToSingle(row["UserLookAtY"]), + Convert.ToSingle(row["UserLookAtZ"])); + } + catch (InvalidCastException) + { + newData.UserLocation = Vector3.Zero; + newData.UserLookAt = Vector3.Zero; + _Log.ErrorFormat("[PARCEL]: unable to get parcel telehub settings for {1}", newData.Name); + } + + newData.ParcelAccessList = new List(); + newData.MediaDescription = (string)row["MediaDescription"]; + newData.MediaType = (string)row["MediaType"]; + newData.MediaWidth = Convert.ToInt32((((string)row["MediaSize"]).Split(','))[0]); + newData.MediaHeight = Convert.ToInt32((((string)row["MediaSize"]).Split(','))[1]); + newData.MediaLoop = Convert.ToBoolean(row["MediaLoop"]); + newData.ObscureMusic = Convert.ToBoolean(row["ObscureMusic"]); + newData.ObscureMedia = Convert.ToBoolean(row["ObscureMedia"]); + + return newData; + } + + /// + /// Builds the landaccess data from a data record. + /// + /// datarecord with landaccess data + /// + private static LandAccessEntry BuildLandAccessData(IDataRecord row) + { + LandAccessEntry entry = new LandAccessEntry(); + entry.AgentID = new UUID((Guid)row["AccessUUID"]); + entry.Flags = (AccessList)Convert.ToInt32(row["Flags"]); + entry.Expires = Convert.ToInt32(row["Expires"]); + return entry; + } + + /// + /// Builds the prim from a datarecord. + /// + /// datarecord + /// + private static SceneObjectPart BuildPrim(IDataRecord primRow) + { + SceneObjectPart prim = new SceneObjectPart(); + + prim.UUID = new UUID((Guid)primRow["UUID"]); + // explicit conversion of integers is required, which sort + // of sucks. No idea if there is a shortcut here or not. + prim.CreationDate = Convert.ToInt32(primRow["CreationDate"]); + prim.Name = (string)primRow["Name"]; + // various text fields + prim.Text = (string)primRow["Text"]; + prim.Color = Color.FromArgb(Convert.ToInt32(primRow["ColorA"]), + Convert.ToInt32(primRow["ColorR"]), + Convert.ToInt32(primRow["ColorG"]), + Convert.ToInt32(primRow["ColorB"])); + prim.Description = (string)primRow["Description"]; + prim.SitName = (string)primRow["SitName"]; + prim.TouchName = (string)primRow["TouchName"]; + // permissions + prim.Flags = (PrimFlags)Convert.ToUInt32(primRow["ObjectFlags"]); + //prim.creatorID = new UUID((Guid)primRow["creatorID"]); + prim.CreatorIdentification = (string)primRow["CreatorID"].ToString(); + prim.OwnerID = new UUID((Guid)primRow["OwnerID"]); + prim.GroupID = new UUID((Guid)primRow["GroupID"]); + prim.LastOwnerID = new UUID((Guid)primRow["LastOwnerID"]); + prim.OwnerMask = Convert.ToUInt32(primRow["OwnerMask"]); + prim.NextOwnerMask = Convert.ToUInt32(primRow["NextOwnerMask"]); + prim.GroupMask = Convert.ToUInt32(primRow["GroupMask"]); + prim.EveryoneMask = Convert.ToUInt32(primRow["EveryoneMask"]); + prim.BaseMask = Convert.ToUInt32(primRow["BaseMask"]); + // vectors + prim.OffsetPosition = new Vector3( + Convert.ToSingle(primRow["PositionX"]), + Convert.ToSingle(primRow["PositionY"]), + Convert.ToSingle(primRow["PositionZ"])); + + prim.GroupPosition = new Vector3( + Convert.ToSingle(primRow["GroupPositionX"]), + Convert.ToSingle(primRow["GroupPositionY"]), + Convert.ToSingle(primRow["GroupPositionZ"])); + + prim.Velocity = new Vector3( + Convert.ToSingle(primRow["VelocityX"]), + Convert.ToSingle(primRow["VelocityY"]), + Convert.ToSingle(primRow["VelocityZ"])); + + prim.AngularVelocity = new Vector3( + Convert.ToSingle(primRow["AngularVelocityX"]), + Convert.ToSingle(primRow["AngularVelocityY"]), + Convert.ToSingle(primRow["AngularVelocityZ"])); + + prim.Acceleration = new Vector3( + Convert.ToSingle(primRow["AccelerationX"]), + Convert.ToSingle(primRow["AccelerationY"]), + Convert.ToSingle(primRow["AccelerationZ"])); + + // quaternions + prim.RotationOffset = new Quaternion( + Convert.ToSingle(primRow["RotationX"]), + Convert.ToSingle(primRow["RotationY"]), + Convert.ToSingle(primRow["RotationZ"]), + Convert.ToSingle(primRow["RotationW"])); + + prim.SitTargetPositionLL = new Vector3( + Convert.ToSingle(primRow["SitTargetOffsetX"]), + Convert.ToSingle(primRow["SitTargetOffsetY"]), + Convert.ToSingle(primRow["SitTargetOffsetZ"])); + + prim.SitTargetOrientationLL = new Quaternion( + Convert.ToSingle(primRow["SitTargetOrientX"]), + Convert.ToSingle(primRow["SitTargetOrientY"]), + Convert.ToSingle(primRow["SitTargetOrientZ"]), + Convert.ToSingle(primRow["SitTargetOrientW"])); + + prim.PayPrice[0] = Convert.ToInt32(primRow["PayPrice"]); + prim.PayPrice[1] = Convert.ToInt32(primRow["PayButton1"]); + prim.PayPrice[2] = Convert.ToInt32(primRow["PayButton2"]); + prim.PayPrice[3] = Convert.ToInt32(primRow["PayButton3"]); + prim.PayPrice[4] = Convert.ToInt32(primRow["PayButton4"]); + + prim.Sound = new UUID((Guid)primRow["LoopedSound"]); + prim.SoundGain = Convert.ToSingle(primRow["LoopedSoundGain"]); + prim.SoundFlags = 1; // If it's persisted at all, it's looped + + if (!(primRow["TextureAnimation"] is DBNull)) + prim.TextureAnimation = (Byte[])primRow["TextureAnimation"]; + if (!(primRow["ParticleSystem"] is DBNull)) + prim.ParticleSystem = (Byte[])primRow["ParticleSystem"]; + + prim.AngularVelocity = new Vector3( + Convert.ToSingle(primRow["OmegaX"]), + Convert.ToSingle(primRow["OmegaY"]), + Convert.ToSingle(primRow["OmegaZ"])); + + prim.SetCameraEyeOffset(new Vector3( + Convert.ToSingle(primRow["CameraEyeOffsetX"]), + Convert.ToSingle(primRow["CameraEyeOffsetY"]), + Convert.ToSingle(primRow["CameraEyeOffsetZ"]) + )); + + prim.SetCameraAtOffset(new Vector3( + Convert.ToSingle(primRow["CameraAtOffsetX"]), + Convert.ToSingle(primRow["CameraAtOffsetY"]), + Convert.ToSingle(primRow["CameraAtOffsetZ"]) + )); + + if (Convert.ToInt16(primRow["ForceMouselook"]) != 0) + prim.SetForceMouselook(true); + + prim.ScriptAccessPin = Convert.ToInt32(primRow["ScriptAccessPin"]); + + if (Convert.ToInt16(primRow["AllowedDrop"]) != 0) + prim.AllowedDrop = true; + + if (Convert.ToInt16(primRow["DieAtEdge"]) != 0) + prim.DIE_AT_EDGE = true; + + prim.SalePrice = Convert.ToInt32(primRow["SalePrice"]); + prim.ObjectSaleType = Convert.ToByte(primRow["SaleType"]); + + prim.Material = Convert.ToByte(primRow["Material"]); + + if (!(primRow["ClickAction"] is DBNull)) + prim.ClickAction = Convert.ToByte(primRow["ClickAction"]); + + prim.CollisionSound = new UUID((Guid)primRow["CollisionSound"]); + prim.CollisionSoundVolume = Convert.ToSingle(primRow["CollisionSoundVolume"]); + + prim.PassTouches = (bool)primRow["PassTouches"]; + + if (!(primRow["MediaURL"] is System.DBNull)) + prim.MediaUrl = (string)primRow["MediaURL"]; + + if (!(primRow["DynAttrs"] is System.DBNull) && (string)primRow["DynAttrs"] != "") + prim.DynAttrs = DAMap.FromXml((string)primRow["DynAttrs"]); + else + prim.DynAttrs = new DAMap(); + + prim.PhysicsShapeType = Convert.ToByte(primRow["PhysicsShapeType"]); + prim.Density = Convert.ToSingle(primRow["Density"]); + prim.GravityModifier = Convert.ToSingle(primRow["GravityModifier"]); + prim.Friction = Convert.ToSingle(primRow["Friction"]); + prim.Restitution = Convert.ToSingle(primRow["Restitution"]); + + return prim; + } + + /// + /// Builds the prim shape from a datarecord. + /// + /// The row. + /// + private static PrimitiveBaseShape BuildShape(IDataRecord shapeRow) + { + PrimitiveBaseShape baseShape = new PrimitiveBaseShape(); + + baseShape.Scale = new Vector3( + (float)Convert.ToDouble(shapeRow["ScaleX"]), + (float)Convert.ToDouble(shapeRow["ScaleY"]), + (float)Convert.ToDouble(shapeRow["ScaleZ"])); + + // paths + baseShape.PCode = Convert.ToByte(shapeRow["PCode"]); + baseShape.PathBegin = Convert.ToUInt16(shapeRow["PathBegin"]); + baseShape.PathEnd = Convert.ToUInt16(shapeRow["PathEnd"]); + baseShape.PathScaleX = Convert.ToByte(shapeRow["PathScaleX"]); + baseShape.PathScaleY = Convert.ToByte(shapeRow["PathScaleY"]); + baseShape.PathShearX = Convert.ToByte(shapeRow["PathShearX"]); + baseShape.PathShearY = Convert.ToByte(shapeRow["PathShearY"]); + baseShape.PathSkew = Convert.ToSByte(shapeRow["PathSkew"]); + baseShape.PathCurve = Convert.ToByte(shapeRow["PathCurve"]); + baseShape.PathRadiusOffset = Convert.ToSByte(shapeRow["PathRadiusOffset"]); + baseShape.PathRevolutions = Convert.ToByte(shapeRow["PathRevolutions"]); + baseShape.PathTaperX = Convert.ToSByte(shapeRow["PathTaperX"]); + baseShape.PathTaperY = Convert.ToSByte(shapeRow["PathTaperY"]); + baseShape.PathTwist = Convert.ToSByte(shapeRow["PathTwist"]); + baseShape.PathTwistBegin = Convert.ToSByte(shapeRow["PathTwistBegin"]); + // profile + baseShape.ProfileBegin = Convert.ToUInt16(shapeRow["ProfileBegin"]); + baseShape.ProfileEnd = Convert.ToUInt16(shapeRow["ProfileEnd"]); + baseShape.ProfileCurve = Convert.ToByte(shapeRow["ProfileCurve"]); + baseShape.ProfileHollow = Convert.ToUInt16(shapeRow["ProfileHollow"]); + + byte[] textureEntry = (byte[])shapeRow["Texture"]; + baseShape.TextureEntry = textureEntry; + + baseShape.ExtraParams = (byte[])shapeRow["ExtraParams"]; + + try + { + baseShape.State = Convert.ToByte(shapeRow["State"]); + } + catch (InvalidCastException) + { + } + + if (!(shapeRow["Media"] is System.DBNull)) + { + baseShape.Media = PrimitiveBaseShape.MediaList.FromXml((string)shapeRow["Media"]); + } + + return baseShape; + } + + /// + /// Build a prim inventory item from the persisted data. + /// + /// + /// + private static TaskInventoryItem BuildItem(IDataRecord inventoryRow) + { + TaskInventoryItem taskItem = new TaskInventoryItem(); + + taskItem.ItemID = new UUID((Guid)inventoryRow["itemID"]); + taskItem.ParentPartID = new UUID((Guid)inventoryRow["primID"]); + taskItem.AssetID = new UUID((Guid)inventoryRow["assetID"]); + taskItem.ParentID = new UUID((Guid)inventoryRow["parentFolderID"]); + + taskItem.InvType = Convert.ToInt32(inventoryRow["invType"]); + taskItem.Type = Convert.ToInt32(inventoryRow["assetType"]); + + taskItem.Name = (string)inventoryRow["name"]; + taskItem.Description = (string)inventoryRow["description"]; + taskItem.CreationDate = Convert.ToUInt32(inventoryRow["creationDate"]); + //taskItem.creatorID = new UUID((Guid)inventoryRow["creatorID"]); + taskItem.CreatorIdentification = (string)inventoryRow["creatorID"].ToString(); + taskItem.OwnerID = new UUID((Guid)inventoryRow["ownerID"]); + taskItem.LastOwnerID = new UUID((Guid)inventoryRow["lastOwnerID"]); + taskItem.GroupID = new UUID((Guid)inventoryRow["groupID"]); + + taskItem.NextPermissions = Convert.ToUInt32(inventoryRow["nextPermissions"]); + taskItem.CurrentPermissions = Convert.ToUInt32(inventoryRow["currentPermissions"]); + taskItem.BasePermissions = Convert.ToUInt32(inventoryRow["basePermissions"]); + taskItem.EveryonePermissions = Convert.ToUInt32(inventoryRow["everyonePermissions"]); + taskItem.GroupPermissions = Convert.ToUInt32(inventoryRow["groupPermissions"]); + taskItem.Flags = Convert.ToUInt32(inventoryRow["flags"]); + + return taskItem; + } + + #endregion + + #region Create parameters methods + + /// + /// Creates the prim inventory parameters. + /// + /// item in inventory. + /// + private NpgsqlParameter[] CreatePrimInventoryParameters(TaskInventoryItem taskItem) + { + List parameters = new List(); + + parameters.Add(_Database.CreateParameter("itemID", taskItem.ItemID)); + parameters.Add(_Database.CreateParameter("primID", taskItem.ParentPartID)); + parameters.Add(_Database.CreateParameter("assetID", taskItem.AssetID)); + parameters.Add(_Database.CreateParameter("parentFolderID", taskItem.ParentID)); + parameters.Add(_Database.CreateParameter("invType", taskItem.InvType)); + parameters.Add(_Database.CreateParameter("assetType", taskItem.Type)); + + parameters.Add(_Database.CreateParameter("name", taskItem.Name)); + parameters.Add(_Database.CreateParameter("description", taskItem.Description)); + parameters.Add(_Database.CreateParameter("creationDate", taskItem.CreationDate)); + parameters.Add(_Database.CreateParameter("creatorID", taskItem.CreatorID)); + parameters.Add(_Database.CreateParameter("ownerID", taskItem.OwnerID)); + parameters.Add(_Database.CreateParameter("lastOwnerID", taskItem.LastOwnerID)); + parameters.Add(_Database.CreateParameter("groupID", taskItem.GroupID)); + parameters.Add(_Database.CreateParameter("nextPermissions", taskItem.NextPermissions)); + parameters.Add(_Database.CreateParameter("currentPermissions", taskItem.CurrentPermissions)); + parameters.Add(_Database.CreateParameter("basePermissions", taskItem.BasePermissions)); + parameters.Add(_Database.CreateParameter("everyonePermissions", taskItem.EveryonePermissions)); + parameters.Add(_Database.CreateParameter("groupPermissions", taskItem.GroupPermissions)); + parameters.Add(_Database.CreateParameter("flags", taskItem.Flags)); + + return parameters.ToArray(); + } + + /// + /// Creates the region setting parameters. + /// + /// regionsettings. + /// + private NpgsqlParameter[] CreateRegionSettingParameters(RegionSettings settings) + { + List parameters = new List(); + + parameters.Add(_Database.CreateParameter("regionUUID", settings.RegionUUID)); + parameters.Add(_Database.CreateParameter("block_terraform", settings.BlockTerraform)); + parameters.Add(_Database.CreateParameter("block_fly", settings.BlockFly)); + parameters.Add(_Database.CreateParameter("allow_damage", settings.AllowDamage)); + parameters.Add(_Database.CreateParameter("restrict_pushing", settings.RestrictPushing)); + parameters.Add(_Database.CreateParameter("allow_land_resell", settings.AllowLandResell)); + parameters.Add(_Database.CreateParameter("allow_land_join_divide", settings.AllowLandJoinDivide)); + parameters.Add(_Database.CreateParameter("block_show_in_search", settings.BlockShowInSearch)); + parameters.Add(_Database.CreateParameter("agent_limit", settings.AgentLimit)); + parameters.Add(_Database.CreateParameter("object_bonus", settings.ObjectBonus)); + parameters.Add(_Database.CreateParameter("maturity", settings.Maturity)); + parameters.Add(_Database.CreateParameter("disable_scripts", settings.DisableScripts)); + parameters.Add(_Database.CreateParameter("disable_collisions", settings.DisableCollisions)); + parameters.Add(_Database.CreateParameter("disable_physics", settings.DisablePhysics)); + parameters.Add(_Database.CreateParameter("terrain_texture_1", settings.TerrainTexture1)); + parameters.Add(_Database.CreateParameter("terrain_texture_2", settings.TerrainTexture2)); + parameters.Add(_Database.CreateParameter("terrain_texture_3", settings.TerrainTexture3)); + parameters.Add(_Database.CreateParameter("terrain_texture_4", settings.TerrainTexture4)); + parameters.Add(_Database.CreateParameter("elevation_1_nw", settings.Elevation1NW)); + parameters.Add(_Database.CreateParameter("elevation_2_nw", settings.Elevation2NW)); + parameters.Add(_Database.CreateParameter("elevation_1_ne", settings.Elevation1NE)); + parameters.Add(_Database.CreateParameter("elevation_2_ne", settings.Elevation2NE)); + parameters.Add(_Database.CreateParameter("elevation_1_se", settings.Elevation1SE)); + parameters.Add(_Database.CreateParameter("elevation_2_se", settings.Elevation2SE)); + parameters.Add(_Database.CreateParameter("elevation_1_sw", settings.Elevation1SW)); + parameters.Add(_Database.CreateParameter("elevation_2_sw", settings.Elevation2SW)); + parameters.Add(_Database.CreateParameter("water_height", settings.WaterHeight)); + parameters.Add(_Database.CreateParameter("terrain_raise_limit", settings.TerrainRaiseLimit)); + parameters.Add(_Database.CreateParameter("terrain_lower_limit", settings.TerrainLowerLimit)); + parameters.Add(_Database.CreateParameter("use_estate_sun", settings.UseEstateSun)); + parameters.Add(_Database.CreateParameter("Sandbox", settings.Sandbox)); + parameters.Add(_Database.CreateParameter("fixed_sun", settings.FixedSun)); + parameters.Add(_Database.CreateParameter("sun_position", settings.SunPosition)); + parameters.Add(_Database.CreateParameter("sunvectorx", settings.SunVector.X)); + parameters.Add(_Database.CreateParameter("sunvectory", settings.SunVector.Y)); + parameters.Add(_Database.CreateParameter("sunvectorz", settings.SunVector.Z)); + parameters.Add(_Database.CreateParameter("covenant", settings.Covenant)); + parameters.Add(_Database.CreateParameter("covenant_datetime", settings.CovenantChangedDateTime)); + parameters.Add(_Database.CreateParameter("Loaded_Creation_DateTime", settings.LoadedCreationDateTime)); + parameters.Add(_Database.CreateParameter("Loaded_Creation_ID", settings.LoadedCreationID)); + parameters.Add(_Database.CreateParameter("TerrainImageID", settings.TerrainImageID)); + parameters.Add(_Database.CreateParameter("ParcelImageID", settings.ParcelImageID)); + parameters.Add(_Database.CreateParameter("TelehubObject", settings.TelehubObject)); + + return parameters.ToArray(); + } + + /// + /// Creates the land parameters. + /// + /// land parameters. + /// region UUID. + /// + private NpgsqlParameter[] CreateLandParameters(LandData land, UUID regionUUID) + { + List parameters = new List(); + + parameters.Add(_Database.CreateParameter("UUID", land.GlobalID)); + parameters.Add(_Database.CreateParameter("RegionUUID", regionUUID)); + parameters.Add(_Database.CreateParameter("LocalLandID", land.LocalID)); + + // Bitmap is a byte[512] + parameters.Add(_Database.CreateParameter("Bitmap", land.Bitmap)); + + parameters.Add(_Database.CreateParameter("Name", land.Name)); + parameters.Add(_Database.CreateParameter("Description", land.Description)); + parameters.Add(_Database.CreateParameter("OwnerUUID", land.OwnerID)); + parameters.Add(_Database.CreateParameter("IsGroupOwned", land.IsGroupOwned)); + parameters.Add(_Database.CreateParameter("Area", land.Area)); + parameters.Add(_Database.CreateParameter("AuctionID", land.AuctionID)); //Unemplemented + parameters.Add(_Database.CreateParameter("Category", (int)land.Category)); //Enum libsecondlife.Parcel.ParcelCategory + parameters.Add(_Database.CreateParameter("ClaimDate", land.ClaimDate)); + parameters.Add(_Database.CreateParameter("ClaimPrice", land.ClaimPrice)); + parameters.Add(_Database.CreateParameter("GroupUUID", land.GroupID)); + parameters.Add(_Database.CreateParameter("SalePrice", land.SalePrice)); + parameters.Add(_Database.CreateParameter("LandStatus", (int)land.Status)); //Enum. libsecondlife.Parcel.ParcelStatus + parameters.Add(_Database.CreateParameter("LandFlags", land.Flags)); + parameters.Add(_Database.CreateParameter("LandingType", Convert.ToInt32( land.LandingType) )); + parameters.Add(_Database.CreateParameter("MediaAutoScale", Convert.ToInt32( land.MediaAutoScale ))); + parameters.Add(_Database.CreateParameter("MediaTextureUUID", land.MediaID)); + parameters.Add(_Database.CreateParameter("MediaURL", land.MediaURL)); + parameters.Add(_Database.CreateParameter("MusicURL", land.MusicURL)); + parameters.Add(_Database.CreateParameter("PassHours", land.PassHours)); + parameters.Add(_Database.CreateParameter("PassPrice", land.PassPrice)); + parameters.Add(_Database.CreateParameter("SnapshotUUID", land.SnapshotID)); + parameters.Add(_Database.CreateParameter("UserLocationX", land.UserLocation.X)); + parameters.Add(_Database.CreateParameter("UserLocationY", land.UserLocation.Y)); + parameters.Add(_Database.CreateParameter("UserLocationZ", land.UserLocation.Z)); + parameters.Add(_Database.CreateParameter("UserLookAtX", land.UserLookAt.X)); + parameters.Add(_Database.CreateParameter("UserLookAtY", land.UserLookAt.Y)); + parameters.Add(_Database.CreateParameter("UserLookAtZ", land.UserLookAt.Z)); + parameters.Add(_Database.CreateParameter("AuthBuyerID", land.AuthBuyerID)); + parameters.Add(_Database.CreateParameter("OtherCleanTime", land.OtherCleanTime)); + + return parameters.ToArray(); + } + + /// + /// Creates the land access parameters. + /// + /// parcel access entry. + /// parcel ID. + /// + private NpgsqlParameter[] CreateLandAccessParameters(LandAccessEntry parcelAccessEntry, UUID parcelID) + { + List parameters = new List(); + + parameters.Add(_Database.CreateParameter("LandUUID", parcelID)); + parameters.Add(_Database.CreateParameter("AccessUUID", parcelAccessEntry.AgentID)); + parameters.Add(_Database.CreateParameter("Flags", parcelAccessEntry.Flags)); + parameters.Add(_Database.CreateParameter("Expires", parcelAccessEntry.Expires)); + + return parameters.ToArray(); + } + + /// + /// Creates the prim parameters for storing in DB. + /// + /// Basic data of SceneObjectpart prim. + /// The scenegroup ID. + /// The region ID. + /// + private NpgsqlParameter[] CreatePrimParameters(SceneObjectPart prim, UUID sceneGroupID, UUID regionUUID) + { + List parameters = new List(); + + parameters.Add(_Database.CreateParameter("UUID", prim.UUID)); + parameters.Add(_Database.CreateParameter("RegionUUID", regionUUID)); + parameters.Add(_Database.CreateParameter("CreationDate", prim.CreationDate)); + parameters.Add(_Database.CreateParameter("Name", prim.Name)); + parameters.Add(_Database.CreateParameter("SceneGroupID", sceneGroupID)); + // the UUID of the root part for this SceneObjectGroup + // various text fields + parameters.Add(_Database.CreateParameter("Text", prim.Text)); + parameters.Add(_Database.CreateParameter("ColorR", prim.Color.R)); + parameters.Add(_Database.CreateParameter("ColorG", prim.Color.G)); + parameters.Add(_Database.CreateParameter("ColorB", prim.Color.B)); + parameters.Add(_Database.CreateParameter("ColorA", prim.Color.A)); + parameters.Add(_Database.CreateParameter("Description", prim.Description)); + parameters.Add(_Database.CreateParameter("SitName", prim.SitName)); + parameters.Add(_Database.CreateParameter("TouchName", prim.TouchName)); + // permissions + parameters.Add(_Database.CreateParameter("ObjectFlags", (uint)prim.Flags)); + parameters.Add(_Database.CreateParameter("CreatorID", prim.CreatorID)); + parameters.Add(_Database.CreateParameter("OwnerID", prim.OwnerID)); + parameters.Add(_Database.CreateParameter("GroupID", prim.GroupID)); + parameters.Add(_Database.CreateParameter("LastOwnerID", prim.LastOwnerID)); + parameters.Add(_Database.CreateParameter("OwnerMask", prim.OwnerMask)); + parameters.Add(_Database.CreateParameter("NextOwnerMask", prim.NextOwnerMask)); + parameters.Add(_Database.CreateParameter("GroupMask", prim.GroupMask)); + parameters.Add(_Database.CreateParameter("EveryoneMask", prim.EveryoneMask)); + parameters.Add(_Database.CreateParameter("BaseMask", prim.BaseMask)); + // vectors + parameters.Add(_Database.CreateParameter("PositionX", prim.OffsetPosition.X)); + parameters.Add(_Database.CreateParameter("PositionY", prim.OffsetPosition.Y)); + parameters.Add(_Database.CreateParameter("PositionZ", prim.OffsetPosition.Z)); + parameters.Add(_Database.CreateParameter("GroupPositionX", prim.GroupPosition.X)); + parameters.Add(_Database.CreateParameter("GroupPositionY", prim.GroupPosition.Y)); + parameters.Add(_Database.CreateParameter("GroupPositionZ", prim.GroupPosition.Z)); + parameters.Add(_Database.CreateParameter("VelocityX", prim.Velocity.X)); + parameters.Add(_Database.CreateParameter("VelocityY", prim.Velocity.Y)); + parameters.Add(_Database.CreateParameter("VelocityZ", prim.Velocity.Z)); + parameters.Add(_Database.CreateParameter("AngularVelocityX", prim.AngularVelocity.X)); + parameters.Add(_Database.CreateParameter("AngularVelocityY", prim.AngularVelocity.Y)); + parameters.Add(_Database.CreateParameter("AngularVelocityZ", prim.AngularVelocity.Z)); + parameters.Add(_Database.CreateParameter("AccelerationX", prim.Acceleration.X)); + parameters.Add(_Database.CreateParameter("AccelerationY", prim.Acceleration.Y)); + parameters.Add(_Database.CreateParameter("AccelerationZ", prim.Acceleration.Z)); + // quaternions + parameters.Add(_Database.CreateParameter("RotationX", prim.RotationOffset.X)); + parameters.Add(_Database.CreateParameter("RotationY", prim.RotationOffset.Y)); + parameters.Add(_Database.CreateParameter("RotationZ", prim.RotationOffset.Z)); + parameters.Add(_Database.CreateParameter("RotationW", prim.RotationOffset.W)); + + // Sit target + Vector3 sitTargetPos = prim.SitTargetPositionLL; + parameters.Add(_Database.CreateParameter("SitTargetOffsetX", sitTargetPos.X)); + parameters.Add(_Database.CreateParameter("SitTargetOffsetY", sitTargetPos.Y)); + parameters.Add(_Database.CreateParameter("SitTargetOffsetZ", sitTargetPos.Z)); + + Quaternion sitTargetOrient = prim.SitTargetOrientationLL; + parameters.Add(_Database.CreateParameter("SitTargetOrientW", sitTargetOrient.W)); + parameters.Add(_Database.CreateParameter("SitTargetOrientX", sitTargetOrient.X)); + parameters.Add(_Database.CreateParameter("SitTargetOrientY", sitTargetOrient.Y)); + parameters.Add(_Database.CreateParameter("SitTargetOrientZ", sitTargetOrient.Z)); + + parameters.Add(_Database.CreateParameter("PayPrice", prim.PayPrice[0])); + parameters.Add(_Database.CreateParameter("PayButton1", prim.PayPrice[1])); + parameters.Add(_Database.CreateParameter("PayButton2", prim.PayPrice[2])); + parameters.Add(_Database.CreateParameter("PayButton3", prim.PayPrice[3])); + parameters.Add(_Database.CreateParameter("PayButton4", prim.PayPrice[4])); + + if ((prim.SoundFlags & 1) != 0) // Looped + { + parameters.Add(_Database.CreateParameter("LoopedSound", prim.Sound)); + parameters.Add(_Database.CreateParameter("LoopedSoundGain", prim.SoundGain)); + } + else + { + parameters.Add(_Database.CreateParameter("LoopedSound", UUID.Zero)); + parameters.Add(_Database.CreateParameter("LoopedSoundGain", 0.0f)); + } + + parameters.Add(_Database.CreateParameter("TextureAnimation", prim.TextureAnimation)); + parameters.Add(_Database.CreateParameter("ParticleSystem", prim.ParticleSystem)); + + parameters.Add(_Database.CreateParameter("OmegaX", prim.AngularVelocity.X)); + parameters.Add(_Database.CreateParameter("OmegaY", prim.AngularVelocity.Y)); + parameters.Add(_Database.CreateParameter("OmegaZ", prim.AngularVelocity.Z)); + + parameters.Add(_Database.CreateParameter("CameraEyeOffsetX", prim.GetCameraEyeOffset().X)); + parameters.Add(_Database.CreateParameter("CameraEyeOffsetY", prim.GetCameraEyeOffset().Y)); + parameters.Add(_Database.CreateParameter("CameraEyeOffsetZ", prim.GetCameraEyeOffset().Z)); + + parameters.Add(_Database.CreateParameter("CameraAtOffsetX", prim.GetCameraAtOffset().X)); + parameters.Add(_Database.CreateParameter("CameraAtOffsetY", prim.GetCameraAtOffset().Y)); + parameters.Add(_Database.CreateParameter("CameraAtOffsetZ", prim.GetCameraAtOffset().Z)); + + if (prim.GetForceMouselook()) + parameters.Add(_Database.CreateParameter("ForceMouselook", 1)); + else + parameters.Add(_Database.CreateParameter("ForceMouselook", 0)); + + parameters.Add(_Database.CreateParameter("ScriptAccessPin", prim.ScriptAccessPin)); + + if (prim.AllowedDrop) + parameters.Add(_Database.CreateParameter("AllowedDrop", 1)); + else + parameters.Add(_Database.CreateParameter("AllowedDrop", 0)); + + if (prim.DIE_AT_EDGE) + parameters.Add(_Database.CreateParameter("DieAtEdge", 1)); + else + parameters.Add(_Database.CreateParameter("DieAtEdge", 0)); + + parameters.Add(_Database.CreateParameter("SalePrice", prim.SalePrice)); + parameters.Add(_Database.CreateParameter("SaleType", prim.ObjectSaleType)); + + byte clickAction = prim.ClickAction; + parameters.Add(_Database.CreateParameter("ClickAction", clickAction)); + + parameters.Add(_Database.CreateParameter("Material", prim.Material)); + + parameters.Add(_Database.CreateParameter("CollisionSound", prim.CollisionSound)); + parameters.Add(_Database.CreateParameter("CollisionSoundVolume", prim.CollisionSoundVolume)); + + parameters.Add(_Database.CreateParameter("PassTouches", prim.PassTouches)); + + parameters.Add(_Database.CreateParameter("LinkNumber", prim.LinkNum)); + parameters.Add(_Database.CreateParameter("MediaURL", prim.MediaUrl)); + + if (prim.DynAttrs.CountNamespaces > 0) + parameters.Add(_Database.CreateParameter("DynAttrs", prim.DynAttrs.ToXml())); + else + parameters.Add(_Database.CreateParameter("DynAttrs", null)); + + parameters.Add(_Database.CreateParameter("PhysicsShapeType", prim.PhysicsShapeType)); + parameters.Add(_Database.CreateParameter("Density", (double)prim.Density)); + parameters.Add(_Database.CreateParameter("GravityModifier", (double)prim.GravityModifier)); + parameters.Add(_Database.CreateParameter("Friction", (double)prim.Friction)); + parameters.Add(_Database.CreateParameter("Restitution", (double)prim.Restitution)); + + return parameters.ToArray(); + } + + /// + /// Creates the primshape parameters for stroing in DB. + /// + /// Basic data of SceneObjectpart prim. + /// The scene group ID. + /// The region UUID. + /// + private NpgsqlParameter[] CreatePrimShapeParameters(SceneObjectPart prim, UUID sceneGroupID, UUID regionUUID) + { + List parameters = new List(); + + PrimitiveBaseShape s = prim.Shape; + parameters.Add(_Database.CreateParameter("UUID", prim.UUID)); + // shape is an enum + parameters.Add(_Database.CreateParameter("Shape", 0)); + // vectors + parameters.Add(_Database.CreateParameter("ScaleX", s.Scale.X)); + parameters.Add(_Database.CreateParameter("ScaleY", s.Scale.Y)); + parameters.Add(_Database.CreateParameter("ScaleZ", s.Scale.Z)); + // paths + parameters.Add(_Database.CreateParameter("PCode", s.PCode)); + parameters.Add(_Database.CreateParameter("PathBegin", s.PathBegin)); + parameters.Add(_Database.CreateParameter("PathEnd", s.PathEnd)); + parameters.Add(_Database.CreateParameter("PathScaleX", s.PathScaleX)); + parameters.Add(_Database.CreateParameter("PathScaleY", s.PathScaleY)); + parameters.Add(_Database.CreateParameter("PathShearX", s.PathShearX)); + parameters.Add(_Database.CreateParameter("PathShearY", s.PathShearY)); + parameters.Add(_Database.CreateParameter("PathSkew", s.PathSkew)); + parameters.Add(_Database.CreateParameter("PathCurve", s.PathCurve)); + parameters.Add(_Database.CreateParameter("PathRadiusOffset", s.PathRadiusOffset)); + parameters.Add(_Database.CreateParameter("PathRevolutions", s.PathRevolutions)); + parameters.Add(_Database.CreateParameter("PathTaperX", s.PathTaperX)); + parameters.Add(_Database.CreateParameter("PathTaperY", s.PathTaperY)); + parameters.Add(_Database.CreateParameter("PathTwist", s.PathTwist)); + parameters.Add(_Database.CreateParameter("PathTwistBegin", s.PathTwistBegin)); + // profile + parameters.Add(_Database.CreateParameter("ProfileBegin", s.ProfileBegin)); + parameters.Add(_Database.CreateParameter("ProfileEnd", s.ProfileEnd)); + parameters.Add(_Database.CreateParameter("ProfileCurve", s.ProfileCurve)); + parameters.Add(_Database.CreateParameter("ProfileHollow", s.ProfileHollow)); + parameters.Add(_Database.CreateParameter("Texture", s.TextureEntry)); + parameters.Add(_Database.CreateParameter("ExtraParams", s.ExtraParams)); + parameters.Add(_Database.CreateParameter("State", s.State)); + + if (null == s.Media) + { + parameters.Add(_Database.CreateParameter("Media", DBNull.Value)); + } + else + { + parameters.Add(_Database.CreateParameter("Media", s.Media.ToXml())); + } + + return parameters.ToArray(); + } + + #endregion + + #endregion + + private void LoadSpawnPoints(RegionSettings rs) + { + rs.ClearSpawnPoints(); + + string sql = @"SELECT ""Yaw"", ""Pitch"", ""Distance"" FROM spawn_points WHERE ""RegionUUID"" = :RegionUUID"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", rs.RegionUUID)); + conn.Open(); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + SpawnPoint sp = new SpawnPoint(); + + sp.Yaw = (float)reader["Yaw"]; + sp.Pitch = (float)reader["Pitch"]; + sp.Distance = (float)reader["Distance"]; + + rs.AddSpawnPoint(sp); + } + } + } + } + + private void SaveSpawnPoints(RegionSettings rs) + { + string sql = @"DELETE FROM spawn_points WHERE ""RegionUUID"" = :RegionUUID"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", rs.RegionUUID)); + conn.Open(); + cmd.ExecuteNonQuery(); + } + foreach (SpawnPoint p in rs.SpawnPoints()) + { + sql = @"INSERT INTO spawn_points (""RegionUUID"", ""Yaw"", ""Pitch"", ""Distance"") VALUES (:RegionUUID, :Yaw, :Pitch, :Distance)"; + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", rs.RegionUUID)); + cmd.Parameters.Add(_Database.CreateParameter("Yaw", p.Yaw)); + cmd.Parameters.Add(_Database.CreateParameter("Pitch", p.Pitch)); + cmd.Parameters.Add(_Database.CreateParameter("Distance", p.Distance)); + conn.Open(); + cmd.ExecuteNonQuery(); + } + } + } + + public void SaveExtra(UUID regionID, string name, string value) + { + } + + public void RemoveExtra(UUID regionID, string name) + { + } + + public Dictionary GetExtra(UUID regionID) + { + return null; + } + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLUserAccountData.cs b/OpenSim/Data/PGSQL/PGSQLUserAccountData.cs new file mode 100644 index 0000000..0a68b23 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLUserAccountData.cs @@ -0,0 +1,329 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using OpenMetaverse; +using OpenSim.Framework; +using System.Text; +using Npgsql; +using log4net; +using System.Reflection; + +namespace OpenSim.Data.PGSQL +{ + public class PGSQLUserAccountData : PGSQLGenericTableHandler,IUserAccountData + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + + public PGSQLUserAccountData(string connectionString, string realm) : + base(connectionString, realm, "UserAccount") + { + } + + /* + private string m_Realm; + private List m_ColumnNames = null; + private PGSQLManager m_database; + + public PGSQLUserAccountData(string connectionString, string realm) : + base(connectionString, realm, "UserAccount") + { + m_Realm = realm; + m_ConnectionString = connectionString; + m_database = new PGSQLManager(connectionString); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + { + conn.Open(); + Migration m = new Migration(conn, GetType().Assembly, "UserAccount"); + m.Update(); + } + } + */ + /* + public List Query(UUID principalID, UUID scopeID, string query) + { + return null; + } + */ + /* + public override UserAccountData[] Get(string[] fields, string[] keys) + { + UserAccountData[] retUA = base.Get(fields,keys); + + if (retUA.Length > 0) + { + Dictionary data = retUA[0].Data; + Dictionary data2 = new Dictionary(); + + foreach (KeyValuePair chave in data) + { + string s2 = chave.Key; + + data2[s2] = chave.Value; + + if (!m_FieldTypes.ContainsKey(chave.Key)) + { + string tipo = ""; + m_FieldTypes.TryGetValue(chave.Key, out tipo); + m_FieldTypes.Add(s2, tipo); + } + } + foreach (KeyValuePair chave in data2) + { + if (!retUA[0].Data.ContainsKey(chave.Key)) + retUA[0].Data.Add(chave.Key, chave.Value); + } + } + + return retUA; + } + */ + /* + public UserAccountData Get(UUID principalID, UUID scopeID) + { + UserAccountData ret = new UserAccountData(); + ret.Data = new Dictionary(); + + string sql = string.Format(@"select * from {0} where ""PrincipalID"" = :principalID", m_Realm); + if (scopeID != UUID.Zero) + sql += @" and ""ScopeID"" = :scopeID"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + cmd.Parameters.Add(m_database.CreateParameter("principalID", principalID)); + cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID)); + + conn.Open(); + using (NpgsqlDataReader result = cmd.ExecuteReader()) + { + if (result.Read()) + { + ret.PrincipalID = principalID; + UUID scope; + UUID.TryParse(result["scopeid"].ToString(), out scope); + ret.ScopeID = scope; + + if (m_ColumnNames == null) + { + m_ColumnNames = new List(); + + DataTable schemaTable = result.GetSchemaTable(); + foreach (DataRow row in schemaTable.Rows) + m_ColumnNames.Add(row["ColumnName"].ToString()); + } + + foreach (string s in m_ColumnNames) + { + string s2 = s; + if (s2 == "uuid") + continue; + if (s2 == "scopeid") + continue; + + ret.Data[s] = result[s].ToString(); + } + return ret; + } + } + } + return null; + } + + + public override bool Store(UserAccountData data) + { + if (data.Data.ContainsKey("PrincipalID")) + data.Data.Remove("PrincipalID"); + if (data.Data.ContainsKey("ScopeID")) + data.Data.Remove("ScopeID"); + + string[] fields = new List(data.Data.Keys).ToArray(); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + m_log.DebugFormat("[USER]: Try to update user {0} {1}", data.FirstName, data.LastName); + + StringBuilder updateBuilder = new StringBuilder(); + updateBuilder.AppendFormat("update {0} set ", m_Realm); + bool first = true; + foreach (string field in fields) + { + if (!first) + updateBuilder.Append(", "); + updateBuilder.AppendFormat("\"{0}\" = :{0}", field); + + first = false; + if (m_FieldTypes.ContainsKey(field)) + cmd.Parameters.Add(m_database.CreateParameter("" + field, data.Data[field], m_FieldTypes[field])); + else + cmd.Parameters.Add(m_database.CreateParameter("" + field, data.Data[field])); + } + + updateBuilder.Append(" where \"PrincipalID\" = :principalID"); + + if (data.ScopeID != UUID.Zero) + updateBuilder.Append(" and \"ScopeID\" = :scopeID"); + + cmd.CommandText = updateBuilder.ToString(); + cmd.Connection = conn; + cmd.Parameters.Add(m_database.CreateParameter("principalID", data.PrincipalID)); + cmd.Parameters.Add(m_database.CreateParameter("scopeID", data.ScopeID)); + + m_log.DebugFormat("[USER]: SQL update user {0} ", cmd.CommandText); + + conn.Open(); + + m_log.DebugFormat("[USER]: CON opened update user {0} ", cmd.CommandText); + + int conta = 0; + try + { + conta = cmd.ExecuteNonQuery(); + } + catch (Exception e){ + m_log.ErrorFormat("[USER]: ERROR opened update user {0} ", e.Message); + } + + + if (conta < 1) + { + m_log.DebugFormat("[USER]: Try to insert user {0} {1}", data.FirstName, data.LastName); + + StringBuilder insertBuilder = new StringBuilder(); + insertBuilder.AppendFormat(@"insert into {0} (""PrincipalID"", ""ScopeID"", ""FirstName"", ""LastName"", """, m_Realm); + insertBuilder.Append(String.Join(@""", """, fields)); + insertBuilder.Append(@""") values (:principalID, :scopeID, :FirstName, :LastName, :"); + insertBuilder.Append(String.Join(", :", fields)); + insertBuilder.Append(");"); + + cmd.Parameters.Add(m_database.CreateParameter("FirstName", data.FirstName)); + cmd.Parameters.Add(m_database.CreateParameter("LastName", data.LastName)); + + cmd.CommandText = insertBuilder.ToString(); + + if (cmd.ExecuteNonQuery() < 1) + { + return false; + } + } + else + m_log.DebugFormat("[USER]: User {0} {1} exists", data.FirstName, data.LastName); + } + return true; + } + + + public bool Store(UserAccountData data, UUID principalID, string token) + { + return false; + } + + + public bool SetDataItem(UUID principalID, string item, string value) + { + string sql = string.Format(@"update {0} set {1} = :{1} where ""UUID"" = :UUID", m_Realm, item); + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + if (m_FieldTypes.ContainsKey(item)) + cmd.Parameters.Add(m_database.CreateParameter("" + item, value, m_FieldTypes[item])); + else + cmd.Parameters.Add(m_database.CreateParameter("" + item, value)); + + cmd.Parameters.Add(m_database.CreateParameter("UUID", principalID)); + conn.Open(); + + if (cmd.ExecuteNonQuery() > 0) + return true; + } + return false; + } + */ + /* + public UserAccountData[] Get(string[] keys, string[] vals) + { + return null; + } + */ + + public UserAccountData[] GetUsers(UUID scopeID, string query) + { + string[] words = query.Split(new char[] { ' ' }); + + for (int i = 0; i < words.Length; i++) + { + if (words[i].Length < 3) + { + if (i != words.Length - 1) + Array.Copy(words, i + 1, words, i, words.Length - i - 1); + Array.Resize(ref words, words.Length - 1); + } + } + + if (words.Length == 0) + return new UserAccountData[0]; + + if (words.Length > 2) + return new UserAccountData[0]; + + string sql = ""; + UUID scope_id; + UUID.TryParse(scopeID.ToString(), out scope_id); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + if (words.Length == 1) + { + sql = String.Format(@"select * from {0} where (""ScopeID""=:ScopeID or ""ScopeID""=:UUIDZero) and (""FirstName"" ilike :search or ""LastName"" ilike :search)", m_Realm); + cmd.Parameters.Add(m_database.CreateParameter("scopeID", (UUID)scope_id)); + cmd.Parameters.Add (m_database.CreateParameter("UUIDZero", (UUID)UUID.Zero)); + cmd.Parameters.Add(m_database.CreateParameter("search", "%" + words[0] + "%")); + } + else + { + sql = String.Format(@"select * from {0} where (""ScopeID""=:ScopeID or ""ScopeID""=:UUIDZero) and (""FirstName"" ilike :searchFirst or ""LastName"" ilike :searchLast)", m_Realm); + cmd.Parameters.Add(m_database.CreateParameter("searchFirst", "%" + words[0] + "%")); + cmd.Parameters.Add(m_database.CreateParameter("searchLast", "%" + words[1] + "%")); + cmd.Parameters.Add (m_database.CreateParameter("UUIDZero", (UUID)UUID.Zero)); + cmd.Parameters.Add(m_database.CreateParameter("ScopeID", (UUID)scope_id)); + } + cmd.Connection = conn; + cmd.CommandText = sql; + conn.Open(); + return DoQuery(cmd); + } + } + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLUserProfilesData.cs b/OpenSim/Data/PGSQL/PGSQLUserProfilesData.cs new file mode 100644 index 0000000..f166976 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLUserProfilesData.cs @@ -0,0 +1,1064 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Data; +using System.Reflection; +using OpenSim.Data; +using OpenSim.Framework; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using log4net; +using Npgsql; + +namespace OpenSim.Data.PGSQL +{ + public class UserProfilesData : IProfilesData + { + static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected PGSQLManager m_database; + + #region Properites + string ConnectionString + { + get; + set; + } + + protected virtual Assembly Assembly + { + get { return GetType().Assembly; } + } + + #endregion Properties + + #region class Member Functions + public UserProfilesData(string connectionString) + { + ConnectionString = connectionString; + Init(); + } + + void Init() + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + + Migration m = new Migration(dbcon, Assembly, "UserProfiles"); + m.Update(); + m_database = new PGSQLManager(ConnectionString); + } + } + #endregion Member Functions + + #region Classifieds Queries + /// + /// Gets the classified records. + /// + /// + /// Array of classified records + /// + /// + /// Creator identifier. + /// + public OSDArray GetClassifiedRecords(UUID creatorId) + { + OSDArray data = new OSDArray(); + + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + string query = @"SELECT classifieduuid, name FROM classifieds WHERE creatoruuid = :Id"; + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("Id", creatorId)); + using (NpgsqlDataReader reader = cmd.ExecuteReader(CommandBehavior.Default)) + { + if (reader.HasRows) + { + while (reader.Read()) + { + OSDMap n = new OSDMap(); + UUID Id = UUID.Zero; + + string Name = null; + try + { + Id = DBGuid.FromDB(reader["classifieduuid"]); + Name = Convert.ToString(reader["name"]); + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: UserAccount exception ", e); + } + + n.Add("classifieduuid", OSD.FromUUID(Id)); + n.Add("name", OSD.FromString(Name)); + data.Add(n); + } + } + } + } + } + return data; + } + + public bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result) + { + string query = string.Empty; + + query = @"WITH upsert AS ( + UPDATE classifieds SET + classifieduuid = :ClassifiedId, creatoruuid = :CreatorId, creationdate = :CreatedDate, + expirationdate = :ExpirationDate,category =:Category, name = :Name, description = :Description, + parceluuid = :ParcelId, parentestate = :ParentEstate, snapshotuuid = :SnapshotId, + simname = :SimName, posglobal = :GlobalPos, parcelname = :ParcelName, classifiedflags = :Flags, + priceforlisting = :ListingPrice + RETURNING * ) + INSERT INTO classifieds (classifieduuid,creatoruuid,creationdate,expirationdate,category,name, + description,parceluuid,parentestate,snapshotuuid,simname,posglobal,parcelname,classifiedflags, + priceforlisting) + SELECT + :ClassifiedId,:CreatorId,:CreatedDate,:ExpirationDate,:Category,:Name,:Description, + :ParcelId,:ParentEstate,:SnapshotId,:SimName,:GlobalPos,:ParcelName,:Flags,:ListingPrice + WHERE NOT EXISTS ( + SELECT * FROM upsert )"; + + if (string.IsNullOrEmpty(ad.ParcelName)) + ad.ParcelName = "Unknown"; + if (ad.ParcelId == null) + ad.ParcelId = UUID.Zero; + if (string.IsNullOrEmpty(ad.Description)) + ad.Description = "No Description"; + + DateTime epoch = new DateTime(1970, 1, 1); + DateTime now = DateTime.Now; + TimeSpan epochnow = now - epoch; + TimeSpan duration; + DateTime expiration; + TimeSpan epochexp; + + if (ad.Flags == 2) + { + duration = new TimeSpan(7, 0, 0, 0); + expiration = now.Add(duration); + epochexp = expiration - epoch; + } + else + { + duration = new TimeSpan(365, 0, 0, 0); + expiration = now.Add(duration); + epochexp = expiration - epoch; + } + ad.CreationDate = (int)epochnow.TotalSeconds; + ad.ExpirationDate = (int)epochexp.TotalSeconds; + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("ClassifiedId", ad.ClassifiedId)); + cmd.Parameters.Add(m_database.CreateParameter("CreatorId", ad.CreatorId)); + cmd.Parameters.Add(m_database.CreateParameter("CreatedDate", (int)ad.CreationDate)); + cmd.Parameters.Add(m_database.CreateParameter("ExpirationDate", (int)ad.ExpirationDate)); + cmd.Parameters.Add(m_database.CreateParameter("Category", ad.Category.ToString())); + cmd.Parameters.Add(m_database.CreateParameter("Name", ad.Name.ToString())); + cmd.Parameters.Add(m_database.CreateParameter("Description", ad.Description.ToString())); + cmd.Parameters.Add(m_database.CreateParameter("ParcelId", ad.ParcelId)); + cmd.Parameters.Add(m_database.CreateParameter("ParentEstate", (int)ad.ParentEstate)); + cmd.Parameters.Add(m_database.CreateParameter("SnapshotId", ad.SnapshotId)); + cmd.Parameters.Add(m_database.CreateParameter("SimName", ad.SimName.ToString())); + cmd.Parameters.Add(m_database.CreateParameter("GlobalPos", ad.GlobalPos.ToString())); + cmd.Parameters.Add(m_database.CreateParameter("ParcelName", ad.ParcelName.ToString())); + cmd.Parameters.Add(m_database.CreateParameter("Flags", (int)Convert.ToInt32(ad.Flags))); + cmd.Parameters.Add(m_database.CreateParameter("ListingPrice", (int)Convert.ToInt32(ad.Price))); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: ClassifiedsUpdate exception ", e); + result = e.Message; + return false; + } + + return true; + } + + public bool DeleteClassifiedRecord(UUID recordId) + { + string query = string.Empty; + + query = @"DELETE FROM classifieds WHERE classifieduuid = :ClassifiedId ;"; + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("ClassifiedId", recordId)); + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: DeleteClassifiedRecord exception ", e); + return false; + } + + return true; + } + + public bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result) + { + string query = string.Empty; + + query += "SELECT * FROM classifieds WHERE "; + query += "classifieduuid = :AdId"; + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("AdId", ad.ClassifiedId)); + + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + ad.CreatorId = DBGuid.FromDB(reader["creatoruuid"]); + ad.ParcelId = DBGuid.FromDB(reader["parceluuid"]); + ad.SnapshotId = DBGuid.FromDB(reader["snapshotuuid"]); + ad.CreationDate = Convert.ToInt32(reader["creationdate"]); + ad.ExpirationDate = Convert.ToInt32(reader["expirationdate"]); + ad.ParentEstate = Convert.ToInt32(reader["parentestate"]); + ad.Flags = (byte)Convert.ToInt16(reader["classifiedflags"]); + ad.Category = Convert.ToInt32(reader["category"]); + ad.Price = Convert.ToInt16(reader["priceforlisting"]); + ad.Name = reader["name"].ToString(); + ad.Description = reader["description"].ToString(); + ad.SimName = reader["simname"].ToString(); + ad.GlobalPos = reader["posglobal"].ToString(); + ad.ParcelName = reader["parcelname"].ToString(); + } + } + } + dbcon.Close(); + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: GetClassifiedInfo exception ", e); + } + + return true; + } + + public static UUID GetUUID(object uuidValue) + { + + UUID ret = UUID.Zero; + + UUID.TryParse(uuidValue.ToString(), out ret); + + return ret; + } + + #endregion Classifieds Queries + + #region Picks Queries + public OSDArray GetAvatarPicks(UUID avatarId) + { + string query = string.Empty; + + query += "SELECT pickuuid, name FROM userpicks WHERE "; + query += "creatoruuid = :Id"; + OSDArray data = new OSDArray(); + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("Id", avatarId)); + + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + while (reader.Read()) + { + OSDMap record = new OSDMap(); + + record.Add("pickuuid", OSD.FromUUID(DBGuid.FromDB(reader["pickuuid"]))); + record.Add("name", OSD.FromString((string)reader["name"])); + data.Add(record); + } + } + } + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: GetAvatarPicks exception ", e); + } + + return data; + } + + public UserProfilePick GetPickInfo(UUID avatarId, UUID pickId) + { + string query = string.Empty; + UserProfilePick pick = new UserProfilePick(); + + query += "SELECT * FROM userpicks WHERE "; + query += "creatoruuid = :CreatorId AND "; + query += "pickuuid = :PickId"; + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("CreatorId", avatarId)); + cmd.Parameters.Add(m_database.CreateParameter("PickId", pickId)); + + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + reader.Read(); + + string description = (string)reader["description"]; + + if (string.IsNullOrEmpty(description)) + description = "No description given."; + + pick.PickId = DBGuid.FromDB(reader["pickuuid"]); + pick.CreatorId = DBGuid.FromDB(reader["creatoruuid"]); + pick.ParcelId = DBGuid.FromDB(reader["parceluuid"]); + pick.SnapshotId = DBGuid.FromDB(reader["snapshotuuid"]); + pick.GlobalPos = (string)reader["posglobal"].ToString(); + pick.TopPick = Convert.ToBoolean(reader["toppick"]); + pick.Enabled = Convert.ToBoolean(reader["enabled"]); + pick.Name = reader["name"].ToString(); + pick.Desc = reader["description"].ToString(); + pick.ParcelName = reader["user"].ToString(); + pick.OriginalName = reader["originalname"].ToString(); + pick.SimName = reader["simname"].ToString(); + pick.SortOrder = (int)reader["sortorder"]; + } + } + } + dbcon.Close(); + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: GetPickInfo exception ", e); + } + + return pick; + } + + public bool UpdatePicksRecord(UserProfilePick pick) + { + string query = string.Empty; + + + query = @"WITH upsert AS ( + UPDATE userpicks SET + pickuuid = :PickId, creatoruuid = :CreatorId, toppick = :TopPick, parceluuid = :ParcelId, + name = :Name, description = :Desc, snapshotuuid = :SnapshotId, ""user"" = :User, + originalname = :Original, simname = :SimName, posglobal = :GlobalPos, + sortorder = :SortOrder, enabled = :Enabled + RETURNING * ) + INSERT INTO userpicks (pickuuid,creatoruuid,toppick,parceluuid,name,description, + snapshotuuid,""user"",originalname,simname,posglobal,sortorder,enabled) + SELECT + :PickId,:CreatorId,:TopPick,:ParcelId,:Name,:Desc,:SnapshotId,:User, + :Original,:SimName,:GlobalPos,:SortOrder,:Enabled + WHERE NOT EXISTS ( + SELECT * FROM upsert )"; + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("PickId", pick.PickId)); + cmd.Parameters.Add(m_database.CreateParameter("CreatorId", pick.CreatorId)); + cmd.Parameters.Add(m_database.CreateParameter("TopPick", pick.TopPick)); + cmd.Parameters.Add(m_database.CreateParameter("ParcelId", pick.ParcelId)); + cmd.Parameters.Add(m_database.CreateParameter("Name", pick.Name)); + cmd.Parameters.Add(m_database.CreateParameter("Desc", pick.Desc)); + cmd.Parameters.Add(m_database.CreateParameter("SnapshotId", pick.SnapshotId)); + cmd.Parameters.Add(m_database.CreateParameter("User", pick.ParcelName)); + cmd.Parameters.Add(m_database.CreateParameter("Original", pick.OriginalName)); + cmd.Parameters.Add(m_database.CreateParameter("SimName", pick.SimName)); + cmd.Parameters.Add(m_database.CreateParameter("GlobalPos", pick.GlobalPos)); + cmd.Parameters.Add(m_database.CreateParameter("SortOrder", pick.SortOrder)); + cmd.Parameters.Add(m_database.CreateParameter("Enabled", pick.Enabled)); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: UpdateAvatarNotes exception ", e); + return false; + } + + return true; + } + + public bool DeletePicksRecord(UUID pickId) + { + string query = string.Empty; + + query += "DELETE FROM userpicks WHERE "; + query += "pickuuid = :PickId"; + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("PickId", pickId)); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: DeleteUserPickRecord exception ", e); + return false; + } + + return true; + } + + #endregion Picks Queries + + #region Avatar Notes Queries + + public bool GetAvatarNotes(ref UserProfileNotes notes) + { // WIP + string query = string.Empty; + + query += "SELECT notes FROM usernotes WHERE "; + query += "useruuid = :Id AND "; + query += "targetuuid = :TargetId"; + OSDArray data = new OSDArray(); + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("Id", notes.UserId)); + cmd.Parameters.Add(m_database.CreateParameter("TargetId", notes.TargetId)); + + using (NpgsqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if (reader.HasRows) + { + reader.Read(); + notes.Notes = OSD.FromString((string)reader["notes"]); + } + } + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: GetAvatarNotes exception ", e); + } + + return true; + } + + public bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result) + { + string query = string.Empty; + bool remove; + + if (string.IsNullOrEmpty(note.Notes)) + { + remove = true; + query += "DELETE FROM usernotes WHERE "; + query += "useruuid=:UserId AND "; + query += "targetuuid=:TargetId"; + } + else + { + remove = false; + + query = @"WITH upsert AS ( + UPDATE usernotes SET notes = :Notes, useruuid = :UserId, targetuuid = :TargetId RETURNING * ) + INSERT INTO usernotes (notes,useruuid,targetuuid) + SELECT :Notes,:UserId,:TargetId + WHERE NOT EXISTS ( + SELECT * FROM upsert + )"; + } + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + if (!remove) + cmd.Parameters.Add(m_database.CreateParameter("Notes", note.Notes)); + + cmd.Parameters.Add(m_database.CreateParameter("TargetId", note.TargetId)); + cmd.Parameters.Add(m_database.CreateParameter("UserId", note.UserId)); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: UpdateAvatarNotes exception ", e); + return false; + } + + return true; + } + + #endregion Avatar Notes Queries + + #region Avatar Properties + + public bool GetAvatarProperties(ref UserProfileProperties props, ref string result) + { + string query = string.Empty; + + query += "SELECT * FROM userprofile WHERE "; + query += "useruuid = :Id"; + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("Id", props.UserId)); + + using (NpgsqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if (reader.HasRows) + { + // m_log.DebugFormat("[PROFILES_DATA]" + + // ": Getting data for {0}.", props.UserId); + reader.Read(); + props.WebUrl = (string)reader["profileURL"].ToString(); + props.ImageId = DBGuid.FromDB(reader["profileImage"]); + props.AboutText = (string)reader["profileAboutText"]; + props.FirstLifeImageId = DBGuid.FromDB(reader["profileFirstImage"]); + props.FirstLifeText = (string)reader["profileFirstText"]; + props.PartnerId = DBGuid.FromDB(reader["profilePartner"]); + props.WantToMask = (int)reader["profileWantToMask"]; + props.WantToText = (string)reader["profileWantToText"]; + props.SkillsMask = (int)reader["profileSkillsMask"]; + props.SkillsText = (string)reader["profileSkillsText"]; + props.Language = (string)reader["profileLanguages"]; + } + else + { + //m_log.DebugFormat("[PROFILES_DATA]" + + // ": No data for {0}", props.UserId); + + props.WebUrl = string.Empty; + props.ImageId = UUID.Zero; + props.AboutText = string.Empty; + props.FirstLifeImageId = UUID.Zero; + props.FirstLifeText = string.Empty; + props.PartnerId = UUID.Zero; + props.WantToMask = 0; + props.WantToText = string.Empty; + props.SkillsMask = 0; + props.SkillsText = string.Empty; + props.Language = string.Empty; + props.PublishProfile = false; + props.PublishMature = false; + + query = "INSERT INTO userprofile ("; + query += "useruuid, "; + query += "\"profilePartner\", "; + query += "\"profileAllowPublish\", "; + query += "\"profileMaturePublish\", "; + query += "\"profileURL\", "; + query += "\"profileWantToMask\", "; + query += "\"profileWantToText\", "; + query += "\"profileSkillsMask\", "; + query += "\"profileSkillsText\", "; + query += "\"profileLanguages\", "; + query += "\"profileImage\", "; + query += "\"profileAboutText\", "; + query += "\"profileFirstImage\", "; + query += "\"profileFirstText\") VALUES ("; + query += ":userId, "; + query += ":profilePartner, "; + query += ":profileAllowPublish, "; + query += ":profileMaturePublish, "; + query += ":profileURL, "; + query += ":profileWantToMask, "; + query += ":profileWantToText, "; + query += ":profileSkillsMask, "; + query += ":profileSkillsText, "; + query += ":profileLanguages, "; + query += ":profileImage, "; + query += ":profileAboutText, "; + query += ":profileFirstImage, "; + query += ":profileFirstText)"; + + dbcon.Close(); + dbcon.Open(); + + using (NpgsqlCommand put = new NpgsqlCommand(query, dbcon)) + { + //m_log.DebugFormat("[PROFILES_DATA]" + + // ": Adding new data for {0}", props.UserId); + + put.Parameters.Add(m_database.CreateParameter("userId", props.UserId)); + put.Parameters.Add(m_database.CreateParameter("profilePartner", props.PartnerId)); + put.Parameters.Add(m_database.CreateParameter("profileAllowPublish", props.PublishProfile)); + put.Parameters.Add(m_database.CreateParameter("profileMaturePublish", props.PublishMature)); + put.Parameters.Add(m_database.CreateParameter("profileURL", props.WebUrl)); + put.Parameters.Add(m_database.CreateParameter("profileWantToMask", props.WantToMask)); + put.Parameters.Add(m_database.CreateParameter("profileWantToText", props.WantToText)); + put.Parameters.Add(m_database.CreateParameter("profileSkillsMask", props.SkillsMask)); + put.Parameters.Add(m_database.CreateParameter("profileSkillsText", props.SkillsText)); + put.Parameters.Add(m_database.CreateParameter("profileLanguages", props.Language)); + put.Parameters.Add(m_database.CreateParameter("profileImage", props.ImageId)); + put.Parameters.Add(m_database.CreateParameter("profileAboutText", props.AboutText)); + put.Parameters.Add(m_database.CreateParameter("profileFirstImage", props.FirstLifeImageId)); + put.Parameters.Add(m_database.CreateParameter("profileFirstText", props.FirstLifeText)); + + put.ExecuteNonQuery(); + } + } + } + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: GetAvatarProperties exception ", e); + result = e.Message; + return false; + } + + return true; + } + + public bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result) + { + string query = string.Empty; + + query += "UPDATE userprofile SET "; + query += "\"profileURL\"=:profileURL, "; + query += "\"profileImage\"=:image, "; + query += "\"profileAboutText\"=:abouttext,"; + query += "\"profileFirstImage\"=:firstlifeimage,"; + query += "\"profileFirstText\"=:firstlifetext "; + query += "WHERE \"useruuid\"=:uuid"; + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("profileURL", props.WebUrl)); + cmd.Parameters.Add(m_database.CreateParameter("image", props.ImageId)); + cmd.Parameters.Add(m_database.CreateParameter("abouttext", props.AboutText)); + cmd.Parameters.Add(m_database.CreateParameter("firstlifeimage", props.FirstLifeImageId)); + cmd.Parameters.Add(m_database.CreateParameter("firstlifetext", props.FirstLifeText)); + cmd.Parameters.Add(m_database.CreateParameter("uuid", props.UserId)); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: AgentPropertiesUpdate exception ", e); + return false; + } + + return true; + } + + #endregion Avatar Properties + + #region Avatar Interests + + public bool UpdateAvatarInterests(UserProfileProperties up, ref string result) + { + string query = string.Empty; + + query += "UPDATE userprofile SET "; + query += "\"profileWantToMask\"=:WantMask, "; + query += "\"profileWantToText\"=:WantText,"; + query += "\"profileSkillsMask\"=:SkillsMask,"; + query += "\"profileSkillsText\"=:SkillsText, "; + query += "\"profileLanguages\"=:Languages "; + query += "WHERE \"useruuid\"=:uuid"; + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("WantMask", up.WantToMask)); + cmd.Parameters.Add(m_database.CreateParameter("WantText", up.WantToText)); + cmd.Parameters.Add(m_database.CreateParameter("SkillsMask", up.SkillsMask)); + cmd.Parameters.Add(m_database.CreateParameter("SkillsText", up.SkillsText)); + cmd.Parameters.Add(m_database.CreateParameter("Languages", up.Language)); + cmd.Parameters.Add(m_database.CreateParameter("uuid", up.UserId)); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: UpdateAvatarInterests exception ", e); + result = e.Message; + return false; + } + + return true; + } + + #endregion Avatar Interests + + public OSDArray GetUserImageAssets(UUID avatarId) + { + OSDArray data = new OSDArray(); + string query = "SELECT \"snapshotuuid\" FROM {0} WHERE \"creatoruuid\" = :Id"; + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + + using (NpgsqlCommand cmd = new NpgsqlCommand(string.Format(query, "\"classifieds\""), dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("Id", avatarId)); + + using (NpgsqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if (reader.HasRows) + { + while (reader.Read()) + { + data.Add(new OSDString(reader["snapshotuuid"].ToString())); + } + } + } + } + + dbcon.Close(); + dbcon.Open(); + + using (NpgsqlCommand cmd = new NpgsqlCommand(string.Format(query, "\"userpicks\""), dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("Id", avatarId)); + + using (NpgsqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if (reader.HasRows) + { + while (reader.Read()) + { + data.Add(new OSDString(reader["snapshotuuid"].ToString())); + } + } + } + } + + dbcon.Close(); + dbcon.Open(); + + query = "SELECT \"profileImage\", \"profileFirstImage\" FROM \"userprofile\" WHERE \"useruuid\" = :Id"; + + using (NpgsqlCommand cmd = new NpgsqlCommand(string.Format(query, "\"userpicks\""), dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("Id", avatarId)); + + using (NpgsqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if (reader.HasRows) + { + while (reader.Read()) + { + data.Add(new OSDString(reader["profileImage"].ToString())); + data.Add(new OSDString(reader["profileFirstImage"].ToString())); + } + } + } + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: GetUserImageAssets exception ", e); + } + + return data; + } + + #region User Preferences + + public bool GetUserPreferences(ref UserPreferences pref, ref string result) + { + string query = string.Empty; + + query += "SELECT imviaemail::VARCHAR,visible::VARCHAR,email FROM "; + query += "usersettings WHERE "; + query += "useruuid = :Id"; + + OSDArray data = new OSDArray(); + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("Id", pref.UserId)); + + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.HasRows) + { + reader.Read(); + bool.TryParse((string)reader["imviaemail"], out pref.IMViaEmail); + bool.TryParse((string)reader["visible"], out pref.Visible); + pref.EMail = (string)reader["email"]; + } + else + { + using (NpgsqlCommand put = new NpgsqlCommand(query, dbcon)) + { + put.Parameters.Add(m_database.CreateParameter("Id", pref.UserId)); + query = "INSERT INTO usersettings VALUES "; + query += "(:Id,'false','false', '')"; + + put.ExecuteNonQuery(); + } + } + } + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: GetUserPreferences exception ", e); + result = e.Message; + } + + return true; + } + + public bool UpdateUserPreferences(ref UserPreferences pref, ref string result) + { + string query = string.Empty; + + query += "UPDATE usersettings SET "; + query += "imviaemail=:ImViaEmail, "; + query += "visible=:Visible, "; + query += "email=:Email "; + query += "WHERE useruuid=:uuid"; + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("ImViaEmail", pref.IMViaEmail)); + cmd.Parameters.Add(m_database.CreateParameter("Visible", pref.Visible)); + cmd.Parameters.Add(m_database.CreateParameter("EMail", pref.EMail.ToString().ToLower())); + cmd.Parameters.Add(m_database.CreateParameter("uuid", pref.UserId)); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: UpdateUserPreferences exception ", e); + result = e.Message; + return false; + } + + return true; + } + + #endregion User Preferences + + #region Integration + + public bool GetUserAppData(ref UserAppData props, ref string result) + { + string query = string.Empty; + + query += "SELECT * FROM userdata WHERE "; + query += "\"UserId\" = :Id AND "; + query += "\"TagId\" = :TagId"; + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("Id", props.UserId)); + cmd.Parameters.Add(m_database.CreateParameter("TagId", props.TagId)); + + using (NpgsqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if (reader.HasRows) + { + reader.Read(); + props.DataKey = (string)reader["DataKey"]; + props.DataVal = (string)reader["DataVal"]; + } + else + { + query += "INSERT INTO userdata VALUES ( "; + query += ":UserId,"; + query += ":TagId,"; + query += ":DataKey,"; + query += ":DataVal) "; + + using (NpgsqlCommand put = new NpgsqlCommand(query, dbcon)) + { + put.Parameters.Add(m_database.CreateParameter("UserId", props.UserId)); + put.Parameters.Add(m_database.CreateParameter("TagId", props.TagId)); + put.Parameters.Add(m_database.CreateParameter("DataKey", props.DataKey.ToString())); + put.Parameters.Add(m_database.CreateParameter("DataVal", props.DataVal.ToString())); + + put.ExecuteNonQuery(); + } + } + } + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: GetUserAppData exception ", e); + result = e.Message; + return false; + } + + return true; + } + + public bool SetUserAppData(UserAppData props, ref string result) + { + string query = string.Empty; + + query += "UPDATE userdata SET "; + query += "\"TagId\" = :TagId, "; + query += "\"DataKey\" = :DataKey, "; + query += "\"DataVal\" = :DataVal WHERE "; + query += "\"UserId\" = :UserId AND "; + query += "\"TagId\" = :TagId"; + + try + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(ConnectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("UserId", props.UserId.ToString())); + cmd.Parameters.Add(m_database.CreateParameter("TagId", props.TagId.ToString())); + cmd.Parameters.Add(m_database.CreateParameter("DataKey", props.DataKey.ToString())); + cmd.Parameters.Add(m_database.CreateParameter("DataVal", props.DataKey.ToString())); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.Error("[PROFILES_DATA]: SetUserData exception ", e); + return false; + } + + return true; + } + + #endregion Integration + } +} \ No newline at end of file diff --git a/OpenSim/Data/PGSQL/PGSQLXAssetData.cs b/OpenSim/Data/PGSQL/PGSQLXAssetData.cs new file mode 100644 index 0000000..4f682f0 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLXAssetData.cs @@ -0,0 +1,587 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.IO.Compression; +using System.Reflection; +using System.Security.Cryptography; +using System.Text; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Data; +using Npgsql; + +namespace OpenSim.Data.PGSQL +{ + public class PGSQLXAssetData : IXAssetDataPlugin + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected virtual Assembly Assembly + { + get { return GetType().Assembly; } + } + + /// + /// Number of days that must pass before we update the access time on an asset when it has been fetched. + /// + private const int DaysBetweenAccessTimeUpdates = 30; + + private bool m_enableCompression = false; + private PGSQLManager m_database; + private string m_connectionString; + private object m_dbLock = new object(); + + /// + /// We can reuse this for all hashing since all methods are single-threaded through m_dbBLock + /// + private HashAlgorithm hasher = new SHA256CryptoServiceProvider(); + + #region IPlugin Members + + public string Version { get { return "1.0.0.0"; } } + + /// + /// Initialises Asset interface + /// + /// + /// Loads and initialises the PGSQL storage plugin. + /// Warns and uses the obsolete pgsql_connection.ini if connect string is empty. + /// Check for migration + /// + /// + /// + /// connect string + public void Initialise(string connect) + { + m_log.ErrorFormat("[PGSQL XASSETDATA]: ***********************************************************"); + m_log.ErrorFormat("[PGSQL XASSETDATA]: ***********************************************************"); + m_log.ErrorFormat("[PGSQL XASSETDATA]: ***********************************************************"); + m_log.ErrorFormat("[PGSQL XASSETDATA]: THIS PLUGIN IS STRICTLY EXPERIMENTAL."); + m_log.ErrorFormat("[PGSQL XASSETDATA]: DO NOT USE FOR ANY DATA THAT YOU DO NOT MIND LOSING."); + m_log.ErrorFormat("[PGSQL XASSETDATA]: DATABASE TABLES CAN CHANGE AT ANY TIME, CAUSING EXISTING DATA TO BE LOST."); + m_log.ErrorFormat("[PGSQL XASSETDATA]: ***********************************************************"); + m_log.ErrorFormat("[PGSQL XASSETDATA]: ***********************************************************"); + m_log.ErrorFormat("[PGSQL XASSETDATA]: ***********************************************************"); + + m_connectionString = connect; + m_database = new PGSQLManager(m_connectionString); + + using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString)) + { + dbcon.Open(); + Migration m = new Migration(dbcon, Assembly, "XAssetStore"); + m.Update(); + } + } + + public void Initialise() + { + throw new NotImplementedException(); + } + + public void Dispose() { } + + /// + /// The name of this DB provider + /// + public string Name + { + get { return "PGSQL XAsset storage engine"; } + } + + #endregion + + #region IAssetDataPlugin Members + + /// + /// Fetch Asset from database + /// + /// Asset UUID to fetch + /// Return the asset + /// On failure : throw an exception and attempt to reconnect to database + public AssetBase GetAsset(UUID assetID) + { +// m_log.DebugFormat("[PGSQL XASSET DATA]: Looking for asset {0}", assetID); + + AssetBase asset = null; + lock (m_dbLock) + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString)) + { + dbcon.Open(); + + using (NpgsqlCommand cmd = new NpgsqlCommand( + @"SELECT name, description, access_time, ""AssetType"", local, temporary, asset_flags, creatorid, data + FROM XAssetsMeta + JOIN XAssetsData ON XAssetsMeta.hash = XAssetsData.Hash WHERE id=:ID", + dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("ID", assetID)); + + try + { + using (NpgsqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if (dbReader.Read()) + { + asset = new AssetBase( + assetID, + (string)dbReader["name"], + Convert.ToSByte(dbReader["AssetType"]), + dbReader["creatorid"].ToString()); + + asset.Data = (byte[])dbReader["data"]; + asset.Description = (string)dbReader["description"]; + + string local = dbReader["local"].ToString(); + if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase)) + asset.Local = true; + else + asset.Local = false; + + asset.Temporary = Convert.ToBoolean(dbReader["temporary"]); + asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); + + if (m_enableCompression) + { + using (GZipStream decompressionStream = new GZipStream(new MemoryStream(asset.Data), CompressionMode.Decompress)) + { + MemoryStream outputStream = new MemoryStream(); + WebUtil.CopyStream(decompressionStream, outputStream, int.MaxValue); + // int compressedLength = asset.Data.Length; + asset.Data = outputStream.ToArray(); + + // m_log.DebugFormat( + // "[XASSET DB]: Decompressed {0} {1} to {2} bytes from {3}", + // asset.ID, asset.Name, asset.Data.Length, compressedLength); + } + } + + UpdateAccessTime(asset.Metadata, (int)dbReader["access_time"]); + } + } + } + catch (Exception e) + { + m_log.Error(string.Format("[PGSQL XASSET DATA]: Failure fetching asset {0}", assetID), e); + } + } + } + } + + return asset; + } + + /// + /// Create an asset in database, or update it if existing. + /// + /// Asset UUID to create + /// On failure : Throw an exception and attempt to reconnect to database + public void StoreAsset(AssetBase asset) + { +// m_log.DebugFormat("[XASSETS DB]: Storing asset {0} {1}", asset.Name, asset.ID); + + lock (m_dbLock) + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString)) + { + dbcon.Open(); + + using (NpgsqlTransaction transaction = dbcon.BeginTransaction()) + { + string assetName = asset.Name; + if (asset.Name.Length > 64) + { + assetName = asset.Name.Substring(0, 64); + m_log.WarnFormat( + "[XASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add", + asset.Name, asset.ID, asset.Name.Length, assetName.Length); + } + + string assetDescription = asset.Description; + if (asset.Description.Length > 64) + { + assetDescription = asset.Description.Substring(0, 64); + m_log.WarnFormat( + "[XASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", + asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); + } + + if (m_enableCompression) + { + MemoryStream outputStream = new MemoryStream(); + + using (GZipStream compressionStream = new GZipStream(outputStream, CompressionMode.Compress, false)) + { + // Console.WriteLine(WebUtil.CopyTo(new MemoryStream(asset.Data), compressionStream, int.MaxValue)); + // We have to close the compression stream in order to make sure it writes everything out to the underlying memory output stream. + compressionStream.Close(); + byte[] compressedData = outputStream.ToArray(); + asset.Data = compressedData; + } + } + + byte[] hash = hasher.ComputeHash(asset.Data); + + UUID asset_id; + UUID.TryParse(asset.ID, out asset_id); + +// m_log.DebugFormat( +// "[XASSET DB]: Compressed data size for {0} {1}, hash {2} is {3}", +// asset.ID, asset.Name, hash, compressedData.Length); + + try + { + using (NpgsqlCommand cmd = + new NpgsqlCommand( + @"insert INTO XAssetsMeta(id, hash, name, description, ""AssetType"", local, temporary, create_time, access_time, asset_flags, creatorid) + Select :ID, :Hash, :Name, :Description, :AssetType, :Local, :Temporary, :CreateTime, :AccessTime, :AssetFlags, :CreatorID + where not exists( Select id from XAssetsMeta where id = :ID); + + update XAssetsMeta + set id = :ID, hash = :Hash, name = :Name, description = :Description, + ""AssetType"" = :AssetType, local = :Local, temporary = :Temporary, create_time = :CreateTime, + access_time = :AccessTime, asset_flags = :AssetFlags, creatorid = :CreatorID + where id = :ID; + ", + dbcon)) + { + + // create unix epoch time + int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); + cmd.Parameters.Add(m_database.CreateParameter("ID", asset_id)); + cmd.Parameters.Add(m_database.CreateParameter("Hash", hash)); + cmd.Parameters.Add(m_database.CreateParameter("Name", assetName)); + cmd.Parameters.Add(m_database.CreateParameter("Description", assetDescription)); + cmd.Parameters.Add(m_database.CreateParameter("AssetType", asset.Type)); + cmd.Parameters.Add(m_database.CreateParameter("Local", asset.Local)); + cmd.Parameters.Add(m_database.CreateParameter("Temporary", asset.Temporary)); + cmd.Parameters.Add(m_database.CreateParameter("CreateTime", now)); + cmd.Parameters.Add(m_database.CreateParameter("AccessTime", now)); + cmd.Parameters.Add(m_database.CreateParameter("CreatorID", asset.Metadata.CreatorID)); + cmd.Parameters.Add(m_database.CreateParameter("AssetFlags", (int)asset.Flags)); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[ASSET DB]: PGSQL failure creating asset metadata {0} with name \"{1}\". Error: {2}", + asset.FullID, asset.Name, e.Message); + + transaction.Rollback(); + + return; + } + + if (!ExistsData(dbcon, transaction, hash)) + { + try + { + using (NpgsqlCommand cmd = + new NpgsqlCommand( + @"INSERT INTO XAssetsData(hash, data) VALUES(:Hash, :Data)", + dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("Hash", hash)); + cmd.Parameters.Add(m_database.CreateParameter("Data", asset.Data)); + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[XASSET DB]: PGSQL failure creating asset data {0} with name \"{1}\". Error: {2}", + asset.FullID, asset.Name, e.Message); + + transaction.Rollback(); + + return; + } + } + + transaction.Commit(); + } + } + } + } + + /// + /// Updates the access time of the asset if it was accessed above a given threshhold amount of time. + /// + /// + /// This gives us some insight into assets which haven't ben accessed for a long period. This is only done + /// over the threshold time to avoid excessive database writes as assets are fetched. + /// + /// + /// + private void UpdateAccessTime(AssetMetadata assetMetadata, int accessTime) + { + DateTime now = DateTime.UtcNow; + + if ((now - Utils.UnixTimeToDateTime(accessTime)).TotalDays < DaysBetweenAccessTimeUpdates) + return; + + lock (m_dbLock) + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString)) + { + dbcon.Open(); + NpgsqlCommand cmd = + new NpgsqlCommand(@"update XAssetsMeta set access_time=:AccessTime where id=:ID", dbcon); + + try + { + UUID asset_id; + UUID.TryParse(assetMetadata.ID, out asset_id); + + using (cmd) + { + // create unix epoch time + cmd.Parameters.Add(m_database.CreateParameter("id", asset_id)); + cmd.Parameters.Add(m_database.CreateParameter("access_time", (int)Utils.DateTimeToUnixTime(now))); + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat( + "[XASSET PGSQL DB]: Failure updating access_time for asset {0} with name {1} : {2}", + assetMetadata.ID, assetMetadata.Name, e.Message); + } + } + } + } + + /// + /// We assume we already have the m_dbLock. + /// + /// TODO: need to actually use the transaction. + /// + /// + /// + /// + private bool ExistsData(NpgsqlConnection dbcon, NpgsqlTransaction transaction, byte[] hash) + { +// m_log.DebugFormat("[ASSETS DB]: Checking for asset {0}", uuid); + + bool exists = false; + + using (NpgsqlCommand cmd = new NpgsqlCommand(@"SELECT hash FROM XAssetsData WHERE hash=:Hash", dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("Hash", hash)); + + try + { + using (NpgsqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if (dbReader.Read()) + { +// m_log.DebugFormat("[ASSETS DB]: Found asset {0}", uuid); + exists = true; + } + } + } + catch (Exception e) + { + m_log.ErrorFormat( + "[XASSETS DB]: PGSql failure in ExistsData fetching hash {0}. Exception {1}{2}", + hash, e.Message, e.StackTrace); + } + } + + return exists; + } + + /// + /// Check if the assets exist in the database. + /// + /// The assets' IDs + /// For each asset: true if it exists, false otherwise + public bool[] AssetsExist(UUID[] uuids) + { + if (uuids.Length == 0) + return new bool[0]; + + HashSet exist = new HashSet(); + + string ids = "'" + string.Join("','", uuids) + "'"; + string sql = string.Format(@"SELECT id FROM XAssetsMeta WHERE id IN ({0})", ids); + + using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) + { + conn.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + UUID id = DBGuid.FromDB(reader["id"]); + exist.Add(id); + } + } + } + } + + bool[] results = new bool[uuids.Length]; + for (int i = 0; i < uuids.Length; i++) + results[i] = exist.Contains(uuids[i]); + return results; + } + + /// + /// Check if the asset exists in the database + /// + /// The asset UUID + /// true if it exists, false otherwise. + public bool ExistsAsset(UUID uuid) + { +// m_log.DebugFormat("[ASSETS DB]: Checking for asset {0}", uuid); + + bool assetExists = false; + + lock (m_dbLock) + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString)) + { + dbcon.Open(); + using (NpgsqlCommand cmd = new NpgsqlCommand(@"SELECT id FROM XAssetsMeta WHERE id=:ID", dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter("id", uuid)); + + try + { + using (NpgsqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if (dbReader.Read()) + { +// m_log.DebugFormat("[ASSETS DB]: Found asset {0}", uuid); + assetExists = true; + } + } + } + catch (Exception e) + { + m_log.Error(string.Format("[XASSETS DB]: PGSql failure fetching asset {0}", uuid), e); + } + } + } + } + + return assetExists; + } + + + /// + /// Returns a list of AssetMetadata objects. The list is a subset of + /// the entire data set offset by containing + /// elements. + /// + /// The number of results to discard from the total data set. + /// The number of rows the returned list should contain. + /// A list of AssetMetadata objects. + public List FetchAssetMetadataSet(int start, int count) + { + List retList = new List(count); + + lock (m_dbLock) + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString)) + { + dbcon.Open(); + NpgsqlCommand cmd = new NpgsqlCommand( @"SELECT name, description, access_time, ""AssetType"", temporary, id, asset_flags, creatorid + FROM XAssetsMeta + LIMIT :start, :count", dbcon); + cmd.Parameters.Add(m_database.CreateParameter("start", start)); + cmd.Parameters.Add(m_database.CreateParameter("count", count)); + + try + { + using (NpgsqlDataReader dbReader = cmd.ExecuteReader()) + { + while (dbReader.Read()) + { + AssetMetadata metadata = new AssetMetadata(); + metadata.Name = (string)dbReader["name"]; + metadata.Description = (string)dbReader["description"]; + metadata.Type = Convert.ToSByte(dbReader["AssetType"]); + metadata.Temporary = Convert.ToBoolean(dbReader["temporary"]); + metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); + metadata.FullID = DBGuid.FromDB(dbReader["id"]); + metadata.CreatorID = dbReader["creatorid"].ToString(); + + // We'll ignore this for now - it appears unused! +// metadata.SHA1 = dbReader["hash"]); + + UpdateAccessTime(metadata, (int)dbReader["access_time"]); + + retList.Add(metadata); + } + } + } + catch (Exception e) + { + m_log.Error("[XASSETS DB]: PGSql failure fetching asset set" + Environment.NewLine + e.ToString()); + } + } + } + + return retList; + } + + public bool Delete(string id) + { +// m_log.DebugFormat("[XASSETS DB]: Deleting asset {0}", id); + + lock (m_dbLock) + { + using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString)) + { + dbcon.Open(); + + using (NpgsqlCommand cmd = new NpgsqlCommand(@"delete from XAssetsMeta where id=:ID", dbcon)) + { + cmd.Parameters.Add(m_database.CreateParameter(id, id)); + cmd.ExecuteNonQuery(); + } + + // TODO: How do we deal with data from deleted assets? Probably not easily reapable unless we + // keep a reference count (?) + } + } + + return true; + } + + #endregion + } +} diff --git a/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs b/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs new file mode 100644 index 0000000..a22b882 --- /dev/null +++ b/OpenSim/Data/PGSQL/PGSQLXInventoryData.cs @@ -0,0 +1,330 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using OpenMetaverse; +using OpenSim.Framework; +using System.Reflection; +using System.Text; +using log4net; +using Npgsql; +using NpgsqlTypes; + +namespace OpenSim.Data.PGSQL +{ + public class PGSQLXInventoryData : IXInventoryData + { +// private static readonly ILog m_log = LogManager.GetLogger( +// MethodBase.GetCurrentMethod().DeclaringType); + + private PGSQLFolderHandler m_Folders; + private PGSQLItemHandler m_Items; + + public PGSQLXInventoryData(string conn, string realm) + { + m_Folders = new PGSQLFolderHandler( + conn, "inventoryfolders", "InventoryStore"); + m_Items = new PGSQLItemHandler( + conn, "inventoryitems", String.Empty); + } + + public static UUID str2UUID(string strUUID) + { + UUID newUUID = UUID.Zero; + + UUID.TryParse(strUUID, out newUUID); + + return newUUID; + } + + public XInventoryFolder[] GetFolders(string[] fields, string[] vals) + { + return m_Folders.Get(fields, vals); + } + + public XInventoryItem[] GetItems(string[] fields, string[] vals) + { + return m_Items.Get(fields, vals); + } + + public bool StoreFolder(XInventoryFolder folder) + { + if (folder.folderName.Length > 64) + folder.folderName = folder.folderName.Substring(0, 64); + return m_Folders.Store(folder); + } + + public bool StoreItem(XInventoryItem item) + { + if (item.inventoryName.Length > 64) + item.inventoryName = item.inventoryName.Substring(0, 64); + if (item.inventoryDescription.Length > 128) + item.inventoryDescription = item.inventoryDescription.Substring(0, 128); + + return m_Items.Store(item); + } + + public bool DeleteFolders(string field, string val) + { + return m_Folders.Delete(field, val); + } + + public bool DeleteFolders(string[] fields, string[] vals) + { + return m_Folders.Delete(fields, vals); + } + + public bool DeleteItems(string field, string val) + { + return m_Items.Delete(field, val); + } + + public bool DeleteItems(string[] fields, string[] vals) + { + return m_Items.Delete(fields, vals); + } + + public bool MoveItem(string id, string newParent) + { + return m_Items.MoveItem(id, newParent); + } + + public bool MoveFolder(string id, string newParent) + { + return m_Folders.MoveFolder(id, newParent); + } + + public XInventoryItem[] GetActiveGestures(UUID principalID) + { + return m_Items.GetActiveGestures(principalID.ToString()); + } + + public int GetAssetPermissions(UUID principalID, UUID assetID) + { + return m_Items.GetAssetPermissions(principalID, assetID); + } + } + + public class PGSQLItemHandler : PGSQLInventoryHandler + { + public PGSQLItemHandler(string c, string t, string m) : + base(c, t, m) + { + } + + public bool MoveItem(string id, string newParent) + { + XInventoryItem[] retrievedItems = Get(new string[] { "inventoryID" }, new string[] { id }); + if (retrievedItems.Length == 0) + return false; + + UUID oldParent = retrievedItems[0].parentFolderID; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + { + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + cmd.CommandText = String.Format(@"update {0} set ""parentFolderID"" = :ParentFolderID where ""inventoryID"" = :InventoryID", m_Realm); + cmd.Parameters.Add(m_database.CreateParameter("ParentFolderID", newParent)); + cmd.Parameters.Add(m_database.CreateParameter("InventoryID", id )); + cmd.Connection = conn; + conn.Open(); + + if (cmd.ExecuteNonQuery() == 0) + return false; + } + } + + IncrementFolderVersion(oldParent); + IncrementFolderVersion(newParent); + + return true; + } + + public XInventoryItem[] GetActiveGestures(string principalID) + { + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + { + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + cmd.CommandText = String.Format(@"select * from inventoryitems where ""avatarID"" = :uuid and ""assetType"" = :type and ""flags"" = 1", m_Realm); + + UUID princID = UUID.Zero; + UUID.TryParse(principalID, out princID); + + cmd.Parameters.Add(m_database.CreateParameter("uuid", principalID)); + cmd.Parameters.Add(m_database.CreateParameter("type", (int)AssetType.Gesture)); + cmd.Connection = conn; + conn.Open(); + return DoQuery(cmd); + } + } + } + + public int GetAssetPermissions(UUID principalID, UUID assetID) + { + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + { + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + cmd.CommandText = String.Format(@"select bit_or(""inventoryCurrentPermissions"") as ""inventoryCurrentPermissions"" + from inventoryitems + where ""avatarID"" = :PrincipalID + and ""assetID"" = :AssetID + group by ""assetID"" ", m_Realm); + + cmd.Parameters.Add(m_database.CreateParameter("PrincipalID", principalID)); + cmd.Parameters.Add(m_database.CreateParameter("AssetID", assetID)); + cmd.Connection = conn; + conn.Open(); + using (NpgsqlDataReader reader = cmd.ExecuteReader()) + { + + int perms = 0; + + if (reader.Read()) + { + perms = Convert.ToInt32(reader["inventoryCurrentPermissions"]); + } + + return perms; + } + + } + } + } + + public override bool Store(XInventoryItem item) + { + if (!base.Store(item)) + return false; + + IncrementFolderVersion(item.parentFolderID); + + return true; + } + } + + public class PGSQLFolderHandler : PGSQLInventoryHandler + { + public PGSQLFolderHandler(string c, string t, string m) : + base(c, t, m) + { + } + + public bool MoveFolder(string id, string newParentFolderID) + { + XInventoryFolder[] folders = Get(new string[] { "folderID" }, new string[] { id }); + + if (folders.Length == 0) + return false; + + UUID oldParentFolderUUID = folders[0].parentFolderID; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + { + using (NpgsqlCommand cmd = new NpgsqlCommand()) + { + UUID foldID = UUID.Zero; + UUID.TryParse(id, out foldID); + + UUID newPar = UUID.Zero; + UUID.TryParse(newParentFolderID, out newPar); + + cmd.CommandText = String.Format(@"update {0} set ""parentFolderID"" = :ParentFolderID where ""folderID"" = :folderID", m_Realm); + cmd.Parameters.Add(m_database.CreateParameter("ParentFolderID", newPar)); + cmd.Parameters.Add(m_database.CreateParameter("folderID", foldID)); + cmd.Connection = conn; + conn.Open(); + + if (cmd.ExecuteNonQuery() == 0) + return false; + } + } + + IncrementFolderVersion(oldParentFolderUUID); + IncrementFolderVersion(newParentFolderID); + + return true; + } + + public override bool Store(XInventoryFolder folder) + { + if (!base.Store(folder)) + return false; + + IncrementFolderVersion(folder.parentFolderID); + + return true; + } + } + + public class PGSQLInventoryHandler : PGSQLGenericTableHandler where T: class, new() + { + public PGSQLInventoryHandler(string c, string t, string m) : base(c, t, m) {} + + protected bool IncrementFolderVersion(UUID folderID) + { + return IncrementFolderVersion(folderID.ToString()); + } + + protected bool IncrementFolderVersion(string folderID) + { +// m_log.DebugFormat("[PGSQL ITEM HANDLER]: Incrementing version on folder {0}", folderID); +// Util.PrintCallStack(); + + string sql = @"update inventoryfolders set version=version+1 where ""folderID"" = :folderID"; + + using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString)) + { + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn)) + { + UUID foldID = UUID.Zero; + UUID.TryParse(folderID, out foldID); + + conn.Open(); + + cmd.Parameters.Add( m_database.CreateParameter("folderID", foldID) ); + + try + { + cmd.ExecuteNonQuery(); + } + catch (Exception) + { + return false; + } + } + } + + return true; + } + } +} diff --git a/OpenSim/Data/PGSQL/Properties/AssemblyInfo.cs b/OpenSim/Data/PGSQL/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1e88b2c --- /dev/null +++ b/OpenSim/Data/PGSQL/Properties/AssemblyInfo.cs @@ -0,0 +1,65 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Reflection; +using System.Runtime.InteropServices; + +// General information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +[assembly : AssemblyTitle("OpenSim.Data.PGSQL")] +[assembly : AssemblyDescription("")] +[assembly : AssemblyConfiguration("")] +[assembly : AssemblyCompany("http://opensimulator.org")] +[assembly : AssemblyProduct("OpenSim.Data.PGSQL")] +[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers 2007-2009")] +[assembly : AssemblyTrademark("")] +[assembly : AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. + +[assembly : ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM + +[assembly : Guid("0e1c1ca4-2cf2-4315-b0e7-432c02feea8a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly : AssemblyVersion("0.8.2.*")] + diff --git a/OpenSim/Data/PGSQL/Resources/AssetStore.migrations b/OpenSim/Data/PGSQL/Resources/AssetStore.migrations new file mode 100644 index 0000000..7a858b4 --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/AssetStore.migrations @@ -0,0 +1,99 @@ +:VERSION 1 + +CREATE TABLE assets ( + "id" varchar(36) NOT NULL PRIMARY KEY, + "name" varchar(64) NOT NULL, + "description" varchar(64) NOT NULL, + "assetType" smallint NOT NULL, + "local" smallint NOT NULL, + "temporary" smallint NOT NULL, + "data" bytea NOT NULL +) ; + +:VERSION 2 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_assets + ( + "id" varchar(36) NOT NULL, + "name" varchar(64) NOT NULL, + "description" varchar(64) NOT NULL, + "assetType" smallint NOT NULL, + "local" boolean NOT NULL, + "temporary" boolean NOT NULL, + "data" bytea NOT NULL + ) ; + +INSERT INTO Tmp_assets ("id", "name", "description", "assetType", "local", "temporary", "data") + SELECT "id", "name", "description", "assetType", case when "local" = 1 then true else false end, case when "temporary" = 1 then true else false end, "data" + FROM assets ; + +DROP TABLE assets; + +Alter table Tmp_assets + rename to assets; + +ALTER TABLE assets ADD PRIMARY KEY ("id"); + +COMMIT; + + +:VERSION 3 + +BEGIN TRANSACTION; + +ALTER TABLE assets add "create_time" integer default 0; +ALTER TABLE assets add "access_time" integer default 0; + +COMMIT; + + +:VERSION 4 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_assets + ( + "id" uuid NOT NULL, + "name" varchar(64) NOT NULL, + "description" varchar(64) NOT NULL, + "assetType" smallint NOT NULL, + "local" boolean NOT NULL, + "temporary" boolean NOT NULL, + "data" bytea NOT NULL, + "create_time" int NULL, + "access_time" int NULL + ) ; + + +INSERT INTO Tmp_assets ("id", "name", "description", "assetType", "local", "temporary", "data", "create_time", "access_time") + SELECT cast("id" as uuid), "name", "description", "assetType", "local", "temporary", "data", "create_time", "access_time" + FROM assets ; + +DROP TABLE assets; + +Alter table Tmp_assets + rename to assets; + + ALTER TABLE assets ADD PRIMARY KEY ("id"); + +COMMIT; + + +:VERSION 5 + +DELETE FROM assets WHERE "id" = 'dc4b9f0b-d008-45c6-96a4-01dd947ac621'; + +:VERSION 6 + +ALTER TABLE assets ADD "asset_flags" INTEGER NOT NULL DEFAULT 0; + +:VERSION 7 + +alter table assets add "creatorid" varchar(36) not null default ''; + +:VERSION 8 + +BEGIN TRANSACTION; +COMMIT; diff --git a/OpenSim/Data/PGSQL/Resources/AuthStore.migrations b/OpenSim/Data/PGSQL/Resources/AuthStore.migrations new file mode 100644 index 0000000..a1f5b61 --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/AuthStore.migrations @@ -0,0 +1,32 @@ +:VERSION 1 + +BEGIN TRANSACTION; + +CREATE TABLE auth ( + uuid uuid NOT NULL default '00000000-0000-0000-0000-000000000000', + "passwordHash" varchar(32) NOT NULL, + "passwordSalt" varchar(32) NOT NULL, + "webLoginKey" varchar(255) NOT NULL, + "accountType" VARCHAR(32) NOT NULL DEFAULT 'UserAccount' +) ; + +CREATE TABLE tokens ( + uuid uuid NOT NULL default '00000000-0000-0000-0000-000000000000', + token varchar(255) NOT NULL, + validity TIMESTAMP NOT NULL ) + ; + +COMMIT; + +:VERSION 2 + +BEGIN TRANSACTION; + + INSERT INTO auth (uuid, "passwordHash", "passwordSalt", "webLoginKey", "accountType") + SELECT uuid AS UUID, passwordHash AS passwordHash, passwordSalt AS passwordSalt, webLoginKey AS webLoginKey, 'UserAccount' as accountType + FROM users + where exists ( Select * from information_schema.tables where table_name = 'users' ) + ; + +COMMIT; + diff --git a/OpenSim/Data/PGSQL/Resources/Avatar.migrations b/OpenSim/Data/PGSQL/Resources/Avatar.migrations new file mode 100644 index 0000000..160086d --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/Avatar.migrations @@ -0,0 +1,59 @@ +:VERSION 1 + +BEGIN TRANSACTION; + +CREATE TABLE Avatars ( +"PrincipalID" uuid NOT NULL PRIMARY KEY, +"Name" varchar(32) NOT NULL, +"Value" varchar(255) NOT NULL DEFAULT '' +); + + +COMMIT; + +:VERSION 2 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_Avatars + ( + "PrincipalID" uuid NOT NULL, + "Name" varchar(32) NOT NULL, + "Value" text NOT NULL DEFAULT '' + ) ; + + INSERT INTO Tmp_Avatars ("PrincipalID", "Name", "Value") + SELECT "PrincipalID", cast("Name" as text), "Value" + FROM Avatars ; + +DROP TABLE Avatars; + +Alter table Tmp_Avatars + rename to Avatars; + +COMMIT; + +:VERSION 3 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_Avatars + ( + "PrincipalID" uuid NOT NULL, + "Name" varchar(32) NOT NULL, + "Value" text NOT NULL DEFAULT '' +); + +ALTER TABLE Tmp_Avatars ADD PRIMARY KEY ("PrincipalID", "Name"); + + +INSERT INTO Tmp_Avatars ("PrincipalID", "Name", "Value") + SELECT "PrincipalID", "Name", cast("Value" as text) FROM Avatars ; + +DROP TABLE Avatars; + +Alter table Tmp_Avatars + rename to Avatars; + +COMMIT; + diff --git a/OpenSim/Data/PGSQL/Resources/EstateStore.migrations b/OpenSim/Data/PGSQL/Resources/EstateStore.migrations new file mode 100644 index 0000000..59270f8 --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/EstateStore.migrations @@ -0,0 +1,307 @@ +:VERSION 1 + +BEGIN TRANSACTION; + +CREATE TABLE estate_managers( + "EstateID" int NOT NULL Primary Key, + uuid varchar(36) NOT NULL + ); + +CREATE TABLE estate_groups( + "EstateID" int NOT NULL, + uuid varchar(36) NOT NULL + ); + + +CREATE TABLE estate_users( + "EstateID" int NOT NULL, + uuid varchar(36) NOT NULL + ); + + +CREATE TABLE estateban( + "EstateID" int NOT NULL, + "bannedUUID" varchar(36) NOT NULL, + "bannedIp" varchar(16) NOT NULL, + "bannedIpHostMask" varchar(16) NOT NULL, + "bannedNameMask" varchar(64) NULL DEFAULT NULL + ); + +Create Sequence estate_settings_id increment by 100 start with 100; + +CREATE TABLE estate_settings( + "EstateID" integer DEFAULT nextval('estate_settings_id') NOT NULL, + "EstateName" varchar(64) NULL DEFAULT (NULL), + "AbuseEmailToEstateOwner" boolean NOT NULL, + "DenyAnonymous" boolean NOT NULL, + "ResetHomeOnTeleport" boolean NOT NULL, + "FixedSun" boolean NOT NULL, + "DenyTransacted" boolean NOT NULL, + "BlockDwell" boolean NOT NULL, + "DenyIdentified" boolean NOT NULL, + "AllowVoice" boolean NOT NULL, + "UseGlobalTime" boolean NOT NULL, + "PricePerMeter" int NOT NULL, + "TaxFree" boolean NOT NULL, + "AllowDirectTeleport" boolean NOT NULL, + "RedirectGridX" int NOT NULL, + "RedirectGridY" int NOT NULL, + "ParentEstateID" int NOT NULL, + "SunPosition" double precision NOT NULL, + "EstateSkipScripts" boolean NOT NULL, + "BillableFactor" double precision NOT NULL, + "PublicAccess" boolean NOT NULL, + "AbuseEmail" varchar(255) NOT NULL, + "EstateOwner" varchar(36) NOT NULL, + "DenyMinors" boolean NOT NULL + ); + + +CREATE TABLE estate_map( + "RegionID" varchar(36) NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), + "EstateID" int NOT NULL + ); + +COMMIT; + +:VERSION 2 + +BEGIN TRANSACTION; + +CREATE INDEX IX_estate_managers ON estate_managers + ( + "EstateID" + ); + + +CREATE INDEX IX_estate_groups ON estate_groups + ( + "EstateID" + ); + + +CREATE INDEX IX_estate_users ON estate_users + ( + "EstateID" + ); + +COMMIT; + +:VERSION 3 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_estateban + ( + "EstateID" int NOT NULL, + "bannedUUID" varchar(36) NOT NULL, + "bannedIp" varchar(16) NULL, + "bannedIpHostMask" varchar(16) NULL, + "bannedNameMask" varchar(64) NULL + ); + + INSERT INTO Tmp_estateban ("EstateID", "bannedUUID", "bannedIp", "bannedIpHostMask", "bannedNameMask") + SELECT "EstateID", "bannedUUID", "bannedIp", "bannedIpHostMask", "bannedNameMask" FROM estateban; + +DROP TABLE estateban; + +Alter table Tmp_estateban + rename to estateban; + +CREATE INDEX IX_estateban ON estateban + ( + "EstateID" + ); + +COMMIT; + + +:VERSION 4 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_estate_managers + ( + "EstateID" int NOT NULL, + uuid uuid NOT NULL + ); + +INSERT INTO Tmp_estate_managers ("EstateID", uuid) + SELECT "EstateID", cast(uuid as uuid) FROM estate_managers; + +DROP TABLE estate_managers; + +Alter table Tmp_estate_managers + rename to estate_managers; + +CREATE INDEX IX_estate_managers ON estate_managers + ( + "EstateID" + ); + +COMMIT; + + +:VERSION 5 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_estate_groups + ( + "EstateID" int NOT NULL, + uuid uuid NOT NULL + ) ; + + INSERT INTO Tmp_estate_groups ("EstateID", uuid) + SELECT "EstateID", cast(uuid as uuid) FROM estate_groups; + +DROP TABLE estate_groups; + +Alter table Tmp_estate_groups + rename to estate_groups; + +CREATE INDEX IX_estate_groups ON estate_groups + ( + "EstateID" + ); + +COMMIT; + + +:VERSION 6 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_estate_users + ( + "EstateID" int NOT NULL, + uuid uuid NOT NULL + ); + +INSERT INTO Tmp_estate_users ("EstateID", uuid) + SELECT "EstateID", cast(uuid as uuid) FROM estate_users ; + +DROP TABLE estate_users; + +Alter table Tmp_estate_users + rename to estate_users; + +CREATE INDEX IX_estate_users ON estate_users + ( + "EstateID" + ); + +COMMIT; + + +:VERSION 7 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_estateban + ( + "EstateID" int NOT NULL, + "bannedUUID" uuid NOT NULL, + "bannedIp" varchar(16) NULL, + "bannedIpHostMask" varchar(16) NULL, + "bannedNameMask" varchar(64) NULL + ); + +INSERT INTO Tmp_estateban ("EstateID", "bannedUUID", "bannedIp", "bannedIpHostMask", "bannedNameMask") + SELECT "EstateID", cast("bannedUUID" as uuid), "bannedIp", "bannedIpHostMask", "bannedNameMask" FROM estateban ; + +DROP TABLE estateban; + +Alter table Tmp_estateban + rename to estateban; + +CREATE INDEX IX_estateban ON estateban + ( + "EstateID" + ); + +COMMIT; + + +:VERSION 8 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_estate_settings + ( + "EstateID" integer default nextval('estate_settings_id') NOT NULL, + "EstateName" varchar(64) NULL DEFAULT (NULL), + "AbuseEmailToEstateOwner" boolean NOT NULL, + "DenyAnonymous" boolean NOT NULL, + "ResetHomeOnTeleport" boolean NOT NULL, + "FixedSun" boolean NOT NULL, + "DenyTransacted" boolean NOT NULL, + "BlockDwell" boolean NOT NULL, + "DenyIdentified" boolean NOT NULL, + "AllowVoice" boolean NOT NULL, + "UseGlobalTime" boolean NOT NULL, + "PricePerMeter" int NOT NULL, + "TaxFree" boolean NOT NULL, + "AllowDirectTeleport" boolean NOT NULL, + "RedirectGridX" int NOT NULL, + "RedirectGridY" int NOT NULL, + "ParentEstateID" int NOT NULL, + "SunPosition" double precision NOT NULL, + "EstateSkipScripts" boolean NOT NULL, + "BillableFactor" double precision NOT NULL, + "PublicAccess" boolean NOT NULL, + "AbuseEmail" varchar(255) NOT NULL, + "EstateOwner" uuid NOT NULL, + "DenyMinors" boolean NOT NULL + ); + +INSERT INTO Tmp_estate_settings ("EstateID", "EstateName", "AbuseEmailToEstateOwner", "DenyAnonymous", "ResetHomeOnTeleport", "FixedSun", "DenyTransacted", "BlockDwell", "DenyIdentified", "AllowVoice", "UseGlobalTime", "PricePerMeter", "TaxFree", "AllowDirectTeleport", "RedirectGridX", "RedirectGridY", "ParentEstateID", "SunPosition", "EstateSkipScripts", "BillableFactor", "PublicAccess", "AbuseEmail", "EstateOwner", "DenyMinors") + SELECT "EstateID", "EstateName", "AbuseEmailToEstateOwner", "DenyAnonymous", "ResetHomeOnTeleport", "FixedSun", "DenyTransacted", "BlockDwell", "DenyIdentified", "AllowVoice", "UseGlobalTime", "PricePerMeter", "TaxFree", "AllowDirectTeleport", "RedirectGridX", "RedirectGridY", "ParentEstateID", "SunPosition", "EstateSkipScripts", "BillableFactor", "PublicAccess", "AbuseEmail", cast("EstateOwner" as uuid), "DenyMinors" FROM estate_settings ; + +DROP TABLE estate_settings; + + +Alter table Tmp_estate_settings + rename to estate_settings; + + +Create index on estate_settings (lower("EstateName")); + +COMMIT; + + +:VERSION 9 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_estate_map + ( + "RegionID" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), + "EstateID" int NOT NULL + ); + +INSERT INTO Tmp_estate_map ("RegionID", "EstateID") + SELECT cast("RegionID" as uuid), "EstateID" FROM estate_map ; + +DROP TABLE estate_map; + +Alter table Tmp_estate_map + rename to estate_map; + +COMMIT; + +:VERSION 10 + +BEGIN TRANSACTION; +ALTER TABLE estate_settings ADD COLUMN "AllowLandmark" boolean NOT NULL default true; +ALTER TABLE estate_settings ADD COLUMN "AllowParcelChanges" boolean NOT NULL default true; +ALTER TABLE estate_settings ADD COLUMN "AllowSetHome" boolean NOT NULL default true; +COMMIT; + +:VERSION 11 + +Begin transaction; + + +Commit; + diff --git a/OpenSim/Data/PGSQL/Resources/FriendsStore.migrations b/OpenSim/Data/PGSQL/Resources/FriendsStore.migrations new file mode 100644 index 0000000..a87199b --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/FriendsStore.migrations @@ -0,0 +1,44 @@ +:VERSION 1 + +BEGIN TRANSACTION; + +CREATE TABLE Friends ( +"PrincipalID" uuid NOT NULL, +"Friend" varchar(255) NOT NULL, +"Flags" char(16) NOT NULL DEFAULT '0', +"Offered" varchar(32) NOT NULL DEFAULT 0); + + +COMMIT; + +:VERSION 2 + +BEGIN TRANSACTION; + +INSERT INTO Friends ("PrincipalID", "Friend", "Flags", "Offered") +SELECT "ownerID", "friendID", "friendPerms", 0 FROM userfriends; + +COMMIT; + +:VERSION 3 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_Friends + ("PrincipalID" varchar(255) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', + "Friend" varchar(255) NOT NULL, + "Flags" char(16) NOT NULL DEFAULT '0', + "Offered" varchar(32) NOT NULL DEFAULT 0) ; + +INSERT INTO Tmp_Friends ("PrincipalID", "Friend", "Flags", "Offered") + SELECT cast("PrincipalID" as varchar(255)), "Friend", "Flags", "Offered" FROM Friends ; + +DROP TABLE Friends; + +Alter table Tmp_Friends + rename to Friends; + +ALTER TABLE Friends ADD PRIMARY KEY("PrincipalID", "Friend"); + + +COMMIT; diff --git a/OpenSim/Data/PGSQL/Resources/GridStore.migrations b/OpenSim/Data/PGSQL/Resources/GridStore.migrations new file mode 100644 index 0000000..0ab8d2b --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/GridStore.migrations @@ -0,0 +1,242 @@ +:VERSION 1 + +BEGIN TRANSACTION; + +CREATE TABLE regions( + "regionHandle" varchar(255) NULL, + "regionName" varchar(255) NULL, + uuid varchar(255) NOT NULL PRIMARY KEY, + "regionRecvKey" varchar(255) NULL, + "regionSecret" varchar(255) NULL, + "regionSendKey" varchar(255) NULL, + "regionDataURI" varchar(255) NULL, + "serverIP" varchar(255) NULL, + "serverPort" varchar(255) NULL, + "serverURI" varchar(255) NULL, + "locX" varchar(255) NULL, + "locY" varchar(255) NULL, + "locZ" varchar(255) NULL, + "eastOverrideHandle" varchar(255) NULL, + "westOverrideHandle" varchar(255) NULL, + "southOverrideHandle" varchar(255) NULL, + "northOverrideHandle" varchar(255) NULL, + "regionAssetURI" varchar(255) NULL, + "regionAssetRecvKey" varchar(255) NULL, + "regionAssetSendKey" varchar(255) NULL, + "regionUserURI" varchar(255) NULL, + "regionUserRecvKey" varchar(255) NULL, + "regionUserSendKey" varchar(255) NULL, + "regionMapTexture" varchar(255) NULL, + "serverHttpPort" varchar(255) NULL, + "serverRemotingPort" varchar(255) NULL, + "owner_uuid" varchar(36) NULL +); + +COMMIT; + + +:VERSION 2 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_regions + ( + uuid varchar(36) NOT NULL, + "regionHandle" bigint NULL, + "regionName" varchar(20) NULL, + "regionRecvKey" varchar(128) NULL, + "regionSendKey" varchar(128) NULL, + "regionSecret" varchar(128) NULL, + "regionDataURI" varchar(128) NULL, + "serverIP" varchar(64) NULL, + "serverPort" int NULL, + "serverURI" varchar(255) NULL, + "locX" int NULL, + "locY" int NULL, + "locZ" int NULL, + "eastOverrideHandle" bigint NULL, + "westOverrideHandle" bigint NULL, + "southOverrideHandle" bigint NULL, + "northOverrideHandle" bigint NULL, + "regionAssetURI" varchar(255) NULL, + "regionAssetRecvKey" varchar(128) NULL, + "regionAssetSendKey" varchar(128) NULL, + "regionUserURI" varchar(255) NULL, + "regionUserRecvKey" varchar(128) NULL, + "regionUserSendKey" varchar(128) NULL, + "regionMapTexture" varchar(36) NULL, + "serverHttpPort" int NULL, + "serverRemotingPort" int NULL, + "owner_uuid" varchar(36) NULL, + "originUUID" varchar(36) NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000') + ); + +INSERT INTO Tmp_regions (uuid, "regionHandle", "regionName", "regionRecvKey", "regionSendKey", "regionSecret", "regionDataURI", "serverIP", "serverPort", "serverURI", "locX", "locY", "locZ", "eastOverrideHandle", "westOverrideHandle", "southOverrideHandle", "northOverrideHandle", "regionAssetURI", "regionAssetRecvKey", "regionAssetSendKey", "regionUserURI", "regionUserRecvKey", "regionUserSendKey", "regionMapTexture", "serverHttpPort", "serverRemotingPort", "owner_uuid") + SELECT cast(uuid as varchar(36)), cast("regionHandle" as bigint), cast("regionName" as varchar(20)), cast("regionRecvKey" as varchar(128)), cast("regionSendKey" as varchar(128)), cast("regionSecret" as varchar(128)), cast("regionDataURI" as varchar(128)), cast("serverIP" as varchar(64)), cast("serverPort" as int), "serverURI", cast("locX" as int), cast("locY" as int), cast("locZ" as int), cast("eastOverrideHandle" as bigint), cast("westOverrideHandle" as bigint), + cast("southOverrideHandle" as bigint), cast("northOverrideHandle" as bigint), "regionAssetURI", cast("regionAssetRecvKey" as varchar(128)), cast("regionAssetSendKey" as varchar(128)), "regionUserURI", cast("regionUserRecvKey" as varchar(128)), cast("regionUserSendKey" as varchar(128)), cast("regionMapTexture" as varchar(36)), + cast("serverHttpPort" as int), cast("serverRemotingPort" as int), "owner_uuid" + FROM regions; + +DROP TABLE regions; + +alter table Tmp_regions + rename to regions; + +COMMIT; + +:VERSION 3 + +BEGIN TRANSACTION; + +CREATE INDEX IX_regions_name ON regions + ( + "regionName" + ); + +CREATE INDEX IX_regions_handle ON regions + ( + "regionHandle" + ); + + +CREATE INDEX IX_regions_override ON regions + ( + "eastOverrideHandle", + "westOverrideHandle", + "southOverrideHandle", + "northOverrideHandle" + ); + +COMMIT; + + +:VERSION 4 + +/* To prevent any potential data loss issues, you should review this script in detail before running it outside the cotext of the database designer.*/ +BEGIN TRANSACTION; + +CREATE TABLE Tmp_regions + ( + uuid uuid NOT NULL, + "regionHandle" bigint NULL, + "regionName" varchar(20) NULL, + "regionRecvKey" varchar(128) NULL, + "regionSendKey" varchar(128) NULL, + "regionSecret" varchar(128) NULL, + "regionDataURI" varchar(128) NULL, + "serverIP" varchar(64) NULL, + "serverPort" int NULL, + "serverURI" varchar(255) NULL, + "locX" int NULL, + "locY" int NULL, + "locZ" int NULL, + "eastOverrideHandle" bigint NULL, + "westOverrideHandle" bigint NULL, + "southOverrideHandle" bigint NULL, + "northOverrideHandle" bigint NULL, + "regionAssetURI" varchar(255) NULL, + "regionAssetRecvKey" varchar(128) NULL, + "regionAssetSendKey" varchar(128) NULL, + "regionUserURI" varchar(255) NULL, + "regionUserRecvKey" varchar(128) NULL, + "regionUserSendKey" varchar(128) NULL, + "regionMapTexture" uuid NULL, + "serverHttpPort" int NULL, + "serverRemotingPort" int NULL, + "owner_uuid" uuid NOT NULL, + "originUUID" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000') + ); + + +INSERT INTO Tmp_regions (uuid, "regionHandle", "regionName", "regionRecvKey", "regionSendKey", "regionSecret", "regionDataURI", "serverIP", "serverPort", "serverURI", "locX", "locY", "locZ", "eastOverrideHandle", "westOverrideHandle", "southOverrideHandle", "northOverrideHandle", "regionAssetURI", "regionAssetRecvKey", "regionAssetSendKey", "regionUserURI", "regionUserRecvKey", "regionUserSendKey", "regionMapTexture", "serverHttpPort", "serverRemotingPort", "owner_uuid", "originUUID") + SELECT cast(uuid as uuid), "regionHandle", "regionName", "regionRecvKey", "regionSendKey", "regionSecret", "regionDataURI", "serverIP", "serverPort", "serverURI", "locX", "locY", "locZ", "eastOverrideHandle", "westOverrideHandle", "southOverrideHandle", "northOverrideHandle", "regionAssetURI", "regionAssetRecvKey", "regionAssetSendKey", "regionUserURI", "regionUserRecvKey", "regionUserSendKey", cast("regionMapTexture" as uuid), "serverHttpPort", "serverRemotingPort", cast( "owner_uuid" as uuid), cast("originUUID" as uuid) FROM regions ; + + +DROP TABLE regions; + +alter table Tmp_regions rename to regions; + +ALTER TABLE regions ADD CONSTRAINT + PK__regions__uuid PRIMARY KEY + ( + uuid + ); + +CREATE INDEX IX_regions_name ON regions + ( + "regionName" + ); + +CREATE INDEX IX_regions_handle ON regions + ( + "regionHandle" + ); + +CREATE INDEX IX_regions_override ON regions + ( + "eastOverrideHandle", + "westOverrideHandle", + "southOverrideHandle", + "northOverrideHandle" + ); + +COMMIT; + + +:VERSION 5 + +BEGIN TRANSACTION; + +ALTER TABLE regions ADD access int default 0; + +COMMIT; + + +:VERSION 6 + +BEGIN TRANSACTION; + +ALTER TABLE regions ADD "ScopeID" uuid default '00000000-0000-0000-0000-000000000000'; +ALTER TABLE regions alter column "owner_uuid" set DEFAULT ('00000000-0000-0000-0000-000000000000'); +ALTER TABLE regions ADD "sizeX" integer not null default 0; +ALTER TABLE regions ADD "sizeY" integer not null default 0; + +COMMIT; + + +:VERSION 7 + +BEGIN TRANSACTION; + +ALTER TABLE regions ADD "flags" integer NOT NULL DEFAULT 0; +CREATE INDEX flags ON regions("flags"); +ALTER TABLE regions ADD "last_seen" integer NOT NULL DEFAULT 0; +ALTER TABLE regions ADD "PrincipalID" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'; +ALTER TABLE regions ADD "Token" varchar(255) NOT NULL DEFAULT 0; + +COMMIT; + +:VERSION 8 + +BEGIN TRANSACTION; +ALTER TABLE regions ALTER COLUMN "regionName" type VarChar(128) ; + +DROP INDEX IX_regions_name; +ALTER TABLE regions ALTER COLUMN "regionName" type VarChar(128), + ALTER COLUMN "regionName" SET NOT NULL; + +CREATE INDEX IX_regions_name ON regions + ( + "regionName" + ); + +COMMIT; + +:VERSION 9 + +BEGIN TRANSACTION; + +ALTER TABLE regions ADD "parcelMapTexture" uuid NULL; + +COMMIT; + diff --git a/OpenSim/Data/PGSQL/Resources/GridUserStore.migrations b/OpenSim/Data/PGSQL/Resources/GridUserStore.migrations new file mode 100644 index 0000000..d37c4f6d --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/GridUserStore.migrations @@ -0,0 +1,60 @@ +:VERSION 1 # -------------------------- + +BEGIN TRANSACTION; + +CREATE TABLE GridUser ( + "UserID" VARCHAR(255) NOT NULL Primary Key, + "HomeRegionID" CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', + "HomePosition" CHAR(64) NOT NULL DEFAULT '<0,0,0>', + "HomeLookAt" CHAR(64) NOT NULL DEFAULT '<0,0,0>', + "LastRegionID" CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', + "LastPosition" CHAR(64) NOT NULL DEFAULT '<0,0,0>', + "LastLookAt" CHAR(64) NOT NULL DEFAULT '<0,0,0>', + "Online" CHAR(5) NOT NULL DEFAULT 'false', + "Login" CHAR(16) NOT NULL DEFAULT '0', + "Logout" CHAR(16) NOT NULL DEFAULT '0' +) ; + +COMMIT; + +:VERSION 2 # -------------------------- + +BEGIN TRANSACTION; + +CREATE TABLE GridUser_tmp ( + "UserID" VARCHAR(255) NOT NULL PRIMARY KEY, + "HomeRegionID" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', + "HomePosition" CHAR(64) NOT NULL DEFAULT '<0,0,0>', + "HomeLookAt" CHAR(64) NOT NULL DEFAULT '<0,0,0>', + "LastRegionID" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', + "LastPosition" CHAR(64) NOT NULL DEFAULT '<0,0,0>', + "LastLookAt" CHAR(64) NOT NULL DEFAULT '<0,0,0>', + "Online" CHAR(5) NOT NULL DEFAULT 'false', + "Login" CHAR(16) NOT NULL DEFAULT '0', + "Logout" CHAR(16) NOT NULL DEFAULT '0' + ); + +COMMIT; + + +INSERT INTO GridUser_tmp ("UserID" + ,"HomeRegionID" + ,"HomePosition" + ,"HomeLookAt" + ,"LastRegionID" + ,"LastPosition" + ,"LastLookAt" + ,"Online" + ,"Login" + ,"Logout") + SELECT "UserID", cast("HomeRegionID" as uuid), "HomePosition" ,"HomeLookAt" , cast("LastRegionID" as uuid), + "LastPosition" + ,"LastLookAt" + ,"Online" + ,"Login" + ,"Logout" FROM GridUser; + +DROP TABLE GridUser; + +alter table GridUser_tmp rename to GridUser; + diff --git a/OpenSim/Data/PGSQL/Resources/HGTravelStore.migrations b/OpenSim/Data/PGSQL/Resources/HGTravelStore.migrations new file mode 100644 index 0000000..adf126d --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/HGTravelStore.migrations @@ -0,0 +1,17 @@ +:VERSION 1 # -------------------------- + +BEGIN; + +CREATE TABLE hg_traveling_data ( + "SessionID" VARCHAR(36) NOT NULL Primary Key, + "UserID" VARCHAR(36) NOT NULL, + "GridExternalName" VARCHAR(255) NOT NULL DEFAULT '', + "ServiceToken" VARCHAR(255) NOT NULL DEFAULT '', + "ClientIPAddress" VARCHAR(16) NOT NULL DEFAULT '', + "MyIPAddress" VARCHAR(16) NOT NULL DEFAULT '', + "TMStamp" timestamp NOT NULL default now() +); + + +COMMIT; + diff --git a/OpenSim/Data/PGSQL/Resources/IM_Store.migrations b/OpenSim/Data/PGSQL/Resources/IM_Store.migrations new file mode 100644 index 0000000..eb97824 --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/IM_Store.migrations @@ -0,0 +1,45 @@ +:VERSION 1 # -------------------------- + +BEGIN Transaction; + +Create Sequence im_offiline_id increment by 1 start with 1; + +CREATE TABLE im_offline ( + "ID" integer PRIMARY KEY NOT NULL DEFAULT nextval('im_offiline_id') , + "PrincipalID" char(36) NOT NULL default '', + "Message" text NOT NULL, + "TMStamp" timestamp NOT NULL default now() +); + +COMMIT; + +:VERSION 2 # -------------------------- + +BEGIN; + +/* +INSERT INTO `im_offline` SELECT * from `diva_im_offline`; +DROP TABLE `diva_im_offline`; +DELETE FROM `migrations` WHERE name='diva_im_Store'; +*/ + +COMMIT; + +:VERSION 3 # -------------------------- + +BEGIN; + +-- dropping the table here as there most likely is only one record in the table at the time of migration + +DROP TABLE IF EXISTS "public"."im_offline"; +CREATE TABLE "public"."im_offline" ( + "ID" serial, + "PrincipalID" uuid NOT NULL, + "Message" text NOT NULL COLLATE "default", + "TMStamp" timestamp(6) NOT NULL DEFAULT clock_timestamp(), + "FromID" uuid NOT NULL +) +WITH (OIDS=FALSE); +ALTER TABLE "public"."im_offline" ADD PRIMARY KEY ("ID","PrincipalID","FromID") NOT DEFERRABLE INITIALLY IMMEDIATE; + +COMMIT; \ No newline at end of file diff --git a/OpenSim/Data/PGSQL/Resources/InventoryStore.migrations b/OpenSim/Data/PGSQL/Resources/InventoryStore.migrations new file mode 100644 index 0000000..8f7982a --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/InventoryStore.migrations @@ -0,0 +1,220 @@ +:VERSION 1 + +BEGIN TRANSACTION; + +CREATE TABLE inventoryfolders ( + "folderID" varchar(36) NOT NULL default '' PRIMARY KEY, + "agentID" varchar(36) default NULL, + "parentFolderID" varchar(36) default NULL, + "folderName" varchar(64) default NULL, + "type" smallint NOT NULL default 0, + "version" int NOT NULL default 0 +); + + +CREATE INDEX owner ON inventoryfolders +( + "agentID" ASC +); + +CREATE INDEX parent ON inventoryfolders +( + "parentFolderID" ASC +); + + +CREATE TABLE inventoryitems ( + "inventoryID" varchar(36) NOT NULL default '' Primary Key, + "assetID" varchar(36) default NULL, + "assetType" int default NULL, + "parentFolderID" varchar(36) default NULL, + "avatarID" varchar(36) default NULL, + "inventoryName" varchar(64) default NULL, + "inventoryDescription" varchar(128) default NULL, + "inventoryNextPermissions" int default NULL, + "inventoryCurrentPermissions" int default NULL, + "invType" int default NULL, + "creatorID" varchar(36) default NULL, + "inventoryBasePermissions" int NOT NULL default 0, + "inventoryEveryOnePermissions" int NOT NULL default 0, + "salePrice" int default NULL, + "saleType" smallint default NULL, + "creationDate" int default NULL, + "groupID" varchar(36) default NULL, + "groupOwned" boolean default NULL, + "flags" int default NULL +); + + +CREATE INDEX ii_owner ON inventoryitems +( + "avatarID" ASC +); + +CREATE INDEX ii_folder ON inventoryitems +( + "parentFolderID" ASC +); + +COMMIT; + + +:VERSION 2 + +BEGIN TRANSACTION; + +ALTER TABLE inventoryitems ADD "inventoryGroupPermissions" INTEGER NOT NULL default 0; + +COMMIT; + +:VERSION 3 + +/* To prevent any potential data loss issues, you should review this script in detail before running it outside the cotext of the database designer.*/ +BEGIN TRANSACTION; + +CREATE TABLE Tmp_inventoryfolders + ( + "folderID" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), + "agentID" uuid NULL DEFAULT (NULL), + "parentFolderID" uuid NULL DEFAULT (NULL), + "folderName" varchar(64) NULL DEFAULT (NULL), + "type" smallint NOT NULL DEFAULT ((0)), + "version" int NOT NULL DEFAULT ((0)) + ); + + INSERT INTO Tmp_inventoryfolders ("folderID", "agentID", "parentFolderID", "folderName", type, version) + SELECT cast("folderID" as uuid), cast("agentID" as uuid), cast("parentFolderID" as uuid), "folderName", "type", "version" + FROM inventoryfolders; + +DROP TABLE inventoryfolders; + +alter table Tmp_inventoryfolders rename to inventoryfolders; + +ALTER TABLE inventoryfolders ADD CONSTRAINT + PK__inventor__C2FABFB3173876EA PRIMARY KEY + ( + "folderID" + ); + +CREATE INDEX owner ON inventoryfolders + ( + "agentID" + ); + +CREATE INDEX parent ON inventoryfolders + ( + "parentFolderID" + ); + +COMMIT; + + +:VERSION 4 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_inventoryitems + ( + "inventoryID" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), + "assetID" uuid NULL DEFAULT (NULL), + "assetType" int NULL DEFAULT (NULL), + "parentFolderID" uuid NULL DEFAULT (NULL), + "avatarID" uuid NULL DEFAULT (NULL), + "inventoryName" varchar(64) NULL DEFAULT (NULL), + "inventoryDescription" varchar(128) NULL DEFAULT (NULL), + "inventoryNextPermissions" int NULL DEFAULT (NULL), + "inventoryCurrentPermissions" int NULL DEFAULT (NULL), + "invType" int NULL DEFAULT (NULL), + "creatorID" uuid NULL DEFAULT (NULL), + "inventoryBasePermissions" int NOT NULL DEFAULT ((0)), + "inventoryEveryOnePermissions" int NOT NULL DEFAULT ((0)), + "salePrice" int NULL DEFAULT (NULL), + "SaleType" smallint NULL DEFAULT (NULL), + "creationDate" int NULL DEFAULT (NULL), + "groupID" uuid NULL DEFAULT (NULL), + "groupOwned" boolean NULL DEFAULT (NULL), + "flags" int NULL DEFAULT (NULL), + "inventoryGroupPermissions" int NOT NULL DEFAULT ((0)) + ); + + + INSERT INTO Tmp_inventoryitems ("inventoryID", "assetID", "assetType", "parentFolderID", "avatarID", "inventoryName", "inventoryDescription", "inventoryNextPermissions", "inventoryCurrentPermissions", "invType", "creatorID", "inventoryBasePermissions", "inventoryEveryOnePermissions", "salePrice", "SaleType", "creationDate", "groupID", "groupOwned", "flags", "inventoryGroupPermissions") + SELECT cast("inventoryID" as uuid), cast("assetID" as uuid), "assetType", cast("parentFolderID" as uuid), cast("avatarID" as uuid), "inventoryName", "inventoryDescription", "inventoryNextPermissions", "inventoryCurrentPermissions", "invType", cast("creatorID" as uuid), "inventoryBasePermissions", "inventoryEveryOnePermissions", "salePrice", "SaleType", "creationDate", cast("groupID" as uuid), "groupOwned", "flags", "inventoryGroupPermissions" + FROM inventoryitems ; + +DROP TABLE inventoryitems; + +alter table Tmp_inventoryitems rename to inventoryitems; + +ALTER TABLE inventoryitems ADD CONSTRAINT + PK__inventor__C4B7BC2220C1E124 PRIMARY KEY + ( + "inventoryID" + ); + + +CREATE INDEX ii2_owner ON inventoryitems + ( + "avatarID" + ); + +CREATE INDEX ii2_folder ON inventoryitems + ( + "parentFolderID" + ); + +COMMIT; + +:VERSION 5 + + +BEGIN TRANSACTION; + +-- # Restoring defaults: +-- # NOTE: "inventoryID" does NOT need one: it's NOT NULL PK and a unique Guid must be provided every time anyway! + +alter table inventoryitems + alter column "inventoryBasePermissions" set default 0; +alter table inventoryitems + alter column "inventoryEveryOnePermissions" set default 0; +alter table inventoryitems + alter column "inventoryGroupPermissions" set default 0 ; + +COMMIT ; + +:VERSION 7 + +BEGIN TRANSACTION; + +-- # "creatorID" goes back to VARCHAR(36) (???) + +alter table inventoryitems + alter column "creatorID" type varchar(36); + +COMMIT ; + +:VERSION 8 + +ALTER TABLE inventoryitems + alter column "creatorID" set DEFAULT '00000000-0000-0000-0000-000000000000'; + + +:VERSION 9 + +BEGIN TRANSACTION; + +--# "creatorID" goes up to VARCHAR(255) + +alter table inventoryitems + alter column "creatorID" type varchar(255); + +Commit; + +:VERSION 10 + +BEGIN TRANSACTION; + +Alter table inventoryitems Rename Column "SaleType" to "saleType"; + +Commit; + diff --git a/OpenSim/Data/PGSQL/Resources/LogStore.migrations b/OpenSim/Data/PGSQL/Resources/LogStore.migrations new file mode 100644 index 0000000..83727c6 --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/LogStore.migrations @@ -0,0 +1,16 @@ +:VERSION 1 + +BEGIN TRANSACTION; + +CREATE TABLE logs ( + "logID" int NOT NULL Primary Key, + "target" varchar(36) default NULL, + "server" varchar(64) default NULL, + "method" varchar(64) default NULL, + "arguments" varchar(255) default NULL, + "priority" int default NULL, + "message" text +); + +COMMIT; + diff --git a/OpenSim/Data/PGSQL/Resources/Presence.migrations b/OpenSim/Data/PGSQL/Resources/Presence.migrations new file mode 100755 index 0000000..5184034 --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/Presence.migrations @@ -0,0 +1,42 @@ +:VERSION 1 + +BEGIN TRANSACTION; + +CREATE TABLE Presence ( +"UserID" varchar(255) NOT NULL, +"RegionID" uuid NOT NULL, +"SessionID" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', +"SecureSessionID" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000' +); + + +COMMIT; + +:VERSION 2 + +BEGIN TRANSACTION; + +CREATE UNIQUE INDEX SessionID ON Presence("SessionID"); +CREATE INDEX UserID ON Presence("UserID"); + +ALTER TABLE Presence ADD "LastSeen" Timestamp; + +COMMIT; + +:VERSION 3 # -------------------------- + +BEGIN; + +CREATE INDEX RegionID ON Presence("RegionID"); + +COMMIT; + +:VERSION 4 # Making sure LastSeen is actually defined in the table as it most likely erred in the double version 2 migration above + +BEGIN; + +ALTER TABLE Presence +DROP COLUMN IF EXISTS "LastSeen", +ADD COLUMN "LastSeen" Timestamp; + +COMMIT; \ No newline at end of file diff --git a/OpenSim/Data/PGSQL/Resources/RegionStore.migrations b/OpenSim/Data/PGSQL/Resources/RegionStore.migrations new file mode 100644 index 0000000..1284ce0 --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/RegionStore.migrations @@ -0,0 +1,1162 @@ +begin transaction ; +:VERSION 1 + +CREATE TABLE prims( + "UUID" varchar(255) NOT NULL Primary key, + "RegionUUID" varchar(255) NULL, + "ParentID" int NULL, + "CreationDate" int NULL, + "Name" varchar(255) NULL, + "SceneGroupID" varchar(255) NULL, + "Text" varchar(255) NULL, + "Description" varchar(255) NULL, + "SitName" varchar(255) NULL, + "TouchName" varchar(255) NULL, + "ObjectFlags" int NULL, + "CreatorID" varchar(255) NULL, + "OwnerID" varchar(255) NULL, + "GroupID" varchar(255) NULL, + "LastOwnerID" varchar(255) NULL, + "OwnerMask" int NULL, + "NextOwnerMask" int NULL, + "GroupMask" int NULL, + "EveryoneMask" int NULL, + "BaseMask" int NULL, + "PositionX" double precision NULL, + "PositionY" double precision NULL, + "PositionZ" double precision NULL, + "GroupPositionX" double precision NULL, + "GroupPositionY" double precision NULL, + "GroupPositionZ" double precision NULL, + "VelocityX" double precision NULL, + "VelocityY" double precision NULL, + "VelocityZ" double precision NULL, + "AngularVelocityX" double precision NULL, + "AngularVelocityY" double precision NULL, + "AngularVelocityZ" double precision NULL, + "AccelerationX" double precision NULL, + "AccelerationY" double precision NULL, + "AccelerationZ" double precision NULL, + "RotationX" double precision NULL, + "RotationY" double precision NULL, + "RotationZ" double precision NULL, + "RotationW" double precision NULL, + "SitTargetOffsetX" double precision NULL, + "SitTargetOffsetY" double precision NULL, + "SitTargetOffsetZ" double precision NULL, + "SitTargetOrientW" double precision NULL, + "SitTargetOrientX" double precision NULL, + "SitTargetOrientY" double precision NULL, + "SitTargetOrientZ" double precision NULL + ); + +CREATE TABLE primshapes( + "UUID" varchar(255) NOT NULL primary key, + "Shape" int NULL, + "ScaleX" double precision NULL, + "ScaleY" double precision NULL, + "ScaleZ" double precision NULL, + "PCode" int NULL, + "PathBegin" int NULL, + "PathEnd" int NULL, + "PathScaleX" int NULL, + "PathScaleY" int NULL, + "PathShearX" int NULL, + "PathShearY" int NULL, + "PathSkew" int NULL, + "PathCurve" int NULL, + "PathRadiusOffset" int NULL, + "PathRevolutions" int NULL, + "PathTaperX" int NULL, + "PathTaperY" int NULL, + "PathTwist" int NULL, + "PathTwistBegin" int NULL, + "ProfileBegin" int NULL, + "ProfileEnd" int NULL, + "ProfileCurve" int NULL, + "ProfileHollow" int NULL, + "State" int NULL, + "Texture" bytea NULL, + "ExtraParams" bytea NULL + ); + +CREATE TABLE primitems( + "itemID" varchar(255) NOT NULL primary key, + "primID" varchar(255) NULL, + "assetID" varchar(255) NULL, + "parentFolderID" varchar(255) NULL, + "invType" int NULL, + "assetType" int NULL, + "name" varchar(255) NULL, + "description" varchar(255) NULL, + "creationDate" varchar(255) NULL, + "creatorID" varchar(255) NULL, + "ownerID" varchar(255) NULL, + "lastOwnerID" varchar(255) NULL, + "groupID" varchar(255) NULL, + "nextPermissions" int NULL, + "currentPermissions" int NULL, + "basePermissions" int NULL, + "everyonePermissions" int NULL, + "groupPermissions" int NULL + ); + +CREATE TABLE terrain( + "RegionUUID" varchar(255) NULL, + "Revision" int NULL, + "Heightfield" bytea NULL +); + + +CREATE TABLE land( + "UUID" varchar(255) NOT NULL primary key, + "RegionUUID" varchar(255) NULL, + "LocalLandID" int NULL, + "Bitmap" bytea NULL, + "Name" varchar(255) NULL, + "Description" varchar(255) NULL, + "OwnerUUID" varchar(255) NULL, + "IsGroupOwned" boolean NULL, + "Area" int NULL, + "AuctionID" int NULL, + "Category" int NULL, + "ClaimDate" int NULL, + "ClaimPrice" int NULL, + "GroupUUID" varchar(255) NULL, + "SalePrice" int NULL, + "LandStatus" int NULL, + "LandFlags" int NULL, + "LandingType" int NULL, + "MediaAutoScale" int NULL, + "MediaTextureUUID" varchar(255) NULL, + "MediaURL" varchar(255) NULL, + "MusicURL" varchar(255) NULL, + "PassHours" double precision NULL, + "PassPrice" int NULL, + "SnapshotUUID" varchar(255) NULL, + "UserLocationX" double precision NULL, + "UserLocationY" double precision NULL, + "UserLocationZ" double precision NULL, + "UserLookAtX" double precision NULL, + "UserLookAtY" double precision NULL, + "UserLookAtZ" double precision NULL +); + +Create index on land (lower("Name")); + +CREATE TABLE landaccesslist( + "LandUUID" varchar(255) NULL, + "AccessUUID" varchar(255) NULL, + "Flags" int NULL +); + +COMMIT; + +:VERSION 2 + +BEGIN TRANSACTION; + +CREATE TABLE regionban ( + "regionUUID" VARCHAR(36) NOT NULL, + "bannedUUID" VARCHAR(36) NOT NULL, + "bannedIp" VARCHAR(16) NOT NULL, + "bannedIpHostMask" VARCHAR(16) NOT NULL + ); + +create table regionsettings ( + "regionUUID" varchar(36) not null primary key, + "block_terraform" boolean not null, + "block_fly" boolean not null, + "allow_damage" boolean not null, + "restrict_pushing" boolean not null, + "allow_land_resell" boolean not null, + "allow_land_join_divide" boolean not null, + "block_show_in_search" boolean not null, + "agent_limit" int not null, + "object_bonus" double precision not null, + "maturity" int not null, + "disable_scripts" boolean not null, + "disable_collisions" boolean not null, + "disable_physics" boolean not null, + "terrain_texture_1" varchar(36) not null, + "terrain_texture_2" varchar(36) not null, + "terrain_texture_3" varchar(36) not null, + "terrain_texture_4" varchar(36) not null, + "elevation_1_nw" double precision not null, + "elevation_2_nw" double precision not null, + "elevation_1_ne" double precision not null, + "elevation_2_ne" double precision not null, + "elevation_1_se" double precision not null, + "elevation_2_se" double precision not null, + "elevation_1_sw" double precision not null, + "elevation_2_sw" double precision not null, + "water_height" double precision not null, + "terrain_raise_limit" double precision not null, + "terrain_lower_limit" double precision not null, + "use_estate_sun" boolean not null, + "fixed_sun" boolean not null, + "sun_position" double precision not null, + "covenant" varchar(36) default NULL, + "Sandbox" boolean NOT NULL + ); + +COMMIT; + +:VERSION 3 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_prims + ( + "UUID" varchar(36) NOT NULL , + "RegionUUID" varchar(36) NULL, + "ParentID" int NULL, + "CreationDate" int NULL, + "Name" varchar(255) NULL, + "SceneGroupID" varchar(36) NULL, + "Text" varchar(255) NULL, + "Description" varchar(255) NULL, + "SitName" varchar(255) NULL, + "TouchName" varchar(255) NULL, + "ObjectFlags" int NULL, + "CreatorID" varchar(36) NULL, + "OwnerID" varchar(36) NULL, + "GroupID" varchar(36) NULL, + "LastOwnerID" varchar(36) NULL, + "OwnerMask" int NULL, + "NextOwnerMask" int NULL, + "GroupMask" int NULL, + "EveryoneMask" int NULL, + "BaseMask" int NULL, + "PositionX" double precision NULL, + "PositionY" double precision NULL, + "PositionZ" double precision NULL, + "GroupPositionX" double precision NULL, + "GroupPositionY" double precision NULL, + "GroupPositionZ" double precision NULL, + "VelocityX" double precision NULL, + "VelocityY" double precision NULL, + "VelocityZ" double precision NULL, + "AngularVelocityX" double precision NULL, + "AngularVelocityY" double precision NULL, + "AngularVelocityZ" double precision NULL, + "AccelerationX" double precision NULL, + "AccelerationY" double precision NULL, + "AccelerationZ" double precision NULL, + "RotationX" double precision NULL, + "RotationY" double precision NULL, + "RotationZ" double precision NULL, + "RotationW" double precision NULL, + "SitTargetOffsetX" double precision NULL, + "SitTargetOffsetY" double precision NULL, + "SitTargetOffsetZ" double precision NULL, + "SitTargetOrientW" double precision NULL, + "SitTargetOrientX" double precision NULL, + "SitTargetOrientY" double precision NULL, + "SitTargetOrientZ" double precision NULL + ); + +INSERT INTO Tmp_prims ("UUID", "RegionUUID", "ParentID", "CreationDate", "Name", "SceneGroupID", "Text", "Description", "SitName", "TouchName", "ObjectFlags", "CreatorID", "OwnerID", "GroupID", "LastOwnerID", "OwnerMask", "NextOwnerMask", "GroupMask", "EveryoneMask", "BaseMask", "PositionX", "PositionY", "PositionZ", "GroupPositionX", "GroupPositionY", "GroupPositionZ", "VelocityX", "VelocityY", "VelocityZ", "AngularVelocityX", "AngularVelocityY", "AngularVelocityZ", "AccelerationX", "AccelerationY", "AccelerationZ", "RotationX", "RotationY", "RotationZ", "RotationW", "SitTargetOffsetX", "SitTargetOffsetY", "SitTargetOffsetZ", "SitTargetOrientW", "SitTargetOrientX", "SitTargetOrientY", "SitTargetOrientZ") + SELECT cast("UUID" as varchar(36)), cast("RegionUUID" as varchar(36)), "ParentID", "CreationDate", "Name", cast("SceneGroupID" as varchar(36)), "Text", "Description", "SitName", "TouchName", "ObjectFlags", cast("CreatorID" as varchar(36)), cast("OwnerID" as varchar(36)), cast( "GroupID" as varchar(36)), cast("LastOwnerID" as varchar(36)), "OwnerMask", "NextOwnerMask", "GroupMask", "EveryoneMask", "BaseMask", "PositionX", "PositionY", "PositionZ", "GroupPositionX", "GroupPositionY", "GroupPositionZ", "VelocityX", "VelocityY", "VelocityZ", "AngularVelocityX", "AngularVelocityY", "AngularVelocityZ", "AccelerationX", "AccelerationY", "AccelerationZ", "RotationX", "RotationY", "RotationZ", "RotationW", "SitTargetOffsetX", "SitTargetOffsetY", "SitTargetOffsetZ", "SitTargetOrientW", "SitTargetOrientX", "SitTargetOrientY", "SitTargetOrientZ" + FROM prims ; + +DROP TABLE prims; + +alter table Tmp_prims rename to prims; + + +ALTER TABLE prims ADD CONSTRAINT + PK__prims__10566F31 PRIMARY KEY + ( + "UUID" + ); + +COMMIT; + +:VERSION 4 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_primitems + ( + "itemID" varchar(36) NOT NULL, + "primID" varchar(36) NULL, + "assetID" varchar(36) NULL, + "parentFolderID" varchar(36) NULL, + "invType" int NULL, + "assetType" int NULL, + "name" varchar(255) NULL, + "description" varchar(255) NULL, + "creationDate" varchar(255) NULL, + "creatorID" varchar(36) NULL, + "ownerID" varchar(36) NULL, + "lastOwnerID" varchar(36) NULL, + "groupID" varchar(36) NULL, + "nextPermissions" int NULL, + "currentPermissions" int NULL, + "basePermissions" int NULL, + "everyonePermissions" int NULL, + "groupPermissions" int NULL + ); + +INSERT INTO Tmp_primitems ("itemID", "primID", "assetID", "parentFolderID", "invType", "assetType", "name", "description", "creationDate", "creatorID", "ownerID", "lastOwnerID", "groupID", "nextPermissions", "currentPermissions", "basePermissions", "everyonePermissions", "groupPermissions") + SELECT cast("itemID" as varchar(36)), cast("primID" as varchar(36)), cast("assetID" as varchar(36)), cast( "parentFolderID" as varchar(36)), "invType", "assetType", "name", "description", "creationDate", cast( "creatorID" as varchar(36)), cast("ownerID" as varchar(36)), cast("lastOwnerID" as varchar(36)), cast("groupID" as varchar(36)), "nextPermissions", "currentPermissions", "basePermissions", "everyonePermissions", "groupPermissions" + from primitems; + +DROP TABLE primitems; + +alter table Tmp_primitems rename to primitems; + +ALTER TABLE primitems ADD CONSTRAINT + PK__primitems__0A688BB1 PRIMARY KEY + ( + "itemID" + ); + + +COMMIT; + + +:VERSION 5 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_primshapes + ( + "UUID" varchar(36) NOT NULL, + "Shape" int NULL, + "ScaleX" double precision NULL, + "ScaleY" double precision NULL, + "ScaleZ" double precision NULL, + "PCode" int NULL, + "PathBegin" int NULL, + "PathEnd" int NULL, + "PathScaleX" int NULL, + "PathScaleY" int NULL, + "PathShearX" int NULL, + "PathShearY" int NULL, + "PathSkew" int NULL, + "PathCurve" int NULL, + "PathRadiusOffset" int NULL, + "PathRevolutions" int NULL, + "PathTaperX" int NULL, + "PathTaperY" int NULL, + "PathTwist" int NULL, + "PathTwistBegin" int NULL, + "ProfileBegin" int NULL, + "ProfileEnd" int NULL, + "ProfileCurve" int NULL, + "ProfileHollow" int NULL, + "State" int NULL, + "Texture" bytea NULL, + "ExtraParams" bytea NULL + ) ; + +INSERT INTO Tmp_primshapes ("UUID", "Shape", "ScaleX", "ScaleY", "ScaleZ", "PCode", "PathBegin", "PathEnd", "PathScaleX", "PathScaleY", "PathShearX", "PathShearY", "PathSkew", "PathCurve", "PathRadiusOffset", "PathRevolutions", "PathTaperX", "PathTaperY", "PathTwist", "PathTwistBegin", "ProfileBegin", "ProfileEnd", "ProfileCurve", "ProfileHollow", "State", "Texture", "ExtraParams") + SELECT cast("UUID" as varchar(36)), "Shape", "ScaleX", "ScaleY", "ScaleZ", "PCode", "PathBegin", "PathEnd", "PathScaleX", "PathScaleY", "PathShearX", "PathShearY", "PathSkew", "PathCurve", "PathRadiusOffset", "PathRevolutions", "PathTaperX", "PathTaperY", "PathTwist", "PathTwistBegin", "ProfileBegin", "ProfileEnd", "ProfileCurve", "ProfileHollow", "State", "Texture", "ExtraParams" + FROM primshapes; + +DROP TABLE primshapes; + +alter table Tmp_primshapes rename to primshapes; + +ALTER TABLE primshapes ADD CONSTRAINT + PK__primshapes__0880433F PRIMARY KEY + ( + "UUID" + ) ; + +COMMIT; + + +:VERSION 6 + +BEGIN TRANSACTION; + +ALTER TABLE prims ADD "PayPrice" int not null default 0; +ALTER TABLE prims ADD "PayButton1" int not null default 0; +ALTER TABLE prims ADD "PayButton2" int not null default 0; +ALTER TABLE prims ADD "PayButton3" int not null default 0; +ALTER TABLE prims ADD "PayButton4" int not null default 0; +ALTER TABLE prims ADD "LoopedSound" varchar(36) not null default '00000000-0000-0000-0000-000000000000'; +ALTER TABLE prims ADD "LoopedSoundGain" double precision not null default 0.0; +ALTER TABLE prims ADD "TextureAnimation" bytea; +ALTER TABLE prims ADD "OmegaX" double precision not null default 0.0; +ALTER TABLE prims ADD "OmegaY" double precision not null default 0.0; +ALTER TABLE prims ADD "OmegaZ" double precision not null default 0.0; +ALTER TABLE prims ADD "CameraEyeOffsetX" double precision not null default 0.0; +ALTER TABLE prims ADD "CameraEyeOffsetY" double precision not null default 0.0; +ALTER TABLE prims ADD "CameraEyeOffsetZ" double precision not null default 0.0; +ALTER TABLE prims ADD "CameraAtOffsetX" double precision not null default 0.0; +ALTER TABLE prims ADD "CameraAtOffsetY" double precision not null default 0.0; +ALTER TABLE prims ADD "CameraAtOffsetZ" double precision not null default 0.0; +ALTER TABLE prims ADD "ForceMouselook" smallint not null default 0; +ALTER TABLE prims ADD "ScriptAccessPin" int not null default 0; +ALTER TABLE prims ADD "AllowedDrop" smallint not null default 0; +ALTER TABLE prims ADD "DieAtEdge" smallint not null default 0; +ALTER TABLE prims ADD "SalePrice" int not null default 10; +ALTER TABLE prims ADD "SaleType" smallint not null default 0; + +ALTER TABLE primitems add "flags" integer not null default 0; + +ALTER TABLE land ADD "AuthbuyerID" varchar(36) NOT NULL default '00000000-0000-0000-0000-000000000000'; + +CREATE index prims_regionuuid on prims("RegionUUID"); +CREATE index prims_parentid on prims("ParentID"); + +CREATE index primitems_primid on primitems("primID"); + +COMMIT; + + +:VERSION 7 + +BEGIN TRANSACTION; + +ALTER TABLE prims ADD "ColorR" int not null default 0; +ALTER TABLE prims ADD "ColorG" int not null default 0; +ALTER TABLE prims ADD "ColorB" int not null default 0; +ALTER TABLE prims ADD "ColorA" int not null default 0; +ALTER TABLE prims ADD "ParticleSystem" bytea; +ALTER TABLE prims ADD "ClickAction" smallint NOT NULL default 0; + +COMMIT; + + +:VERSION 8 + +BEGIN TRANSACTION; + +ALTER TABLE land ADD "OtherCleanTime" integer NOT NULL default 0; +ALTER TABLE land ADD "Dwell" integer NOT NULL default 0; + +COMMIT; + +:VERSION 9 + +BEGIN TRANSACTION; + +ALTER TABLE prims ADD "Material" smallint NOT NULL default 3; + +COMMIT; + + +:VERSION 10 + +BEGIN TRANSACTION; + +ALTER TABLE regionsettings ADD "sunvectorx" double precision NOT NULL default 0; +ALTER TABLE regionsettings ADD "sunvectory" double precision NOT NULL default 0; +ALTER TABLE regionsettings ADD "sunvectorz" double precision NOT NULL default 0; + +COMMIT; + + +:VERSION 11 + +BEGIN TRANSACTION; + +ALTER TABLE prims ADD "CollisionSound" char(36) not null default '00000000-0000-0000-0000-000000000000'; +ALTER TABLE prims ADD "CollisionSoundVolume" double precision not null default 0.0; + +COMMIT; + + +:VERSION 12 + +BEGIN TRANSACTION; + +ALTER TABLE prims ADD "LinkNumber" integer not null default 0; + +COMMIT; + + +:VERSION 13 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_prims + ( + "UUID" uuid NOT NULL, + "RegionUUID" uuid NULL, + "ParentID" int NULL, + "CreationDate" int NULL, + "Name" varchar(255) NULL, + "SceneGroupID" uuid NULL, + "Text" varchar(255) NULL, + "Description" varchar(255) NULL, + "SitName" varchar(255) NULL, + "TouchName" varchar(255) NULL, + "ObjectFlags" int NULL, + "CreatorID" uuid NULL, + "OwnerID" uuid NULL, + "GroupID" uuid NULL, + "LastOwnerID" uuid NULL, + "OwnerMask" int NULL, + "NextOwnerMask" int NULL, + "GroupMask" int NULL, + "EveryoneMask" int NULL, + "BaseMask" int NULL, + "PositionX" double precision NULL, + "PositionY" double precision NULL, + "PositionZ" double precision NULL, + "GroupPositionX" double precision NULL, + "GroupPositionY" double precision NULL, + "GroupPositionZ" double precision NULL, + "VelocityX" double precision NULL, + "VelocityY" double precision NULL, + "VelocityZ" double precision NULL, + "AngularVelocityX" double precision NULL, + "AngularVelocityY" double precision NULL, + "AngularVelocityZ" double precision NULL, + "AccelerationX" double precision NULL, + "AccelerationY" double precision NULL, + "AccelerationZ" double precision NULL, + "RotationX" double precision NULL, + "RotationY" double precision NULL, + "RotationZ" double precision NULL, + "RotationW" double precision NULL, + "SitTargetOffsetX" double precision NULL, + "SitTargetOffsetY" double precision NULL, + "SitTargetOffsetZ" double precision NULL, + "SitTargetOrientW" double precision NULL, + "SitTargetOrientX" double precision NULL, + "SitTargetOrientY" double precision NULL, + "SitTargetOrientZ" double precision NULL, + "PayPrice" int NOT NULL DEFAULT ((0)), + "PayButton1" int NOT NULL DEFAULT ((0)), + "PayButton2" int NOT NULL DEFAULT ((0)), + "PayButton3" int NOT NULL DEFAULT ((0)), + "PayButton4" int NOT NULL DEFAULT ((0)), + "LoopedSound" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), + "LoopedSoundGain" double precision NOT NULL DEFAULT ((0.0)), + "TextureAnimation" bytea NULL, + "OmegaX" double precision NOT NULL DEFAULT ((0.0)), + "OmegaY" double precision NOT NULL DEFAULT ((0.0)), + "OmegaZ" double precision NOT NULL DEFAULT ((0.0)), + "CameraEyeOffsetX" double precision NOT NULL DEFAULT ((0.0)), + "CameraEyeOffsetY" double precision NOT NULL DEFAULT ((0.0)), + "CameraEyeOffsetZ" double precision NOT NULL DEFAULT ((0.0)), + "CameraAtOffsetX" double precision NOT NULL DEFAULT ((0.0)), + "CameraAtOffsetY" double precision NOT NULL DEFAULT ((0.0)), + "CameraAtOffsetZ" double precision NOT NULL DEFAULT ((0.0)), + "ForceMouselook" smallint NOT NULL DEFAULT ((0)), + "ScriptAccessPin" int NOT NULL DEFAULT ((0)), + "AllowedDrop" smallint NOT NULL DEFAULT ((0)), + "DieAtEdge" smallint NOT NULL DEFAULT ((0)), + "SalePrice" int NOT NULL DEFAULT ((10)), + "SaleType" smallint NOT NULL DEFAULT ((0)), + "ColorR" int NOT NULL DEFAULT ((0)), + "ColorG" int NOT NULL DEFAULT ((0)), + "ColorB" int NOT NULL DEFAULT ((0)), + "ColorA" int NOT NULL DEFAULT ((0)), + "ParticleSystem" bytea NULL, + "ClickAction" smallint NOT NULL DEFAULT ((0)), + "Material" smallint NOT NULL DEFAULT ((3)), + "CollisionSound" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), + "CollisionSoundVolume" double precision NOT NULL DEFAULT ((0.0)), + "LinkNumber" int NOT NULL DEFAULT ((0)) + ); + +INSERT INTO Tmp_prims ("UUID", "RegionUUID", "ParentID", "CreationDate", "Name", "SceneGroupID", "Text", "Description", "SitName", "TouchName", "ObjectFlags", "CreatorID", "OwnerID", "GroupID", "LastOwnerID", "OwnerMask", "NextOwnerMask", "GroupMask", "EveryoneMask", "BaseMask", "PositionX", "PositionY", "PositionZ", "GroupPositionX", "GroupPositionY", "GroupPositionZ", "VelocityX", "VelocityY", "VelocityZ", "AngularVelocityX", "AngularVelocityY", "AngularVelocityZ", "AccelerationX", "AccelerationY", "AccelerationZ", "RotationX", "RotationY", "RotationZ", "RotationW", "SitTargetOffsetX", "SitTargetOffsetY", "SitTargetOffsetZ", "SitTargetOrientW", "SitTargetOrientX", "SitTargetOrientY", "SitTargetOrientZ", "PayPrice", "PayButton1", "PayButton2", "PayButton3", "PayButton4", "LoopedSound", "LoopedSoundGain", "TextureAnimation", "OmegaX", "OmegaY", "OmegaZ", "CameraEyeOffsetX", "CameraEyeOffsetY", "CameraEyeOffsetZ", "CameraAtOffsetX", "CameraAtOffsetY", "CameraAtOffsetZ", "ForceMouselook", "ScriptAccessPin", "AllowedDrop", "DieAtEdge", "SalePrice", "SaleType", "ColorR", "ColorG", "ColorB", "ColorA", "ParticleSystem", "ClickAction", "Material", "CollisionSound", "CollisionSoundVolume", "LinkNumber") + SELECT cast("UUID" as uuid), cast("RegionUUID" as uuid), "ParentID", "CreationDate", "Name", cast("SceneGroupID" as uuid), "Text", "Description", "SitName", "TouchName", "ObjectFlags", cast("CreatorID" as uuid), cast("OwnerID" as uuid), cast("GroupID" as uuid), cast("LastOwnerID" as uuid), "OwnerMask", "NextOwnerMask", "GroupMask", "EveryoneMask", "BaseMask", "PositionX", "PositionY", "PositionZ", "GroupPositionX", "GroupPositionY", "GroupPositionZ", "VelocityX", "VelocityY", "VelocityZ", "AngularVelocityX", "AngularVelocityY", "AngularVelocityZ", "AccelerationX", "AccelerationY", "AccelerationZ", "RotationX", "RotationY", "RotationZ", "RotationW", "SitTargetOffsetX", "SitTargetOffsetY", "SitTargetOffsetZ", "SitTargetOrientW", "SitTargetOrientX", "SitTargetOrientY", "SitTargetOrientZ", "PayPrice", "PayButton1", "PayButton2", "PayButton3", "PayButton4", cast("LoopedSound" as uuid), "LoopedSoundGain", "TextureAnimation", "OmegaX", "OmegaY", "OmegaZ", "CameraEyeOffsetX", "CameraEyeOffsetY", "CameraEyeOffsetZ", "CameraAtOffsetX", "CameraAtOffsetY", "CameraAtOffsetZ", "ForceMouselook", "ScriptAccessPin", "AllowedDrop", "DieAtEdge", "SalePrice", "SaleType", "ColorR", "ColorG", "ColorB", "ColorA", "ParticleSystem", "ClickAction", "Material", cast("CollisionSound" as uuid), "CollisionSoundVolume", "LinkNumber" + FROM prims ; + +DROP TABLE prims; + +alter table Tmp_prims rename to prims; + +ALTER TABLE prims ADD CONSTRAINT + PK__prims__10566F31 PRIMARY KEY + ( + "UUID" + ); + + +CREATE INDEX prims_regionuuid ON prims + ( + "RegionUUID" + ); + +CREATE INDEX prims_parentid ON prims + ( + "ParentID" + ); + +COMMIT; + + +:VERSION 14 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_primshapes + ( + "UUID" uuid NOT NULL, + "Shape" int NULL, + "ScaleX" double precision NULL, + "ScaleY" double precision NULL, + "ScaleZ" double precision NULL, + "PCode" int NULL, + "PathBegin" int NULL, + "PathEnd" int NULL, + "PathScaleX" int NULL, + "PathScaleY" int NULL, + "PathShearX" int NULL, + "PathShearY" int NULL, + "PathSkew" int NULL, + "PathCurve" int NULL, + "PathRadiusOffset" int NULL, + "PathRevolutions" int NULL, + "PathTaperX" int NULL, + "PathTaperY" int NULL, + "PathTwist" int NULL, + "PathTwistBegin" int NULL, + "ProfileBegin" int NULL, + "ProfileEnd" int NULL, + "ProfileCurve" int NULL, + "ProfileHollow" int NULL, + "State" int NULL, + "Texture" bytea NULL, + "ExtraParams" bytea NULL + ); + +INSERT INTO Tmp_primshapes ("UUID", "Shape", "ScaleX", "ScaleY", "ScaleZ", "PCode", "PathBegin", "PathEnd", "PathScaleX", "PathScaleY", "PathShearX", "PathShearY", "PathSkew", "PathCurve", "PathRadiusOffset", "PathRevolutions", "PathTaperX", "PathTaperY", "PathTwist", "PathTwistBegin", "ProfileBegin", "ProfileEnd", "ProfileCurve", "ProfileHollow", "State", "Texture", "ExtraParams") + SELECT cast("UUID" as uuid), "Shape", "ScaleX", "ScaleY", "ScaleZ", "PCode", "PathBegin", "PathEnd", "PathScaleX", "PathScaleY", "PathShearX", "PathShearY", "PathSkew", "PathCurve", "PathRadiusOffset", "PathRevolutions", "PathTaperX", "PathTaperY", "PathTwist", "PathTwistBegin", "ProfileBegin", "ProfileEnd", "ProfileCurve", "ProfileHollow", "State", "Texture", "ExtraParams" + FROM primshapes; + +DROP TABLE primshapes; + +alter table Tmp_primshapes rename to primshapes; + +ALTER TABLE primshapes ADD CONSTRAINT + PK__primshapes__0880433F PRIMARY KEY + ( + "UUID" + ); + +COMMIT; + + +:VERSION 15 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_primitems + ( + "itemID" uuid NOT NULL, + "primID" uuid NULL, + "assetID" uuid NULL, + "parentFolderID" uuid NULL, + "invType" int NULL, + "assetType" int NULL, + "name" varchar(255) NULL, + "description" varchar(255) NULL, + "creationDate" varchar(255) NULL, + "creatorID" uuid NULL, + "ownerID" uuid NULL, + "lastOwnerID" uuid NULL, + "groupID" uuid NULL, + "nextPermissions" int NULL, + "currentPermissions" int NULL, + "basePermissions" int NULL, + "everyonePermissions" int NULL, + "groupPermissions" int NULL, + flags int NOT NULL DEFAULT ((0)) + ); + +INSERT INTO Tmp_primitems ("itemID", "primID", "assetID", "parentFolderID", "invType", "assetType", "name", "description", "creationDate", "creatorID", "ownerID", "lastOwnerID", "groupID", "nextPermissions", "currentPermissions", "basePermissions", "everyonePermissions", "groupPermissions", flags) + SELECT cast("itemID" as uuid), cast("primID" as uuid), cast("assetID" as uuid), cast("parentFolderID" as uuid), "invType", "assetType", "name", "description", "creationDate", cast("creatorID" as uuid), cast("ownerID" as uuid), cast("lastOwnerID" as uuid), cast("groupID" as uuid), "nextPermissions", "currentPermissions", "basePermissions", "everyonePermissions", "groupPermissions", flags + FROM primitems ; + +DROP TABLE primitems; + +alter table Tmp_primitems rename to primitems; + +ALTER TABLE primitems ADD CONSTRAINT + PK__primitems__0A688BB1 PRIMARY KEY + ( + "itemID" + ); + +CREATE INDEX primitems_primid ON primitems + ( + "primID" + ) ; + +COMMIT; + + +:VERSION 16 + + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_terrain + ( + "RegionUUID" uuid NULL, + "Revision" int NULL, + "Heightfield" bytea NULL + ); + +INSERT INTO Tmp_terrain ("RegionUUID", "Revision", "Heightfield") + SELECT cast("RegionUUID" as uuid), "Revision", "Heightfield" + FROM terrain ; + +DROP TABLE terrain; + +alter table Tmp_terrain rename to terrain; + +COMMIT; + + +:VERSION 17 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_land + ( + "UUID" uuid NOT NULL, + "RegionUUID" uuid NULL, + "LocalLandID" int NULL, + "Bitmap" bytea NULL, + "Name" varchar(255) NULL, + "Description" varchar(255) NULL, + "OwnerUUID" uuid NULL, + "IsGroupOwned" boolean NULL, + "Area" int NULL, + "AuctionID" int NULL, + "Category" int NULL, + "ClaimDate" int NULL, + "ClaimPrice" int NULL, + "GroupUUID" uuid NULL, + "SalePrice" int NULL, + "LandStatus" int NULL, + "LandFlags" int NULL, + "LandingType" int NULL, + "MediaAutoScale" int NULL, + "MediaTextureUUID" uuid NULL, + "MediaURL" varchar(255) NULL, + "MusicURL" varchar(255) NULL, + "PassHours" double precision NULL, + "PassPrice" int NULL, + "SnapshotUUID" uuid NULL, + "UserLocationX" double precision NULL, + "UserLocationY" double precision NULL, + "UserLocationZ" double precision NULL, + "UserLookAtX" double precision NULL, + "UserLookAtY" double precision NULL, + "UserLookAtZ" double precision NULL, + "AuthbuyerID" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), + "OtherCleanTime" int NOT NULL DEFAULT ((0)), + "Dwell" int NOT NULL DEFAULT ((0)) + ); + +INSERT INTO Tmp_land ("UUID", "RegionUUID", "LocalLandID", "Bitmap", "Name", "Description", "OwnerUUID", "IsGroupOwned", "Area", "AuctionID", "Category", "ClaimDate", "ClaimPrice", "GroupUUID", "SalePrice", "LandStatus", "LandFlags", "LandingType", "MediaAutoScale", "MediaTextureUUID", "MediaURL", "MusicURL", "PassHours", "PassPrice", "SnapshotUUID", "UserLocationX", "UserLocationY", "UserLocationZ", "UserLookAtX", "UserLookAtY", "UserLookAtZ", "AuthbuyerID", "OtherCleanTime", "Dwell") + SELECT cast("UUID" as uuid), cast("RegionUUID" as uuid), "LocalLandID", "Bitmap", "Name", "Description", cast("OwnerUUID" as uuid), "IsGroupOwned", "Area", "AuctionID", "Category", "ClaimDate", "ClaimPrice", cast("GroupUUID" as uuid), "SalePrice", "LandStatus", "LandFlags", "LandingType", "MediaAutoScale", cast("MediaTextureUUID" as uuid), "MediaURL", "MusicURL", "PassHours", "PassPrice", cast("SnapshotUUID" as uuid), "UserLocationX", "UserLocationY", "UserLocationZ", "UserLookAtX", "UserLookAtY", "UserLookAtZ", cast("AuthbuyerID" as uuid), "OtherCleanTime", "Dwell" + FROM land ; + +DROP TABLE land; + +alter table Tmp_land rename to land; + +ALTER TABLE land ADD CONSTRAINT + PK__land__65A475E71BFD2C07 PRIMARY KEY + ( + "UUID" + ); + +Create index on land (lower("Name")); + +COMMIT; + + + +:VERSION 18 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_landaccesslist + ( + "LandUUID" uuid NULL, + "AccessUUID" uuid NULL, + "Flags" int NULL + ); + +INSERT INTO Tmp_landaccesslist ("LandUUID", "AccessUUID", "Flags") + SELECT cast("LandUUID" as uuid), cast("AccessUUID" as uuid), "Flags" + FROM landaccesslist ; + +DROP TABLE landaccesslist; + +alter table Tmp_landaccesslist rename to landaccesslist; + +COMMIT; + + + +:VERSION 19 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_regionban + ( + "regionUUID" uuid NOT NULL, + "bannedUUID" uuid NOT NULL, + "bannedIp" varchar(16) NOT NULL, + "bannedIpHostMask" varchar(16) NOT NULL + ); + +INSERT INTO Tmp_regionban ("regionUUID", "bannedUUID", "bannedIp", "bannedIpHostMask") + SELECT cast("regionUUID" as uuid), cast("bannedUUID" as uuid), "bannedIp", "bannedIpHostMask" + FROM regionban ; + +DROP TABLE regionban; + +alter table Tmp_regionban rename to regionban; + +COMMIT; + + +:VERSION 20 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_regionsettings + ( + "regionUUID" uuid NOT NULL, + "block_terraform" boolean NOT NULL, + "block_fly" boolean NOT NULL, + "allow_damage" boolean NOT NULL, + "restrict_pushing" boolean NOT NULL, + "allow_land_resell" boolean NOT NULL, + "allow_land_join_divide" boolean NOT NULL, + "block_show_in_search" boolean NOT NULL, + "agent_limit" int NOT NULL, + "object_bonus" double precision NOT NULL, + "maturity" int NOT NULL, + "disable_scripts" boolean NOT NULL, + "disable_collisions" boolean NOT NULL, + "disable_physics" boolean NOT NULL, + "terrain_texture_1" uuid NOT NULL, + "terrain_texture_2" uuid NOT NULL, + "terrain_texture_3" uuid NOT NULL, + "terrain_texture_4" uuid NOT NULL, + "elevation_1_nw" double precision NOT NULL, + "elevation_2_nw" double precision NOT NULL, + "elevation_1_ne" double precision NOT NULL, + "elevation_2_ne" double precision NOT NULL, + "elevation_1_se" double precision NOT NULL, + "elevation_2_se" double precision NOT NULL, + "elevation_1_sw" double precision NOT NULL, + "elevation_2_sw" double precision NOT NULL, + "water_height" double precision NOT NULL, + "terrain_raise_limit" double precision NOT NULL, + "terrain_lower_limit" double precision NOT NULL, + "use_estate_sun" boolean NOT NULL, + "fixed_sun" boolean NOT NULL, + "sun_position" double precision NOT NULL, + "covenant" uuid NULL DEFAULT (NULL), + "Sandbox" boolean NOT NULL, + "sunvectorx" double precision NOT NULL DEFAULT ((0)), + "sunvectory" double precision NOT NULL DEFAULT ((0)), + "sunvectorz" double precision NOT NULL DEFAULT ((0)) + ); + +INSERT INTO Tmp_regionsettings ("regionUUID", "block_terraform", "block_fly", "allow_damage", "restrict_pushing", "allow_land_resell", "allow_land_join_divide", "block_show_in_search", "agent_limit", "object_bonus", "maturity", "disable_scripts", "disable_collisions", "disable_physics", "terrain_texture_1", "terrain_texture_2", "terrain_texture_3", "terrain_texture_4", "elevation_1_nw", "elevation_2_nw", "elevation_1_ne", "elevation_2_ne", "elevation_1_se", "elevation_2_se", "elevation_1_sw", "elevation_2_sw", "water_height", "terrain_raise_limit", "terrain_lower_limit", "use_estate_sun", "fixed_sun", "sun_position", "covenant", "Sandbox", "sunvectorx", "sunvectory", "sunvectorz") + SELECT cast("regionUUID" as uuid), "block_terraform", "block_fly", "allow_damage", "restrict_pushing", "allow_land_resell", "allow_land_join_divide", "block_show_in_search", "agent_limit", "object_bonus", "maturity", "disable_scripts", "disable_collisions", "disable_physics", cast("terrain_texture_1" as uuid), cast("terrain_texture_2" as uuid), cast("terrain_texture_3" as uuid), cast("terrain_texture_4" as uuid), "elevation_1_nw", "elevation_2_nw", "elevation_1_ne", "elevation_2_ne", "elevation_1_se", "elevation_2_se", "elevation_1_sw", "elevation_2_sw", "water_height", "terrain_raise_limit", "terrain_lower_limit", "use_estate_sun", "fixed_sun", "sun_position", cast("covenant" as uuid), "Sandbox", "sunvectorx", "sunvectory", "sunvectorz" + FROM regionsettings ; + +DROP TABLE regionsettings; + +alter table Tmp_regionsettings rename to regionsettings; + +ALTER TABLE regionsettings ADD CONSTRAINT + PK__regionse__5B35159D21B6055D PRIMARY KEY + ( + "regionUUID" + ); + +COMMIT; + + +:VERSION 21 + +BEGIN TRANSACTION; + +ALTER TABLE prims ADD "PassTouches" boolean not null default false; + +COMMIT; + + +:VERSION 22 + +BEGIN TRANSACTION; + +ALTER TABLE regionsettings ADD "loaded_creation_date" varchar(20) ; +ALTER TABLE regionsettings ADD "loaded_creation_time" varchar(20) ; +ALTER TABLE regionsettings ADD "loaded_creation_id" varchar(64) ; + +COMMIT; + +:VERSION 23 + +BEGIN TRANSACTION; + +ALTER TABLE regionsettings DROP COLUMN "loaded_creation_date"; +ALTER TABLE regionsettings DROP COLUMN "loaded_creation_time"; +ALTER TABLE regionsettings ADD "loaded_creation_datetime" int NOT NULL default 0; + +COMMIT; + +:VERSION 24 + +BEGIN TRANSACTION; + +ALTER TABLE prims ADD "MediaURL" varchar(255); +ALTER TABLE primshapes ADD "Media" TEXT NULL; + +COMMIT; + +:VERSION 25 + +BEGIN TRANSACTION; +CREATE TABLE regionwindlight ( + "region_id" varchar(36) NOT NULL DEFAULT '000000-0000-0000-0000-000000000000' PRIMARY KEY, + "water_color_r" double precision NOT NULL DEFAULT '4.000000', + water_color_g double precision NOT NULL DEFAULT '38.000000', + water_color_b double precision NOT NULL DEFAULT '64.000000', + water_fog_density_exponent double precision NOT NULL DEFAULT '4.0', + underwater_fog_modifier double precision NOT NULL DEFAULT '0.25', + reflection_wavelet_scale_1 double precision NOT NULL DEFAULT '2.0', + reflection_wavelet_scale_2 double precision NOT NULL DEFAULT '2.0', + reflection_wavelet_scale_3 double precision NOT NULL DEFAULT '2.0', + fresnel_scale double precision NOT NULL DEFAULT '0.40', + fresnel_offset double precision NOT NULL DEFAULT '0.50', + refract_scale_above double precision NOT NULL DEFAULT '0.03', + refract_scale_below double precision NOT NULL DEFAULT '0.20', + blur_multiplier double precision NOT NULL DEFAULT '0.040', + big_wave_direction_x double precision NOT NULL DEFAULT '1.05', + big_wave_direction_y double precision NOT NULL DEFAULT '-0.42', + little_wave_direction_x double precision NOT NULL DEFAULT '1.11', + little_wave_direction_y double precision NOT NULL DEFAULT '-1.16', + normal_map_texture varchar(36) NOT NULL DEFAULT '822ded49-9a6c-f61c-cb89-6df54f42cdf4', + horizon_r double precision NOT NULL DEFAULT '0.25', + horizon_g double precision NOT NULL DEFAULT '0.25', + horizon_b double precision NOT NULL DEFAULT '0.32', + horizon_i double precision NOT NULL DEFAULT '0.32', + haze_horizon double precision NOT NULL DEFAULT '0.19', + blue_density_r double precision NOT NULL DEFAULT '0.12', + blue_density_g double precision NOT NULL DEFAULT '0.22', + blue_density_b double precision NOT NULL DEFAULT '0.38', + blue_density_i double precision NOT NULL DEFAULT '0.38', + haze_density double precision NOT NULL DEFAULT '0.70', + density_multiplier double precision NOT NULL DEFAULT '0.18', + distance_multiplier double precision NOT NULL DEFAULT '0.8', + max_altitude int NOT NULL DEFAULT '1605', + sun_moon_color_r double precision NOT NULL DEFAULT '0.24', + sun_moon_color_g double precision NOT NULL DEFAULT '0.26', + sun_moon_color_b double precision NOT NULL DEFAULT '0.30', + sun_moon_color_i double precision NOT NULL DEFAULT '0.30', + sun_moon_position double precision NOT NULL DEFAULT '0.317', + ambient_r double precision NOT NULL DEFAULT '0.35', + ambient_g double precision NOT NULL DEFAULT '0.35', + ambient_b double precision NOT NULL DEFAULT '0.35', + ambient_i double precision NOT NULL DEFAULT '0.35', + east_angle double precision NOT NULL DEFAULT '0.00', + sun_glow_focus double precision NOT NULL DEFAULT '0.10', + sun_glow_size double precision NOT NULL DEFAULT '1.75', + scene_gamma double precision NOT NULL DEFAULT '1.00', + star_brightness double precision NOT NULL DEFAULT '0.00', + cloud_color_r double precision NOT NULL DEFAULT '0.41', + cloud_color_g double precision NOT NULL DEFAULT '0.41', + cloud_color_b double precision NOT NULL DEFAULT '0.41', + cloud_color_i double precision NOT NULL DEFAULT '0.41', + cloud_x double precision NOT NULL DEFAULT '1.00', + cloud_y double precision NOT NULL DEFAULT '0.53', + cloud_density double precision NOT NULL DEFAULT '1.00', + cloud_coverage double precision NOT NULL DEFAULT '0.27', + cloud_scale double precision NOT NULL DEFAULT '0.42', + cloud_detail_x double precision NOT NULL DEFAULT '1.00', + cloud_detail_y double precision NOT NULL DEFAULT '0.53', + cloud_detail_density double precision NOT NULL DEFAULT '0.12', + cloud_scroll_x double precision NOT NULL DEFAULT '0.20', + cloud_scroll_x_lock smallint NOT NULL DEFAULT '0', + cloud_scroll_y double precision NOT NULL DEFAULT '0.01', + cloud_scroll_y_lock smallint NOT NULL DEFAULT '0', + draw_classic_clouds smallint NOT NULL DEFAULT '1' +); + +COMMIT; + +:VERSION 26 + +BEGIN TRANSACTION; + +ALTER TABLE regionsettings ADD "map_tile_ID" CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'; + +COMMIT; + +:VERSION 27 #--------------------- + +BEGIN TRANSACTION; +ALTER TABLE land ADD "MediaType" VARCHAR(32) NOT NULL DEFAULT 'none/none' ; +ALTER TABLE land ADD "MediaDescription" VARCHAR(255) NOT NULL DEFAULT ''; +ALTER TABLE land ADD "MediaSize" VARCHAR(16) NOT NULL DEFAULT '0,0'; +ALTER TABLE land ADD "MediaLoop" boolean NOT NULL DEFAULT false; +ALTER TABLE land ADD "ObscureMusic" boolean NOT NULL DEFAULT false; +ALTER TABLE land ADD "ObscureMedia" boolean NOT NULL DEFAULT false; +COMMIT; + +:VERSION 28 #--------------------- + +BEGIN TRANSACTION; + +ALTER TABLE prims +alter column "CreatorID" set DEFAULT '00000000-0000-0000-0000-000000000000' ; + +ALTER TABLE prims ALTER COLUMN "CreatorID" set NOT NULL; + +ALTER TABLE primitems +alter column "creatorID" set DEFAULT '00000000-0000-0000-0000-000000000000' ; + +ALTER TABLE primitems ALTER COLUMN "creatorID" set NOT NULL; + +COMMIT; + +:VERSION 29 #----------------- Region Covenant changed time + +BEGIN TRANSACTION; + +ALTER TABLE regionsettings ADD "covenant_datetime" int NOT NULL default 0; + +COMMIT; + +:VERSION 30 #------------------Migrate "creatorID" storage to varchars instead of UUIDs for HG support + +BEGIN TRANSACTION; + +alter table prims rename column "CreatorID" to "CreatorIDOld"; +alter table primitems rename column "creatorID" to "creatorIDOld"; + +COMMIT; + +:VERSION 31 #--------------------- + +BEGIN TRANSACTION; + +ALTER TABLE prims ADD "CreatorID" varchar(255); +ALTER TABLE primitems ADD "creatorID" varchar(255); + +COMMIT; + +:VERSION 32 #--------------------- + +BEGIN TRANSACTION; + +UPDATE prims SET "CreatorID" = cast("CreatorIDOld" as varchar(255)); +UPDATE primitems SET "creatorID" = cast("creatorIDOld" as varchar(255)); + +COMMIT; + +:VERSION 33 #--------------------- + +BEGIN TRANSACTION; + +ALTER TABLE prims alter column "CreatorID" set default '00000000-0000-0000-0000-000000000000' ; + +ALTER TABLE prims ALTER COLUMN "CreatorID" set NOT NULL; + +ALTER TABLE primitems alter column "creatorID" set DEFAULT '00000000-0000-0000-0000-000000000000' ; + +ALTER TABLE primitems ALTER COLUMN "creatorID" set NOT NULL; + +COMMIT; + +:VERSION 34 #--------------- Telehub support + +BEGIN TRANSACTION; + +CREATE TABLE spawn_points( + "RegionUUID" uuid NOT NULL PRIMARY KEY, + "Yaw" double precision NOT NULL, + "Pitch" double precision NOT NULL, + "Distance" double precision NOT NULL +); + +ALTER TABLE regionsettings ADD "TelehubObject" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'; + +COMMIT; + +:VERSION 35 #---------------- Parcels for sale + +BEGIN TRANSACTION; + +ALTER TABLE regionsettings ADD "parcel_tile_ID" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'; + +COMMIT; + +:VERSION 36 #---------------- Timed bans/access + +BEGIN TRANSACTION; + +ALTER TABLE landaccesslist ADD "Expires" integer NOT NULL DEFAULT 0; + +COMMIT; + +:VERSION 37 #---------------- Environment Settings + +BEGIN TRANSACTION; + +CREATE TABLE regionenvironment( + "region_id" uuid NOT NULL primary key, + "llsd_settings" varchar NOT NULL +); + +COMMIT; + +:VERSION 38 #---------------- Dynamic attributes + +BEGIN TRANSACTION; + +ALTER TABLE prims ADD "DynAttrs" TEXT; + +COMMIT; + +:VERSION 39 #---------------- Extra physics params + +BEGIN TRANSACTION; + +ALTER TABLE prims ADD "PhysicsShapeType" smallint NOT NULL default '0'; +ALTER TABLE prims ADD "Density" double precision NOT NULL default '1000'; +ALTER TABLE prims ADD "GravityModifier" double precision NOT NULL default '1'; +ALTER TABLE prims ADD "Friction" double precision NOT NULL default '0.6'; +ALTER TABLE prims ADD "Restitution" double precision NOT NULL default '0.5'; + +COMMIT; + +:VERSION 40 #-- regionwindlight changed type from smallint to bool + +BEGIN TRANSACTION; + +ALTER TABLE regionwindlight ALTER COLUMN cloud_scroll_x_lock DROP DEFAULT; +ALTER TABLE regionwindlight ALTER cloud_scroll_x_lock TYPE bool USING CASE WHEN cloud_scroll_x_lock=0 THEN FALSE ELSE TRUE END; +ALTER TABLE regionwindlight ALTER COLUMN cloud_scroll_x_lock SET DEFAULT FALSE; + +ALTER TABLE regionwindlight ALTER COLUMN cloud_scroll_y_lock DROP DEFAULT; +ALTER TABLE regionwindlight ALTER cloud_scroll_y_lock TYPE bool USING CASE WHEN cloud_scroll_y_lock=0 THEN FALSE ELSE TRUE END; +ALTER TABLE regionwindlight ALTER COLUMN cloud_scroll_y_lock SET DEFAULT FALSE; + +ALTER TABLE regionwindlight ALTER COLUMN draw_classic_clouds DROP DEFAULT; +ALTER TABLE regionwindlight ALTER draw_classic_clouds TYPE bool USING CASE WHEN draw_classic_clouds=0 THEN FALSE ELSE TRUE END; +ALTER TABLE regionwindlight ALTER COLUMN draw_classic_clouds SET DEFAULT FALSE; + +COMMIT; + +VERSION 41 #-- Change Landlags to bigint + +BEGIN TRANSACTION; + +ALTER TABLE land ALTER "LandFlags" TYPE bigint; + +COMMIT; diff --git a/OpenSim/Data/PGSQL/Resources/UserAccount.migrations b/OpenSim/Data/PGSQL/Resources/UserAccount.migrations new file mode 100644 index 0000000..c785463 --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/UserAccount.migrations @@ -0,0 +1,51 @@ +:VERSION 1 + +CREATE TABLE UserAccounts ( + "PrincipalID" uuid NOT NULL Primary key, + "ScopeID" uuid NOT NULL, + "FirstName" varchar(64) NOT NULL, + "LastName" varchar(64) NOT NULL, + "Email" varchar(64) NULL, + "ServiceURLs" text NULL, + "Created" int default NULL +); + + +:VERSION 2 + +BEGIN TRANSACTION; + +INSERT INTO UserAccounts ("PrincipalID", "ScopeID", "FirstName", "LastName", "Email", "ServiceURLs", "Created") +SELECT UUID AS "PrincipalID", '00000000-0000-0000-0000-000000000000' AS "ScopeID", +username AS "FirstName", +lastname AS "LastName", +email as "Email", ( +'AssetServerURI=' + +userAssetURI + ' InventoryServerURI=' + userInventoryURI + ' GatewayURI= HomeURI=') AS "ServiceURLs", +created as "Created" FROM users; + +COMMIT; + +:VERSION 3 + +BEGIN TRANSACTION; + +CREATE UNIQUE INDEX "PrincipalID" ON UserAccounts("PrincipalID"); +CREATE INDEX "Email" ON UserAccounts("Email"); +CREATE INDEX "FirstName" ON UserAccounts("FirstName"); +CREATE INDEX "LastName" ON UserAccounts("LastName"); +CREATE INDEX Name ON UserAccounts("FirstName","LastName"); + +COMMIT; + +:VERSION 4 + +BEGIN TRANSACTION; + +ALTER TABLE UserAccounts ADD "UserLevel" integer NOT NULL DEFAULT 0; +ALTER TABLE UserAccounts ADD "UserFlags" integer NOT NULL DEFAULT 0; +ALTER TABLE UserAccounts ADD "UserTitle" varchar(64) NOT NULL DEFAULT ''; + +COMMIT; + + diff --git a/OpenSim/Data/PGSQL/Resources/UserProfiles.migrations b/OpenSim/Data/PGSQL/Resources/UserProfiles.migrations new file mode 100644 index 0000000..a6bd8ca --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/UserProfiles.migrations @@ -0,0 +1,155 @@ +:VERSION 1 # ------------------------------- + +begin; + +CREATE TABLE classifieds ( + "classifieduuid" char(36) NOT NULL, + "creatoruuid" char(36) NOT NULL, + "creationdate" integer NOT NULL, + "expirationdate" integer NOT NULL, + "category" varchar(20) NOT NULL, + "name" varchar(255) NOT NULL, + "description" text NOT NULL, + "parceluuid" char(36) NOT NULL, + "parentestate" integer NOT NULL, + "snapshotuuid" char(36) NOT NULL, + "simname" varchar(255) NOT NULL, + "posglobal" varchar(255) NOT NULL, + "parcelname" varchar(255) NOT NULL, + "classifiedflags" integer NOT NULL, + "priceforlisting" integer NOT NULL, + constraint classifiedspk PRIMARY KEY ("classifieduuid") +); + + +CREATE TABLE usernotes ( + "useruuid" varchar(36) NOT NULL, + "targetuuid" varchar(36) NOT NULL, + "notes" text NOT NULL, + constraint usernoteuk UNIQUE ("useruuid","targetuuid") +); + + +CREATE TABLE userpicks ( + "pickuuid" varchar(36) NOT NULL, + "creatoruuid" varchar(36) NOT NULL, + "toppick" boolean NOT NULL, + "parceluuid" varchar(36) NOT NULL, + "name" varchar(255) NOT NULL, + "description" text NOT NULL, + "snapshotuuid" varchar(36) NOT NULL, + "user" varchar(255) NOT NULL, + "originalname" varchar(255) NOT NULL, + "simname" varchar(255) NOT NULL, + "posglobal" varchar(255) NOT NULL, + "sortorder" integer NOT NULL, + "enabled" boolean NOT NULL, + PRIMARY KEY ("pickuuid") +); + + +CREATE TABLE userprofile ( + "useruuid" varchar(36) NOT NULL, + "profilePartner" varchar(36) NOT NULL, + "profileAllowPublish" bytea NOT NULL, + "profileMaturePublish" bytea NOT NULL, + "profileURL" varchar(255) NOT NULL, + "profileWantToMask" integer NOT NULL, + "profileWantToText" text NOT NULL, + "profileSkillsMask" integer NOT NULL, + "profileSkillsText" text NOT NULL, + "profileLanguages" text NOT NULL, + "profileImage" varchar(36) NOT NULL, + "profileAboutText" text NOT NULL, + "profileFirstImage" varchar(36) NOT NULL, + "profileFirstText" text NOT NULL, + PRIMARY KEY ("useruuid") +); + +commit; + +:VERSION 2 # ------------------------------- + +begin; +CREATE TABLE userdata ( + "UserId" char(36) NOT NULL, + "TagId" varchar(64) NOT NULL, + "DataKey" varchar(255), + "DataVal" varchar(255), + PRIMARY KEY ("UserId","TagId") +); + +commit; + +:VERSION 3 # ------------------------------- +begin; +CREATE TABLE usersettings ( + "useruuid" char(36) NOT NULL, + "imviaemail" bytea NOT NULL, + "visible" bytea NOT NULL, + PRIMARY KEY ("useruuid") +); +commit; + +:VERSION 4 + +BEGIN; + +-- Classifieds +ALTER TABLE classifieds DROP CONSTRAINT classifiedspk; +ALTER TABLE classifieds ALTER COLUMN classifieduuid SET DATA TYPE uuid using classifieduuid::uuid; +ALTER TABLE classifieds ALTER COLUMN creatoruuid SET DATA TYPE uuid using creatoruuid::uuid; +ALTER TABLE classifieds ALTER COLUMN parceluuid SET DATA TYPE uuid using parceluuid::uuid; +ALTER TABLE classifieds ALTER COLUMN snapshotuuid SET DATA TYPE uuid using snapshotuuid::uuid; +ALTER TABLE classifieds ADD CONSTRAINT classifiedspk PRIMARY KEY (classifieduuid); + +-- Notes +ALTER TABLE usernotes DROP CONSTRAINT usernoteuk; +ALTER TABLE usernotes ALTER COLUMN useruuid SET DATA TYPE uuid USING useruuid::uuid; +ALTER TABLE usernotes ALTER COLUMN targetuuid SET DATA TYPE uuid USING targetuuid::uuid; +ALTER TABLE usernotes ADD CONSTRAINT usernoteuk UNIQUE (useruuid,targetuuid); + + +-- Userpicks +ALTER TABLE userpicks DROP CONSTRAINT userpicks_pkey; +ALTER TABLE userpicks ALTER COLUMN pickuuid SET DATA TYPE uuid USING pickuuid::uuid; +ALTER TABLE userpicks ALTER COLUMN creatoruuid SET DATA TYPE uuid USING creatoruuid::uuid; +ALTER TABLE userpicks ALTER COLUMN parceluuid SET DATA TYPE uuid USING parceluuid::uuid; +ALTER TABLE userpicks ALTER COLUMN parceluuid SET DATA TYPE uuid USING parceluuid::uuid; +ALTER TABLE userpicks ADD PRIMARY KEY (pickuuid); + +-- Userprofile +ALTER TABLE userprofile DROP CONSTRAINT userprofile_pkey; +ALTER TABLE userprofile ALTER COLUMN useruuid SET DATA TYPE uuid USING useruuid::uuid; +ALTER TABLE userprofile ALTER COLUMN "profilePartner" SET DATA TYPE uuid USING "profilePartner"::uuid; +-- Force column conversions +ALTER TABLE userprofile ALTER COLUMN "profileAllowPublish" SET DATA TYPE boolean USING CASE WHEN false THEN false ELSE true END; +ALTER TABLE userprofile ALTER COLUMN "profileMaturePublish" SET DATA TYPE boolean USING CASE WHEN false THEN false ELSE true END; +ALTER TABLE userprofile ALTER COLUMN "profileImage" SET DATA TYPE uuid USING "profileImage"::uuid; +ALTER TABLE userprofile ALTER COLUMN "profileFirstImage" SET DATA TYPE uuid USING "profileFirstImage"::uuid; +ALTER TABLE userprofile ADD PRIMARY KEY (useruuid); + +-- Userdata +ALTER TABLE userdata DROP CONSTRAINT userdata_pkey; +ALTER TABLE userdata ALTER COLUMN "UserId" SET DATA TYPE uuid USING "UserId"::uuid; +ALTER TABLE userdata ALTER COLUMN "UserId" SET DATA TYPE uuid USING "UserId"::uuid; +ALTER TABLE userdata ADD PRIMARY KEY ("UserId","TagId"); + + +-- Usersettings +ALTER TABLE usersettings DROP CONSTRAINT usersettings_pkey; +ALTER TABLE usersettings ALTER COLUMN useruuid SET DATA TYPE uuid USING useruuid::uuid; +ALTER TABLE usersettings ALTER COLUMN visible SET DATA TYPE boolean USING CASE WHEN false THEN false ELSE true END; +ALTER TABLE usersettings ADD COLUMN email varchar(254) NOT NULL; +ALTER TABLE usersettings ADD PRIMARY KEY (useruuid); + +COMMIT; + + +:VERSION 5 # ------------------------------- + +BEGIN; + +ALTER TABLE usersettings ALTER COLUMN imviaemail SET DATA TYPE boolean USING CASE WHEN false THEN false ELSE true END; + +COMMIT; \ No newline at end of file diff --git a/OpenSim/Data/PGSQL/Resources/UserStore.migrations b/OpenSim/Data/PGSQL/Resources/UserStore.migrations new file mode 100644 index 0000000..974d489 --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/UserStore.migrations @@ -0,0 +1,404 @@ +:VERSION 1 + +CREATE TABLE users ( + "UUID" varchar(36) NOT NULL default '' Primary Key, + "username" varchar(32) NOT NULL, + "lastname" varchar(32) NOT NULL, + "passwordHash" varchar(32) NOT NULL, + "passwordSalt" varchar(32) NOT NULL, + "homeRegion" bigint default NULL, + "homeLocationX" double precision default NULL, + "homeLocationY" double precision default NULL, + "homeLocationZ" double precision default NULL, + "homeLookAtX" double precision default NULL, + "homeLookAtY" double precision default NULL, + "homeLookAtZ" double precision default NULL, + "created" int NOT NULL, + "lastLogin" int NOT NULL, + "userInventoryURI" varchar(255) default NULL, + "userAssetURI" varchar(255) default NULL, + "profileCanDoMask" int default NULL, + "profileWantDoMask" int default NULL, + "profileAboutText" text, + "profileFirstText" text, + "profileImage" varchar(36) default NULL, + "profileFirstImage" varchar(36) default NULL, + "webLoginKey" varchar(36) default NULL +); + +CREATE INDEX "usernames" ON users +( + "username" ASC, + "lastname" ASC +); + + +CREATE TABLE agents ( + "UUID" varchar(36) NOT NULL Primary Key, + "sessionID" varchar(36) NOT NULL, + "secureSessionID" varchar(36) NOT NULL, + "agentIP" varchar(16) NOT NULL, + "agentPort" int NOT NULL, + "agentOnline" smallint NOT NULL, + "loginTime" int NOT NULL, + "logoutTime" int NOT NULL, + "currentRegion" varchar(36) NOT NULL, + "currentHandle" bigint NOT NULL, + "currentPos" varchar(64) NOT NULL +); + +CREATE INDEX session ON agents +( + "sessionID" ASC +); + +CREATE INDEX ssession ON agents +( + "secureSessionID" ASC +); + + +CREATE TABLE userfriends( + "ownerID" varchar(50) NOT NULL, + "friendID" varchar(50) NOT NULL, + "friendPerms" varchar(50) NOT NULL, + "datetimestamp" varchar(50) NOT NULL +); + +CREATE TABLE avatarappearance ( + "Owner" varchar(36) NOT NULL primary key, + "Serial" int NOT NULL, + "Visual_Params" bytea NOT NULL, + "Texture" bytea NOT NULL, + "Avatar_Height" double precision NOT NULL, + "Body_Item" varchar(36) NOT NULL, + "Body_Asset" varchar(36) NOT NULL, + "Skin_Item" varchar(36) NOT NULL, + "Skin_Asset" varchar(36) NOT NULL, + "Hair_Item" varchar(36) NOT NULL, + "Hair_Asset" varchar(36) NOT NULL, + "Eyes_Item" varchar(36) NOT NULL, + "Eyes_Asset" varchar(36) NOT NULL, + "Shirt_Item" varchar(36) NOT NULL, + "Shirt_Asset" varchar(36) NOT NULL, + "Pants_Item" varchar(36) NOT NULL, + "Pants_Asset" varchar(36) NOT NULL, + "Shoes_Item" varchar(36) NOT NULL, + "Shoes_Asset" varchar(36) NOT NULL, + "Socks_Item" varchar(36) NOT NULL, + "Socks_Asset" varchar(36) NOT NULL, + "Jacket_Item" varchar(36) NOT NULL, + "Jacket_Asset" varchar(36) NOT NULL, + "Gloves_Item" varchar(36) NOT NULL, + "Gloves_Asset" varchar(36) NOT NULL, + "Undershirt_Item" varchar(36) NOT NULL, + "Undershirt_Asset" varchar(36) NOT NULL, + "Underpants_Item" varchar(36) NOT NULL, + "Underpants_Asset" varchar(36) NOT NULL, + "Skirt_Item" varchar(36) NOT NULL, + "Skirt_Asset" varchar(36) NOT NULL +); + +:VERSION 2 + +BEGIN TRANSACTION; + +ALTER TABLE users ADD "homeRegionID" varchar(36) NOT NULL default '00000000-0000-0000-0000-000000000000'; +ALTER TABLE users ADD "userFlags" int NOT NULL default 0; +ALTER TABLE users ADD "godLevel" int NOT NULL default 0; +ALTER TABLE users ADD "customType" varchar(32) not null default ''; +ALTER TABLE users ADD "partner" varchar(36) not null default '00000000-0000-0000-0000-000000000000'; + +COMMIT; + + +:VERSION 3 + +BEGIN TRANSACTION; + +CREATE TABLE avatarattachments ( + "UUID" varchar(36) NOT NULL + , "attachpoint" int NOT NULL + , item varchar(36) NOT NULL + , asset varchar(36) NOT NULL); + +CREATE INDEX IX_avatarattachments ON avatarattachments + ( + "UUID" + ); + +COMMIT; + + +:VERSION 4 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_userfriends + ( + "ownerID" varchar(36) NOT NULL, + "friendID" varchar(36) NOT NULL, + "friendPerms" int NOT NULL, + "datetimestamp" int NOT NULL + ); + +INSERT INTO Tmp_userfriends ("ownerID", "friendID", "friendPerms", "datetimestamp") + SELECT cast("ownerID" as varchar(36)), cast("friendID" as varchar(36)), cast("friendPerms" as int), cast("datetimestamp" as int) + FROM userfriends; + +DROP TABLE userfriends; + +alter table Tmp_userfriends rename to userfriends; + +CREATE INDEX IX_userfriends_ownerID ON userfriends + ( + "ownerID" + ); + +CREATE INDEX IX_userfriends_friendID ON userfriends + ( + "friendID" + ); + +COMMIT; + + +:VERSION 5 + +BEGIN TRANSACTION; + + ALTER TABLE users add "email" varchar(250); + +COMMIT; + + +:VERSION 6 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_users + ( + "UUID" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), + "username" varchar(32) NOT NULL, + "lastname" varchar(32) NOT NULL, + "passwordHash" varchar(32) NOT NULL, + "passwordSalt" varchar(32) NOT NULL, + "homeRegion" bigint NULL DEFAULT (NULL), + "homeLocationX" double precision NULL DEFAULT (NULL), + "homeLocationY" double precision NULL DEFAULT (NULL), + "homeLocationZ" double precision NULL DEFAULT (NULL), + "homeLookAtX" double precision NULL DEFAULT (NULL), + "homeLookAtY" double precision NULL DEFAULT (NULL), + "homeLookAtZ" double precision NULL DEFAULT (NULL), + "created" int NOT NULL, + "lastLogin" int NOT NULL, + "userInventoryURI" varchar(255) NULL DEFAULT (NULL), + "userAssetURI" varchar(255) NULL DEFAULT (NULL), + "profileCanDoMask" int NULL DEFAULT (NULL), + "profileWantDoMask" int NULL DEFAULT (NULL), + "profileAboutText" text NULL, + "profileFirstText" text NULL, + "profileImage" uuid NULL DEFAULT (NULL), + "profileFirstImage" uuid NULL DEFAULT (NULL), + "webLoginKey" uuid NULL DEFAULT (NULL), + "homeRegionID" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), + "userFlags" int NOT NULL DEFAULT ((0)), + "godLevel" int NOT NULL DEFAULT ((0)), + "customType" varchar(32) NOT NULL DEFAULT (''), + "partner" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'), + email varchar(250) NULL + ); + +INSERT INTO Tmp_users ("UUID", "username", "lastname", "passwordHash", "passwordSalt", "homeRegion", "homeLocationX", "homeLocationY", "homeLocationZ", "homeLookAtX", "homeLookAtY", "homeLookAtZ", "created", "lastLogin", "userInventoryURI", "userAssetURI", "profileCanDoMask", "profileWantDoMask", "profileAboutText", "profileFirstText", "profileImage", "profileFirstImage", "webLoginKey", "homeRegionID", "userFlags", "godLevel", "customType", "partner", email) + SELECT cast("UUID" as uuid), "username", "lastname", "passwordHash", "passwordSalt", "homeRegion", "homeLocationX", "homeLocationY", "homeLocationZ", "homeLookAtX", "homeLookAtY", "homeLookAtZ", "created", "lastLogin", "userInventoryURI", "userAssetURI", "profileCanDoMask", "profileWantDoMask", "profileAboutText", "profileFirstText", cast("profileImage" as uuid), cast("profileFirstImage" as uuid), cast("webLoginKey" as uuid), cast("homeRegionID" as uuid), "userFlags", "godLevel", "customType", cast("partner" as uuid), email + FROM users ; + +DROP TABLE users; + +alter table Tmp_users rename to users; + +ALTER TABLE users ADD CONSTRAINT + PK__users__65A475E737A5467C PRIMARY KEY + ( + "UUID" + ); + +CREATE INDEX "usernames" ON users + ( + "username", + "lastname" + ); + +COMMIT; + + +:VERSION 7 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_agents + ( + "UUID" uuid NOT NULL, + "sessionID" uuid NOT NULL, + "secureSessionID" uuid NOT NULL, + "agentIP" varchar(16) NOT NULL, + "agentPort" int NOT NULL, + "agentOnline" smallint NOT NULL, + "loginTime" int NOT NULL, + "logoutTime" int NOT NULL, + "currentRegion" uuid NOT NULL, + "currentHandle" bigint NOT NULL, + "currentPos" varchar(64) NOT NULL + ); + +INSERT INTO Tmp_agents ("UUID", "sessionID", "secureSessionID", "agentIP", "agentPort", "agentOnline", "loginTime", "logoutTime", "currentRegion", "currentHandle", "currentPos") + SELECT cast("UUID" as uuid), cast("sessionID" as uuid), cast("secureSessionID" as uuid), "agentIP", "agentPort", "agentOnline", "loginTime", "logoutTime", cast("currentRegion" as uuid), "currentHandle", "currentPos" + FROM agents ; + +DROP TABLE agents; + +alter table Tmp_agents rename to agents; + +ALTER TABLE agents ADD CONSTRAINT + PK__agents__65A475E749C3F6B7 PRIMARY KEY + ( + "UUID" + ) ; + +CREATE INDEX session ON agents + ( + "sessionID" + ); + +CREATE INDEX ssession ON agents + ( + "secureSessionID" + ); + +COMMIT; + + +:VERSION 8 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_userfriends + ( + "ownerID" uuid NOT NULL, + "friendID" uuid NOT NULL, + "friendPerms" int NOT NULL, + "datetimestamp" int NOT NULL + ); + +INSERT INTO Tmp_userfriends ("ownerID", "friendID", "friendPerms", "datetimestamp") + SELECT cast("ownerID" as uuid), cast( "friendID" as uuid), "friendPerms", "datetimestamp" + FROM userfriends; + +DROP TABLE userfriends; + +alter table Tmp_userfriends rename to userfriends; + +CREATE INDEX IX_userfriends_ownerID ON userfriends + ( + "ownerID" + ); + +CREATE INDEX IX_userfriends_friendID ON userfriends + ( + "friendID" + ); + +COMMIT; + + +:VERSION 9 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_avatarappearance + ( + "Owner" uuid NOT NULL, + "Serial" int NOT NULL, + "Visual_Params" bytea NOT NULL, + "Texture" bytea NOT NULL, + "Avatar_Height" double precision NOT NULL, + "Body_Item" uuid NOT NULL, + "Body_Asset" uuid NOT NULL, + "Skin_Item" uuid NOT NULL, + "Skin_Asset" uuid NOT NULL, + "Hair_Item" uuid NOT NULL, + "Hair_Asset" uuid NOT NULL, + "Eyes_Item" uuid NOT NULL, + "Eyes_Asset" uuid NOT NULL, + "Shirt_Item" uuid NOT NULL, + "Shirt_Asset" uuid NOT NULL, + "Pants_Item" uuid NOT NULL, + "Pants_Asset" uuid NOT NULL, + "Shoes_Item" uuid NOT NULL, + "Shoes_Asset" uuid NOT NULL, + "Socks_Item" uuid NOT NULL, + "Socks_Asset" uuid NOT NULL, + "Jacket_Item" uuid NOT NULL, + "Jacket_Asset" uuid NOT NULL, + "Gloves_Item" uuid NOT NULL, + "Gloves_Asset" uuid NOT NULL, + "Undershirt_Item" uuid NOT NULL, + "Undershirt_Asset" uuid NOT NULL, + "Underpants_Item" uuid NOT NULL, + "Underpants_Asset" uuid NOT NULL, + "Skirt_Item" uuid NOT NULL, + "Skirt_Asset" uuid NOT NULL + ); + +INSERT INTO Tmp_avatarappearance ("Owner", "Serial", "Visual_Params", "Texture", "Avatar_Height", "Body_Item", "Body_Asset", "Skin_Item", "Skin_Asset", "Hair_Item", "Hair_Asset", "Eyes_Item", "Eyes_Asset", "Shirt_Item", "Shirt_Asset", "Pants_Item", "Pants_Asset", "Shoes_Item", "Shoes_Asset", "Socks_Item", "Socks_Asset", "Jacket_Item", "Jacket_Asset", "Gloves_Item", "Gloves_Asset", "Undershirt_Item", "Undershirt_Asset", "Underpants_Item", "Underpants_Asset", "Skirt_Item", "Skirt_Asset") + SELECT cast("Owner" as uuid), "Serial", "Visual_Params", "Texture", "Avatar_Height", cast("Body_Item" as uuid), cast("Body_Asset" as uuid), cast("Skin_Item" as uuid), cast("Skin_Asset" as uuid), cast("Hair_Item" as uuid), cast("Hair_Asset" as uuid), cast("Eyes_Item" as uuid), cast("Eyes_Asset" as uuid), cast("Shirt_Item" as uuid), cast("Shirt_Asset" as uuid), cast("Pants_Item" as uuid), cast("Pants_Asset" as uuid), cast("Shoes_Item" as uuid), cast("Shoes_Asset" as uuid), cast("Socks_Item" as uuid), cast("Socks_Asset" as uuid), cast("Jacket_Item" as uuid), cast("Jacket_Asset" as uuid), cast("Gloves_Item" as uuid), cast("Gloves_Asset" as uuid), cast("Undershirt_Item" as uuid), cast("Undershirt_Asset" as uuid), cast("Underpants_Item" as uuid), cast("Underpants_Asset" as uuid), cast("Skirt_Item" as uuid), cast("Skirt_Asset" as uuid) + FROM avatarappearance ; + +DROP TABLE avatarappearance; + +alter table Tmp_avatarappearance rename to avatarappearance; + +ALTER TABLE avatarappearance ADD CONSTRAINT + PK__avatarap__7DD115CC4E88ABD4 PRIMARY KEY + ( + "Owner" + ); + +COMMIT; + + +:VERSION 10 + +BEGIN TRANSACTION; + +CREATE TABLE Tmp_avatarattachments + ( + "UUID" uuid NOT NULL, + "attachpoint" int NOT NULL, + item uuid NOT NULL, + asset uuid NOT NULL + ); + +INSERT INTO Tmp_avatarattachments ("UUID", "attachpoint", item, asset) + SELECT cast("UUID" as uuid), "attachpoint", cast(item as uuid), cast(asset as uuid) + FROM avatarattachments ; + +DROP TABLE avatarattachments; + +alter table Tmp_avatarattachments rename to avatarattachments; + +CREATE INDEX IX_avatarattachments ON avatarattachments + ( + "UUID" + ); + +COMMIT; + + +:VERSION 11 + +BEGIN TRANSACTION; + +ALTER TABLE users ADD "scopeID" uuid not null default '00000000-0000-0000-0000-000000000000'; + +COMMIT; diff --git a/OpenSim/Data/PGSQL/Resources/XAssetStore.migrations b/OpenSim/Data/PGSQL/Resources/XAssetStore.migrations new file mode 100644 index 0000000..df9d821 --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/XAssetStore.migrations @@ -0,0 +1,80 @@ +# ----------------- +:VERSION 1 + +BEGIN; + +CREATE TABLE XAssetsMeta ( + "ID" char(36) NOT NULL, + "Hash" char(32) NOT NULL, + "Name" varchar(64) NOT NULL, + "Description" varchar(64) NOT NULL, + "AssetType" smallint NOT NULL, + "Local" smallint NOT NULL, + "Temporary" smallint NOT NULL, + "CreateTime" integer NOT NULL, + "AccessTime" integer NOT NULL, + "AssetFlags" integer NOT NULL, + "CreatorID" varchar(128) NOT NULL, + PRIMARY KEY ("ID") +); + +CREATE TABLE XAssetsData ( + "Hash" char(32) NOT NULL, + "Data" bytea NOT NULL, + PRIMARY KEY ("Hash") +); + +COMMIT; + + +:VERSION 2 + +BEGIN; + +ALTER TABLE xassetsmeta ALTER COLUMN "Local" SET DATA TYPE boolean USING CASE WHEN '0' THEN FALSE ELSE TRUE END; +ALTER TABLE xassetsmeta ALTER COLUMN "Temporary" SET DATA TYPE boolean USING CASE WHEN '0' THEN FALSE ELSE TRUE END; +ALTER TABLE xassetsmeta ALTER COLUMN "Hash" SET DATA TYPE char(66); +ALTER TABLE xassetsdata ALTER COLUMN "Hash" SET DATA TYPE char(66); + +COMMIT; + +:VERSION 3 + +BEGIN; + +ALTER TABLE xassetsmeta RENAME COLUMN "ID" TO id; +ALTER TABLE xassetsmeta RENAME COLUMN "Hash" TO hash; +ALTER TABLE xassetsmeta RENAME COLUMN "Name" TO name; +ALTER TABLE xassetsmeta RENAME COLUMN "Description" TO description; +ALTER TABLE xassetsmeta RENAME COLUMN "Local" to local; +ALTER TABLE xassetsmeta RENAME COLUMN "Temporary" TO temporary; +ALTER TABLE xassetsmeta RENAME COLUMN "CreateTime" TO create_time; +ALTER TABLE xassetsmeta RENAME COLUMN "AccessTime" TO access_time; +ALTER TABLE xassetsmeta RENAME COLUMN "AssetFlags" TO asset_flags; +ALTER TABLE xassetsmeta RENAME COLUMN "CreatorID" TO creatorid; +ALTER TABLE xassetsmeta DROP CONSTRAINT xassetsmeta_pkey; +ALTER TABLE xassetsmeta ADD PRIMARY KEY (id); + + +ALTER TABLE xassetsdata RENAME COLUMN "Hash" TO hash; +ALTER TABLE xassetsdata RENAME COLUMN "Data" TO data; +ALTER TABLE xassetsdata DROP CONSTRAINT xassetsdata_pkey; +ALTER TABLE xassetsdata ADD PRIMARY KEY (hash); + +COMMIT; + + +:VERSION 4 + +BEGIN; + +ALTER TABLE xassetsmeta ALTER COLUMN id SET DATA TYPE uuid USING id::uuid; +ALTER TABLE xassetsmeta ALTER COLUMN hash SET DATA TYPE bytea USING hash::bytea; +ALTER TABLE xassetsdata ALTER COLUMN hash SET DATA TYPE bytea USING hash::bytea; + +COMMIT; + +:VERSION 5 + +BEGIN; +COMMIT; diff --git a/OpenSim/Data/PGSQL/Resources/os_groups_Store.migrations b/OpenSim/Data/PGSQL/Resources/os_groups_Store.migrations new file mode 100644 index 0000000..74b07c3 --- /dev/null +++ b/OpenSim/Data/PGSQL/Resources/os_groups_Store.migrations @@ -0,0 +1,211 @@ +:VERSION 1 # -------------------------- + +BEGIN; + +CREATE TABLE os_groups_groups ( + "GroupID" char(36) Primary Key NOT NULL default '', + "Location" varchar(255) NOT NULL default '', + "Name" varchar(255) NOT NULL default '', + "Charter" text NOT NULL, + "InsigniaID" char(36) NOT NULL default '', + "FounderID" char(36) NOT NULL default '', + "MembershipFee" integer NOT NULL default '0', + "OpenEnrollment" varchar(255) NOT NULL default '', + "ShowInList" integer NOT NULL default '0', + "AllowPublish" integer NOT NULL default '0', + "MaturePublish" integer NOT NULL default '0', + "OwnerRoleID" char(36) NOT NULL default '' +); + + +CREATE TABLE os_groups_membership ( + "GroupID"char(36) NOT NULL default '', + "PrincipalID" VARCHAR(255) NOT NULL default '', + "SelectedRoleID" char(36) NOT NULL default '', + "Contribution" integer NOT NULL default '0', + "ListInProfile" integer NOT NULL default '1', + "AcceptNotices" integer NOT NULL default '1', + "AccessToken" char(36) NOT NULL default '', + constraint os_groupmemberpk primary key ("GroupID", "PrincipalID") +); + + + +CREATE TABLE os_groups_roles ( + "GroupID" char(36) NOT NULL default '', + "RoleID" char(36) NOT NULL default '', + "Name" varchar(255) NOT NULL default '', + "Description" varchar(255) NOT NULL default '', + "Title" varchar(255) NOT NULL default '', + "Powers" bigint NOT NULL default 0, + constraint os_grouprolepk PRIMARY KEY ("GroupID","RoleID") +); + + +CREATE TABLE os_groups_rolemembership ( + "GroupID" char(36) NOT NULL default '', + "RoleID" char(36) NOT NULL default '', + "PrincipalID" VARCHAR(255) NOT NULL default '', + constraint os_grouprolememberpk PRIMARY KEY ("GroupID","RoleID","PrincipalID") +); + + +CREATE TABLE os_groups_invites ( + "InviteID" char(36) NOT NULL default '', + "GroupID" char(36) NOT NULL default '', + "RoleID" char(36) NOT NULL default '', + "PrincipalID" VARCHAR(255) NOT NULL default '', + "TMStamp" timestamp NOT NULL default now(), + constraint os_groupinvitespk PRIMARY KEY ("InviteID") +); +-- UNIQUE KEY "PrincipalGroup" ("GroupID","PrincipalID") + + +CREATE TABLE os_groups_notices ( + "GroupID" char(36) NOT NULL default '', + "NoticeID" char(36) NOT NULL default '', + "TMStamp" integer NOT NULL default '0', + "FromName" varchar(255) NOT NULL default '', + "Subject" varchar(255) NOT NULL default '', + "Message" text NOT NULL, + "HasAttachment" integer NOT NULL default '0', + "AttachmentType" integer NOT NULL default '0', + "AttachmentName" varchar(128) NOT NULL default '', + "AttachmentItemID" char(36) NOT NULL default '', + "AttachmentOwnerID" varchar(255) NOT NULL default '', + constraint os_groupsnoticespk PRIMARY KEY ("NoticeID") +); +-- KEY "GroupID" ("GroupID"), +-- KEY "TMStamp" ("TMStamp") + +CREATE TABLE os_groups_principals ( + "PrincipalID" VARCHAR(255) NOT NULL default '', + "ActiveGroupID" char(36) NOT NULL default '', + constraint os_groupprincpk PRIMARY KEY ("PrincipalID") +); + +COMMIT; + +:VERSION 2 # -------------------------- + +BEGIN; + + +COMMIT; + + + +:VERSION 3 + +BEGIN; + +-- Not a pretty way to do this, but it did not work as-is +-- and nothing was found about converting between existing data +-- and the new type. +-- Since there should be nothing to preserve ... + +DROP TABLE IF EXISTS os_groups_groups CASCADE; + +CREATE TABLE os_groups_groups ( + "GroupID" uuid PRIMARY KEY NOT NULL, + "Location" varchar(255) NOT NULL DEFAULT '', + "Name" varchar(255) NOT NULL DEFAULT '', + "Charter" text NOT NULL, + "InsigniaID" uuid NOT NULL, + "FounderID" uuid NOT NULL, + "MembershipFee" integer NOT NULL DEFAULT '0', + "OpenEnrollment" varchar(255) NOT NULL DEFAULT '', + "ShowInList" integer NOT NULL DEFAULT '0', + "AllowPublish" integer NOT NULL DEFAULT '0', + "MaturePublish" integer NOT NULL DEFAULT '0', + "OwnerRoleID" uuid NOT NULL +); + + +DROP TABLE IF EXISTS os_groups_membership; + +CREATE TABLE os_groups_membership ( + "GroupID"uuid NOT NULL, + "PrincipalID" VARCHAR(255) NOT NULL DEFAULT '', + "SelectedRoleID" uuid NOT NULL, + "Contribution" integer NOT NULL DEFAULT '0', + "ListInProfile" integer NOT NULL DEFAULT '1', + "AcceptNotices" integer NOT NULL DEFAULT '1', + "AccessToken" uuid NOT NULL, + constraint os_groupmemberpk PRIMARY KEY ("GroupID", "PrincipalID") +); + + + +DROP TABLE IF EXISTS os_groups_roles; + +CREATE TABLE os_groups_roles ( + "GroupID" uuid NOT NULL, + "RoleID" uuid NOT NULL, + "Name" varchar(255) NOT NULL DEFAULT '', + "Description" varchar(255) NOT NULL DEFAULT '', + "Title" varchar(255) NOT NULL DEFAULT '', + "Powers" varchar(36) NOT NULL DEFAULT '', + constraint os_grouprolepk PRIMARY KEY ("GroupID","RoleID") +); + + +DROP TABLE IF EXISTS os_groups_rolemembership; + +CREATE TABLE os_groups_rolemembership ( + "GroupID" uuid NOT NULL, + "RoleID" uuid NOT NULL, + "PrincipalID" VARCHAR(255) NOT NULL DEFAULT '', + constraint os_grouprolememberpk PRIMARY KEY ("GroupID","RoleID","PrincipalID") +); + + +DROP TABLE IF EXISTS os_groups_invites; + +CREATE TABLE os_groups_invites ( + "InviteID" uuid NOT NULL, + "GroupID" uuid NOT NULL, + "RoleID" uuid NOT NULL, + "PrincipalID" VARCHAR(255) NOT NULL DEFAULT '', + "TMStamp" timestamp NOT NULL DEFAULT now(), + constraint os_groupinvitespk PRIMARY KEY ("InviteID") +); + + +DROP TABLE IF EXISTS os_groups_notices; + +CREATE TABLE os_groups_notices ( + "GroupID" uuid NOT NULL, + "NoticeID" uuid NOT NULL, + "TMStamp" integer NOT NULL DEFAULT '0', + "FromName" varchar(255) NOT NULL DEFAULT '', + "Subject" varchar(255) NOT NULL DEFAULT '', + "Message" text NOT NULL, + "HasAttachment" integer NOT NULL DEFAULT '0', + "AttachmentType" integer NOT NULL DEFAULT '0', + "AttachmentName" varchar(128) NOT NULL DEFAULT '', + "AttachmentItemID" uuid NOT NULL, + "AttachmentOwnerID" varchar(255) NOT NULL DEFAULT '', + constraint os_groupsnoticespk PRIMARY KEY ("NoticeID") +); + + +DROP TABLE IF EXISTS os_groups_principals; + +CREATE TABLE os_groups_principals ( + "PrincipalID" VARCHAR(255) NOT NULL DEFAULT '', + "ActiveGroupID" uuid NOT NULL, + constraint os_groupprincpk PRIMARY KEY ("PrincipalID") +); + +COMMIT; + +:VERSION 4 + +BEGIN; + +ALTER TABLE IF EXISTS os_groups_notices + ALTER COLUMN "AttachmentItemID" SET DEFAULT '00000000-0000-0000-0000-000000000000' +; + +COMMIT; diff --git a/OpenSim/Data/Properties/AssemblyInfo.cs b/OpenSim/Data/Properties/AssemblyInfo.cs index 0da1a6b..b1f234b 100644 --- a/OpenSim/Data/Properties/AssemblyInfo.cs +++ b/OpenSim/Data/Properties/AssemblyInfo.cs @@ -61,5 +61,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly : AssemblyVersion("0.7.5.*")] -[assembly : AssemblyFileVersion("0.6.5.0")] +[assembly : AssemblyVersion("0.8.2.*")] + diff --git a/OpenSim/Data/SQLite/Properties/AssemblyInfo.cs b/OpenSim/Data/SQLite/Properties/AssemblyInfo.cs index c9a8553..d2e62d2 100644 --- a/OpenSim/Data/SQLite/Properties/AssemblyInfo.cs +++ b/OpenSim/Data/SQLite/Properties/AssemblyInfo.cs @@ -61,5 +61,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly : AssemblyVersion("0.7.5.*")] -[assembly : AssemblyFileVersion("0.6.5.0")] +[assembly : AssemblyVersion("0.8.2.*")] + diff --git a/OpenSim/Data/SQLite/Resources/AgentPrefs.migrations b/OpenSim/Data/SQLite/Resources/AgentPrefs.migrations new file mode 100644 index 0000000..7e0525d --- /dev/null +++ b/OpenSim/Data/SQLite/Resources/AgentPrefs.migrations @@ -0,0 +1,36 @@ +:VERSION 1 + +BEGIN TRANSACTION; + +CREATE TABLE `AgentPrefs` ( + `PrincipalID` CHAR(36) NOT NULL, + `AccessPrefs` CHAR(2) NOT NULL DEFAULT 'M', + `HoverHeight` DOUBLE(30, 27) NOT NULL DEFAULT 0, + `Language` CHAR(5) NOT NULL DEFAULT 'en-us', + `LanguageIsPublic` BOOLEAN NOT NULL DEFAULT 1, + `PermEveryone` INT(6) NOT NULL DEFAULT 0, + `PermGroup` INT(6) NOT NULL DEFAULT 0, + `PermNextOwner` INT(6) NOT NULL DEFAULT 532480, + UNIQUE KEY `PrincipalID` (`PrincipalID`), + PRIMARY KEY(`PrincipalID`)); + +COMMIT; + +:VERSION 2 + +BEGIN; + +CREATE TABLE AgentPrefs( + PrincipalID CHAR(36) NOT NULL, + AccessPrefs CHAR(2) NOT NULL DEFAULT 'M', + HoverHeight DOUBLE(30, 27) NOT NULL DEFAULT 0, + Language CHAR(5) NOT NULL DEFAULT 'en-us', + LanguageIsPublic BOOLEAN NOT NULL DEFAULT 1, + PermEveryone INT(6) NOT NULL DEFAULT 0, + PermGroup INT(6) NOT NULL DEFAULT 0, + PermNextOwner INT(6) NOT NULL DEFAULT 532480, + UNIQUE(PrincipalID), + PRIMARY KEY(PrincipalID) +); + +COMMIT; diff --git a/OpenSim/Data/SQLite/Resources/EstateStore.migrations b/OpenSim/Data/SQLite/Resources/EstateStore.migrations index 62f6464..0aec49b 100644 --- a/OpenSim/Data/SQLite/Resources/EstateStore.migrations +++ b/OpenSim/Data/SQLite/Resources/EstateStore.migrations @@ -86,3 +86,12 @@ begin; alter table estate_settings add column DenyMinors tinyint not null default 0; commit; + +:VERSION 9 + +begin; +alter table estate_settings add column AllowLandmark tinyint not null default '1'; +alter table estate_settings add column AllowParcelChanges tinyint not null default '1'; +alter table estate_settings add column AllowSetHome tinyint not null default '1'; +commit; + diff --git a/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations b/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations new file mode 100644 index 0000000..02612ce --- /dev/null +++ b/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations @@ -0,0 +1,18 @@ +:VERSION 2 # -------------------------- + +BEGIN; + +CREATE TABLE hg_traveling_data( + SessionID VARCHAR(36) NOT NULL, + UserID VARCHAR(36) NOT NULL, + GridExternalName VARCHAR(255) NOT NULL DEFAULT "", + ServiceToken VARCHAR(255) NOT NULL DEFAULT "", + ClientIPAddress VARCHAR(16) NOT NULL DEFAULT "", + MyIPAddress VARCHAR(16) NOT NULL DEFAULT "", + TMStamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY(SessionID), + UNIQUE(UserID) +); + +COMMIT; + diff --git a/OpenSim/Data/SQLite/Resources/RegionStore.migrations b/OpenSim/Data/SQLite/Resources/RegionStore.migrations index e872977..901068f 100644 --- a/OpenSim/Data/SQLite/Resources/RegionStore.migrations +++ b/OpenSim/Data/SQLite/Resources/RegionStore.migrations @@ -575,3 +575,40 @@ CREATE TABLE `regionenvironment` ( ); COMMIT; + +:VERSION 27 +BEGIN; +ALTER TABLE prims ADD COLUMN DynAttrs TEXT; +COMMIT; + +:VERSION 28 + +BEGIN; + +ALTER TABLE prims ADD COLUMN `PhysicsShapeType` tinyint(4) NOT NULL default '0'; +ALTER TABLE prims ADD COLUMN `Density` double NOT NULL default '1000'; +ALTER TABLE prims ADD COLUMN `GravityModifier` double NOT NULL default '1'; +ALTER TABLE prims ADD COLUMN `Friction` double NOT NULL default '0.6'; +ALTER TABLE prims ADD COLUMN `Restitution` double NOT NULL default '0.5'; + +COMMIT; + +:VERSION 29 #---------------- Keyframes + +BEGIN; + +ALTER TABLE prims ADD COLUMN `KeyframeMotion` blob; + +COMMIT; + +:VERSION 30 #---------------- Save Attachment info + +BEGIN; + +ALTER TABLE prims ADD COLUMN AttachedPosX double default '0'; +ALTER TABLE prims ADD COLUMN AttachedPosY double default '0'; +ALTER TABLE prims ADD COLUMN AttachedPosZ double default '0'; +ALTER TABLE primshapes ADD COLUMN LastAttachPoint int not null default '0'; + +COMMIT; + diff --git a/OpenSim/Data/SQLite/Resources/UserProfiles.migrations b/OpenSim/Data/SQLite/Resources/UserProfiles.migrations new file mode 100644 index 0000000..86434e8 --- /dev/null +++ b/OpenSim/Data/SQLite/Resources/UserProfiles.migrations @@ -0,0 +1,102 @@ +:VERSION 1 # ------------------------------- + +begin; + +CREATE TABLE IF NOT EXISTS classifieds ( + classifieduuid char(36) NOT NULL PRIMARY KEY, + creatoruuid char(36) NOT NULL, + creationdate int(20) NOT NULL, + expirationdate int(20) NOT NULL, + category varchar(20) NOT NULL, + name varchar(255) NOT NULL, + description text NOT NULL, + parceluuid char(36) NOT NULL, + parentestate int(11) NOT NULL, + snapshotuuid char(36) NOT NULL, + simname varchar(255) NOT NULL, + posglobal varchar(255) NOT NULL, + parcelname varchar(255) NOT NULL, + classifiedflags int(8) NOT NULL, + priceforlisting int(5) NOT NULL +); + +commit; + +begin; + +CREATE TABLE IF NOT EXISTS usernotes ( + useruuid varchar(36) NOT NULL, + targetuuid varchar(36) NOT NULL, + notes text NOT NULL, + UNIQUE (useruuid,targetuuid) ON CONFLICT REPLACE +); + +commit; + +begin; + +CREATE TABLE IF NOT EXISTS userpicks ( + pickuuid varchar(36) NOT NULL PRIMARY KEY, + creatoruuid varchar(36) NOT NULL, + toppick int NOT NULL, + parceluuid varchar(36) NOT NULL, + name varchar(255) NOT NULL, + description text NOT NULL, + snapshotuuid varchar(36) NOT NULL, + user varchar(255) NOT NULL, + originalname varchar(255) NOT NULL, + simname varchar(255) NOT NULL, + posglobal varchar(255) NOT NULL, + sortorder int(2) NOT NULL, + enabled int NOT NULL +); + +commit; + +begin; + +CREATE TABLE IF NOT EXISTS userprofile ( + useruuid varchar(36) NOT NULL PRIMARY KEY, + profilePartner varchar(36) NOT NULL, + profileAllowPublish binary(1) NOT NULL, + profileMaturePublish binary(1) NOT NULL, + profileURL varchar(255) NOT NULL, + profileWantToMask int(3) NOT NULL, + profileWantToText text NOT NULL, + profileSkillsMask int(3) NOT NULL, + profileSkillsText text NOT NULL, + profileLanguages text NOT NULL, + profileImage varchar(36) NOT NULL, + profileAboutText text NOT NULL, + profileFirstImage varchar(36) NOT NULL, + profileFirstText text NOT NULL +); + +commit; + +:VERSION 2 # ------------------------------- + +begin; + +CREATE TABLE IF NOT EXISTS userdata ( + UserId char(36) NOT NULL, + TagId varchar(64) NOT NULL, + DataKey varchar(255), + DataVal varchar(255), + PRIMARY KEY (UserId,TagId) +); + +commit; + + +:VERSION 3 # ------------------------------- + +begin; +CREATE TABLE IF NOT EXISTS usersettings ( + useruuid char(36) NOT NULL, + imviaemail binary(1) NOT NULL, + visible binary(1) NOT NULL, + email varchar(254) NOT NULL, + PRIMARY KEY (useruuid) +) +commit; \ No newline at end of file diff --git a/OpenSim/Data/SQLite/SQLiteAgentPreferencesData.cs b/OpenSim/Data/SQLite/SQLiteAgentPreferencesData.cs new file mode 100644 index 0000000..d22393d --- /dev/null +++ b/OpenSim/Data/SQLite/SQLiteAgentPreferencesData.cs @@ -0,0 +1,60 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using OpenMetaverse; +using OpenSim.Framework; +#if CSharpSqlite + using Community.CsharpSqlite.Sqlite; +#else + using Mono.Data.Sqlite; +#endif + +namespace OpenSim.Data.SQLite +{ + public class SQLiteAgentPreferencesData : SQLiteGenericTableHandler, IAgentPreferencesData + { + public SQLiteAgentPreferencesData(string connectionString, string realm) + : base(connectionString, realm, "AgentPrefs") + { + } + + public AgentPreferencesData GetPrefs(UUID agentID) + { + AgentPreferencesData[] ret = Get("PrincipalID", agentID.ToString()); + + if (ret.Length == 0) + return null; + + return ret[0]; + } + + } +} diff --git a/OpenSim/Data/SQLite/SQLiteAssetData.cs b/OpenSim/Data/SQLite/SQLiteAssetData.cs index 61e7aaf..f0dda64 100644 --- a/OpenSim/Data/SQLite/SQLiteAssetData.cs +++ b/OpenSim/Data/SQLite/SQLiteAssetData.cs @@ -46,7 +46,7 @@ namespace OpenSim.Data.SQLite /// public class SQLiteAssetData : AssetDataBase { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private const string SelectAssetSQL = "select * from assets where UUID=:UUID"; private const string SelectAssetMetadataSQL = "select Name, Description, Type, Temporary, asset_flags, UUID, CreatorID from assets limit :start, :count"; @@ -133,8 +133,26 @@ namespace OpenSim.Data.SQLite /// Asset Base override public void StoreAsset(AssetBase asset) { + string assetName = asset.Name; + if (asset.Name.Length > AssetBase.MAX_ASSET_NAME) + { + assetName = asset.Name.Substring(0, AssetBase.MAX_ASSET_NAME); + m_log.WarnFormat( + "[ASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add", + asset.Name, asset.ID, asset.Name.Length, assetName.Length); + } + + string assetDescription = asset.Description; + if (asset.Description.Length > AssetBase.MAX_ASSET_DESC) + { + assetDescription = asset.Description.Substring(0, AssetBase.MAX_ASSET_DESC); + m_log.WarnFormat( + "[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add", + asset.Description, asset.ID, asset.Description.Length, assetDescription.Length); + } + //m_log.Info("[ASSET DB]: Creating Asset " + asset.FullID.ToString()); - if (ExistsAsset(asset.FullID)) + if (AssetsExist(new[] { asset.FullID })[0]) { //LogAssetLoad(asset); @@ -143,8 +161,8 @@ namespace OpenSim.Data.SQLite using (SqliteCommand cmd = new SqliteCommand(UpdateAssetSQL, m_conn)) { cmd.Parameters.Add(new SqliteParameter(":UUID", asset.FullID.ToString())); - cmd.Parameters.Add(new SqliteParameter(":Name", asset.Name)); - cmd.Parameters.Add(new SqliteParameter(":Description", asset.Description)); + cmd.Parameters.Add(new SqliteParameter(":Name", assetName)); + cmd.Parameters.Add(new SqliteParameter(":Description", assetDescription)); cmd.Parameters.Add(new SqliteParameter(":Type", asset.Type)); cmd.Parameters.Add(new SqliteParameter(":Local", asset.Local)); cmd.Parameters.Add(new SqliteParameter(":Temporary", asset.Temporary)); @@ -163,8 +181,8 @@ namespace OpenSim.Data.SQLite using (SqliteCommand cmd = new SqliteCommand(InsertAssetSQL, m_conn)) { cmd.Parameters.Add(new SqliteParameter(":UUID", asset.FullID.ToString())); - cmd.Parameters.Add(new SqliteParameter(":Name", asset.Name)); - cmd.Parameters.Add(new SqliteParameter(":Description", asset.Description)); + cmd.Parameters.Add(new SqliteParameter(":Name", assetName)); + cmd.Parameters.Add(new SqliteParameter(":Description", assetDescription)); cmd.Parameters.Add(new SqliteParameter(":Type", asset.Type)); cmd.Parameters.Add(new SqliteParameter(":Local", asset.Local)); cmd.Parameters.Add(new SqliteParameter(":Temporary", asset.Temporary)); @@ -196,32 +214,39 @@ namespace OpenSim.Data.SQLite // } /// - /// Check if an asset exist in database + /// Check if the assets exist in the database. /// - /// The asset UUID - /// True if exist, or false. - override public bool ExistsAsset(UUID uuid) + /// The assets' IDs + /// For each asset: true if it exists, false otherwise + public override bool[] AssetsExist(UUID[] uuids) { - lock (this) + if (uuids.Length == 0) + return new bool[0]; + + HashSet exist = new HashSet(); + + string ids = "'" + string.Join("','", uuids) + "'"; + string sql = string.Format("select UUID from assets where UUID in ({0})", ids); + + lock (this) { - using (SqliteCommand cmd = new SqliteCommand(SelectAssetSQL, m_conn)) + using (SqliteCommand cmd = new SqliteCommand(sql, m_conn)) { - cmd.Parameters.Add(new SqliteParameter(":UUID", uuid.ToString())); using (IDataReader reader = cmd.ExecuteReader()) { - if (reader.Read()) - { - reader.Close(); - return true; - } - else + while (reader.Read()) { - reader.Close(); - return false; + UUID id = new UUID((string)reader["UUID"]); + exist.Add(id); } } } } + + bool[] results = new bool[uuids.Length]; + for (int i = 0; i < uuids.Length; i++) + results[i] = exist.Contains(uuids[i]); + return results; } /// diff --git a/OpenSim/Data/SQLite/SQLiteFriendsData.cs b/OpenSim/Data/SQLite/SQLiteFriendsData.cs index cab85eb..331f426 100644 --- a/OpenSim/Data/SQLite/SQLiteFriendsData.cs +++ b/OpenSim/Data/SQLite/SQLiteFriendsData.cs @@ -67,7 +67,7 @@ namespace OpenSim.Data.SQLite return Delete(principalID.ToString(), friend); } - public bool Delete(string principalID, string friend) + public override bool Delete(string principalID, string friend) { using (SqliteCommand cmd = new SqliteCommand()) { diff --git a/OpenSim/Data/SQLite/SQLiteGridUserData.cs b/OpenSim/Data/SQLite/SQLiteGridUserData.cs index 1bb5ed8..d8c52f8 100644 --- a/OpenSim/Data/SQLite/SQLiteGridUserData.cs +++ b/OpenSim/Data/SQLite/SQLiteGridUserData.cs @@ -56,6 +56,10 @@ namespace OpenSim.Data.SQLite return ret[0]; } + public GridUserData[] GetAll(string userID) + { + return base.Get(String.Format("UserID LIKE '{0}%'", userID)); + } } } \ No newline at end of file diff --git a/OpenSim/Data/SQLite/SQLiteHGTravelData.cs b/OpenSim/Data/SQLite/SQLiteHGTravelData.cs new file mode 100644 index 0000000..db288b2 --- /dev/null +++ b/OpenSim/Data/SQLite/SQLiteHGTravelData.cs @@ -0,0 +1,82 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Data; +using System.Reflection; +using System.Threading; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using Mono.Data.Sqlite; + +namespace OpenSim.Data.SQLite +{ + /// + /// A SQL Interface for user grid data + /// + public class SQLiteHGTravelData : SQLiteGenericTableHandler, IHGTravelingData + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public SQLiteHGTravelData(string connectionString, string realm) + : base(connectionString, realm, "HGTravelStore") {} + + public HGTravelingData Get(UUID sessionID) + { + HGTravelingData[] ret = Get("SessionID", sessionID.ToString()); + + if (ret.Length == 0) + return null; + + return ret[0]; + } + + public HGTravelingData[] GetSessions(UUID userID) + { + return base.Get("UserID", userID.ToString()); + } + + public bool Delete(UUID sessionID) + { + return Delete("SessionID", sessionID.ToString()); + } + + public void DeleteOld() + { + using (SqliteCommand cmd = new SqliteCommand()) + { + cmd.CommandText = String.Format("delete from {0} where TMStamp < datetime('now', '-2 day') ", m_Realm); + + DoQuery(cmd); + } + + } + + } +} \ No newline at end of file diff --git a/OpenSim/Data/SQLite/SQLiteInventoryStore.cs b/OpenSim/Data/SQLite/SQLiteInventoryStore.cs index ccbd154..7d493ca 100644 --- a/OpenSim/Data/SQLite/SQLiteInventoryStore.cs +++ b/OpenSim/Data/SQLite/SQLiteInventoryStore.cs @@ -239,7 +239,7 @@ namespace OpenSim.Data.SQLite if (inventoryRow == null) { if (! add) - m_log.ErrorFormat("Interface Misuse: Attempting to Update non-existant inventory folder: {0}", folder.ID); + m_log.ErrorFormat("Interface Misuse: Attempting to Update non-existent inventory folder: {0}", folder.ID); inventoryRow = inventoryFolderTable.NewRow(); fillFolderRow(inventoryRow, folder); @@ -298,7 +298,7 @@ namespace OpenSim.Data.SQLite if (inventoryRow == null) { if (!add) - m_log.ErrorFormat("[INVENTORY DB]: Interface Misuse: Attempting to Update non-existant inventory item: {0}", item.ID); + m_log.ErrorFormat("[INVENTORY DB]: Interface Misuse: Attempting to Update non-existent inventory item: {0}", item.ID); inventoryRow = inventoryItemTable.NewRow(); fillItemRow(inventoryRow, item); diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs index 29cac3c..6ed3d40 100644 --- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs +++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs @@ -51,6 +51,7 @@ namespace OpenSim.Data.SQLite public class SQLiteSimulationData : ISimulationDataStore { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly string LogHeader = "[REGION DB SQLITE]"; private const string primSelect = "select * from prims"; private const string shapeSelect = "select * from primshapes"; @@ -732,9 +733,12 @@ namespace OpenSim.Data.SQLite } SceneObjectGroup group = new SceneObjectGroup(prim); + createdObjects.Add(group.UUID, group); retvals.Add(group); LoadItems(prim); + + } } catch (Exception e) @@ -816,45 +820,44 @@ namespace OpenSim.Data.SQLite prim.Inventory.RestoreInventoryItems(inventory); } + // Legacy entry point for when terrain was always a 256x256 hieghtmap + public void StoreTerrain(double[,] ter, UUID regionID) + { + StoreTerrain(new HeightmapTerrainData(ter), regionID); + } + /// /// Store a terrain revision in region storage /// /// terrain heightfield /// region UUID - public void StoreTerrain(double[,] ter, UUID regionID) + public void StoreTerrain(TerrainData terrData, UUID regionID) { lock (ds) { - int revision = Util.UnixTimeSinceEpoch(); - - // This is added to get rid of the infinitely growing - // terrain databases which negatively impact on SQLite - // over time. Before reenabling this feature there - // needs to be a limitter put on the number of - // revisions in the database, as this old - // implementation is a DOS attack waiting to happen. - using ( - SqliteCommand cmd = - new SqliteCommand("delete from terrain where RegionUUID=:RegionUUID and Revision <= :Revision", - m_conn)) + SqliteCommand cmd = new SqliteCommand("delete from terrain where RegionUUID=:RegionUUID", m_conn)) { cmd.Parameters.Add(new SqliteParameter(":RegionUUID", regionID.ToString())); - cmd.Parameters.Add(new SqliteParameter(":Revision", revision)); cmd.ExecuteNonQuery(); } // the following is an work around for .NET. The perf // issues associated with it aren't as bad as you think. - m_log.Debug("[SQLITE REGION DB]: Storing terrain revision r" + revision.ToString()); String sql = "insert into terrain(RegionUUID, Revision, Heightfield)" + " values(:RegionUUID, :Revision, :Heightfield)"; + int terrainDBRevision; + Array terrainDBblob; + terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob); + + m_log.DebugFormat("{0} Storing terrain revision r {1}", LogHeader, terrainDBRevision); + using (SqliteCommand cmd = new SqliteCommand(sql, m_conn)) { cmd.Parameters.Add(new SqliteParameter(":RegionUUID", regionID.ToString())); - cmd.Parameters.Add(new SqliteParameter(":Revision", revision)); - cmd.Parameters.Add(new SqliteParameter(":Heightfield", serializeTerrain(ter))); + cmd.Parameters.Add(new SqliteParameter(":Revision", terrainDBRevision)); + cmd.Parameters.Add(new SqliteParameter(":Heightfield", terrainDBblob)); cmd.ExecuteNonQuery(); } } @@ -867,11 +870,20 @@ namespace OpenSim.Data.SQLite /// Heightfield data public double[,] LoadTerrain(UUID regionID) { + double[,] ret = null; + TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight); + if (terrData != null) + ret = terrData.GetDoubles(); + return ret; + } + + // Returns 'null' if region not found + public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ) + { + TerrainData terrData = null; + lock (ds) { - double[,] terret = new double[(int)Constants.RegionSize, (int)Constants.RegionSize]; - terret.Initialize(); - String sql = "select RegionUUID, Revision, Heightfield from terrain" + " where RegionUUID=:RegionUUID order by Revision desc"; @@ -884,21 +896,9 @@ namespace OpenSim.Data.SQLite int rev = 0; if (row.Read()) { - // TODO: put this into a function - using (MemoryStream str = new MemoryStream((byte[])row["Heightfield"])) - { - using (BinaryReader br = new BinaryReader(str)) - { - for (int x = 0; x < (int)Constants.RegionSize; x++) - { - for (int y = 0; y < (int)Constants.RegionSize; y++) - { - terret[x, y] = br.ReadDouble(); - } - } - } - } rev = Convert.ToInt32(row["Revision"]); + byte[] blob = (byte[])row["Heightfield"]; + terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob); } else { @@ -909,8 +909,8 @@ namespace OpenSim.Data.SQLite m_log.Debug("[SQLITE REGION DB]: Loaded terrain revision r" + rev.ToString()); } } - return terret; } + return terrData; } public void RemoveLandObject(UUID globalID) @@ -1232,7 +1232,20 @@ namespace OpenSim.Data.SQLite createCol(prims, "VolumeDetect", typeof(Int16)); createCol(prims, "MediaURL", typeof(String)); + + createCol(prims, "AttachedPosX", typeof(Double)); + createCol(prims, "AttachedPosY", typeof(Double)); + createCol(prims, "AttachedPosZ", typeof(Double)); + + createCol(prims, "DynAttrs", typeof(String)); + + createCol(prims, "PhysicsShapeType", typeof(Byte)); + createCol(prims, "Density", typeof(Double)); + createCol(prims, "GravityModifier", typeof(Double)); + createCol(prims, "Friction", typeof(Double)); + createCol(prims, "Restitution", typeof(Double)); + createCol(prims, "KeyframeMotion", typeof(Byte[])); // Add in contraints prims.PrimaryKey = new DataColumn[] { prims.Columns["UUID"] }; @@ -1592,7 +1605,7 @@ namespace OpenSim.Data.SQLite prim.SitName = (String)row["SitName"]; prim.TouchName = (String)row["TouchName"]; // permissions - prim.ObjectFlags = Convert.ToUInt32(row["ObjectFlags"]); + prim.Flags = (PrimFlags)Convert.ToUInt32(row["ObjectFlags"]); prim.CreatorIdentification = (String)row["CreatorID"]; prim.OwnerID = new UUID((String)row["OwnerID"]); prim.GroupID = new UUID((String)row["GroupID"]); @@ -1711,7 +1724,43 @@ namespace OpenSim.Data.SQLite // m_log.DebugFormat("[SQLITE]: MediaUrl type [{0}]", row["MediaURL"].GetType()); prim.MediaUrl = (string)row["MediaURL"]; } + + prim.AttachedPos = new Vector3( + Convert.ToSingle(row["AttachedPosX"]), + Convert.ToSingle(row["AttachedPosY"]), + Convert.ToSingle(row["AttachedPosZ"]) + ); + + if (!(row["DynAttrs"] is System.DBNull)) + { + //m_log.DebugFormat("[SQLITE]: DynAttrs type [{0}]", row["DynAttrs"].GetType()); + prim.DynAttrs = DAMap.FromXml((string)row["DynAttrs"]); + } + else + { + prim.DynAttrs = new DAMap(); + } + + prim.PhysicsShapeType = Convert.ToByte(row["PhysicsShapeType"]); + prim.Density = Convert.ToSingle(row["Density"]); + prim.GravityModifier = Convert.ToSingle(row["GravityModifier"]); + prim.Friction = Convert.ToSingle(row["Friction"]); + prim.Restitution = Convert.ToSingle(row["Restitution"]); + + if (!(row["KeyframeMotion"] is DBNull)) + { + Byte[] data = (byte[])row["KeyframeMotion"]; + if (data.Length > 0) + prim.KeyframeMotion = KeyframeMotion.FromData(null, data); + else + prim.KeyframeMotion = null; + } + else + { + prim.KeyframeMotion = null; + } + return prim; } @@ -1967,40 +2016,6 @@ namespace OpenSim.Data.SQLite /// /// /// - /// - /// - private static Array serializeTerrain(double[,] val) - { - MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize) * sizeof(double)); - BinaryWriter bw = new BinaryWriter(str); - - // TODO: COMPATIBILITY - Add byte-order conversions - for (int x = 0; x < (int)Constants.RegionSize; x++) - for (int y = 0; y < (int)Constants.RegionSize; y++) - bw.Write(val[x, y]); - - return str.ToArray(); - } - - // private void fillTerrainRow(DataRow row, UUID regionUUID, int rev, double[,] val) - // { - // row["RegionUUID"] = regionUUID; - // row["Revision"] = rev; - - // MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize)*sizeof (double)); - // BinaryWriter bw = new BinaryWriter(str); - - // // TODO: COMPATIBILITY - Add byte-order conversions - // for (int x = 0; x < (int)Constants.RegionSize; x++) - // for (int y = 0; y < (int)Constants.RegionSize; y++) - // bw.Write(val[x, y]); - - // row["Heightfield"] = str.ToArray(); - // } - - /// - /// - /// /// /// /// @@ -2019,7 +2034,7 @@ namespace OpenSim.Data.SQLite row["SitName"] = prim.SitName; row["TouchName"] = prim.TouchName; // permissions - row["ObjectFlags"] = prim.ObjectFlags; + row["ObjectFlags"] = (uint)prim.Flags; row["CreatorID"] = prim.CreatorIdentification.ToString(); row["OwnerID"] = prim.OwnerID.ToString(); row["GroupID"] = prim.GroupID.ToString(); @@ -2133,6 +2148,28 @@ namespace OpenSim.Data.SQLite row["VolumeDetect"] = 0; row["MediaURL"] = prim.MediaUrl; + + row["AttachedPosX"] = prim.AttachedPos.X; + row["AttachedPosY"] = prim.AttachedPos.Y; + row["AttachedPosZ"] = prim.AttachedPos.Z; + + if (prim.DynAttrs.CountNamespaces > 0) + row["DynAttrs"] = prim.DynAttrs.ToXml(); + else + row["DynAttrs"] = null; + + row["PhysicsShapeType"] = prim.PhysicsShapeType; + row["Density"] = (double)prim.Density; + row["GravityModifier"] = (double)prim.GravityModifier; + row["Friction"] = (double)prim.Friction; + row["Restitution"] = (double)prim.Restitution; + + if (prim.KeyframeMotion != null) + row["KeyframeMotion"] = prim.KeyframeMotion.Serialize(); + else + row["KeyframeMotion"] = new Byte[0]; + + } /// @@ -2384,6 +2421,7 @@ namespace OpenSim.Data.SQLite s.ProfileCurve = Convert.ToByte(row["ProfileCurve"]); s.ProfileHollow = Convert.ToUInt16(row["ProfileHollow"]); s.State = Convert.ToByte(row["State"]); + s.LastAttachPoint = Convert.ToByte(row["LastAttachPoint"]); byte[] textureEntry = (byte[])row["Texture"]; s.TextureEntry = textureEntry; @@ -2392,7 +2430,7 @@ namespace OpenSim.Data.SQLite if (!(row["Media"] is System.DBNull)) s.Media = PrimitiveBaseShape.MediaList.FromXml((string)row["Media"]); - + return s; } @@ -2433,6 +2471,7 @@ namespace OpenSim.Data.SQLite row["ProfileCurve"] = s.ProfileCurve; row["ProfileHollow"] = s.ProfileHollow; row["State"] = s.State; + row["LastAttachPoint"] = s.LastAttachPoint; row["Texture"] = s.TextureEntry; row["ExtraParams"] = s.ExtraParams; diff --git a/OpenSim/Data/SQLite/SQLiteUserProfilesData.cs b/OpenSim/Data/SQLite/SQLiteUserProfilesData.cs new file mode 100644 index 0000000..cd3e8b6 --- /dev/null +++ b/OpenSim/Data/SQLite/SQLiteUserProfilesData.cs @@ -0,0 +1,981 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Data; +using System.Reflection; +using log4net; +#if CSharpSqlite +using Community.CsharpSqlite.Sqlite; +#else +using Mono.Data.Sqlite; +#endif +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Data.SQLite +{ + public class SQLiteUserProfilesData: IProfilesData + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private SqliteConnection m_connection; + private string m_connectionString; + + private Dictionary m_FieldMap = + new Dictionary(); + + protected virtual Assembly Assembly + { + get { return GetType().Assembly; } + } + + public SQLiteUserProfilesData() + { + } + + public SQLiteUserProfilesData(string connectionString) + { + Initialise(connectionString); + } + + public void Initialise(string connectionString) + { + if (Util.IsWindows()) + Util.LoadArchSpecificWindowsDll("sqlite3.dll"); + + m_connectionString = connectionString; + + m_log.Info("[PROFILES_DATA]: Sqlite - connecting: "+m_connectionString); + + m_connection = new SqliteConnection(m_connectionString); + m_connection.Open(); + + Migration m = new Migration(m_connection, Assembly, "UserProfiles"); + m.Update(); + } + + private string[] FieldList + { + get { return new List(m_FieldMap.Keys).ToArray(); } + } + + #region IProfilesData implementation + public OSDArray GetClassifiedRecords(UUID creatorId) + { + OSDArray data = new OSDArray(); + string query = "SELECT classifieduuid, name FROM classifieds WHERE creatoruuid = :Id"; + IDataReader reader = null; + + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", creatorId); + reader = cmd.ExecuteReader(); + } + + while (reader.Read()) + { + OSDMap n = new OSDMap(); + UUID Id = UUID.Zero; + string Name = null; + try + { + UUID.TryParse(Convert.ToString( reader["classifieduuid"]), out Id); + Name = Convert.ToString(reader["name"]); + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": UserAccount exception {0}", e.Message); + } + n.Add("classifieduuid", OSD.FromUUID(Id)); + n.Add("name", OSD.FromString(Name)); + data.Add(n); + } + + reader.Close(); + + return data; + } + public bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result) + { + string query = string.Empty; + + query += "INSERT OR REPLACE INTO classifieds ("; + query += "`classifieduuid`,"; + query += "`creatoruuid`,"; + query += "`creationdate`,"; + query += "`expirationdate`,"; + query += "`category`,"; + query += "`name`,"; + query += "`description`,"; + query += "`parceluuid`,"; + query += "`parentestate`,"; + query += "`snapshotuuid`,"; + query += "`simname`,"; + query += "`posglobal`,"; + query += "`parcelname`,"; + query += "`classifiedflags`,"; + query += "`priceforlisting`) "; + query += "VALUES ("; + query += ":ClassifiedId,"; + query += ":CreatorId,"; + query += ":CreatedDate,"; + query += ":ExpirationDate,"; + query += ":Category,"; + query += ":Name,"; + query += ":Description,"; + query += ":ParcelId,"; + query += ":ParentEstate,"; + query += ":SnapshotId,"; + query += ":SimName,"; + query += ":GlobalPos,"; + query += ":ParcelName,"; + query += ":Flags,"; + query += ":ListingPrice ) "; + + if(string.IsNullOrEmpty(ad.ParcelName)) + ad.ParcelName = "Unknown"; + if(ad.ParcelId == null) + ad.ParcelId = UUID.Zero; + if(string.IsNullOrEmpty(ad.Description)) + ad.Description = "No Description"; + + DateTime epoch = new DateTime(1970, 1, 1); + DateTime now = DateTime.Now; + TimeSpan epochnow = now - epoch; + TimeSpan duration; + DateTime expiration; + TimeSpan epochexp; + + if(ad.Flags == 2) + { + duration = new TimeSpan(7,0,0,0); + expiration = now.Add(duration); + epochexp = expiration - epoch; + } + else + { + duration = new TimeSpan(365,0,0,0); + expiration = now.Add(duration); + epochexp = expiration - epoch; + } + ad.CreationDate = (int)epochnow.TotalSeconds; + ad.ExpirationDate = (int)epochexp.TotalSeconds; + + try { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":ClassifiedId", ad.ClassifiedId.ToString()); + cmd.Parameters.AddWithValue(":CreatorId", ad.CreatorId.ToString()); + cmd.Parameters.AddWithValue(":CreatedDate", ad.CreationDate.ToString()); + cmd.Parameters.AddWithValue(":ExpirationDate", ad.ExpirationDate.ToString()); + cmd.Parameters.AddWithValue(":Category", ad.Category.ToString()); + cmd.Parameters.AddWithValue(":Name", ad.Name.ToString()); + cmd.Parameters.AddWithValue(":Description", ad.Description.ToString()); + cmd.Parameters.AddWithValue(":ParcelId", ad.ParcelId.ToString()); + cmd.Parameters.AddWithValue(":ParentEstate", ad.ParentEstate.ToString()); + cmd.Parameters.AddWithValue(":SnapshotId", ad.SnapshotId.ToString ()); + cmd.Parameters.AddWithValue(":SimName", ad.SimName.ToString()); + cmd.Parameters.AddWithValue(":GlobalPos", ad.GlobalPos.ToString()); + cmd.Parameters.AddWithValue(":ParcelName", ad.ParcelName.ToString()); + cmd.Parameters.AddWithValue(":Flags", ad.Flags.ToString()); + cmd.Parameters.AddWithValue(":ListingPrice", ad.Price.ToString ()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": ClassifiedesUpdate exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + public bool DeleteClassifiedRecord(UUID recordId) + { + string query = string.Empty; + + query += "DELETE FROM classifieds WHERE "; + query += "classifieduuid = :ClasifiedId"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":ClassifiedId", recordId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": DeleteClassifiedRecord exception {0}", e.Message); + return false; + } + return true; + } + + public bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result) + { + IDataReader reader = null; + string query = string.Empty; + + query += "SELECT * FROM classifieds WHERE "; + query += "classifieduuid = :AdId"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":AdId", ad.ClassifiedId.ToString()); + + using (reader = cmd.ExecuteReader()) + { + if(reader.Read ()) + { + ad.CreatorId = new UUID(reader["creatoruuid"].ToString()); + ad.ParcelId = new UUID(reader["parceluuid"].ToString ()); + ad.SnapshotId = new UUID(reader["snapshotuuid"].ToString ()); + ad.CreationDate = Convert.ToInt32(reader["creationdate"]); + ad.ExpirationDate = Convert.ToInt32(reader["expirationdate"]); + ad.ParentEstate = Convert.ToInt32(reader["parentestate"]); + ad.Flags = (byte) Convert.ToUInt32(reader["classifiedflags"]); + ad.Category = Convert.ToInt32(reader["category"]); + ad.Price = Convert.ToInt16(reader["priceforlisting"]); + ad.Name = reader["name"].ToString(); + ad.Description = reader["description"].ToString(); + ad.SimName = reader["simname"].ToString(); + ad.GlobalPos = reader["posglobal"].ToString(); + ad.ParcelName = reader["parcelname"].ToString(); + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": GetPickInfo exception {0}", e.Message); + } + return true; + } + + public OSDArray GetAvatarPicks(UUID avatarId) + { + IDataReader reader = null; + string query = string.Empty; + + query += "SELECT `pickuuid`,`name` FROM userpicks WHERE "; + query += "creatoruuid = :Id"; + OSDArray data = new OSDArray(); + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", avatarId.ToString()); + + using (reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + OSDMap record = new OSDMap(); + + record.Add("pickuuid",OSD.FromString((string)reader["pickuuid"])); + record.Add("name",OSD.FromString((string)reader["name"])); + data.Add(record); + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": GetAvatarPicks exception {0}", e.Message); + } + return data; + } + public UserProfilePick GetPickInfo(UUID avatarId, UUID pickId) + { + IDataReader reader = null; + string query = string.Empty; + UserProfilePick pick = new UserProfilePick(); + + query += "SELECT * FROM userpicks WHERE "; + query += "creatoruuid = :CreatorId AND "; + query += "pickuuid = :PickId"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":CreatorId", avatarId.ToString()); + cmd.Parameters.AddWithValue(":PickId", pickId.ToString()); + + using (reader = cmd.ExecuteReader()) + { + + while (reader.Read()) + { + string description = (string)reader["description"]; + + if (string.IsNullOrEmpty(description)) + description = "No description given."; + + UUID.TryParse((string)reader["pickuuid"], out pick.PickId); + UUID.TryParse((string)reader["creatoruuid"], out pick.CreatorId); + UUID.TryParse((string)reader["parceluuid"], out pick.ParcelId); + UUID.TryParse((string)reader["snapshotuuid"], out pick.SnapshotId); + pick.GlobalPos = (string)reader["posglobal"]; + bool.TryParse((string)reader["toppick"].ToString(), out pick.TopPick); + bool.TryParse((string)reader["enabled"].ToString(), out pick.Enabled); + pick.Name = (string)reader["name"]; + pick.Desc = description; + pick.ParcelName = (string)reader["user"]; + pick.OriginalName = (string)reader["originalname"]; + pick.SimName = (string)reader["simname"]; + pick.SortOrder = (int)reader["sortorder"]; + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": GetPickInfo exception {0}", e.Message); + } + return pick; + } + + public bool UpdatePicksRecord(UserProfilePick pick) + { + string query = string.Empty; + + query += "INSERT OR REPLACE INTO userpicks ("; + query += "pickuuid, "; + query += "creatoruuid, "; + query += "toppick, "; + query += "parceluuid, "; + query += "name, "; + query += "description, "; + query += "snapshotuuid, "; + query += "user, "; + query += "originalname, "; + query += "simname, "; + query += "posglobal, "; + query += "sortorder, "; + query += "enabled ) "; + query += "VALUES ("; + query += ":PickId,"; + query += ":CreatorId,"; + query += ":TopPick,"; + query += ":ParcelId,"; + query += ":Name,"; + query += ":Desc,"; + query += ":SnapshotId,"; + query += ":User,"; + query += ":Original,"; + query += ":SimName,"; + query += ":GlobalPos,"; + query += ":SortOrder,"; + query += ":Enabled) "; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + int top_pick; + int.TryParse(pick.TopPick.ToString(), out top_pick); + int enabled; + int.TryParse(pick.Enabled.ToString(), out enabled); + + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":PickId", pick.PickId.ToString()); + cmd.Parameters.AddWithValue(":CreatorId", pick.CreatorId.ToString()); + cmd.Parameters.AddWithValue(":TopPick", top_pick); + cmd.Parameters.AddWithValue(":ParcelId", pick.ParcelId.ToString()); + cmd.Parameters.AddWithValue(":Name", pick.Name.ToString()); + cmd.Parameters.AddWithValue(":Desc", pick.Desc.ToString()); + cmd.Parameters.AddWithValue(":SnapshotId", pick.SnapshotId.ToString()); + cmd.Parameters.AddWithValue(":User", pick.ParcelName.ToString()); + cmd.Parameters.AddWithValue(":Original", pick.OriginalName.ToString()); + cmd.Parameters.AddWithValue(":SimName",pick.SimName.ToString()); + cmd.Parameters.AddWithValue(":GlobalPos", pick.GlobalPos); + cmd.Parameters.AddWithValue(":SortOrder", pick.SortOrder.ToString ()); + cmd.Parameters.AddWithValue(":Enabled", enabled); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": UpdateAvatarNotes exception {0}", e.Message); + return false; + } + return true; + } + + public bool DeletePicksRecord(UUID pickId) + { + string query = string.Empty; + + query += "DELETE FROM userpicks WHERE "; + query += "pickuuid = :PickId"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":PickId", pickId.ToString()); + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": DeleteUserPickRecord exception {0}", e.Message); + return false; + } + return true; + } + + public bool GetAvatarNotes(ref UserProfileNotes notes) + { + IDataReader reader = null; + string query = string.Empty; + + query += "SELECT `notes` FROM usernotes WHERE "; + query += "useruuid = :Id AND "; + query += "targetuuid = :TargetId"; + OSDArray data = new OSDArray(); + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", notes.UserId.ToString()); + cmd.Parameters.AddWithValue(":TargetId", notes.TargetId.ToString()); + + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + while (reader.Read()) + { + notes.Notes = OSD.FromString((string)reader["notes"]); + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": GetAvatarNotes exception {0}", e.Message); + } + return true; + } + + public bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result) + { + string query = string.Empty; + bool remove; + + if(string.IsNullOrEmpty(note.Notes)) + { + remove = true; + query += "DELETE FROM usernotes WHERE "; + query += "useruuid=:UserId AND "; + query += "targetuuid=:TargetId"; + } + else + { + remove = false; + query += "INSERT OR REPLACE INTO usernotes VALUES ( "; + query += ":UserId,"; + query += ":TargetId,"; + query += ":Notes )"; + } + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + + if(!remove) + cmd.Parameters.AddWithValue(":Notes", note.Notes); + cmd.Parameters.AddWithValue(":TargetId", note.TargetId.ToString ()); + cmd.Parameters.AddWithValue(":UserId", note.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": UpdateAvatarNotes exception {0}", e.Message); + return false; + } + return true; + } + + public bool GetAvatarProperties(ref UserProfileProperties props, ref string result) + { + IDataReader reader = null; + string query = string.Empty; + + query += "SELECT * FROM userprofile WHERE "; + query += "useruuid = :Id"; + + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", props.UserId.ToString()); + + + try + { + reader = cmd.ExecuteReader(); + } + catch(Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": GetAvatarProperties exception {0}", e.Message); + result = e.Message; + return false; + } + if(reader != null && reader.Read()) + { + props.WebUrl = (string)reader["profileURL"]; + UUID.TryParse((string)reader["profileImage"], out props.ImageId); + props.AboutText = (string)reader["profileAboutText"]; + UUID.TryParse((string)reader["profileFirstImage"], out props.FirstLifeImageId); + props.FirstLifeText = (string)reader["profileFirstText"]; + UUID.TryParse((string)reader["profilePartner"], out props.PartnerId); + props.WantToMask = (int)reader["profileWantToMask"]; + props.WantToText = (string)reader["profileWantToText"]; + props.SkillsMask = (int)reader["profileSkillsMask"]; + props.SkillsText = (string)reader["profileSkillsText"]; + props.Language = (string)reader["profileLanguages"]; + } + else + { + props.WebUrl = string.Empty; + props.ImageId = UUID.Zero; + props.AboutText = string.Empty; + props.FirstLifeImageId = UUID.Zero; + props.FirstLifeText = string.Empty; + props.PartnerId = UUID.Zero; + props.WantToMask = 0; + props.WantToText = string.Empty; + props.SkillsMask = 0; + props.SkillsText = string.Empty; + props.Language = string.Empty; + props.PublishProfile = false; + props.PublishMature = false; + + query = "INSERT INTO userprofile ("; + query += "useruuid, "; + query += "profilePartner, "; + query += "profileAllowPublish, "; + query += "profileMaturePublish, "; + query += "profileURL, "; + query += "profileWantToMask, "; + query += "profileWantToText, "; + query += "profileSkillsMask, "; + query += "profileSkillsText, "; + query += "profileLanguages, "; + query += "profileImage, "; + query += "profileAboutText, "; + query += "profileFirstImage, "; + query += "profileFirstText) VALUES ("; + query += ":userId, "; + query += ":profilePartner, "; + query += ":profileAllowPublish, "; + query += ":profileMaturePublish, "; + query += ":profileURL, "; + query += ":profileWantToMask, "; + query += ":profileWantToText, "; + query += ":profileSkillsMask, "; + query += ":profileSkillsText, "; + query += ":profileLanguages, "; + query += ":profileImage, "; + query += ":profileAboutText, "; + query += ":profileFirstImage, "; + query += ":profileFirstText)"; + + using (SqliteCommand put = (SqliteCommand)m_connection.CreateCommand()) + { + put.CommandText = query; + put.Parameters.AddWithValue(":userId", props.UserId.ToString()); + put.Parameters.AddWithValue(":profilePartner", props.PartnerId.ToString()); + put.Parameters.AddWithValue(":profileAllowPublish", props.PublishProfile); + put.Parameters.AddWithValue(":profileMaturePublish", props.PublishMature); + put.Parameters.AddWithValue(":profileURL", props.WebUrl); + put.Parameters.AddWithValue(":profileWantToMask", props.WantToMask); + put.Parameters.AddWithValue(":profileWantToText", props.WantToText); + put.Parameters.AddWithValue(":profileSkillsMask", props.SkillsMask); + put.Parameters.AddWithValue(":profileSkillsText", props.SkillsText); + put.Parameters.AddWithValue(":profileLanguages", props.Language); + put.Parameters.AddWithValue(":profileImage", props.ImageId.ToString()); + put.Parameters.AddWithValue(":profileAboutText", props.AboutText); + put.Parameters.AddWithValue(":profileFirstImage", props.FirstLifeImageId.ToString()); + put.Parameters.AddWithValue(":profileFirstText", props.FirstLifeText); + + put.ExecuteNonQuery(); + } + } + } + return true; + } + + public bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result) + { + string query = string.Empty; + + query += "UPDATE userprofile SET "; + query += "profileURL=:profileURL, "; + query += "profileImage=:image, "; + query += "profileAboutText=:abouttext,"; + query += "profileFirstImage=:firstlifeimage,"; + query += "profileFirstText=:firstlifetext "; + query += "WHERE useruuid=:uuid"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":profileURL", props.WebUrl); + cmd.Parameters.AddWithValue(":image", props.ImageId.ToString()); + cmd.Parameters.AddWithValue(":abouttext", props.AboutText); + cmd.Parameters.AddWithValue(":firstlifeimage", props.FirstLifeImageId.ToString()); + cmd.Parameters.AddWithValue(":firstlifetext", props.FirstLifeText); + cmd.Parameters.AddWithValue(":uuid", props.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": AgentPropertiesUpdate exception {0}", e.Message); + + return false; + } + return true; + } + + public bool UpdateAvatarInterests(UserProfileProperties up, ref string result) + { + string query = string.Empty; + + query += "UPDATE userprofile SET "; + query += "profileWantToMask=:WantMask, "; + query += "profileWantToText=:WantText,"; + query += "profileSkillsMask=:SkillsMask,"; + query += "profileSkillsText=:SkillsText, "; + query += "profileLanguages=:Languages "; + query += "WHERE useruuid=:uuid"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":WantMask", up.WantToMask); + cmd.Parameters.AddWithValue(":WantText", up.WantToText); + cmd.Parameters.AddWithValue(":SkillsMask", up.SkillsMask); + cmd.Parameters.AddWithValue(":SkillsText", up.SkillsText); + cmd.Parameters.AddWithValue(":Languages", up.Language); + cmd.Parameters.AddWithValue(":uuid", up.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": AgentInterestsUpdate exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + + public bool UpdateUserPreferences(ref UserPreferences pref, ref string result) + { + string query = string.Empty; + + query += "UPDATE usersettings SET "; + query += "imviaemail=:ImViaEmail, "; + query += "visible=:Visible, "; + query += "email=:EMail "; + query += "WHERE useruuid=:uuid"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":ImViaEmail", pref.IMViaEmail); + cmd.Parameters.AddWithValue(":Visible", pref.Visible); + cmd.Parameters.AddWithValue(":EMail", pref.EMail); + cmd.Parameters.AddWithValue(":uuid", pref.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": AgentInterestsUpdate exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + + public bool GetUserPreferences(ref UserPreferences pref, ref string result) + { + IDataReader reader = null; + string query = string.Empty; + + query += "SELECT imviaemail,visible,email FROM "; + query += "usersettings WHERE "; + query += "useruuid = :Id"; + + OSDArray data = new OSDArray(); + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue("?Id", pref.UserId.ToString()); + + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.Read()) + { + bool.TryParse((string)reader["imviaemail"], out pref.IMViaEmail); + bool.TryParse((string)reader["visible"], out pref.Visible); + pref.EMail = (string)reader["email"]; + } + else + { + query = "INSERT INTO usersettings VALUES "; + query += "(:Id,'false','false', :Email)"; + + using (SqliteCommand put = (SqliteCommand)m_connection.CreateCommand()) + { + put.Parameters.AddWithValue(":Id", pref.UserId.ToString()); + put.Parameters.AddWithValue(":Email", pref.EMail); + put.ExecuteNonQuery(); + + } + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": Get preferences exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + + public bool GetUserAppData(ref UserAppData props, ref string result) + { + IDataReader reader = null; + string query = string.Empty; + + query += "SELECT * FROM `userdata` WHERE "; + query += "UserId = :Id AND "; + query += "TagId = :TagId"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", props.UserId.ToString()); + cmd.Parameters.AddWithValue (":TagId", props.TagId.ToString()); + + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.Read()) + { + props.DataKey = (string)reader["DataKey"]; + props.DataVal = (string)reader["DataVal"]; + } + else + { + query += "INSERT INTO userdata VALUES ( "; + query += ":UserId,"; + query += ":TagId,"; + query += ":DataKey,"; + query += ":DataVal) "; + + using (SqliteCommand put = (SqliteCommand)m_connection.CreateCommand()) + { + put.Parameters.AddWithValue(":Id", props.UserId.ToString()); + put.Parameters.AddWithValue(":TagId", props.TagId.ToString()); + put.Parameters.AddWithValue(":DataKey", props.DataKey.ToString()); + put.Parameters.AddWithValue(":DataVal", props.DataVal.ToString()); + + put.ExecuteNonQuery(); + } + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": Requst application data exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + public bool SetUserAppData(UserAppData props, ref string result) + { + string query = string.Empty; + + query += "UPDATE userdata SET "; + query += "TagId = :TagId, "; + query += "DataKey = :DataKey, "; + query += "DataVal = :DataVal WHERE "; + query += "UserId = :UserId AND "; + query += "TagId = :TagId"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":UserId", props.UserId.ToString()); + cmd.Parameters.AddWithValue(":TagId", props.TagId.ToString ()); + cmd.Parameters.AddWithValue(":DataKey", props.DataKey.ToString ()); + cmd.Parameters.AddWithValue(":DataVal", props.DataKey.ToString ()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": SetUserData exception {0}", e.Message); + return false; + } + return true; + } + public OSDArray GetUserImageAssets(UUID avatarId) + { + IDataReader reader = null; + OSDArray data = new OSDArray(); + string query = "SELECT `snapshotuuid` FROM {0} WHERE `creatoruuid` = :Id"; + + // Get classified image assets + + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", avatarId.ToString()); + + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + while(reader.Read()) + { + data.Add(new OSDString((string)reader["snapshotuuid"].ToString())); + } + } + } + + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", avatarId.ToString()); + + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.Read()) + { + data.Add(new OSDString((string)reader["snapshotuuid"].ToString ())); + } + } + } + + query = "SELECT `profileImage`, `profileFirstImage` FROM `userprofile` WHERE `useruuid` = :Id"; + + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", avatarId.ToString()); + + using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.Read()) + { + data.Add(new OSDString((string)reader["profileImage"].ToString ())); + data.Add(new OSDString((string)reader["profileFirstImage"].ToString ())); + } + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[PROFILES_DATA]" + + ": GetAvatarNotes exception {0}", e.Message); + } + return data; + } + #endregion + } +} + diff --git a/OpenSim/Data/Tests/AssetTests.cs b/OpenSim/Data/Tests/AssetTests.cs index 8cb2ee0..5d7b169 100644 --- a/OpenSim/Data/Tests/AssetTests.cs +++ b/OpenSim/Data/Tests/AssetTests.cs @@ -40,9 +40,6 @@ using log4net; using MySql.Data.MySqlClient; using OpenSim.Data.MySQL; -using System.Data.SqlClient; -using OpenSim.Data.MSSQL; - using Mono.Data.Sqlite; using OpenSim.Data.SQLite; @@ -58,11 +55,6 @@ namespace OpenSim.Data.Tests { } - [TestFixture(Description = "Asset store tests (MS SQL Server)")] - public class MSSQLAssetTests : AssetTests - { - } - public class AssetTests : BasicDataServiceTest where TConn : DbConnection, new() where TAssetData : AssetDataBase, new() @@ -107,10 +99,11 @@ namespace OpenSim.Data.Tests public void T001_LoadEmpty() { TestHelpers.InMethod(); - - Assert.That(m_db.ExistsAsset(uuid1), Is.False); - Assert.That(m_db.ExistsAsset(uuid2), Is.False); - Assert.That(m_db.ExistsAsset(uuid3), Is.False); + + bool[] exist = m_db.AssetsExist(new[] { uuid1, uuid2, uuid3 }); + Assert.IsFalse(exist[0]); + Assert.IsFalse(exist[1]); + Assert.IsFalse(exist[2]); } [Test] @@ -159,9 +152,10 @@ namespace OpenSim.Data.Tests AssetBase a3b = m_db.GetAsset(uuid3); Assert.That(a3b, Constraints.PropertyCompareConstraint(a3a)); - Assert.That(m_db.ExistsAsset(uuid1), Is.True); - Assert.That(m_db.ExistsAsset(uuid2), Is.True); - Assert.That(m_db.ExistsAsset(uuid3), Is.True); + bool[] exist = m_db.AssetsExist(new[] { uuid1, uuid2, uuid3 }); + Assert.IsTrue(exist[0]); + Assert.IsTrue(exist[1]); + Assert.IsTrue(exist[2]); List metadatas = m_db.FetchAssetMetadataSet(0, 1000); diff --git a/OpenSim/Data/Tests/BasicDataServiceTest.cs b/OpenSim/Data/Tests/BasicDataServiceTest.cs index 69b79bf..acfebd0 100644 --- a/OpenSim/Data/Tests/BasicDataServiceTest.cs +++ b/OpenSim/Data/Tests/BasicDataServiceTest.cs @@ -99,6 +99,9 @@ namespace OpenSim.Data.Tests if (Directory.Exists("/proc/ppc64") || Directory.Exists("/proc/dasd")) Assert.Ignore(); + if (Util.IsWindows()) + Util.LoadArchSpecificWindowsDll("sqlite3.dll"); + // for SQLite, if no explicit conn string is specified, use a temp file if (String.IsNullOrEmpty(m_connStr)) { diff --git a/OpenSim/Data/Tests/EstateTests.cs b/OpenSim/Data/Tests/EstateTests.cs index 3e47bcf..e2b2d12 100644 --- a/OpenSim/Data/Tests/EstateTests.cs +++ b/OpenSim/Data/Tests/EstateTests.cs @@ -41,9 +41,6 @@ using System.Data.Common; using MySql.Data.MySqlClient; using OpenSim.Data.MySQL; -using System.Data.SqlClient; -using OpenSim.Data.MSSQL; - using Mono.Data.Sqlite; using OpenSim.Data.SQLite; @@ -59,11 +56,6 @@ namespace OpenSim.Data.Tests { } - [TestFixture(Description = "Estate store tests (MS SQL Server)")] - public class MSSQLEstateTests : EstateTests - { - } - public class EstateTests : BasicDataServiceTest where TConn : DbConnection, new() where TEstateStore : class, IEstateDataStore, new() diff --git a/OpenSim/Data/Tests/InventoryTests.cs b/OpenSim/Data/Tests/InventoryTests.cs index 5b6b61b..3edf89d 100644 --- a/OpenSim/Data/Tests/InventoryTests.cs +++ b/OpenSim/Data/Tests/InventoryTests.cs @@ -39,9 +39,6 @@ using System.Data.Common; using MySql.Data.MySqlClient; using OpenSim.Data.MySQL; -using System.Data.SqlClient; -using OpenSim.Data.MSSQL; - using Mono.Data.Sqlite; using OpenSim.Data.SQLite; @@ -57,11 +54,6 @@ namespace OpenSim.Data.Tests { } - [TestFixture(Description = "Inventory store tests (MS SQL Server)")] - public class MSSQLInventoryTests : InventoryTests - { - } - public class InventoryTests : BasicDataServiceTest where TConn : DbConnection, new() where TInvStore : class, IInventoryDataPlugin, new() diff --git a/OpenSim/Data/Tests/RegionTests.cs b/OpenSim/Data/Tests/RegionTests.cs index dbed8f6..8d4249a 100644 --- a/OpenSim/Data/Tests/RegionTests.cs +++ b/OpenSim/Data/Tests/RegionTests.cs @@ -44,9 +44,6 @@ using System.Data.Common; using MySql.Data.MySqlClient; using OpenSim.Data.MySQL; -using System.Data.SqlClient; -using OpenSim.Data.MSSQL; - using Mono.Data.Sqlite; using OpenSim.Data.SQLite; @@ -62,11 +59,6 @@ namespace OpenSim.Data.Tests { } - [TestFixture(Description = "Region store tests (MS SQL Server)")] - public class MSSQLRegionTests : RegionTests - { - } - public class RegionTests : BasicDataServiceTest where TConn : DbConnection, new() where TRegStore : class, ISimulationDataStore, new() diff --git a/OpenSim/Framework/AgentCircuitData.cs b/OpenSim/Framework/AgentCircuitData.cs index ffcc584..0d053e4 100644 --- a/OpenSim/Framework/AgentCircuitData.cs +++ b/OpenSim/Framework/AgentCircuitData.cs @@ -128,7 +128,31 @@ namespace OpenSim.Framework /// /// Viewer's version string as reported by the viewer at login /// - public string Viewer; + private string m_viewerInternal; + + /// + /// Viewer's version string + /// + public string Viewer + { + set { m_viewerInternal = value; } + + // Try to return consistent viewer string taking into account + // that viewers have chaagned how version is reported + // See http://opensimulator.org/mantis/view.php?id=6851 + get + { + // Old style version string contains viewer name followed by a space followed by a version number + if (m_viewerInternal == null || m_viewerInternal.Contains(" ")) + { + return m_viewerInternal; + } + else // New style version contains no spaces, just version number + { + return Channel + " " + m_viewerInternal; + } + } + } /// /// The channel strinf sent by the viewer at login @@ -297,6 +321,8 @@ namespace OpenSim.Framework Mac = args["mac"].AsString(); if (args["id0"] != null) Id0 = args["id0"].AsString(); + if (args["teleport_flags"] != null) + teleportFlags = args["teleport_flags"].AsUInteger(); if (args["start_pos"] != null) Vector3.TryParse(args["start_pos"].AsString(), out startpos); diff --git a/OpenSim/Framework/Animation.cs b/OpenSim/Framework/Animation.cs index 232f5a1..e958b75 100644 --- a/OpenSim/Framework/Animation.cs +++ b/OpenSim/Framework/Animation.cs @@ -120,5 +120,29 @@ namespace OpenSim.Framework sequenceNum = args["seq_num"].AsInteger(); } + public override bool Equals(object obj) + { + Animation other = obj as Animation; + if (other != null) + { + return (other.AnimID.Equals(this.AnimID) + && other.SequenceNum == this.SequenceNum + && other.ObjectID.Equals(this.ObjectID) ); + } + return base.Equals(obj); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public override string ToString() + { + return "AnimID=" + AnimID.ToString() + + "/seq=" + SequenceNum.ToString() + + "/objID=" + ObjectID.ToString(); + } + } } diff --git a/OpenSim/Framework/AssemblyInfo.cs b/OpenSim/Framework/AssemblyInfo.cs index 02986d5..a797424 100644 --- a/OpenSim/Framework/AssemblyInfo.cs +++ b/OpenSim/Framework/AssemblyInfo.cs @@ -59,5 +59,4 @@ using System.Runtime.InteropServices; // Revision // -[assembly : AssemblyVersion("0.7.5.*")] -[assembly : AssemblyFileVersion("0.6.5.0")] \ No newline at end of file +[assembly : AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Framework/AssetBase.cs b/OpenSim/Framework/AssetBase.cs index d2c6c57..2f04d2e 100644 --- a/OpenSim/Framework/AssetBase.cs +++ b/OpenSim/Framework/AssetBase.cs @@ -50,6 +50,9 @@ namespace OpenSim.Framework { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public static readonly int MAX_ASSET_NAME = 64; + public static readonly int MAX_ASSET_DESC = 64; + /// /// Data of the Asset /// @@ -133,7 +136,7 @@ namespace OpenSim.Framework get { return - (Type == (sbyte) AssetType.Animation || + (Type == (sbyte)AssetType.Animation || Type == (sbyte)AssetType.Gesture || Type == (sbyte)AssetType.Simstate || Type == (sbyte)AssetType.Unknown || @@ -143,13 +146,9 @@ namespace OpenSim.Framework Type == (sbyte)AssetType.Texture || Type == (sbyte)AssetType.TextureTGA || Type == (sbyte)AssetType.Folder || - Type == (sbyte)AssetType.RootFolder || - Type == (sbyte)AssetType.LostAndFoundFolder || - Type == (sbyte)AssetType.SnapshotFolder || - Type == (sbyte)AssetType.TrashFolder || Type == (sbyte)AssetType.ImageJPEG || - Type == (sbyte) AssetType.ImageTGA || - Type == (sbyte) AssetType.LSLBytecode); + Type == (sbyte)AssetType.ImageTGA || + Type == (sbyte)AssetType.LSLBytecode); } } diff --git a/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs b/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs index 0498ed4..76df564 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; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index 95e9667..26dd5df 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -40,8 +40,17 @@ namespace OpenSim.Framework /// public class AvatarAppearance { + // SL box diferent to size + const float AVBOXAJUST = 0.2f; + // constrains for ubitode physics + const float AVBOXMINX = 0.2f; + const float AVBOXMINY = 0.3f; + const float AVBOXMINZ = 1.2f; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + // this is viewer capabilities and weared things dependent + // should be only used as initial default value ( V1 viewers ) public readonly static int VISUALPARAM_COUNT = 218; public readonly static int TEXTURE_COUNT = 21; @@ -53,7 +62,15 @@ namespace OpenSim.Framework protected AvatarWearable[] m_wearables; protected Dictionary> m_attachments; protected float m_avatarHeight = 0; + protected Vector3 m_avatarSize = new Vector3(0.45f, 0.6f, 1.9f); // sl Z cloud value + protected Vector3 m_avatarBoxSize = new Vector3(0.45f, 0.6f, 1.9f); + protected float m_avatarFeetOffset = 0; + protected float m_avatarAnimOffset = 0; + protected WearableCacheItem[] m_cacheitems; + protected bool m_cacheItemsDirty = true; + + public bool PackLegacyWearables {get; set; } public virtual int Serial { get { return m_serial; } @@ -66,6 +83,21 @@ namespace OpenSim.Framework set { m_visualparams = value; } } + public virtual Vector3 AvatarSize + { + get { return m_avatarSize; } + } + + public virtual Vector3 AvatarBoxSize + { + get { return m_avatarBoxSize; } + } + + public virtual float AvatarFeetOffset + { + get { return m_avatarFeetOffset + m_avatarAnimOffset; } + } + public virtual Primitive.TextureEntry Texture { get { return m_texture; } @@ -87,16 +119,29 @@ namespace OpenSim.Framework get { return m_avatarHeight; } set { m_avatarHeight = value; } } + + public virtual WearableCacheItem[] WearableCacheItems + { + get { return m_cacheitems; } + set { m_cacheitems = value; } + } + + public virtual bool WearableCacheItemsDirty + { + get { return m_cacheItemsDirty; } + set { m_cacheItemsDirty = value; } + } public AvatarAppearance() { // m_log.WarnFormat("[AVATAR APPEARANCE]: create empty appearance"); - + PackLegacyWearables = false; m_serial = 0; SetDefaultWearables(); SetDefaultTexture(); SetDefaultParams(); - SetHeight(); +// SetHeight(); + SetSize(new Vector3(0.45f,0.6f,1.9f)); m_attachments = new Dictionary>(); } @@ -105,7 +150,7 @@ namespace OpenSim.Framework // m_log.WarnFormat("[AVATAR APPEARANCE]: create appearance from OSDMap"); Unpack(map); - SetHeight(); +// SetHeight(); done in Unpack } public AvatarAppearance(AvatarWearable[] wearables, Primitive.TextureEntry textureEntry, byte[] visualParams) @@ -129,7 +174,9 @@ namespace OpenSim.Framework else SetDefaultParams(); - SetHeight(); +// SetHeight(); + if(m_avatarHeight == 0) + SetSize(new Vector3(0.45f,0.6f,1.9f)); m_attachments = new Dictionary>(); } @@ -148,7 +195,8 @@ namespace OpenSim.Framework SetDefaultWearables(); SetDefaultTexture(); SetDefaultParams(); - SetHeight(); +// SetHeight(); + SetSize(new Vector3(0.45f, 0.6f, 1.9f)); m_attachments = new Dictionary>(); return; @@ -162,7 +210,10 @@ namespace OpenSim.Framework if (copyWearables && (appearance.Wearables != null)) { - for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) + int len = appearance.Wearables.Length; + if(len > AvatarWearable.MAX_WEARABLES) + len = AvatarWearable.MAX_WEARABLES; + for (int i = 0; i < len; i++) SetWearable(i,appearance.Wearables[i]); } @@ -177,7 +228,8 @@ namespace OpenSim.Framework if (appearance.VisualParams != null) m_visualparams = (byte[])appearance.VisualParams.Clone(); - m_avatarHeight = appearance.m_avatarHeight; +// m_avatarHeight = appearance.m_avatarHeight; + SetSize(appearance.AvatarSize); // Copy the attachment, force append mode since that ensures consistency m_attachments = new Dictionary>(); @@ -240,6 +292,21 @@ namespace OpenSim.Framework // } } + /// + /// Invalidate all of the baked textures in the appearance, useful + /// if you know that none are valid + /// + public virtual void ResetBakedTextures() + { + SetDefaultTexture(); + + //for (int i = 0; i < BAKE_INDICES.Length; i++) + // { + // int idx = BAKE_INDICES[i]; + // m_texture.FaceTextures[idx].TextureID = UUID.Zero; + // } + } + protected virtual void SetDefaultTexture() { m_texture = new Primitive.TextureEntry(new UUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE)); @@ -304,22 +371,33 @@ namespace OpenSim.Framework // made. We determine if any of the visual parameters actually // changed to know if the appearance should be saved later bool changed = false; - for (int i = 0; i < AvatarAppearance.VISUALPARAM_COUNT; i++) + + int newsize = visualParams.Length; + + if (newsize != m_visualparams.Length) { - if (visualParams[i] != m_visualparams[i]) + changed = true; + m_visualparams = (byte[])visualParams.Clone(); + } + else + { + + for (int i = 0; i < newsize; i++) { -// DEBUG ON -// m_log.WarnFormat("[AVATARAPPEARANCE] vparams changed [{0}] {1} ==> {2}", -// i,m_visualparams[i],visualParams[i]); -// DEBUG OFF - m_visualparams[i] = visualParams[i]; - changed = true; + if (visualParams[i] != m_visualparams[i]) + { + // DEBUG ON + // m_log.WarnFormat("[AVATARAPPEARANCE] vparams changed [{0}] {1} ==> {2}", + // i,m_visualparams[i],visualParams[i]); + // DEBUG OFF + m_visualparams[i] = visualParams[i]; + changed = true; + } } } - // Reset the height if the visual parameters actually changed - if (changed) - SetHeight(); +// if (changed) +// SetHeight(); return changed; } @@ -335,6 +413,7 @@ namespace OpenSim.Framework /// public virtual void SetHeight() { +/* // Start with shortest possible female avatar height m_avatarHeight = 1.14597f; // Add offset for male avatars @@ -347,6 +426,35 @@ namespace OpenSim.Framework + 0.07f * (float)m_visualparams[(int)VPElement.SHOES_PLATFORM_HEIGHT] / 255.0f + 0.08f * (float)m_visualparams[(int)VPElement.SHOES_HEEL_HEIGHT] / 255.0f + 0.076f * (float)m_visualparams[(int)VPElement.SHAPE_NECK_LENGTH] / 255.0f; +*/ + } + + public void SetSize(Vector3 avSize) + { + if (avSize.X > 32f) + avSize.X = 32f; + else if (avSize.X < 0.1f) + avSize.X = 0.1f; + + if (avSize.Y > 32f) + avSize.Y = 32f; + else if (avSize.Y < 0.1f) + avSize.Y = 0.1f; + if (avSize.Z > 32f) + avSize.Z = 32f; + else if (avSize.Z < 0.1f) + avSize.Z = 0.1f; + + m_avatarSize = avSize; + m_avatarBoxSize = avSize; + m_avatarBoxSize.Z += AVBOXAJUST; + if (m_avatarBoxSize.X < AVBOXMINX) + m_avatarBoxSize.X = AVBOXMINX; + if (m_avatarBoxSize.Y < AVBOXMINY) + m_avatarBoxSize.Y = AVBOXMINY; + if (m_avatarBoxSize.Z < AVBOXMINZ) + m_avatarBoxSize.Z = AVBOXMINZ; + m_avatarHeight = m_avatarSize.Z; } public virtual void SetWearable(int wearableId, AvatarWearable wearable) @@ -355,8 +463,11 @@ namespace OpenSim.Framework // m_log.WarnFormat("[AVATARAPPEARANCE] set wearable {0} --> {1}:{2}",wearableId,wearable.ItemID,wearable.AssetID); // DEBUG OFF m_wearables[wearableId].Clear(); - for (int i = 0; i < wearable.Count; i++) - m_wearables[wearableId].Add(wearable[i].ItemID, wearable[i].AssetID); + int count = wearable.Count; + if (count > AvatarWearable.MAX_WEARABLES) + count = AvatarWearable.MAX_WEARABLES; + for (int i = 0; i < count; i++) + m_wearables[wearableId].Add(wearable[i].ItemID, wearable[i].AssetID); } // DEBUG ON @@ -377,7 +488,8 @@ namespace OpenSim.Framework } s += "Visual Params: "; - for (uint j = 0; j < AvatarAppearance.VISUALPARAM_COUNT; j++) + // for (uint j = 0; j < AvatarAppearance.VISUALPARAM_COUNT; j++) + for (uint j = 0; j < m_visualparams.Length; j++) s += String.Format("{0},",m_visualparams[j]); s += "\n"; @@ -393,18 +505,16 @@ namespace OpenSim.Framework /// public List GetAttachments() { - List alist = new List(); - lock (m_attachments) { + List alist = new List(); foreach (KeyValuePair> kvp in m_attachments) { foreach (AvatarAttachment attach in kvp.Value) alist.Add(new AvatarAttachment(attach)); } - } - - return alist; + return alist; + } } internal void AppendAttachment(AvatarAttachment attach) @@ -418,6 +528,12 @@ namespace OpenSim.Framework if (!m_attachments.ContainsKey(attach.AttachPoint)) m_attachments[attach.AttachPoint] = new List(); + foreach (AvatarAttachment prev in m_attachments[attach.AttachPoint]) + { + if (prev.ItemID == attach.ItemID) + return; + } + m_attachments[attach.AttachPoint].Add(attach); } } @@ -459,45 +575,59 @@ namespace OpenSim.Framework if (attachpoint == 0) return false; - if (item == UUID.Zero) + lock (m_attachments) { - lock (m_attachments) + if (item == UUID.Zero) { if (m_attachments.ContainsKey(attachpoint)) { m_attachments.Remove(attachpoint); return true; } + + return false; } - - return false; - } - // When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However, - // the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If - // we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments - // later fail unless the attachment is detached and reattached. - // - // Therefore, we will carry on with the set if the existing attachment has no asset id. - AvatarAttachment existingAttachment = GetAttachmentForItem(item); - if (existingAttachment != null - && existingAttachment.AssetID != UUID.Zero - && existingAttachment.AttachPoint == (attachpoint & 0x7F)) - { - // m_log.DebugFormat("[AVATAR APPEARANCE] attempt to attach an already attached item {0}",item); - return false; - } - - // check if this is an append or a replace, 0x80 marks it as an append - if ((attachpoint & 0x80) > 0) - { - // strip the append bit - int point = attachpoint & 0x7F; - AppendAttachment(new AvatarAttachment(point, item, asset)); - } - else - { - ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset)); + // When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However, + // the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If + // we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments + // later fail unless the attachment is detached and reattached. + // + // Therefore, we will carry on with the set if the existing attachment has no asset id. + AvatarAttachment existingAttachment = GetAttachmentForItem(item); + if (existingAttachment != null) + { +// m_log.DebugFormat( +// "[AVATAR APPEARANCE]: Found existing attachment for {0}, asset {1} at point {2}", +// existingAttachment.ItemID, existingAttachment.AssetID, existingAttachment.AttachPoint); + + if (existingAttachment.AssetID != UUID.Zero && existingAttachment.AttachPoint == (attachpoint & 0x7F)) + { + m_log.DebugFormat( + "[AVATAR APPEARANCE]: Ignoring attempt to attach an already attached item {0} at point {1}", + item, attachpoint); + + return false; + } + else + { + // Remove it here so that the later append does not add a second attachment but we still update + // the assetID + DetachAttachment(existingAttachment.ItemID); + } + } + + // check if this is an append or a replace, 0x80 marks it as an append + if ((attachpoint & 0x80) > 0) + { + // strip the append bit + int point = attachpoint & 0x7F; + AppendAttachment(new AvatarAttachment(point, item, asset)); + } + else + { + ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset)); + } } return true; @@ -534,7 +664,6 @@ namespace OpenSim.Framework return kvp.Key; } } - return 0; } @@ -547,6 +676,10 @@ namespace OpenSim.Framework int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); if (index >= 0) { +// m_log.DebugFormat( +// "[AVATAR APPEARANCE]: Detaching attachment {0}, index {1}, point {2}", +// m_attachments[kvp.Key][index].ItemID, index, m_attachments[kvp.Key][index].AttachPoint); + // Remove it from the list of attachments at that attach point m_attachments[kvp.Key].RemoveAt(index); @@ -581,8 +714,15 @@ namespace OpenSim.Framework data["height"] = OSD.FromReal(m_avatarHeight); // Wearables - OSDArray wears = new OSDArray(AvatarWearable.MAX_WEARABLES); - for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) + + int wearsCount; + if(PackLegacyWearables) + wearsCount = AvatarWearable.LEGACY_VERSION_MAX_WEARABLES; + else + wearsCount = AvatarWearable.MAX_WEARABLES; + + OSDArray wears = new OSDArray(wearsCount); + for (int i = 0; i < wearsCount; i++) wears.Add(m_wearables[i].Pack()); data["wearables"] = wears; @@ -601,12 +741,14 @@ namespace OpenSim.Framework OSDBinary visualparams = new OSDBinary(m_visualparams); data["visualparams"] = visualparams; - // Attachments - List attachments = GetAttachments(); - OSDArray attachs = new OSDArray(attachments.Count); - foreach (AvatarAttachment attach in GetAttachments()) - attachs.Add(attach.Pack()); - data["attachments"] = attachs; + lock (m_attachments) + { + // Attachments + OSDArray attachs = new OSDArray(m_attachments.Count); + foreach (AvatarAttachment attach in GetAttachments()) + attachs.Add(attach.Pack()); + data["attachments"] = attachs; + } return data; } @@ -620,7 +762,8 @@ namespace OpenSim.Framework if ((data != null) && (data["serial"] != null)) m_serial = data["serial"].AsInteger(); if ((data != null) && (data["height"] != null)) - m_avatarHeight = (float)data["height"].AsReal(); +// m_avatarHeight = (float)data["height"].AsReal(); + SetSize(new Vector3(0.45f,0.6f, (float)data["height"].AsReal())); try { @@ -629,7 +772,12 @@ namespace OpenSim.Framework if ((data != null) && (data["wearables"] != null) && (data["wearables"]).Type == OSDType.Array) { OSDArray wears = (OSDArray)(data["wearables"]); - for (int i = 0; i < wears.Count; i++) + + int count = wears.Count; + if (count > AvatarWearable.MAX_WEARABLES) + count = AvatarWearable.MAX_WEARABLES; + + for (int i = 0; i < count; i++) m_wearables[i] = new AvatarWearable((OSDArray)wears[i]); } else @@ -1453,7 +1601,58 @@ namespace OpenSim.Framework SHAPE_EYELID_INNER_CORNER_UP = 214, SKIRT_SKIRT_RED = 215, SKIRT_SKIRT_GREEN = 216, - SKIRT_SKIRT_BLUE = 217 + SKIRT_SKIRT_BLUE = 217, + + /// + /// Avatar Physics section. These are 0 type visual params which get transmitted. + /// + + /// + /// Breast Part 1 + /// + BREAST_PHYSICS_MASS = 218, + BREAST_PHYSICS_GRAVITY = 219, + BREAST_PHYSICS_DRAG = 220, + BREAST_PHYSICS_UPDOWN_MAX_EFFECT = 221, + BREAST_PHYSICS_UPDOWN_SPRING = 222, + BREAST_PHYSICS_UPDOWN_GAIN = 223, + BREAST_PHYSICS_UPDOWN_DAMPING = 224, + BREAST_PHYSICS_INOUT_MAX_EFFECT = 225, + BREAST_PHYSICS_INOUT_SPRING = 226, + BREAST_PHYSICS_INOUT_GAIN = 227, + BREAST_PHYSICS_INOUT_DAMPING = 228, + /// + /// Belly + /// + BELLY_PHYISCS_MASS = 229, + BELLY_PHYSICS_GRAVITY = 230, + BELLY_PHYSICS_DRAG = 231, + BELLY_PHYISCS_UPDOWN_MAX_EFFECT = 232, + BELLY_PHYSICS_UPDOWN_SPRING = 233, + BELLY_PHYSICS_UPDOWN_GAIN = 234, + BELLY_PHYSICS_UPDOWN_DAMPING = 235, + + /// + /// Butt + /// + BUTT_PHYSICS_MASS = 236, + BUTT_PHYSICS_GRAVITY = 237, + BUTT_PHYSICS_DRAG = 238, + BUTT_PHYSICS_UPDOWN_MAX_EFFECT = 239, + BUTT_PHYSICS_UPDOWN_SPRING = 240, + BUTT_PHYSICS_UPDOWN_GAIN = 241, + BUTT_PHYSICS_UPDOWN_DAMPING = 242, + BUTT_PHYSICS_LEFTRIGHT_MAX_EFFECT = 243, + BUTT_PHYSICS_LEFTRIGHT_SPRING = 244, + BUTT_PHYSICS_LEFTRIGHT_GAIN = 245, + BUTT_PHYSICS_LEFTRIGHT_DAMPING = 246, + /// + /// Breast Part 2 + /// + BREAST_PHYSICS_LEFTRIGHT_MAX_EFFECT = 247, + BREAST_PHYSICS_LEFTRIGHT_SPRING= 248, + BREAST_PHYSICS_LEFTRIGHT_GAIN = 249, + BREAST_PHYSICS_LEFTRIGHT_DAMPING = 250 } #endregion } diff --git a/OpenSim/Framework/AvatarWearable.cs b/OpenSim/Framework/AvatarWearable.cs index 8e27596..e7615f2 100644 --- a/OpenSim/Framework/AvatarWearable.cs +++ b/OpenSim/Framework/AvatarWearable.cs @@ -65,7 +65,9 @@ namespace OpenSim.Framework public static readonly int ALPHA = 13; public static readonly int TATTOO = 14; - public static readonly int MAX_WEARABLES = 15; + public static readonly int LEGACY_VERSION_MAX_WEARABLES = 15; + public static readonly int PHYSICS = 15; + public static readonly int MAX_WEARABLES = 16; public static readonly UUID DEFAULT_BODY_ITEM = new UUID("66c41e39-38f9-f75a-024e-585989bfaba9"); public static readonly UUID DEFAULT_BODY_ASSET = new UUID("66c41e39-38f9-f75a-024e-585989bfab73"); diff --git a/OpenSim/Framework/BasicDOSProtector.cs b/OpenSim/Framework/BasicDOSProtector.cs new file mode 100644 index 0000000..89bfa94 --- /dev/null +++ b/OpenSim/Framework/BasicDOSProtector.cs @@ -0,0 +1,275 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Reflection; +using log4net; + +namespace OpenSim.Framework +{ + + public class BasicDOSProtector + { + public enum ThrottleAction + { + DoThrottledMethod, + DoThrow + } + private readonly CircularBuffer _generalRequestTimes; // General request checker + private readonly BasicDosProtectorOptions _options; + private readonly Dictionary> _deeperInspection; // per client request checker + private readonly Dictionary _tempBlocked; // blocked list + private readonly Dictionary _sessions; + private readonly System.Timers.Timer _forgetTimer; // Cleanup timer + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private readonly System.Threading.ReaderWriterLockSlim _blockLockSlim = new System.Threading.ReaderWriterLockSlim(); + private readonly System.Threading.ReaderWriterLockSlim _sessionLockSlim = new System.Threading.ReaderWriterLockSlim(); + public BasicDOSProtector(BasicDosProtectorOptions options) + { + _generalRequestTimes = new CircularBuffer(options.MaxRequestsInTimeframe + 1, true); + _generalRequestTimes.Put(0); + _options = options; + _deeperInspection = new Dictionary>(); + _tempBlocked = new Dictionary(); + _sessions = new Dictionary(); + _forgetTimer = new System.Timers.Timer(); + _forgetTimer.Elapsed += delegate + { + _forgetTimer.Enabled = false; + + List removes = new List(); + _blockLockSlim.EnterReadLock(); + foreach (string str in _tempBlocked.Keys) + { + if ( + Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), + _tempBlocked[str]) > 0) + removes.Add(str); + } + _blockLockSlim.ExitReadLock(); + lock (_deeperInspection) + { + _blockLockSlim.EnterWriteLock(); + for (int i = 0; i < removes.Count; i++) + { + _tempBlocked.Remove(removes[i]); + _deeperInspection.Remove(removes[i]); + _sessions.Remove(removes[i]); + } + _blockLockSlim.ExitWriteLock(); + } + foreach (string str in removes) + { + m_log.InfoFormat("[{0}] client: {1} is no longer blocked.", + _options.ReportingName, str); + } + _blockLockSlim.EnterReadLock(); + if (_tempBlocked.Count > 0) + _forgetTimer.Enabled = true; + _blockLockSlim.ExitReadLock(); + }; + + _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds; + } + + /// + /// Given a string Key, Returns if that context is blocked + /// + /// A Key identifying the context + /// bool Yes or No, True or False for blocked + public bool IsBlocked(string key) + { + bool ret = false; + _blockLockSlim.EnterReadLock(); + ret = _tempBlocked.ContainsKey(key); + _blockLockSlim.ExitReadLock(); + return ret; + } + + /// + /// Process the velocity of this context + /// + /// + /// + /// + public bool Process(string key, string endpoint) + { + if (_options.MaxRequestsInTimeframe < 1 || _options.RequestTimeSpan.TotalMilliseconds < 1) + return true; + + string clientstring = key; + + _blockLockSlim.EnterReadLock(); + if (_tempBlocked.ContainsKey(clientstring)) + { + _blockLockSlim.ExitReadLock(); + + if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) + return false; + else + throw new System.Security.SecurityException("Throttled"); + } + + _blockLockSlim.ExitReadLock(); + + lock (_generalRequestTimes) + _generalRequestTimes.Put(Util.EnvironmentTickCount()); + + if (_options.MaxConcurrentSessions > 0) + { + int sessionscount = 0; + + _sessionLockSlim.EnterReadLock(); + if (_sessions.ContainsKey(key)) + sessionscount = _sessions[key]; + _sessionLockSlim.ExitReadLock(); + + if (sessionscount > _options.MaxConcurrentSessions) + { + // Add to blocking and cleanup methods + lock (_deeperInspection) + { + _blockLockSlim.EnterWriteLock(); + if (!_tempBlocked.ContainsKey(clientstring)) + { + _tempBlocked.Add(clientstring, + Util.EnvironmentTickCount() + + (int) _options.ForgetTimeSpan.TotalMilliseconds); + _forgetTimer.Enabled = true; + m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds based on concurrency, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, endpoint); + + } + else + _tempBlocked[clientstring] = Util.EnvironmentTickCount() + + (int) _options.ForgetTimeSpan.TotalMilliseconds; + _blockLockSlim.ExitWriteLock(); + + } + + + } + else + ProcessConcurrency(key, endpoint); + } + if (_generalRequestTimes.Size == _generalRequestTimes.Capacity && + (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) < + _options.RequestTimeSpan.TotalMilliseconds)) + { + //Trigger deeper inspection + if (DeeperInspection(key, endpoint)) + return true; + if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) + return false; + else + throw new System.Security.SecurityException("Throttled"); + } + return true; + } + private void ProcessConcurrency(string key, string endpoint) + { + _sessionLockSlim.EnterWriteLock(); + if (_sessions.ContainsKey(key)) + _sessions[key] = _sessions[key] + 1; + else + _sessions.Add(key,1); + _sessionLockSlim.ExitWriteLock(); + } + public void ProcessEnd(string key, string endpoint) + { + _sessionLockSlim.EnterWriteLock(); + if (_sessions.ContainsKey(key)) + { + _sessions[key]--; + if (_sessions[key] <= 0) + _sessions.Remove(key); + } + else + _sessions.Add(key, 1); + + _sessionLockSlim.ExitWriteLock(); + } + + /// + /// At this point, the rate limiting code needs to track 'per user' velocity. + /// + /// Context Key, string representing a rate limiting context + /// + /// + private bool DeeperInspection(string key, string endpoint) + { + lock (_deeperInspection) + { + string clientstring = key; + + + if (_deeperInspection.ContainsKey(clientstring)) + { + _deeperInspection[clientstring].Put(Util.EnvironmentTickCount()); + if (_deeperInspection[clientstring].Size == _deeperInspection[clientstring].Capacity && + (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _deeperInspection[clientstring].Get()) < + _options.RequestTimeSpan.TotalMilliseconds)) + { + //Looks like we're over the limit + _blockLockSlim.EnterWriteLock(); + if (!_tempBlocked.ContainsKey(clientstring)) + _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds); + else + _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds; + _blockLockSlim.ExitWriteLock(); + + m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, endpoint); + + return false; + } + //else + // return true; + } + else + { + _deeperInspection.Add(clientstring, new CircularBuffer(_options.MaxRequestsInTimeframe + 1, true)); + _deeperInspection[clientstring].Put(Util.EnvironmentTickCount()); + _forgetTimer.Enabled = true; + } + + } + return true; + } + + } + + + public class BasicDosProtectorOptions + { + public int MaxRequestsInTimeframe; + public TimeSpan RequestTimeSpan; + public TimeSpan ForgetTimeSpan; + public bool AllowXForwardedFor; + public string ReportingName = "BASICDOSPROTECTOR"; + public BasicDOSProtector.ThrottleAction ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod; + public int MaxConcurrentSessions; + } +} diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index 3658161..d11ad11 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -58,7 +58,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + while (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync); } @@ -76,9 +76,10 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + bool success = true; + while (m_queue.Count < 1 && m_pqueue.Count < 1 && success) { - Monitor.Wait(m_queueSync, msTimeout); + success = Monitor.Wait(m_queueSync, msTimeout); } if (m_pqueue.Count > 0) @@ -89,28 +90,47 @@ namespace OpenSim.Framework } } + /// + /// Indicate whether this queue contains the given item. + /// + /// + /// This method is not thread-safe. Do not rely on the result without consistent external locking. + /// public bool Contains(T item) { lock (m_queueSync) { + if (m_queue.Count < 1 && m_pqueue.Count < 1) + return false; + if (m_pqueue.Contains(item)) return true; return m_queue.Contains(item); } } + /// + /// Return a count of the number of requests on this queue. + /// public int Count() { lock (m_queueSync) - { - return m_queue.Count+m_pqueue.Count; - } + return m_queue.Count + m_pqueue.Count; } + /// + /// Return the array of items on this queue. + /// + /// + /// This method is not thread-safe. Do not rely on the result without consistent external locking. + /// public T[] GetQueueArray() { lock (m_queueSync) { + if (m_queue.Count < 1 && m_pqueue.Count < 1) + return new T[0]; + return m_queue.ToArray(); } } diff --git a/OpenSim/Framework/CachedTextureEventArg.cs b/OpenSim/Framework/CachedTextureEventArg.cs new file mode 100644 index 0000000..239fc56 --- /dev/null +++ b/OpenSim/Framework/CachedTextureEventArg.cs @@ -0,0 +1,46 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Text; +using OpenMetaverse; + +namespace OpenSim.Framework +{ + public class CachedTextureRequestArg + { + public int BakedTextureIndex; + public UUID WearableHashID; + } + + public class CachedTextureResponseArg + { + public int BakedTextureIndex; + public UUID BakedTextureID; + public String HostName; + } +} diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs index dfe60aa..1504f21 100644 --- a/OpenSim/Framework/ChildAgentDataUpdate.cs +++ b/OpenSim/Framework/ChildAgentDataUpdate.cs @@ -171,9 +171,10 @@ namespace OpenSim.Framework /// Soon to be decommissioned /// /// - public void CopyFrom(ChildAgentDataUpdate cAgent) + public void CopyFrom(ChildAgentDataUpdate cAgent, UUID sid) { AgentID = new UUID(cAgent.AgentID); + SessionID = sid; // next: ??? Size = new Vector3(); @@ -229,12 +230,14 @@ namespace OpenSim.Framework public class ControllerData { + public UUID ObjectID; public UUID ItemID; public uint IgnoreControls; public uint EventControls; - public ControllerData(UUID item, uint ignore, uint ev) + public ControllerData(UUID obj, UUID item, uint ignore, uint ev) { + ObjectID = obj; ItemID = item; IgnoreControls = ignore; EventControls = ev; @@ -248,6 +251,7 @@ namespace OpenSim.Framework public OSDMap PackUpdateMessage() { OSDMap controldata = new OSDMap(); + controldata["object"] = OSD.FromUUID(ObjectID); controldata["item"] = OSD.FromUUID(ItemID); controldata["ignore"] = OSD.FromInteger(IgnoreControls); controldata["event"] = OSD.FromInteger(EventControls); @@ -258,6 +262,8 @@ namespace OpenSim.Framework public void UnpackUpdateMessage(OSDMap args) { + if (args["object"] != null) + ObjectID = args["object"].AsUUID(); if (args["item"] != null) ItemID = args["item"].AsUUID(); if (args["ignore"] != null) @@ -286,7 +292,13 @@ namespace OpenSim.Framework public Vector3 AtAxis; public Vector3 LeftAxis; public Vector3 UpAxis; - public bool ChangedGrid; + + /// + /// Signal on a V2 teleport that Scene.IncomingChildAgentDataUpdate(AgentData ad) should wait for the + /// scene presence to become root (triggered when the viewer sends a CompleteAgentMovement UDP packet after + /// establishing the connection triggered by it's receipt of a TeleportFinish EQ message). + /// + public bool SenderWantsToWaitForRoot; public float Far; public float Aspect; @@ -310,6 +322,8 @@ namespace OpenSim.Framework public Animation AnimState = null; public UUID GranterID; + public UUID ParentPart; + public Vector3 SitOffset; // Appearance public AvatarAppearance Appearance; @@ -355,8 +369,9 @@ namespace OpenSim.Framework args["left_axis"] = OSD.FromString(LeftAxis.ToString()); args["up_axis"] = OSD.FromString(UpAxis.ToString()); - - args["changed_grid"] = OSD.FromBoolean(ChangedGrid); + //backwards compatibility + args["changed_grid"] = OSD.FromBoolean(SenderWantsToWaitForRoot); + args["wait_for_root"] = OSD.FromBoolean(SenderWantsToWaitForRoot); args["far"] = OSD.FromReal(Far); args["aspect"] = OSD.FromReal(Aspect); @@ -428,9 +443,18 @@ namespace OpenSim.Framework // We might not pass this in all cases... if ((Appearance.Wearables != null) && (Appearance.Wearables.Length > 0)) { - OSDArray wears = new OSDArray(Appearance.Wearables.Length); - foreach (AvatarWearable awear in Appearance.Wearables) - wears.Add(awear.Pack()); + int wearsCount; + if(Appearance.PackLegacyWearables) + wearsCount = AvatarWearable.LEGACY_VERSION_MAX_WEARABLES; + else + wearsCount = AvatarWearable.MAX_WEARABLES; + + if(wearsCount > Appearance.Wearables.Length) + wearsCount = Appearance.Wearables.Length; + + OSDArray wears = new OSDArray(wearsCount); + for(int i = 0; i < wearsCount ; i++) + wears.Add(Appearance.Wearables[i].Pack()); args["wearables"] = wears; } @@ -480,6 +504,10 @@ namespace OpenSim.Framework } args["attach_objects"] = attObjs; } + + args["parent_part"] = OSD.FromUUID(ParentPart); + args["sit_offset"] = OSD.FromString(SitOffset.ToString()); + return args; } @@ -525,8 +553,8 @@ namespace OpenSim.Framework if (args["up_axis"] != null) Vector3.TryParse(args["up_axis"].AsString(), out AtAxis); - if (args["changed_grid"] != null) - ChangedGrid = args["changed_grid"].AsBoolean(); + if (args.ContainsKey("wait_for_root") && args["wait_for_root"] != null) + SenderWantsToWaitForRoot = args["wait_for_root"].AsBoolean(); if (args["far"] != null) Far = (float)(args["far"].AsReal()); @@ -646,7 +674,12 @@ namespace OpenSim.Framework if ((args["wearables"] != null) && (args["wearables"]).Type == OSDType.Array) { OSDArray wears = (OSDArray)(args["wearables"]); - for (int i = 0; i < wears.Count / 2; i++) + + int count = wears.Count; + if (count > AvatarWearable.MAX_WEARABLES) + count = AvatarWearable.MAX_WEARABLES; + + for (int i = 0; i < count / 2; i++) { AvatarWearable awear = new AvatarWearable((OSDArray)wears[i]); Appearance.SetWearable(i,awear); @@ -711,6 +744,11 @@ namespace OpenSim.Framework } } } + + if (args["parent_part"] != null) + ParentPart = args["parent_part"].AsUUID(); + if (args["sit_offset"] != null) + Vector3.TryParse(args["sit_offset"].AsString(), out SitOffset); } public AgentData() diff --git a/OpenSim/Framework/CircularBuffer.cs b/OpenSim/Framework/CircularBuffer.cs new file mode 100644 index 0000000..e919337 --- /dev/null +++ b/OpenSim/Framework/CircularBuffer.cs @@ -0,0 +1,312 @@ +/* +Copyright (c) 2012, Alex Regueiro +All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; + +namespace OpenSim.Framework +{ + public class CircularBuffer : ICollection, IEnumerable, ICollection, IEnumerable + { + private int capacity; + private int size; + private int head; + private int tail; + private T[] buffer; + + [NonSerialized()] + private object syncRoot; + + public CircularBuffer(int capacity) + : this(capacity, false) + { + } + + public CircularBuffer(int capacity, bool allowOverflow) + { + if (capacity < 0) + throw new ArgumentException("Needs to have at least 1","capacity"); + + this.capacity = capacity; + size = 0; + head = 0; + tail = 0; + buffer = new T[capacity]; + AllowOverflow = allowOverflow; + } + + public bool AllowOverflow + { + get; + set; + } + + public int Capacity + { + get { return capacity; } + set + { + if (value == capacity) + return; + + if (value < size) + throw new ArgumentOutOfRangeException("value","Capacity is too small."); + + var dst = new T[value]; + if (size > 0) + CopyTo(dst); + buffer = dst; + + capacity = value; + } + } + + public int Size + { + get { return size; } + } + + public bool Contains(T item) + { + int bufferIndex = head; + var comparer = EqualityComparer.Default; + for (int i = 0; i < size; i++, bufferIndex++) + { + if (bufferIndex == capacity) + bufferIndex = 0; + + if (item == null && buffer[bufferIndex] == null) + return true; + else if ((buffer[bufferIndex] != null) && + comparer.Equals(buffer[bufferIndex], item)) + return true; + } + + return false; + } + + public void Clear() + { + size = 0; + head = 0; + tail = 0; + } + + public int Put(T[] src) + { + return Put(src, 0, src.Length); + } + + public int Put(T[] src, int offset, int count) + { + if (!AllowOverflow && count > capacity - size) + throw new InvalidOperationException("Buffer Overflow"); + + int srcIndex = offset; + for (int i = 0; i < count; i++, tail++, srcIndex++) + { + if (tail == capacity) + tail = 0; + buffer[tail] = src[srcIndex]; + } + size = Math.Min(size + count, capacity); + return count; + } + + public void Put(T item) + { + if (!AllowOverflow && size == capacity) + throw new InvalidOperationException("Buffer Overflow"); + + buffer[tail] = item; + if (++tail == capacity) + tail = 0; + size++; + } + + public void Skip(int count) + { + head += count; + if (head >= capacity) + head -= capacity; + } + + public T[] Get(int count) + { + var dst = new T[count]; + Get(dst); + return dst; + } + + public int Get(T[] dst) + { + return Get(dst, 0, dst.Length); + } + + public int Get(T[] dst, int offset, int count) + { + int realCount = Math.Min(count, size); + int dstIndex = offset; + for (int i = 0; i < realCount; i++, head++, dstIndex++) + { + if (head == capacity) + head = 0; + dst[dstIndex] = buffer[head]; + } + size -= realCount; + return realCount; + } + + public T Get() + { + if (size == 0) + throw new InvalidOperationException("Buffer Empty"); + + var item = buffer[head]; + if (++head == capacity) + head = 0; + size--; + return item; + } + + public void CopyTo(T[] array) + { + CopyTo(array, 0); + } + + public void CopyTo(T[] array, int arrayIndex) + { + CopyTo(0, array, arrayIndex, size); + } + + public void CopyTo(int index, T[] array, int arrayIndex, int count) + { + if (count > size) + throw new ArgumentOutOfRangeException("count", "Count Too Large"); + + int bufferIndex = head; + for (int i = 0; i < count; i++, bufferIndex++, arrayIndex++) + { + if (bufferIndex == capacity) + bufferIndex = 0; + array[arrayIndex] = buffer[bufferIndex]; + } + } + + public IEnumerator GetEnumerator() + { + int bufferIndex = head; + for (int i = 0; i < size; i++, bufferIndex++) + { + if (bufferIndex == capacity) + bufferIndex = 0; + + yield return buffer[bufferIndex]; + } + } + + public T[] GetBuffer() + { + return buffer; + } + + public T[] ToArray() + { + var dst = new T[size]; + CopyTo(dst); + return dst; + } + + #region ICollection Members + + int ICollection.Count + { + get { return Size; } + } + + bool ICollection.IsReadOnly + { + get { return false; } + } + + void ICollection.Add(T item) + { + Put(item); + } + + bool ICollection.Remove(T item) + { + if (size == 0) + return false; + + Get(); + return true; + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + + #region ICollection Members + + int ICollection.Count + { + get { return Size; } + } + + bool ICollection.IsSynchronized + { + get { return false; } + } + + object ICollection.SyncRoot + { + get + { + if (syncRoot == null) + Interlocked.CompareExchange(ref syncRoot, new object(), null); + return syncRoot; + } + } + + void ICollection.CopyTo(Array array, int arrayIndex) + { + CopyTo((T[])array, arrayIndex); + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return (IEnumerator)GetEnumerator(); + } + + #endregion + } +} diff --git a/OpenSim/Framework/ClientInfo.cs b/OpenSim/Framework/ClientInfo.cs index 62acb70..98e4465 100644 --- a/OpenSim/Framework/ClientInfo.cs +++ b/OpenSim/Framework/ClientInfo.cs @@ -33,12 +33,13 @@ namespace OpenSim.Framework { public class ClientInfo { - public AgentCircuitData agentcircuit; + public readonly DateTime StartedTime = DateTime.Now; + public AgentCircuitData agentcircuit = null; public Dictionary needAck; - public List out_packets; - public Dictionary pendingAcks; + public List out_packets = new List(); + public Dictionary pendingAcks = new Dictionary(); public EndPoint proxyEP; public uint sequence; @@ -53,5 +54,14 @@ namespace OpenSim.Framework public int assetThrottle; public int textureThrottle; public int totalThrottle; + + // Used by adaptive only + public int targetThrottle; + + public int maxThrottle; + + public Dictionary SyncRequests = new Dictionary(); + public Dictionary AsyncRequests = new Dictionary(); + public Dictionary GenericRequests = new Dictionary(); } } diff --git a/OpenSim/Framework/Communications/GenericAsyncResult.cs b/OpenSim/Framework/Communications/GenericAsyncResult.cs deleted file mode 100644 index 8e3f62b..0000000 --- a/OpenSim/Framework/Communications/GenericAsyncResult.cs +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Threading; - -namespace OpenSim.Framework.Communications -{ - internal class SimpleAsyncResult : IAsyncResult - { - private readonly AsyncCallback m_callback; - - /// - /// Is process completed? - /// - /// Should really be boolean, but VolatileRead has no boolean method - private byte m_completed; - - /// - /// Did process complete synchronously? - /// - /// I have a hard time imagining a scenario where this is the case, again, same issue about - /// booleans and VolatileRead as m_completed - /// - private byte m_completedSynchronously; - - private readonly object m_asyncState; - private ManualResetEvent m_waitHandle; - private Exception m_exception; - - internal SimpleAsyncResult(AsyncCallback cb, object state) - { - m_callback = cb; - m_asyncState = state; - m_completed = 0; - m_completedSynchronously = 1; - } - - #region IAsyncResult Members - - public object AsyncState - { - get { return m_asyncState; } - } - - public WaitHandle AsyncWaitHandle - { - get - { - if (m_waitHandle == null) - { - bool done = IsCompleted; - ManualResetEvent mre = new ManualResetEvent(done); - if (Interlocked.CompareExchange(ref m_waitHandle, mre, null) != null) - { - mre.Close(); - } - else - { - if (!done && IsCompleted) - { - m_waitHandle.Set(); - } - } - } - - return m_waitHandle; - } - } - - - public bool CompletedSynchronously - { - get { return Thread.VolatileRead(ref m_completedSynchronously) == 1; } - } - - - public bool IsCompleted - { - get { return Thread.VolatileRead(ref m_completed) == 1; } - } - - #endregion - - #region class Methods - - internal void SetAsCompleted(bool completedSynchronously) - { - m_completed = 1; - if (completedSynchronously) - m_completedSynchronously = 1; - else - m_completedSynchronously = 0; - - SignalCompletion(); - } - - internal void HandleException(Exception e, bool completedSynchronously) - { - m_completed = 1; - if (completedSynchronously) - m_completedSynchronously = 1; - else - m_completedSynchronously = 0; - m_exception = e; - - SignalCompletion(); - } - - private void SignalCompletion() - { - if (m_waitHandle != null) m_waitHandle.Set(); - - if (m_callback != null) m_callback(this); - } - - public void EndInvoke() - { - // This method assumes that only 1 thread calls EndInvoke - if (!IsCompleted) - { - // If the operation isn't done, wait for it - AsyncWaitHandle.WaitOne(); - AsyncWaitHandle.Close(); - m_waitHandle.Close(); - m_waitHandle = null; // Allow early GC - } - - // Operation is done: if an exception occured, throw it - if (m_exception != null) throw m_exception; - } - - #endregion - } - - internal class AsyncResult : SimpleAsyncResult - { - private T m_result = default(T); - - public AsyncResult(AsyncCallback asyncCallback, Object state) : - base(asyncCallback, state) - { - } - - public void SetAsCompleted(T result, bool completedSynchronously) - { - // Save the asynchronous operation's result - m_result = result; - - // Tell the base class that the operation completed - // sucessfully (no exception) - base.SetAsCompleted(completedSynchronously); - } - - public new T EndInvoke() - { - base.EndInvoke(); - return m_result; - } - } -} \ No newline at end of file diff --git a/OpenSim/Framework/Communications/IUserService.cs b/OpenSim/Framework/Communications/IUserService.cs deleted file mode 100644 index dfa059d..0000000 --- a/OpenSim/Framework/Communications/IUserService.cs +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using OpenMetaverse; -using OpenSim.Services.Interfaces; - -namespace OpenSim.Framework.Communications -{ - public interface IUserService - { - /// - /// Add a temporary user profile. - /// - /// A temporary user profile is one that should exist only for the lifetime of the process. - /// - void AddTemporaryUserProfile(UserProfileData userProfile); - - /// - /// Loads a user profile by name - /// - /// First name - /// Last name - /// A user profile. Returns null if no profile is found - UserProfileData GetUserProfile(string firstName, string lastName); - - /// - /// Loads a user profile from a database by UUID - /// - /// The target UUID - /// A user profile. Returns null if no user profile is found. - UserProfileData GetUserProfile(UUID userId); - - UserProfileData GetUserProfile(Uri uri); - - Uri GetUserUri(UserProfileData userProfile); - - UserAgentData GetAgentByUUID(UUID userId); - - void ClearUserAgent(UUID avatarID); - List GenerateAgentPickerRequestResponse(UUID QueryID, string Query); - - UserProfileData SetupMasterUser(string firstName, string lastName); - UserProfileData SetupMasterUser(string firstName, string lastName, string password); - UserProfileData SetupMasterUser(UUID userId); - - /// - /// Update the user's profile. - /// - /// UserProfileData object with updated data. Should be obtained - /// via a call to GetUserProfile(). - /// true if the update could be applied, false if it could not be applied. - bool UpdateUserProfile(UserProfileData data); - - /// - /// Adds a new friend to the database for XUser - /// - /// The agent that who's friends list is being added to - /// The agent that being added to the friends list of the friends list owner - /// A uint bit vector for set perms that the friend being added has; 0 = none, 1=This friend can see when they sign on, 2 = map, 4 edit objects - void AddNewUserFriend(UUID friendlistowner, UUID friend, uint perms); - - /// - /// Delete friend on friendlistowner's friendlist. - /// - /// The agent that who's friends list is being updated - /// The Ex-friend agent - void RemoveUserFriend(UUID friendlistowner, UUID friend); - - /// - /// Update permissions for friend on friendlistowner's friendlist. - /// - /// The agent that who's friends list is being updated - /// The agent that is getting or loosing permissions - /// A uint bit vector for set perms that the friend being added has; 0 = none, 1=This friend can see when they sign on, 2 = map, 4 edit objects - void UpdateUserFriendPerms(UUID friendlistowner, UUID friend, uint perms); - - /// - /// Logs off a user on the user server - /// - /// UUID of the user - /// UUID of the Region - /// regionhandle - /// final position - /// final lookat - void LogOffUser(UUID userid, UUID regionid, ulong regionhandle, Vector3 position, Vector3 lookat); - - /// - /// Logs off a user on the user server (deprecated as of 2008-08-27) - /// - /// UUID of the user - /// UUID of the Region - /// regionhandle - /// final position x - /// final position y - /// final position z - void LogOffUser(UUID userid, UUID regionid, ulong regionhandle, float posx, float posy, float posz); - - /// - /// Returns a list of FriendsListItems that describe the friends and permissions in the friend relationship - /// for UUID friendslistowner - /// - /// - /// The agent for whom we're retreiving the friends Data. - /// - /// A List of FriendListItems that contains info about the user's friends. - /// Always returns a list even if the user has no friends - /// - List GetUserFriendList(UUID friendlistowner); - - // This probably shouldn't be here, it belongs to IAuthentication - // But since Scenes only have IUserService references, I'm placing it here for now. - bool VerifySession(UUID userID, UUID sessionID); - - /// - /// Authenticate a user by their password. - /// - /// - /// This is used by callers outside the login process that want to - /// verify a user who has given their password. - /// - /// This should probably also be in IAuthentication but is here for the same reasons as VerifySession() is - /// - /// - /// - /// - bool AuthenticateUserByPassword(UUID userID, string password); - - // Temporary Hack until we move everything to the new service model - void SetInventoryService(IInventoryService invService); - } -} diff --git a/OpenSim/Framework/Communications/Limit/IRequestLimitStrategy.cs b/OpenSim/Framework/Communications/Limit/IRequestLimitStrategy.cs deleted file mode 100644 index 070d106..0000000 --- a/OpenSim/Framework/Communications/Limit/IRequestLimitStrategy.cs +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -namespace OpenSim.Framework.Communications.Limit -{ - /// - /// Interface for strategies that can limit requests from the client. Currently only used in the - /// texture modules to deal with repeated requests for certain textures. However, limiting strategies - /// could be used with other requests. - /// - public interface IRequestLimitStrategy - { - /// - /// Should the request be allowed? If the id is not monitored, then the request is always allowed. - /// Otherwise, the strategy criteria will be applied. - /// - /// - /// - bool AllowRequest(TId id); - - /// - /// Has the request been refused just once? - /// - /// False if the request has not yet been refused, or if the request has been refused more - /// than once. - bool IsFirstRefusal(TId id); - - /// - /// Start monitoring for future AllowRequest calls. If the id is already monitored, then monitoring - /// continues. - /// - /// - void MonitorRequests(TId id); - - /// - /// Is the id being monitored? - /// - /// - /// - bool IsMonitoringRequests(TId id); - } -} diff --git a/OpenSim/Framework/Communications/Limit/NullLimitStrategy.cs b/OpenSim/Framework/Communications/Limit/NullLimitStrategy.cs deleted file mode 100644 index 7672653..0000000 --- a/OpenSim/Framework/Communications/Limit/NullLimitStrategy.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -namespace OpenSim.Framework.Communications.Limit -{ - /// - /// Strategy which polices no limits - /// - public class NullLimitStrategy : IRequestLimitStrategy - { - public bool AllowRequest(TId id) { return true; } - public bool IsFirstRefusal(TId id) { return false; } - public void MonitorRequests(TId id) { /* intentionally blank */ } - public bool IsMonitoringRequests(TId id) { return false; } - } -} diff --git a/OpenSim/Framework/Communications/Limit/RepeatLimitStrategy.cs b/OpenSim/Framework/Communications/Limit/RepeatLimitStrategy.cs deleted file mode 100644 index 44dd592..0000000 --- a/OpenSim/Framework/Communications/Limit/RepeatLimitStrategy.cs +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Collections.Generic; - -namespace OpenSim.Framework.Communications.Limit -{ - /// - /// Limit requests by discarding them after they've been repeated a certain number of times. - /// - public class RepeatLimitStrategy : IRequestLimitStrategy - { - /// - /// Record each asset request that we're notified about. - /// - private readonly Dictionary requestCounts = new Dictionary(); - - /// - /// The maximum number of requests that can be made before we drop subsequent requests. - /// - private readonly int m_maxRequests; - public int MaxRequests - { - get { return m_maxRequests; } - } - - /// - /// The maximum number of requests that may be served before all further - /// requests are dropped. - public RepeatLimitStrategy(int maxRequests) - { - m_maxRequests = maxRequests; - } - - /// - /// - /// - public bool AllowRequest(TId id) - { - if (requestCounts.ContainsKey(id)) - { - requestCounts[id] += 1; - - if (requestCounts[id] > m_maxRequests) - { - return false; - } - } - - return true; - } - - /// - /// - /// - public bool IsFirstRefusal(TId id) - { - if (requestCounts.ContainsKey(id) && m_maxRequests + 1 == requestCounts[id]) - { - return true; - } - - return false; - } - - /// - /// - /// - public void MonitorRequests(TId id) - { - if (!IsMonitoringRequests(id)) - { - requestCounts.Add(id, 1); - } - } - - /// - /// - /// - public bool IsMonitoringRequests(TId id) - { - return requestCounts.ContainsKey(id); - } - } -} diff --git a/OpenSim/Framework/Communications/Limit/TimeLimitStrategy.cs b/OpenSim/Framework/Communications/Limit/TimeLimitStrategy.cs deleted file mode 100644 index 7ac8293..0000000 --- a/OpenSim/Framework/Communications/Limit/TimeLimitStrategy.cs +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; - -namespace OpenSim.Framework.Communications.Limit -{ - /// - /// Limit requests by discarding repeat attempts that occur within a given time period - /// - /// XXX Don't use this for limiting texture downloading, at least not until we better handle multiple requests - /// for the same texture at different resolutions. - /// - public class TimeLimitStrategy : IRequestLimitStrategy - { - /// - /// Record the time at which an asset request occurs. - /// - private readonly Dictionary requests = new Dictionary(); - - /// - /// The minimum time period between which requests for the same data will be serviced. - /// - private readonly TimeSpan m_repeatPeriod; - public TimeSpan RepeatPeriod - { - get { return m_repeatPeriod; } - } - - /// - /// - public TimeLimitStrategy(TimeSpan repeatPeriod) - { - m_repeatPeriod = repeatPeriod; - } - - /// - /// - /// - public bool AllowRequest(TId id) - { - if (IsMonitoringRequests(id)) - { - DateTime now = DateTime.Now; - TimeSpan elapsed = now - requests[id].Time; - - if (elapsed < RepeatPeriod) - { - requests[id].Refusals += 1; - return false; - } - - requests[id].Time = now; - } - - return true; - } - - /// - /// - /// - public bool IsFirstRefusal(TId id) - { - if (IsMonitoringRequests(id)) - { - if (1 == requests[id].Refusals) - { - return true; - } - } - - return false; - } - - /// - /// - /// - public void MonitorRequests(TId id) - { - if (!IsMonitoringRequests(id)) - { - requests.Add(id, new Request(DateTime.Now)); - } - } - - /// - /// - /// - public bool IsMonitoringRequests(TId id) - { - return requests.ContainsKey(id); - } - } - - /// - /// Private request details. - /// - class Request - { - /// - /// Time of last request - /// - public DateTime Time; - - /// - /// Number of refusals associated with this request - /// - public int Refusals; - - public Request(DateTime time) - { - Time = time; - } - } -} diff --git a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs b/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs deleted file mode 100644 index 6d1c03a..0000000 --- a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Reflection; -using System.Runtime.InteropServices; - -// General information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. - -[assembly : AssemblyTitle("OpenSim.Framework.Communications")] -[assembly : AssemblyDescription("")] -[assembly : AssemblyConfiguration("")] -[assembly : AssemblyCompany("http://opensimulator.org")] -[assembly : AssemblyProduct("OpenSim")] -[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] -[assembly : AssemblyTrademark("")] -[assembly : AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. - -[assembly : ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM - -[assembly : Guid("13e7c396-78a9-4a5c-baf2-6f980ea75d95")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: - -[assembly : AssemblyVersion("0.7.5.*")] -[assembly : AssemblyFileVersion("0.6.5.0")] diff --git a/OpenSim/Framework/Communications/RestClient.cs b/OpenSim/Framework/Communications/RestClient.cs deleted file mode 100644 index 97b3b60..0000000 --- a/OpenSim/Framework/Communications/RestClient.cs +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Reflection; -using System.Text; -using System.Threading; -using System.Web; -using log4net; - -namespace OpenSim.Framework.Communications -{ - /// - /// Implementation of a generic REST client - /// - /// - /// This class is a generic implementation of a REST (Representational State Transfer) web service. This - /// class is designed to execute both synchronously and asynchronously. - /// - /// Internally the implementation works as a two stage asynchronous web-client. - /// When the request is initiated, RestClient will query asynchronously for for a web-response, - /// sleeping until the initial response is returned by the server. Once the initial response is retrieved - /// the second stage of asynchronous requests will be triggered, in an attempt to read of the response - /// object into a memorystream as a sequence of asynchronous reads. - /// - /// The asynchronisity of RestClient is designed to move as much processing into the back-ground, allowing - /// other threads to execute, while it waits for a response from the web-service. RestClient itself can be - /// invoked by the caller in either synchronous mode or asynchronous modes. - /// - public class RestClient - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - // private string realuri; - - #region member variables - - /// - /// The base Uri of the web-service e.g. http://www.google.com - /// - private string _url; - - /// - /// Path elements of the query - /// - private List _pathElements = new List(); - - /// - /// Parameter elements of the query, e.g. min=34 - /// - private Dictionary _parameterElements = new Dictionary(); - - /// - /// Request method. E.g. GET, POST, PUT or DELETE - /// - private string _method; - - /// - /// Temporary buffer used to store bytes temporarily as they come in from the server - /// - private byte[] _readbuf; - - /// - /// MemoryStream representing the resultiong resource - /// - private Stream _resource; - - /// - /// WebRequest object, held as a member variable - /// - private HttpWebRequest _request; - - /// - /// WebResponse object, held as a member variable, so we can close it - /// - private HttpWebResponse _response; - - /// - /// This flag will help block the main synchroneous method, in case we run in synchroneous mode - /// - //public static ManualResetEvent _allDone = new ManualResetEvent(false); - - /// - /// Default time out period - /// - //private const int DefaultTimeout = 10*1000; // 10 seconds timeout - - /// - /// Default Buffer size of a block requested from the web-server - /// - private const int BufferSize = 4096; // Read blocks of 4 KB. - - - /// - /// if an exception occours during async processing, we need to save it, so it can be - /// rethrown on the primary thread; - /// - private Exception _asyncException; - - #endregion member variables - - #region constructors - - /// - /// Instantiate a new RestClient - /// - /// Web-service to query, e.g. http://osgrid.org:8003 - public RestClient(string url) - { - _url = url; - _readbuf = new byte[BufferSize]; - _resource = new MemoryStream(); - _request = null; - _response = null; - _lock = new object(); - } - - private object _lock; - - #endregion constructors - - /// - /// Add a path element to the query, e.g. assets - /// - /// path entry - public void AddResourcePath(string element) - { - if (isSlashed(element)) - _pathElements.Add(element.Substring(0, element.Length - 1)); - else - _pathElements.Add(element); - } - - /// - /// Add a query parameter to the Url - /// - /// Name of the parameter, e.g. min - /// Value of the parameter, e.g. 42 - public void AddQueryParameter(string name, string value) - { - try - { - _parameterElements.Add(HttpUtility.UrlEncode(name), HttpUtility.UrlEncode(value)); - } - catch (ArgumentException) - { - m_log.Error("[REST]: Query parameter " + name + " is already added."); - } - catch (Exception e) - { - m_log.Error("[REST]: An exception was raised adding query parameter to dictionary. Exception: {0}",e); - } - } - - /// - /// Add a query parameter to the Url - /// - /// Name of the parameter, e.g. min - public void AddQueryParameter(string name) - { - try - { - _parameterElements.Add(HttpUtility.UrlEncode(name), null); - } - catch (ArgumentException) - { - m_log.Error("[REST]: Query parameter " + name + " is already added."); - } - catch (Exception e) - { - m_log.Error("[REST]: An exception was raised adding query parameter to dictionary. Exception: {0}",e); - } - } - - /// - /// Web-Request method, e.g. GET, PUT, POST, DELETE - /// - public string RequestMethod - { - get { return _method; } - set { _method = value; } - } - - /// - /// True if string contains a trailing slash '/' - /// - /// string to be examined - /// true if slash is present - private static bool isSlashed(string s) - { - return s.Substring(s.Length - 1, 1) == "/"; - } - - /// - /// Build a Uri based on the initial Url, path elements and parameters - /// - /// fully constructed Uri - private Uri buildUri() - { - StringBuilder sb = new StringBuilder(); - sb.Append(_url); - - foreach (string e in _pathElements) - { - sb.Append("/"); - sb.Append(e); - } - - bool firstElement = true; - foreach (KeyValuePair kv in _parameterElements) - { - if (firstElement) - { - sb.Append("?"); - firstElement = false; - } - else - sb.Append("&"); - - sb.Append(kv.Key); - if (!string.IsNullOrEmpty(kv.Value)) - { - sb.Append("="); - sb.Append(kv.Value); - } - } - // realuri = sb.ToString(); - //m_log.InfoFormat("[REST CLIENT]: RestURL: {0}", realuri); - return new Uri(sb.ToString()); - } - - #region Async communications with server - - /// - /// Async method, invoked when a block of data has been received from the service - /// - /// - private void StreamIsReadyDelegate(IAsyncResult ar) - { - try - { - Stream s = (Stream) ar.AsyncState; - int read = s.EndRead(ar); - - if (read > 0) - { - _resource.Write(_readbuf, 0, read); - // IAsyncResult asynchronousResult = - // s.BeginRead(_readbuf, 0, BufferSize, new AsyncCallback(StreamIsReadyDelegate), s); - s.BeginRead(_readbuf, 0, BufferSize, new AsyncCallback(StreamIsReadyDelegate), s); - - // TODO! Implement timeout, without killing the server - //ThreadPool.RegisterWaitForSingleObject(asynchronousResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); - } - else - { - s.Close(); - //_allDone.Set(); - } - } - catch (Exception e) - { - //_allDone.Set(); - _asyncException = e; - } - } - - #endregion Async communications with server - - /// - /// Perform a synchronous request - /// - public Stream Request() - { - lock (_lock) - { - _request = (HttpWebRequest) WebRequest.Create(buildUri()); - _request.KeepAlive = false; - _request.ContentType = "application/xml"; - _request.Timeout = 200000; - _request.Method = RequestMethod; - _asyncException = null; - -// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request); - try - { - _response = (HttpWebResponse) _request.GetResponse(); - } - catch (WebException e) - { - HttpWebResponse errorResponse = e.Response as HttpWebResponse; - if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode) - { - m_log.Warn("[REST CLIENT] Resource not found (404)"); - } - else - { - m_log.Error("[REST CLIENT] Error fetching resource from server " + _request.Address.ToString()); - m_log.Debug(e.ToString()); - } - - return null; - } - - Stream src = _response.GetResponseStream(); - int length = src.Read(_readbuf, 0, BufferSize); - while (length > 0) - { - _resource.Write(_readbuf, 0, length); - length = src.Read(_readbuf, 0, BufferSize); - } - - - // TODO! Implement timeout, without killing the server - // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted - //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); - -// _allDone.WaitOne(); - if (_response != null) - _response.Close(); - if (_asyncException != null) - throw _asyncException; - - if (_resource != null) - { - _resource.Flush(); - _resource.Seek(0, SeekOrigin.Begin); - } - - return _resource; - } - } - - public Stream Request(Stream src) - { - _request = (HttpWebRequest) WebRequest.Create(buildUri()); - _request.KeepAlive = false; - _request.ContentType = "application/xml"; - _request.Timeout = 900000; - _request.Method = RequestMethod; - _asyncException = null; - _request.ContentLength = src.Length; - - m_log.InfoFormat("[REST]: Request Length {0}", _request.ContentLength); - m_log.InfoFormat("[REST]: Sending Web Request {0}", buildUri()); - src.Seek(0, SeekOrigin.Begin); - m_log.Info("[REST]: Seek is ok"); - Stream dst = _request.GetRequestStream(); - m_log.Info("[REST]: GetRequestStream is ok"); - - byte[] buf = new byte[1024]; - int length = src.Read(buf, 0, 1024); - m_log.Info("[REST]: First Read is ok"); - while (length > 0) - { - dst.Write(buf, 0, length); - length = src.Read(buf, 0, 1024); - } - - _response = (HttpWebResponse) _request.GetResponse(); - -// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request); - - // TODO! Implement timeout, without killing the server - // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted - //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); - - return null; - } - - #region Async Invocation - - public IAsyncResult BeginRequest(AsyncCallback callback, object state) - { - /// - /// In case, we are invoked asynchroneously this object will keep track of the state - /// - AsyncResult ar = new AsyncResult(callback, state); - Util.FireAndForget(RequestHelper, ar); - return ar; - } - - public Stream EndRequest(IAsyncResult asyncResult) - { - AsyncResult ar = (AsyncResult) asyncResult; - - // Wait for operation to complete, then return result or - // throw exception - return ar.EndInvoke(); - } - - private void RequestHelper(Object asyncResult) - { - // We know that it's really an AsyncResult object - AsyncResult ar = (AsyncResult) asyncResult; - try - { - // Perform the operation; if sucessful set the result - Stream s = Request(); - ar.SetAsCompleted(s, false); - } - catch (Exception e) - { - // If operation fails, set the exception - ar.HandleException(e, false); - } - } - - #endregion Async Invocation - } -} diff --git a/OpenSim/Framework/Communications/XMPP/XmppError.cs b/OpenSim/Framework/Communications/XMPP/XmppError.cs deleted file mode 100644 index 3d36e9c..0000000 --- a/OpenSim/Framework/Communications/XMPP/XmppError.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Xml.Serialization; - -namespace OpenSim.Framework.Communications.XMPP -{ - [XmlRoot("error")] - public class XmppErrorStanza - { - public XmppErrorStanza() - { - } - } -} diff --git a/OpenSim/Framework/Communications/XMPP/XmppIqStanza.cs b/OpenSim/Framework/Communications/XMPP/XmppIqStanza.cs deleted file mode 100644 index 12263f4..0000000 --- a/OpenSim/Framework/Communications/XMPP/XmppIqStanza.cs +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Xml.Serialization; - -namespace OpenSim.Framework.Communications.XMPP -{ - /// - /// An IQ needs to have one of the follow types set. - /// - public enum XmppIqType - { - [XmlEnum("set")] set, - [XmlEnum("get")] get, - [XmlEnum("result")] result, - [XmlEnum("error")] error, - } - - /// - /// XmppIqStanza needs to be subclassed as the query content is - /// specific to the query type. - /// - [XmlRoot("iq")] - public abstract class XmppIqStanza: XmppStanza - { - /// - /// IQ type: one of set, get, result, error - /// - [XmlAttribute("type")] - public XmppIqType Type; - - public XmppIqStanza(): base() - { - } - } -} diff --git a/OpenSim/Framework/Communications/XMPP/XmppMessageStanza.cs b/OpenSim/Framework/Communications/XMPP/XmppMessageStanza.cs deleted file mode 100644 index 1e8c33e..0000000 --- a/OpenSim/Framework/Communications/XMPP/XmppMessageStanza.cs +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Xml.Serialization; - -namespace OpenSim.Framework.Communications.XMPP -{ - /// - /// Message types. - /// - public enum XmppMessageType - { - [XmlEnum("chat")] chat, - [XmlEnum("error")] error, - [XmlEnum("groupchat")] groupchat, - [XmlEnum("headline")] headline, - [XmlEnum("normal")] normal, - } - - /// - /// Message body. - /// - public class XmppMessageBody - { - [XmlText] - public string Text; - - public XmppMessageBody() - { - } - - public XmppMessageBody(string message) - { - Text = message; - } - - new public string ToString() - { - return Text; - } - } - - [XmlRoot("message")] - public class XmppMessageStanza: XmppStanza - { - /// - /// IQ type: one of set, get, result, error - /// - [XmlAttribute("type")] - public XmppMessageType MessageType; - - // [XmlAttribute("error")] - // public XmppError Error; - - [XmlElement("body")] - public XmppMessageBody Body; - - public XmppMessageStanza() : base() - { - } - - public XmppMessageStanza(string fromJid, string toJid, XmppMessageType mType, string message) : - base(fromJid, toJid) - { - MessageType = mType; - Body = new XmppMessageBody(message); - } - } -} diff --git a/OpenSim/Framework/Communications/XMPP/XmppPresenceStanza.cs b/OpenSim/Framework/Communications/XMPP/XmppPresenceStanza.cs deleted file mode 100644 index 4d45ac0..0000000 --- a/OpenSim/Framework/Communications/XMPP/XmppPresenceStanza.cs +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Xml.Serialization; - -namespace OpenSim.Framework.Communications.XMPP -{ - /// - /// Message types. - /// - public enum XmppPresenceType - { - [XmlEnum("unavailable")] unavailable, - [XmlEnum("subscribe")] subscribe, - [XmlEnum("subscribed")] subscribed, - [XmlEnum("unsubscribe")] unsubscribe, - [XmlEnum("unsubscribed")] unsubscribed, - [XmlEnum("probe")] probe, - [XmlEnum("error")] error, - } - - - [XmlRoot("message")] - public class XmppPresenceStanza: XmppStanza - { - /// - /// IQ type: one of set, get, result, error - /// - [XmlAttribute("type")] - public XmppPresenceType PresenceType; - - // [XmlAttribute("error")] - // public XmppError Error; - - public XmppPresenceStanza() : base() - { - } - - public XmppPresenceStanza(string fromJid, string toJid, XmppPresenceType pType) : - base(fromJid, toJid) - { - PresenceType = pType; - } - } -} diff --git a/OpenSim/Framework/Communications/XMPP/XmppSerializer.cs b/OpenSim/Framework/Communications/XMPP/XmppSerializer.cs deleted file mode 100644 index e37ef28..0000000 --- a/OpenSim/Framework/Communications/XMPP/XmppSerializer.cs +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Xml; -using System.Xml.Serialization; - -namespace OpenSim.Framework.Communications.XMPP -{ - public class XmppSerializer - { - // private static readonly ILog _log = - // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - // need to do it this way, as XmlSerializer(type, extratypes) - // does not work on mono (at least). - private Dictionary _serializerForType = new Dictionary(); - private Dictionary _serializerForName = new Dictionary(); - private XmlSerializerNamespaces _xmlNs; - private string _defaultNS; - - public XmppSerializer(bool server) - { - _xmlNs = new XmlSerializerNamespaces(); - _xmlNs.Add(String.Empty, String.Empty); - if (server) - _defaultNS = "jabber:server"; - else - _defaultNS = "jabber:client"; - - // TODO: do this via reflection - _serializerForType[typeof(XmppMessageStanza)] = _serializerForName["message"] = - new XmlSerializer(typeof(XmppMessageStanza), _defaultNS); - } - - public void Serialize(XmlWriter xw, object o) - { - if (!_serializerForType.ContainsKey(o.GetType())) - throw new ArgumentException(String.Format("no serializer available for type {0}", o.GetType())); - - _serializerForType[o.GetType()].Serialize(xw, o, _xmlNs); - } - - public object Deserialize(XmlReader xr) - { - // position on next element - xr.Read(); - if (!_serializerForName.ContainsKey(xr.LocalName)) - throw new ArgumentException(String.Format("no serializer available for name {0}", xr.LocalName)); - - return _serializerForName[xr.LocalName].Deserialize(xr); - } - } -} diff --git a/OpenSim/Framework/Communications/XMPP/XmppStanza.cs b/OpenSim/Framework/Communications/XMPP/XmppStanza.cs deleted file mode 100644 index 5312a31..0000000 --- a/OpenSim/Framework/Communications/XMPP/XmppStanza.cs +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Xml.Serialization; - -namespace OpenSim.Framework.Communications.XMPP -{ - public abstract class XmppStanza - { - /// - /// counter used for generating ID - /// - [XmlIgnore] - private static ulong _ctr = 0; - - /// - /// recipient JID - /// - [XmlAttribute("to")] - public string ToJid; - - /// - /// sender JID - /// - [XmlAttribute("from")] - public string FromJid; - - /// - /// unique ID. - /// - [XmlAttribute("id")] - public string MessageId; - - public XmppStanza() - { - } - - public XmppStanza(string fromJid, string toJid) - { - ToJid = toJid; - FromJid = fromJid; - MessageId = String.Format("OpenSim_{0}{1}", DateTime.UtcNow.Ticks, _ctr++); - } - } -} diff --git a/OpenSim/Framework/Communications/XMPP/XmppWriter.cs b/OpenSim/Framework/Communications/XMPP/XmppWriter.cs deleted file mode 100644 index 415d808..0000000 --- a/OpenSim/Framework/Communications/XMPP/XmppWriter.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.IO; -using System.Text; -using System.Xml; -using IOStream = System.IO.Stream; - -namespace OpenSim.Framework.Communications.XMPP -{ - public class XMPPWriter: XmlTextWriter - { - public XMPPWriter(TextWriter textWriter) : base(textWriter) - { - } - - public XMPPWriter(IOStream stream) : this(stream, Util.UTF8) - { - } - - public XMPPWriter(IOStream stream, Encoding enc) : base(stream, enc) - { - } - - public override void WriteStartDocument() - { - } - - public override void WriteStartDocument(bool standalone) - { - } - } -} diff --git a/OpenSim/Framework/ConfigSettings.cs b/OpenSim/Framework/ConfigSettings.cs index 002a371..108a3e4 100644 --- a/OpenSim/Framework/ConfigSettings.cs +++ b/OpenSim/Framework/ConfigSettings.cs @@ -31,7 +31,6 @@ namespace OpenSim.Framework { public string PhysicsEngine { get; set; } public string MeshEngineName { get; set; } - public string StorageDll { get; set; } public string ClientstackDll { get; set; } public string LibrariesXMLFile { get; set; } diff --git a/OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs b/OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs deleted file mode 100644 index 3dce578..0000000 --- a/OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Net; -using System.Reflection; -using System.Text; -using log4net; -using OpenSim.Framework.Configuration.XML; - -namespace OpenSim.Framework.Configuration.HTTP -{ - public class HTTPConfiguration : IGenericConfig - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private RemoteConfigSettings remoteConfigSettings; - - private XmlConfiguration xmlConfig; - - private string configFileName = String.Empty; - - public HTTPConfiguration() - { - remoteConfigSettings = new RemoteConfigSettings("remoteconfig.xml"); - xmlConfig = new XmlConfiguration(); - } - - public void SetFileName(string fileName) - { - configFileName = fileName; - } - - public void LoadData() - { - try - { - StringBuilder sb = new StringBuilder(); - - byte[] buf = new byte[8192]; - HttpWebRequest request = - (HttpWebRequest) WebRequest.Create(remoteConfigSettings.baseConfigURL + configFileName); - HttpWebResponse response = (HttpWebResponse) request.GetResponse(); - - Stream resStream = response.GetResponseStream(); - - string tempString = null; - int count = 0; - - do - { - count = resStream.Read(buf, 0, buf.Length); - if (count != 0) - { - tempString = Util.UTF8.GetString(buf, 0, count); - sb.Append(tempString); - } - } while (count > 0); - LoadDataFromString(sb.ToString()); - } - catch (WebException) - { - m_log.Warn("Unable to connect to remote configuration file (" + - remoteConfigSettings.baseConfigURL + configFileName + - "). Creating local file instead."); - xmlConfig.SetFileName(configFileName); - xmlConfig.LoadData(); - } - } - - public void LoadDataFromString(string data) - { - xmlConfig.LoadDataFromString(data); - } - - public string GetAttribute(string attributeName) - { - return xmlConfig.GetAttribute(attributeName); - } - - public bool SetAttribute(string attributeName, string attributeValue) - { - return true; - } - - public void Commit() - { - } - - public void Close() - { - } - } -} diff --git a/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs b/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs deleted file mode 100644 index 0674656..0000000 --- a/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenSim.Framework.Configuration.HTTP")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("http://opensimulator.org")] -[assembly: AssemblyProduct("OpenSim")] -[assembly: AssemblyCopyright("OpenSimulator develoeprs")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("cb78b672-d000-4f93-88f9-dae151cc0061")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs b/OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs deleted file mode 100644 index 10bc88a..0000000 --- a/OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; - -namespace OpenSim.Framework.Configuration.HTTP -{ - public class RemoteConfigSettings - { - private ConfigurationMember configMember; - - public string baseConfigURL = String.Empty; - - public RemoteConfigSettings(string filename) - { - configMember = - new ConfigurationMember(filename, "REMOTE CONFIG SETTINGS", loadConfigurationOptions, - handleIncomingConfiguration,true); - configMember.forceConfigurationPluginLibrary("OpenSim.Framework.Configuration.XML.dll"); - configMember.performConfigurationRetrieve(); - } - - public void loadConfigurationOptions() - { - configMember.addConfigurationOption("base_config_url", - ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, - "URL Containing Configuration Files", "http://localhost/", false); - } - - public bool handleIncomingConfiguration(string configuration_key, object configuration_result) - { - if (configuration_key == "base_config_url") - { - baseConfigURL = (string) configuration_result; - } - return true; - } - } -} diff --git a/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs b/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs deleted file mode 100644 index 1095b23..0000000 --- a/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenSim.Framework.Configuration.XML")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("http://opensimulator.org")] -[assembly: AssemblyProduct("OpenSim")] -[assembly: AssemblyCopyright("OpenSimulator developers")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("eeb880df-0112-4c3d-87ed-b2108d614c55")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Framework/Configuration/XML/XmlConfiguration.cs b/OpenSim/Framework/Configuration/XML/XmlConfiguration.cs deleted file mode 100644 index 43162fc..0000000 --- a/OpenSim/Framework/Configuration/XML/XmlConfiguration.cs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Xml; - -namespace OpenSim.Framework.Configuration.XML -{ - public class XmlConfiguration : IGenericConfig - { - private XmlDocument doc; - private XmlNode rootNode; - private XmlNode configNode; - private string fileName; - private bool createdFile = false; - - public void SetFileName(string file) - { - fileName = file; - } - - private void LoadDataToClass() - { - rootNode = doc.SelectSingleNode("Root"); - if (null == rootNode) - throw new Exception("Error: Invalid .xml File. Missing "); - - configNode = rootNode.SelectSingleNode("Config"); - if (null == configNode) - throw new Exception("Error: Invalid .xml File. should contain a "); - } - - public void LoadData() - { - lock (this) - { - doc = new XmlDocument(); - if (File.Exists(fileName)) - { - XmlTextReader reader = new XmlTextReader(fileName); - reader.WhitespaceHandling = WhitespaceHandling.None; - doc.Load(reader); - reader.Close(); - } - else - { - createdFile = true; - rootNode = doc.CreateNode(XmlNodeType.Element, "Root", String.Empty); - doc.AppendChild(rootNode); - configNode = doc.CreateNode(XmlNodeType.Element, "Config", String.Empty); - rootNode.AppendChild(configNode); - } - - LoadDataToClass(); - - if (createdFile) - { - Commit(); - } - } - } - - public void LoadDataFromString(string data) - { - doc = new XmlDocument(); - doc.LoadXml(data); - - LoadDataToClass(); - } - - public string GetAttribute(string attributeName) - { - string result = null; - if (configNode.Attributes[attributeName] != null) - { - result = ((XmlAttribute) configNode.Attributes.GetNamedItem(attributeName)).Value; - } - return result; - } - - public bool SetAttribute(string attributeName, string attributeValue) - { - if (configNode.Attributes[attributeName] != null) - { - ((XmlAttribute) configNode.Attributes.GetNamedItem(attributeName)).Value = attributeValue; - } - else - { - XmlAttribute attri; - attri = doc.CreateAttribute(attributeName); - attri.Value = attributeValue; - configNode.Attributes.Append(attri); - } - return true; - } - - public void Commit() - { - if (fileName == null || fileName == String.Empty) - return; - - if (!Directory.Exists(Util.configDir())) - { - Directory.CreateDirectory(Util.configDir()); - } - doc.Save(fileName); - } - - public void Close() - { - configNode = null; - rootNode = null; - doc = null; - } - } -} diff --git a/OpenSim/Framework/ConfigurationMember.cs b/OpenSim/Framework/ConfigurationMember.cs deleted file mode 100644 index 7afa68a..0000000 --- a/OpenSim/Framework/ConfigurationMember.cs +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Net; -using System.Reflection; -using System.Xml; -using log4net; -using OpenMetaverse; -//using OpenSim.Framework.Console; - -namespace OpenSim.Framework -{ - public class ConfigurationMember - { - #region Delegates - - public delegate bool ConfigurationOptionResult(string configuration_key, object configuration_result); - - public delegate void ConfigurationOptionsLoad(); - - #endregion - - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private int cE = 0; - - private string configurationDescription = String.Empty; - private string configurationFilename = String.Empty; - private XmlNode configurationFromXMLNode = null; - private List configurationOptions = new List(); - private IGenericConfig configurationPlugin = null; - - /// - /// This is the default configuration DLL loaded - /// - private string configurationPluginFilename = "OpenSim.Framework.Configuration.XML.dll"; - - private ConfigurationOptionsLoad loadFunction; - private ConfigurationOptionResult resultFunction; - - private bool useConsoleToPromptOnError = true; - - public ConfigurationMember(string configuration_filename, string configuration_description, - ConfigurationOptionsLoad load_function, ConfigurationOptionResult result_function, bool use_console_to_prompt_on_error) - { - configurationFilename = configuration_filename; - configurationDescription = configuration_description; - loadFunction = load_function; - resultFunction = result_function; - useConsoleToPromptOnError = use_console_to_prompt_on_error; - } - - public ConfigurationMember(XmlNode configuration_xml, string configuration_description, - ConfigurationOptionsLoad load_function, ConfigurationOptionResult result_function, bool use_console_to_prompt_on_error) - { - configurationFilename = String.Empty; - configurationFromXMLNode = configuration_xml; - configurationDescription = configuration_description; - loadFunction = load_function; - resultFunction = result_function; - useConsoleToPromptOnError = use_console_to_prompt_on_error; - } - - public void setConfigurationFilename(string filename) - { - configurationFilename = filename; - } - - public void setConfigurationDescription(string desc) - { - configurationDescription = desc; - } - - public void setConfigurationResultFunction(ConfigurationOptionResult result) - { - resultFunction = result; - } - - public void forceConfigurationPluginLibrary(string dll_filename) - { - configurationPluginFilename = dll_filename; - } - - private void checkAndAddConfigOption(ConfigurationOption option) - { - if ((option.configurationKey != String.Empty && option.configurationQuestion != String.Empty) || - (option.configurationKey != String.Empty && option.configurationUseDefaultNoPrompt)) - { - if (!configurationOptions.Contains(option)) - { - configurationOptions.Add(option); - } - } - else - { - m_log.Info( - "Required fields for adding a configuration option is invalid. Will not add this option (" + - option.configurationKey + ")"); - } - } - - public void addConfigurationOption(string configuration_key, - ConfigurationOption.ConfigurationTypes configuration_type, - string configuration_question, string configuration_default, - bool use_default_no_prompt) - { - ConfigurationOption configOption = new ConfigurationOption(); - configOption.configurationKey = configuration_key; - configOption.configurationQuestion = configuration_question; - configOption.configurationDefault = configuration_default; - configOption.configurationType = configuration_type; - configOption.configurationUseDefaultNoPrompt = use_default_no_prompt; - configOption.shouldIBeAsked = null; //Assumes true, I can ask whenever - checkAndAddConfigOption(configOption); - } - - public void addConfigurationOption(string configuration_key, - ConfigurationOption.ConfigurationTypes configuration_type, - string configuration_question, string configuration_default, - bool use_default_no_prompt, - ConfigurationOption.ConfigurationOptionShouldBeAsked shouldIBeAskedDelegate) - { - ConfigurationOption configOption = new ConfigurationOption(); - configOption.configurationKey = configuration_key; - configOption.configurationQuestion = configuration_question; - configOption.configurationDefault = configuration_default; - configOption.configurationType = configuration_type; - configOption.configurationUseDefaultNoPrompt = use_default_no_prompt; - configOption.shouldIBeAsked = shouldIBeAskedDelegate; - checkAndAddConfigOption(configOption); - } - - // TEMP - REMOVE - public void performConfigurationRetrieve() - { - if (cE > 1) - m_log.Error("READING CONFIGURATION COUT: " + cE.ToString()); - - - configurationPlugin = LoadConfigDll(configurationPluginFilename); - configurationOptions.Clear(); - if (loadFunction == null) - { - m_log.Error("Load Function for '" + configurationDescription + - "' is null. Refusing to run configuration."); - return; - } - - if (resultFunction == null) - { - m_log.Error("Result Function for '" + configurationDescription + - "' is null. Refusing to run configuration."); - return; - } - - //m_log.Debug("[CONFIG]: Calling Configuration Load Function..."); - loadFunction(); - - if (configurationOptions.Count <= 0) - { - m_log.Error("[CONFIG]: No configuration options were specified for '" + configurationOptions + - "'. Refusing to continue configuration."); - return; - } - - bool useFile = true; - if (configurationPlugin == null) - { - m_log.Error("[CONFIG]: Configuration Plugin NOT LOADED!"); - return; - } - - if (configurationFilename.Trim() != String.Empty) - { - configurationPlugin.SetFileName(configurationFilename); - try - { - configurationPlugin.LoadData(); - useFile = true; - } - catch (XmlException e) - { - m_log.WarnFormat("[CONFIG] Not using {0}: {1}", - configurationFilename, - e.Message.ToString()); - //m_log.Error("Error loading " + configurationFilename + ": " + e.ToString()); - useFile = false; - } - } - else - { - if (configurationFromXMLNode != null) - { - m_log.Info("Loading from XML Node, will not save to the file"); - configurationPlugin.LoadDataFromString(configurationFromXMLNode.OuterXml); - } - - m_log.Info("XML Configuration Filename is not valid; will not save to the file."); - useFile = false; - } - - foreach (ConfigurationOption configOption in configurationOptions) - { - bool convertSuccess = false; - object return_result = null; - string errorMessage = String.Empty; - bool ignoreNextFromConfig = false; - while (convertSuccess == false) - { - string console_result = String.Empty; - string attribute = null; - if (useFile || configurationFromXMLNode != null) - { - if (!ignoreNextFromConfig) - { - attribute = configurationPlugin.GetAttribute(configOption.configurationKey); - } - else - { - ignoreNextFromConfig = false; - } - } - - if (attribute == null) - { - if (configOption.configurationUseDefaultNoPrompt || useConsoleToPromptOnError == false) - { - console_result = configOption.configurationDefault; - } - else - { - if ((configOption.shouldIBeAsked != null && - configOption.shouldIBeAsked(configOption.configurationKey)) || - configOption.shouldIBeAsked == null) - { - if (configurationDescription.Trim() != String.Empty) - { - console_result = - MainConsole.Instance.CmdPrompt( - configurationDescription + ": " + configOption.configurationQuestion, - configOption.configurationDefault); - } - else - { - console_result = - MainConsole.Instance.CmdPrompt(configOption.configurationQuestion, - configOption.configurationDefault); - } - } - else - { - //Dont Ask! Just use default - console_result = configOption.configurationDefault; - } - } - } - else - { - console_result = attribute; - } - - // if the first character is a "$", assume it's the name - // of an environment variable and substitute with the value of that variable - if (console_result.StartsWith("$")) - console_result = Environment.GetEnvironmentVariable(console_result.Substring(1)); - - switch (configOption.configurationType) - { - case ConfigurationOption.ConfigurationTypes.TYPE_STRING: - return_result = console_result; - convertSuccess = true; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY: - if (console_result.Length > 0) - { - return_result = console_result; - convertSuccess = true; - } - errorMessage = "a string that is not empty"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN: - bool boolResult; - if (Boolean.TryParse(console_result, out boolResult)) - { - convertSuccess = true; - return_result = boolResult; - } - errorMessage = "'true' or 'false' (Boolean)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_BYTE: - byte byteResult; - if (Byte.TryParse(console_result, out byteResult)) - { - convertSuccess = true; - return_result = byteResult; - } - errorMessage = "a byte (Byte)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_CHARACTER: - char charResult; - if (Char.TryParse(console_result, out charResult)) - { - convertSuccess = true; - return_result = charResult; - } - errorMessage = "a character (Char)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_INT16: - short shortResult; - if (Int16.TryParse(console_result, out shortResult)) - { - convertSuccess = true; - return_result = shortResult; - } - errorMessage = "a signed 32 bit integer (short)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_INT32: - int intResult; - if (Int32.TryParse(console_result, out intResult)) - { - convertSuccess = true; - return_result = intResult; - } - errorMessage = "a signed 32 bit integer (int)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_INT64: - long longResult; - if (Int64.TryParse(console_result, out longResult)) - { - convertSuccess = true; - return_result = longResult; - } - errorMessage = "a signed 32 bit integer (long)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_IP_ADDRESS: - IPAddress ipAddressResult; - if (IPAddress.TryParse(console_result, out ipAddressResult)) - { - convertSuccess = true; - return_result = ipAddressResult; - } - errorMessage = "an IP Address (IPAddress)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_UUID: - UUID uuidResult; - if (UUID.TryParse(console_result, out uuidResult)) - { - convertSuccess = true; - return_result = uuidResult; - } - errorMessage = "a UUID (UUID)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_UUID_NULL_FREE: - UUID uuidResult2; - if (UUID.TryParse(console_result, out uuidResult2)) - { - convertSuccess = true; - - if (uuidResult2 == UUID.Zero) - uuidResult2 = UUID.Random(); - - return_result = uuidResult2; - } - errorMessage = "a non-null UUID (UUID)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_Vector3: - Vector3 vectorResult; - if (Vector3.TryParse(console_result, out vectorResult)) - { - convertSuccess = true; - return_result = vectorResult; - } - errorMessage = "a vector (Vector3)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_UINT16: - ushort ushortResult; - if (UInt16.TryParse(console_result, out ushortResult)) - { - convertSuccess = true; - return_result = ushortResult; - } - errorMessage = "an unsigned 16 bit integer (ushort)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_UINT32: - uint uintResult; - if (UInt32.TryParse(console_result, out uintResult)) - { - convertSuccess = true; - return_result = uintResult; - } - errorMessage = "an unsigned 32 bit integer (uint)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_UINT64: - ulong ulongResult; - if (UInt64.TryParse(console_result, out ulongResult)) - { - convertSuccess = true; - return_result = ulongResult; - } - errorMessage = "an unsigned 64 bit integer (ulong)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_FLOAT: - float floatResult; - if ( - float.TryParse(console_result, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, Culture.NumberFormatInfo, - out floatResult)) - { - convertSuccess = true; - return_result = floatResult; - } - errorMessage = "a single-precision floating point number (float)"; - break; - case ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE: - double doubleResult; - if ( - Double.TryParse(console_result, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, Culture.NumberFormatInfo, - out doubleResult)) - { - convertSuccess = true; - return_result = doubleResult; - } - errorMessage = "an double-precision floating point number (double)"; - break; - } - - if (convertSuccess) - { - if (useFile) - { - configurationPlugin.SetAttribute(configOption.configurationKey, console_result); - } - - if (!resultFunction(configOption.configurationKey, return_result)) - { - m_log.Info( - "The handler for the last configuration option denied that input, please try again."); - convertSuccess = false; - ignoreNextFromConfig = true; - } - } - else - { - if (configOption.configurationUseDefaultNoPrompt) - { - m_log.Error(string.Format( - "[CONFIG]: [{3}]:[{1}] is not valid default for parameter [{0}].\nThe configuration result must be parsable to {2}.\n", - configOption.configurationKey, console_result, errorMessage, - configurationFilename)); - convertSuccess = true; - } - else - { - m_log.Warn(string.Format( - "[CONFIG]: [{3}]:[{1}] is not a valid value [{0}].\nThe configuration result must be parsable to {2}.\n", - configOption.configurationKey, console_result, errorMessage, - configurationFilename)); - ignoreNextFromConfig = true; - } - } - } - } - - if (useFile) - { - configurationPlugin.Commit(); - configurationPlugin.Close(); - } - } - - private static IGenericConfig LoadConfigDll(string dllName) - { - Assembly pluginAssembly = Assembly.LoadFrom(dllName); - IGenericConfig plug = null; - - foreach (Type pluginType in pluginAssembly.GetTypes()) - { - if (pluginType.IsPublic) - { - if (!pluginType.IsAbstract) - { - Type typeInterface = pluginType.GetInterface("IGenericConfig", true); - - if (typeInterface != null) - { - plug = - (IGenericConfig) Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString())); - } - } - } - } - - pluginAssembly = null; - return plug; - } - - public void forceSetConfigurationOption(string configuration_key, string configuration_value) - { - configurationPlugin.LoadData(); - configurationPlugin.SetAttribute(configuration_key, configuration_value); - configurationPlugin.Commit(); - configurationPlugin.Close(); - } - } -} diff --git a/OpenSim/Framework/Console/AssemblyInfo.cs b/OpenSim/Framework/Console/AssemblyInfo.cs index 37c7304..67af471 100644 --- a/OpenSim/Framework/Console/AssemblyInfo.cs +++ b/OpenSim/Framework/Console/AssemblyInfo.cs @@ -55,4 +55,4 @@ using System.Runtime.InteropServices; // You can specify all values by your own or you can build default build and revision // numbers with the '*' character (the default): -[assembly : AssemblyVersion("0.7.5.*")] +[assembly : AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Framework/Console/CommandConsole.cs b/OpenSim/Framework/Console/CommandConsole.cs index b9f402a..0f68afe 100644 --- a/OpenSim/Framework/Console/CommandConsole.cs +++ b/OpenSim/Framework/Console/CommandConsole.cs @@ -424,9 +424,9 @@ namespace OpenSim.Framework.Console return new string[] { new List(current.Keys)[0] }; } - public string[] Resolve(string[] cmd) + private CommandInfo ResolveCommand(string[] cmd, out string[] result) { - string[] result = cmd; + result = cmd; int index = -1; Dictionary current = tree; @@ -458,7 +458,7 @@ namespace OpenSim.Framework.Console } else if (found.Count > 0) { - return new string[0]; + return null; } else { @@ -467,21 +467,37 @@ namespace OpenSim.Framework.Console } if (current.ContainsKey(String.Empty)) + return (CommandInfo)current[String.Empty]; + + return null; + } + + public bool HasCommand(string command) + { + string[] result; + return ResolveCommand(Parser.Parse(command), out result) != null; + } + + public string[] Resolve(string[] cmd) + { + string[] result; + CommandInfo ci = ResolveCommand(cmd, out result); + + if (ci == null) + return new string[0]; + + if (ci.fn.Count == 0) + return new string[0]; + + foreach (CommandDelegate fn in ci.fn) { - CommandInfo ci = (CommandInfo)current[String.Empty]; - if (ci.fn.Count == 0) + if (fn != null) + fn(ci.module, result); + else return new string[0]; - foreach (CommandDelegate fn in ci.fn) - { - if (fn != null) - fn(ci.module, result); - else - return new string[0]; - } - return result; } - - return new string[0]; + + return result; } public XmlElement GetXml(XmlDocument doc) diff --git a/OpenSim/Framework/Console/ConsoleDisplayUtil.cs b/OpenSim/Framework/Console/ConsoleDisplayUtil.cs new file mode 100644 index 0000000..6417663 --- /dev/null +++ b/OpenSim/Framework/Console/ConsoleDisplayUtil.cs @@ -0,0 +1,48 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenSim.Framework.Console +{ + /// + /// This will be a set of typical column sizes to allow greater consistency between console commands. + /// + public static class ConsoleDisplayUtil + { + public const int CoordTupleSize = 11; + public const int PortSize = 5; + + public const int EstateNameSize = 20; + public const int ParcelNameSize = 40; + public const int RegionNameSize = 20; + public const int UserNameSize = 35; + + public const int UuidSize = 36; + public const int VectorSize = 15; + } +} \ No newline at end of file diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs index dff956a..44f6dc1 100644 --- a/OpenSim/Framework/Console/ConsoleUtil.cs +++ b/OpenSim/Framework/Console/ConsoleUtil.cs @@ -49,14 +49,14 @@ namespace OpenSim.Framework.Console = @"Each component of the coord is comma separated. There must be no spaces between the commas. If you don't care about the z component you can simply omit it. If you don't care about the x or y components then you can leave them blank (though a comma is still required) - If you want to specify the maxmimum value of a component then you can use ~ instead of a number + If you want to specify the maximum value of a component then you can use ~ instead of a number If you want to specify the minimum value of a component then you can use -~ instead of a number e.g. - delete object pos 20,20,20 to 40,40,40 + show object pos 20,20,20 to 40,40,40 delete object pos 20,20 to 40,40 - delete object pos ,20,20 to ,40,40 + show object pos ,20,20 to ,40,40 delete object pos ,,30 to ,,~ - delete object pos ,,-~ to ,,30"; + show object pos ,,-~ to ,,30"; public const string MinRawConsoleVectorValue = "-~"; public const string MaxRawConsoleVectorValue = "~"; @@ -156,12 +156,32 @@ namespace OpenSim.Framework.Console } /// - /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 + /// Convert a console input to a bool, automatically complaining if a console is given. /// /// Can be null if no console is available. /// /param> /// /// + public static bool TryParseConsoleBool(ICommandConsole console, string rawConsoleString, out bool b) + { + if (!bool.TryParse(rawConsoleString, out b)) + { + if (console != null) + console.OutputFormat("ERROR: {0} is not a true or false value", rawConsoleString); + + return false; + } + + return true; + } + + /// + /// Convert a console input to an int, automatically complaining if a console is given. + /// + /// Can be null if no console is available. + /// /param> + /// + /// public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i) { if (!int.TryParse(rawConsoleInt, out i)) @@ -174,6 +194,71 @@ namespace OpenSim.Framework.Console return true; } + + /// + /// Convert a console input to a float, automatically complaining if a console is given. + /// + /// Can be null if no console is available. + /// /param> + /// + /// + public static bool TryParseConsoleFloat(ICommandConsole console, string rawConsoleInput, out float i) + { + if (!float.TryParse(rawConsoleInput, out i)) + { + if (console != null) + console.OutputFormat("ERROR: {0} is not a valid float", rawConsoleInput); + + return false; + } + + return true; + } + + /// + /// Convert a console input to a double, automatically complaining if a console is given. + /// + /// Can be null if no console is available. + /// /param> + /// + /// + public static bool TryParseConsoleDouble(ICommandConsole console, string rawConsoleInput, out double i) + { + if (!double.TryParse(rawConsoleInput, out i)) + { + if (console != null) + console.OutputFormat("ERROR: {0} is not a valid double", rawConsoleInput); + + return false; + } + + return true; + } + + /// + /// Convert a console integer to a natural int, automatically complaining if a console is given. + /// + /// Can be null if no console is available. + /// /param> + /// + /// + public static bool TryParseConsoleNaturalInt(ICommandConsole console, string rawConsoleInt, out int i) + { + if (TryParseConsoleInt(console, rawConsoleInt, out i)) + { + if (i < 0) + { + if (console != null) + console.OutputFormat("ERROR: {0} is not a positive integer", rawConsoleInt); + + return false; + } + + return true; + } + + return false; + } /// /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 @@ -207,24 +292,82 @@ namespace OpenSim.Framework.Console /// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue /// Other than that, component values must be numeric. /// - /// + /// + /// Behaviour if component is blank. If null then conversion fails on a blank component. + /// /// /// public static bool TryParseConsoleVector( string rawConsoleVector, Func blankComponentFunc, out Vector3 vector) { - List components = rawConsoleVector.Split(VectorSeparatorChars).ToList(); - - if (components.Count < 1 || components.Count > 3) + return Vector3.TryParse(CookVector(rawConsoleVector, 3, blankComponentFunc), out vector); + } + + /// + /// Convert a vector input from the console to an OpenMetaverse.Vector2 + /// + /// + /// A string in the form , where there is no space between values. + /// Any component can be missing (e.g. ,40). blankComponentFunc is invoked to replace the blank with a suitable value + /// Also, if the blank component is at the end, then the comma can be missed off entirely (e.g. 40) + /// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue + /// Other than that, component values must be numeric. + /// + /// + /// Behaviour if component is blank. If null then conversion fails on a blank component. + /// + /// + /// + public static bool TryParseConsole2DVector( + string rawConsoleVector, Func blankComponentFunc, out Vector2 vector) + { + // We don't use Vector2.TryParse() for now because for some reason it expects an input with 3 components + // rather than 2. + string cookedVector = CookVector(rawConsoleVector, 2, blankComponentFunc); + + if (cookedVector == null) { - vector = Vector3.Zero; + vector = Vector2.Zero; + return false; } + else + { + string[] cookedComponents = cookedVector.Split(VectorSeparatorChars); + + vector = new Vector2(float.Parse(cookedComponents[0]), float.Parse(cookedComponents[1])); + + return true; + } + + //return Vector2.TryParse(CookVector(rawConsoleVector, 2, blankComponentFunc), out vector); + } + + /// + /// Convert a raw console vector into a vector that can be be parsed by the relevant OpenMetaverse.TryParse() + /// + /// + /// + /// + /// null if conversion was not possible + private static string CookVector( + string rawConsoleVector, int dimensions, Func blankComponentFunc) + { + List components = rawConsoleVector.Split(VectorSeparatorChars).ToList(); - for (int i = components.Count; i < 3; i++) - components.Add(""); + if (components.Count < 1 || components.Count > dimensions) + return null; - List semiDigestedComponents + if (components.Count < dimensions) + { + if (blankComponentFunc == null) + return null; + else + for (int i = components.Count; i < dimensions; i++) + components.Add(""); + } + + List cookedComponents = components.ConvertAll( c => { @@ -238,11 +381,7 @@ namespace OpenSim.Framework.Console return c; }); - string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray()); - - // m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector); - - return Vector3.TryParse(semiDigestedConsoleVector, out vector); + return string.Join(VectorSeparator, cookedComponents.ToArray()); } } } \ No newline at end of file diff --git a/OpenSim/Framework/Console/LocalConsole.cs b/OpenSim/Framework/Console/LocalConsole.cs index d41481f..28293c0 100644 --- a/OpenSim/Framework/Console/LocalConsole.cs +++ b/OpenSim/Framework/Console/LocalConsole.cs @@ -32,6 +32,8 @@ using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading; +using System.IO; +using Nini.Config; using log4net; namespace OpenSim.Framework.Console @@ -41,11 +43,18 @@ namespace OpenSim.Framework.Console /// public class LocalConsole : CommandConsole { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private string m_historyPath; + private bool m_historyEnable; // private readonly object m_syncRoot = new object(); private const string LOGLEVEL_NONE = "(none)"; + // Used to extract categories for colourization. + private Regex m_categoryRegex + = new Regex( + @"^(?.*?)\[(?[^\]]+)\]:?(?.*)", RegexOptions.Singleline | RegexOptions.Compiled); + private int m_cursorYPosition = -1; private int m_cursorXPosition = 0; private StringBuilder m_commandLine = new StringBuilder(); @@ -74,8 +83,54 @@ namespace OpenSim.Framework.Console return Colors[(Math.Abs(input.ToUpper().GetHashCode()) % Colors.Length)]; } - public LocalConsole(string defaultPrompt) : base(defaultPrompt) + public LocalConsole(string defaultPrompt, IConfig startupConfig = null) : base(defaultPrompt) { + + if (startupConfig == null) return; + + m_historyEnable = startupConfig.GetBoolean("ConsoleHistoryFileEnabled", false); + if (!m_historyEnable) + { + m_log.Info("[LOCAL CONSOLE]: Persistent command line history from file is Disabled"); + return; + } + + string m_historyFile = startupConfig.GetString("ConsoleHistoryFile", "OpenSimConsoleHistory.txt"); + int m_historySize = startupConfig.GetInt("ConsoleHistoryFileLines", 100); + m_historyPath = Path.GetFullPath(Path.Combine(Util.configDir(), m_historyFile)); + m_log.InfoFormat("[LOCAL CONSOLE]: Persistent command line history is Enabled, up to {0} lines from file {1}", m_historySize, m_historyPath); + + if (File.Exists(m_historyPath)) + { + using (StreamReader history_file = new StreamReader(m_historyPath)) + { + string line; + while ((line = history_file.ReadLine()) != null) + { + m_history.Add(line); + } + } + + if (m_history.Count > m_historySize) + { + while (m_history.Count > m_historySize) + m_history.RemoveAt(0); + + using (StreamWriter history_file = new StreamWriter(m_historyPath)) + { + foreach (string line in m_history) + { + history_file.WriteLine(line); + } + } + } + m_log.InfoFormat("[LOCAL CONSOLE]: Read {0} lines of command line history from file {1}", m_history.Count, m_historyPath); + } + else + { + m_log.InfoFormat("[LOCAL CONSOLE]: Creating new empty command line history file {0}", m_historyPath); + File.Create(m_historyPath).Dispose(); + } } private void AddToHistory(string text) @@ -84,6 +139,10 @@ namespace OpenSim.Framework.Console m_history.RemoveAt(0); m_history.Add(text); + if (m_historyEnable) + { + File.AppendAllText(m_historyPath, text + Environment.NewLine); + } } /// @@ -280,11 +339,8 @@ namespace OpenSim.Framework.Console string outText = text; if (level != LOGLEVEL_NONE) - { - string regex = @"^(?.*?)\[(?[^\]]+)\]:?(?.*)"; - - Regex RE = new Regex(regex, RegexOptions.Multiline); - MatchCollection matches = RE.Matches(text); + { + MatchCollection matches = m_categoryRegex.Matches(text); if (matches.Count == 1) { @@ -426,6 +482,21 @@ namespace OpenSim.Framework.Console System.Console.Write("{0}", prompt); break; + case ConsoleKey.Delete: + if (m_cursorXPosition == m_commandLine.Length) + break; + + m_commandLine.Remove(m_cursorXPosition, 1); + + SetCursorLeft(0); + m_cursorYPosition = SetCursorTop(m_cursorYPosition); + + if (m_echo) + System.Console.Write("{0}{1} ", prompt, m_commandLine); + else + System.Console.Write("{0}", prompt); + + break; case ConsoleKey.End: m_cursorXPosition = m_commandLine.Length; break; diff --git a/OpenSim/Framework/Console/MockConsole.cs b/OpenSim/Framework/Console/MockConsole.cs index 8ba58e4..1a142df 100644 --- a/OpenSim/Framework/Console/MockConsole.cs +++ b/OpenSim/Framework/Console/MockConsole.cs @@ -40,7 +40,9 @@ namespace OpenSim.Framework.Console /// public class MockConsole : ICommandConsole { +#pragma warning disable 0067 public event OnOutputDelegate OnOutput; +#pragma warning restore 0067 private MockCommands m_commands = new MockCommands(); @@ -80,6 +82,7 @@ namespace OpenSim.Framework.Console public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn) {} public void AddCommand(string module, bool shared, string command, string help, string longhelp, string descriptivehelp, CommandDelegate fn) {} public string[] FindNextOption(string[] cmd, bool term) { return null; } + public bool HasCommand(string cmd) { return false; } public string[] Resolve(string[] cmd) { return null; } public XmlElement GetXml(XmlDocument doc) { return null; } } diff --git a/OpenSim/Framework/Console/RemoteConsole.cs b/OpenSim/Framework/Console/RemoteConsole.cs index 27edd4b..8ad7b0d 100644 --- a/OpenSim/Framework/Console/RemoteConsole.cs +++ b/OpenSim/Framework/Console/RemoteConsole.cs @@ -234,7 +234,7 @@ namespace OpenSim.Framework.Console string uri = "/ReadResponses/" + sessionID.ToString() + "/"; m_Server.AddPollServiceHTTPHandler( - uri, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, sessionID)); + uri, new PollServiceEventArgs(null, uri, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout XmlDocument xmldoc = new XmlDocument(); XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, @@ -425,7 +425,7 @@ namespace OpenSim.Framework.Console return false; } - private Hashtable GetEvents(UUID RequestID, UUID sessionID, string request) + private Hashtable GetEvents(UUID RequestID, UUID sessionID) { ConsoleConnection c = null; diff --git a/OpenSim/Framework/Constants.cs b/OpenSim/Framework/Constants.cs index a2eb5ee..3ba264c 100644 --- a/OpenSim/Framework/Constants.cs +++ b/OpenSim/Framework/Constants.cs @@ -30,9 +30,18 @@ namespace OpenSim.Framework { public class Constants { + // 'RegionSize' is the legacy region size. + // DO NOT USE THIS FOR ANY NEW CODE. Use Scene.RegionInfo.RegionSize[XYZ] as a region might not + // be the legacy region size. public const uint RegionSize = 256; public const uint RegionHeight = 4096; - public const byte TerrainPatchSize = 16; + // This could be a parameters but, really, a region of greater than this is pretty unmanageable + public const uint MaximumRegionSize = 8192; + + // Since terrain is stored in 16x16 heights, regions must be a multiple of this number and that is the minimum + public const int MinRegionSize = 16; + public const int TerrainPatchSize = 16; + public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f"; public enum EstateAccessCodex : uint diff --git a/OpenSim/Framework/DAMap.cs b/OpenSim/Framework/DAMap.cs new file mode 100644 index 0000000..4995a92 --- /dev/null +++ b/OpenSim/Framework/DAMap.cs @@ -0,0 +1,328 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; +using log4net; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework +{ + /// + /// This class stores and retrieves dynamic attributes. + /// + /// + /// Modules that want to use dynamic attributes need to do so in a private data store + /// which is accessed using a unique name. DAMap provides access to the data stores, + /// each of which is an OSDMap. Modules are free to store any type of data they want + /// within their data store. However, avoid storing large amounts of data because that + /// would slow down database access. + /// + public class DAMap : IXmlSerializable + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private static readonly int MIN_NAMESPACE_LENGTH = 4; + + private OSDMap m_map = new OSDMap(); + + // WARNING: this is temporary for experimentation only, it will be removed!!!! + public OSDMap TopLevelMap + { + get { return m_map; } + set { m_map = value; } + } + + public XmlSchema GetSchema() { return null; } + + public static DAMap FromXml(string rawXml) + { + DAMap map = new DAMap(); + map.ReadXml(rawXml); + return map; + } + + public void ReadXml(XmlReader reader) + { + ReadXml(reader.ReadInnerXml()); + } + + public void ReadXml(string rawXml) + { + // System.Console.WriteLine("Trying to deserialize [{0}]", rawXml); + + lock (this) + { + m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml); + SanitiseMap(this); + } + } + + public void WriteXml(XmlWriter writer) + { + writer.WriteRaw(ToXml()); + } + + public string ToXml() + { + lock (this) + return OSDParser.SerializeLLSDXmlString(m_map); + } + + public void CopyFrom(DAMap other) + { + // Deep copy + + string data = null; + lock (other) + { + if (other.CountNamespaces > 0) + { + data = OSDParser.SerializeLLSDXmlString(other.m_map); + } + } + + lock (this) + { + if (data == null) + Clear(); + else + m_map = (OSDMap)OSDParser.DeserializeLLSDXml(data); + } + } + + /// + /// Sanitise the map to remove any namespaces or stores that are not OSDMap. + /// + /// + /// + public static void SanitiseMap(DAMap daMap) + { + List keysToRemove = null; + + OSDMap namespacesMap = daMap.m_map; + + foreach (string key in namespacesMap.Keys) + { +// Console.WriteLine("Processing ns {0}", key); + if (!(namespacesMap[key] is OSDMap)) + { + if (keysToRemove == null) + keysToRemove = new List(); + + keysToRemove.Add(key); + } + } + + if (keysToRemove != null) + { + foreach (string key in keysToRemove) + { +// Console.WriteLine ("Removing bad ns {0}", key); + namespacesMap.Remove(key); + } + } + + foreach (OSD nsOsd in namespacesMap.Values) + { + OSDMap nsOsdMap = (OSDMap)nsOsd; + keysToRemove = null; + + foreach (string key in nsOsdMap.Keys) + { + if (!(nsOsdMap[key] is OSDMap)) + { + if (keysToRemove == null) + keysToRemove = new List(); + + keysToRemove.Add(key); + } + } + + if (keysToRemove != null) + foreach (string key in keysToRemove) + nsOsdMap.Remove(key); + } + } + + /// + /// Get the number of namespaces + /// + public int CountNamespaces { get { lock (this) { return m_map.Count; } } } + + /// + /// Get the number of stores. + /// + public int CountStores + { + get + { + int count = 0; + + lock (this) + { + foreach (OSD osdNamespace in m_map) + { + count += ((OSDMap)osdNamespace).Count; + } + } + + return count; + } + } + + /// + /// Retrieve a Dynamic Attribute store + /// + /// namespace for the store - use "OpenSim" for in-core modules + /// name of the store within the namespace + /// an OSDMap representing the stored data, or null if not found + public OSDMap GetStore(string ns, string storeName) + { + OSD namespaceOsd; + + lock (this) + { + if (m_map.TryGetValue(ns, out namespaceOsd)) + { + OSD store; + + if (((OSDMap)namespaceOsd).TryGetValue(storeName, out store)) + return (OSDMap)store; + } + } + + return null; + } + + /// + /// Saves a Dynamic attribute store + /// + /// namespace for the store - use "OpenSim" for in-core modules + /// name of the store within the namespace + /// an OSDMap representing the data to store + public void SetStore(string ns, string storeName, OSDMap store) + { + ValidateNamespace(ns); + OSDMap nsMap; + + lock (this) + { + if (!m_map.ContainsKey(ns)) + { + nsMap = new OSDMap(); + m_map[ns] = nsMap; + } + + nsMap = (OSDMap)m_map[ns]; + +// m_log.DebugFormat("[DA MAP]: Setting store to {0}:{1}", ns, storeName); + nsMap[storeName] = store; + } + } + + /// + /// Validate the key used for storing separate data stores. + /// + /// + public static void ValidateNamespace(string ns) + { + if (ns.Length < MIN_NAMESPACE_LENGTH) + throw new Exception("Minimum namespace length is " + MIN_NAMESPACE_LENGTH); + } + + public bool ContainsStore(string ns, string storeName) + { + OSD namespaceOsd; + + lock (this) + { + if (m_map.TryGetValue(ns, out namespaceOsd)) + { + return ((OSDMap)namespaceOsd).ContainsKey(storeName); + } + } + + return false; + } + + public bool TryGetStore(string ns, string storeName, out OSDMap store) + { + OSD namespaceOsd; + + lock (this) + { + if (m_map.TryGetValue(ns, out namespaceOsd)) + { + OSD storeOsd; + + bool result = ((OSDMap)namespaceOsd).TryGetValue(storeName, out storeOsd); + store = (OSDMap)storeOsd; + + return result; + } + } + + store = null; + return false; + } + + public void Clear() + { + lock (this) + m_map.Clear(); + } + + public bool RemoveStore(string ns, string storeName) + { + OSD namespaceOsd; + + lock (this) + { + if (m_map.TryGetValue(ns, out namespaceOsd)) + { + OSDMap namespaceOsdMap = (OSDMap)namespaceOsd; + namespaceOsdMap.Remove(storeName); + + // Don't keep empty namespaces around + if (namespaceOsdMap.Count <= 0) + m_map.Remove(ns); + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/DOMap.cs b/OpenSim/Framework/DOMap.cs new file mode 100644 index 0000000..f5b650b --- /dev/null +++ b/OpenSim/Framework/DOMap.cs @@ -0,0 +1,98 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework +{ + /// + /// This class stores and retrieves dynamic objects. + /// + /// + /// Experimental - DO NOT USE. Does not yet have namespace support. + /// + public class DOMap + { + private IDictionary m_map; + + public void Add(string ns, string objName, object dynObj) + { + DAMap.ValidateNamespace(ns); + + lock (this) + { + if (m_map == null) + m_map = new Dictionary(); + + m_map.Add(objName, dynObj); + } + } + + public bool ContainsKey(string key) + { + return Get(key) != null; + } + + /// + /// Get a dynamic object + /// + /// + /// Not providing an index method so that users can't casually overwrite each other's objects. + /// + /// + public object Get(string key) + { + lock (this) + { + if (m_map == null) + return null; + else + return m_map[key]; + } + } + + public bool Remove(string key) + { + lock (this) + { + if (m_map == null) + return false; + else + return m_map.Remove(key); + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/EstateBan.cs b/OpenSim/Framework/EstateBan.cs index de9ebf6..ebed794 100644 --- a/OpenSim/Framework/EstateBan.cs +++ b/OpenSim/Framework/EstateBan.cs @@ -25,6 +25,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System; +using System.Collections.Generic; +using System.Reflection; + using OpenMetaverse; namespace OpenSim.Framework @@ -111,5 +115,50 @@ namespace OpenSim.Framework } } + public EstateBan() { } + + public Dictionary ToMap() + { + Dictionary map = new Dictionary(); + PropertyInfo[] properties = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); + foreach (PropertyInfo p in properties) + map[p.Name] = p.GetValue(this, null); + + return map; + } + + public EstateBan(Dictionary map) + { + foreach (KeyValuePair kvp in map) + { + PropertyInfo p = this.GetType().GetProperty(kvp.Key, BindingFlags.Public | BindingFlags.Instance); + if (p == null) + continue; + object value = p.GetValue(this, null); + if (value is String) + p.SetValue(this, map[p.Name], null); + else if (value is UInt32) + p.SetValue(this, UInt32.Parse((string)map[p.Name]), null); + else if (value is Boolean) + p.SetValue(this, Boolean.Parse((string)map[p.Name]), null); + else if (value is UUID) + p.SetValue(this, UUID.Parse((string)map[p.Name]), null); + } + } + + + /// + /// For debugging + /// + /// + public override string ToString() + { + Dictionary map = ToMap(); + string result = string.Empty; + foreach (KeyValuePair kvp in map) + result += string.Format("{0}: {1} {2}", kvp.Key, kvp.Value, Environment.NewLine); + + return result; + } } } diff --git a/OpenSim/Framework/EstateSettings.cs b/OpenSim/Framework/EstateSettings.cs index a92abbf..4df7860 100644 --- a/OpenSim/Framework/EstateSettings.cs +++ b/OpenSim/Framework/EstateSettings.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Reflection; using OpenMetaverse; namespace OpenSim.Framework @@ -58,6 +59,30 @@ namespace OpenSim.Framework set { m_EstateName = value; } } + private bool m_AllowLandmark = true; + + public bool AllowLandmark + { + get { return m_AllowLandmark; } + set { m_AllowLandmark = value; } + } + + private bool m_AllowParcelChanges = true; + + public bool AllowParcelChanges + { + get { return m_AllowParcelChanges; } + set { m_AllowParcelChanges = value; } + } + + private bool m_AllowSetHome = true; + + public bool AllowSetHome + { + get { return m_AllowSetHome; } + set { m_AllowSetHome = value; } + } + private uint m_ParentEstateID = 1; public uint ParentEstateID @@ -374,10 +399,132 @@ namespace OpenSim.Framework return l_EstateAccess.Contains(user); } + public void SetFromFlags(ulong regionFlags) + { + ResetHomeOnTeleport = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport) == (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport); + BlockDwell = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.BlockDwell) == (ulong)OpenMetaverse.RegionFlags.BlockDwell); + AllowLandmark = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowLandmark) == (ulong)OpenMetaverse.RegionFlags.AllowLandmark); + AllowParcelChanges = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges) == (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges); + AllowSetHome = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowSetHome) == (ulong)OpenMetaverse.RegionFlags.AllowSetHome); + } + public bool GroupAccess(UUID groupID) { return l_EstateGroups.Contains(groupID); } + public Dictionary ToMap() + { + Dictionary map = new Dictionary(); + PropertyInfo[] properties = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); + foreach (PropertyInfo p in properties) + { + // EstateBans is a complex type, let's treat it as special + if (p.Name == "EstateBans") + continue; + + object value = p.GetValue(this, null); + if (value != null) + { + if (p.PropertyType.IsArray) // of UUIDs + { + if (((Array)value).Length > 0) + { + string[] args = new string[((Array)value).Length]; + int index = 0; + foreach (object o in (Array)value) + args[index++] = o.ToString(); + map[p.Name] = String.Join(",", args); + } + } + else // simple types + map[p.Name] = value; + } + } + + // EstateBans are special + if (EstateBans.Length > 0) + { + Dictionary bans = new Dictionary(); + int i = 0; + foreach (EstateBan ban in EstateBans) + bans["ban" + i++] = ban.ToMap(); + map["EstateBans"] = bans; + } + + return map; + } + + /// + /// For debugging + /// + /// + public override string ToString() + { + Dictionary map = ToMap(); + String result = String.Empty; + + foreach (KeyValuePair kvp in map) + { + if (kvp.Key == "EstateBans") + { + result += "EstateBans:" + Environment.NewLine; + foreach (KeyValuePair ban in (Dictionary)kvp.Value) + result += ban.Value.ToString(); + } + else + result += string.Format("{0}: {1} {2}", kvp.Key, kvp.Value.ToString(), Environment.NewLine); + } + + return result; + } + + public EstateSettings(Dictionary map) + { + foreach (KeyValuePair kvp in map) + { + PropertyInfo p = this.GetType().GetProperty(kvp.Key, BindingFlags.Public | BindingFlags.Instance); + if (p == null) + continue; + + // EstateBans is a complex type, let's treat it as special + if (p.Name == "EstateBans") + continue; + + if (p.PropertyType.IsArray) + { + string[] elements = ((string)map[p.Name]).Split(new char[] { ',' }); + UUID[] uuids = new UUID[elements.Length]; + int i = 0; + foreach (string e in elements) + uuids[i++] = new UUID(e); + p.SetValue(this, uuids, null); + } + else + { + object value = p.GetValue(this, null); + if (value is String) + p.SetValue(this, map[p.Name], null); + else if (value is UInt32) + p.SetValue(this, UInt32.Parse((string)map[p.Name]), null); + else if (value is Boolean) + p.SetValue(this, Boolean.Parse((string)map[p.Name]), null); + else if (value is UUID) + p.SetValue(this, UUID.Parse((string)map[p.Name]), null); + } + } + + // EstateBans are special + if (map.ContainsKey("EstateBans")) + { + var banData = ((Dictionary)map["EstateBans"]).Values; + EstateBan[] bans = new EstateBan[banData.Count]; + int b = 0; + foreach (Dictionary ban in banData) + bans[b++] = new EstateBan(ban); + PropertyInfo bansProperty = this.GetType().GetProperty("EstateBans", BindingFlags.Public | BindingFlags.Instance); + bansProperty.SetValue(this, bans, null); + } + } } } diff --git a/OpenSim/Framework/ExtraPhysicsData.cs b/OpenSim/Framework/ExtraPhysicsData.cs new file mode 100644 index 0000000..9e7334f --- /dev/null +++ b/OpenSim/Framework/ExtraPhysicsData.cs @@ -0,0 +1,50 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using OpenMetaverse; + +namespace OpenSim.Framework +{ + public enum PhysShapeType : byte + { + prim = 0, + none = 1, + convex = 2, + + invalid = 255 // use to mark invalid data in ExtraPhysicsData + } + + public struct ExtraPhysicsData + { + public float Density; + public float GravitationModifier; + public float Friction; + public float Bounce; + public PhysShapeType PhysShapeType; + + } +} diff --git a/OpenSim/Framework/ForeignUserProfileData.cs b/OpenSim/Framework/ForeignUserProfileData.cs deleted file mode 100644 index 2beaf80..0000000 --- a/OpenSim/Framework/ForeignUserProfileData.cs +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; - -namespace OpenSim.Framework -{ - public class ForeignUserProfileData : UserProfileData - { - /// - /// The address of the users home sim, used for foreigners. - /// - private string _userUserServerURI = String.Empty; - - /// - /// The address of the users home sim, used for foreigners. - /// - private string _userHomeAddress = String.Empty; - - /// - /// The port of the users home sim, used for foreigners. - /// - private string _userHomePort = String.Empty; - /// - /// The remoting port of the users home sim, used for foreigners. - /// - private string _userHomeRemotingPort = String.Empty; - - public string UserServerURI - { - get { return _userUserServerURI; } - set { _userUserServerURI = value; } - } - - public string UserHomeAddress - { - get { return _userHomeAddress; } - set { _userHomeAddress = value; } - } - - public string UserHomePort - { - get { return _userHomePort; } - set { _userHomePort = value; } - } - - public string UserHomeRemotingPort - { - get { return _userHomeRemotingPort; } - set { _userHomeRemotingPort = value; } - } - } -} diff --git a/OpenSim/Framework/GridInstantMessage.cs b/OpenSim/Framework/GridInstantMessage.cs index 6ae0488..da3690c 100644 --- a/OpenSim/Framework/GridInstantMessage.cs +++ b/OpenSim/Framework/GridInstantMessage.cs @@ -53,6 +53,24 @@ namespace OpenSim.Framework binaryBucket = new byte[0]; } + public GridInstantMessage(GridInstantMessage im, bool addTimestamp) + { + fromAgentID = im.fromAgentID; + fromAgentName = im.fromAgentName; + toAgentID = im.toAgentID; + dialog = im.dialog; + fromGroup = im.fromGroup; + message = im.message; + imSessionID = im.imSessionID; + offline = im.offline; + Position = im.Position; + binaryBucket = im.binaryBucket; + RegionID = im.RegionID; + + if (addTimestamp) + timestamp = (uint)Util.UnixTimeSinceEpoch(); + } + public GridInstantMessage(IScene scene, UUID _fromAgentID, string _fromAgentName, UUID _toAgentID, byte _dialog, bool _fromGroup, string _message, diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 87433cc..e36edb2 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -64,7 +64,9 @@ namespace OpenSim.Framework public delegate void NetworkStats(int inPackets, int outPackets, int unAckedBytes); - public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams); + public delegate void CachedTextureRequest(IClientAPI remoteClient, int serial, List cachedTextureRequest); + + public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 AvSize, WearableCacheItem[] CacheItems); public delegate void StartAnim(IClientAPI remoteClient, UUID animID); @@ -124,7 +126,7 @@ namespace OpenSim.Framework public delegate void ObjectDrop(uint localID, IClientAPI remoteClient); public delegate void UpdatePrimFlags( - uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, IClientAPI remoteClient); + uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient); public delegate void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient); @@ -313,7 +315,7 @@ namespace OpenSim.Framework public delegate void ObjectPermissions( IClientAPI controller, UUID agentID, UUID sessionID, byte field, uint localId, uint mask, byte set); - public delegate void EconomyDataRequest(UUID agentID); + public delegate void EconomyDataRequest(IClientAPI client); public delegate void ObjectIncludeInSearch(IClientAPI remoteClient, bool IncludeInSearch, uint localID); @@ -780,6 +782,7 @@ namespace OpenSim.Framework event EstateChangeInfo OnEstateChangeInfo; event EstateManageTelehub OnEstateManageTelehub; // [Obsolete("LLClientView Specific.")] + event CachedTextureRequest OnCachedTextureRequest; event SetAppearance OnSetAppearance; // [Obsolete("LLClientView Specific - Replace and rename OnAvatarUpdate. Difference from SetAppearance?")] event AvatarNowWearing OnAvatarNowWearing; @@ -822,6 +825,8 @@ namespace OpenSim.Framework /// event UpdateAgent OnAgentUpdate; + event UpdateAgent OnAgentCameraUpdate; + event AgentRequestSit OnAgentRequestSit; event AgentSit OnAgentSit; event AvatarPickerRequest OnAvatarPickerRequest; @@ -1087,14 +1092,15 @@ namespace OpenSim.Framework /// void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry); + void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures); + void SendStartPingCheck(byte seq); /// /// Tell the client that an object has been deleted /// - /// /// - void SendKillObject(ulong regionHandle, List localID); + void SendKillObject(List localID); void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs); void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args); @@ -1116,8 +1122,8 @@ namespace OpenSim.Framework void SendInstantMessage(GridInstantMessage im); - void SendGenericMessage(string method, List message); - void SendGenericMessage(string method, List message); + void SendGenericMessage(string method, UUID invoice, List message); + void SendGenericMessage(string method, UUID invoice, List message); void SendLayerData(float[] map); void SendLayerData(int px, int py, float[] map); @@ -1155,7 +1161,8 @@ namespace OpenSim.Framework void SendTeleportStart(uint flags); void SendTeleportProgress(uint flags, string message); - void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance); + void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item); + void SendPayPrice(UUID objectID, int[] payPrice); void SendCoarseLocationUpdate(List users, List CoarseLocations); @@ -1250,8 +1257,6 @@ namespace OpenSim.Framework void SendDialog(string objectname, UUID objectID, UUID ownerID, string ownerFirstName, string ownerLastName, string msg, UUID textureID, int ch, string[] buttonlabels); - bool AddMoney(int debit); - /// /// Update the client as to where the sun is currently located. /// @@ -1356,6 +1361,8 @@ namespace OpenSim.Framework void SendObjectPropertiesReply(ISceneEntity Entity); + void SendPartPhysicsProprieties(ISceneEntity Entity); + void SendAgentOffline(UUID[] agentIDs); void SendAgentOnline(UUID[] agentIDs); @@ -1469,7 +1476,7 @@ namespace OpenSim.Framework void SendChangeUserRights(UUID agentID, UUID friendID, int rights); void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId); - void StopFlying(ISceneEntity presence); + void SendAgentTerseUpdate(ISceneEntity presence); void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data); } diff --git a/OpenSim/Framework/ICommandConsole.cs b/OpenSim/Framework/ICommandConsole.cs index a6573f8..3db2765 100644 --- a/OpenSim/Framework/ICommandConsole.cs +++ b/OpenSim/Framework/ICommandConsole.cs @@ -67,9 +67,16 @@ namespace OpenSim.Framework string help, string longhelp, string descriptivehelp, CommandDelegate fn); - string[] FindNextOption(string[] cmd, bool term); + /// + /// Has the given command already been registered? + /// + /// + /// Command. + bool HasCommand(string command); + + string[] FindNextOption(string[] command, bool term); - string[] Resolve(string[] cmd); + string[] Resolve(string[] command); XmlElement GetXml(XmlDocument doc); } diff --git a/OpenSim/Framework/IImprovedAssetCache.cs b/OpenSim/Framework/IImprovedAssetCache.cs index 251215a..a853e90 100644 --- a/OpenSim/Framework/IImprovedAssetCache.cs +++ b/OpenSim/Framework/IImprovedAssetCache.cs @@ -31,9 +31,34 @@ namespace OpenSim.Framework { public interface IImprovedAssetCache { + /// + /// Cache the specified asset. + /// + /// void Cache(AssetBase asset); + + /// + /// Get an asset by its id. + /// + /// + /// null if the asset does not exist. AssetBase Get(string id); + + /// + /// Check whether an asset with the specified id exists in the cache. + /// + /// + bool Check(string id); + + /// + /// Expire an asset from the cache. + /// + /// void Expire(string id); + + /// + /// Clear the cache. + /// void Clear(); } -} +} \ No newline at end of file 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 ILandObject GetLandObject(float x, float y); /// + /// Get the parcel at the specified point + /// + /// Vector where x and y components are between 0 and 256. z component is ignored. + /// Land object at the point supplied + ILandObject GetLandObject(Vector3 position); + + /// /// Get the parcels near the specified point /// /// diff --git a/OpenSim/Framework/ILandObject.cs b/OpenSim/Framework/ILandObject.cs index 4f98d7b..8465c86 100644 --- a/OpenSim/Framework/ILandObject.cs +++ b/OpenSim/Framework/ILandObject.cs @@ -38,6 +38,7 @@ namespace OpenSim.Framework int GetParcelMaxPrimCount(); int GetSimulatorMaxPrimCount(); int GetPrimsFree(); + Dictionary GetLandObjectOwners(); LandData LandData { get; set; } bool[,] LandBitmap { get; set; } @@ -70,6 +71,7 @@ namespace OpenSim.Framework void UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client); bool IsEitherBannedOrRestricted(UUID avatar); bool IsBannedFromLand(UUID avatar); + bool CanBeOnThisLand(UUID avatar, float posHeight); bool IsRestrictedFromLand(UUID avatar); bool IsInLandAccessList(UUID avatar); void SendLandUpdateToClient(IClientAPI remote_client); diff --git a/OpenSim/Framework/IMoneyModule.cs b/OpenSim/Framework/IMoneyModule.cs index 1e09728..52f3e83 100644 --- a/OpenSim/Framework/IMoneyModule.cs +++ b/OpenSim/Framework/IMoneyModule.cs @@ -38,7 +38,8 @@ namespace OpenSim.Framework int GetBalance(UUID agentID); bool UploadCovered(UUID agentID, int amount); bool AmountCovered(UUID agentID, int amount); - void ApplyCharge(UUID agentID, int amount, string text); + void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type); + void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string extraData); void ApplyUploadCharge(UUID agentID, int amount, string text); int UploadCharge { get; } diff --git a/OpenSim/Framework/IPeople.cs b/OpenSim/Framework/IPeople.cs new file mode 100644 index 0000000..8d274d0 --- /dev/null +++ b/OpenSim/Framework/IPeople.cs @@ -0,0 +1,49 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse; + +namespace OpenSim.Framework +{ + public class UserData + { + public UUID Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string HomeURL { get; set; } + public Dictionary ServerURLs { get; set; } + public bool IsUnknownUser { get; set; } + public bool HasGridUserTried { get; set; } + } + + public interface IPeople + { + List GetUserData(string query, int page_size, int page_number); + } +} \ No newline at end of file diff --git a/OpenSim/Framework/IRegionLoader.cs b/OpenSim/Framework/IRegionLoader.cs deleted file mode 100644 index c566fc7..0000000 --- a/OpenSim/Framework/IRegionLoader.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using Nini.Config; - -namespace OpenSim.Framework -{ - public interface IRegionLoader - { - void SetIniConfigSource(IConfigSource configSource); - RegionInfo[] LoadRegions(); - } -} \ No newline at end of file diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs index 87ec99e..e1b6d1e 100644 --- a/OpenSim/Framework/IScene.cs +++ b/OpenSim/Framework/IScene.cs @@ -86,24 +86,26 @@ namespace OpenSim.Framework event restart OnRestart; /// - /// Add a new client and create a presence for it. All clients except initial login clients will starts off as a child agent + /// Add a new agent with an attached client. All agents except initial login clients will starts off as a child agent /// - the later agent crossing will promote it to a root agent. /// /// /// The type of agent to add. /// /// The scene agent if the new client was added or if an agent that already existed. - ISceneAgent AddNewClient(IClientAPI client, PresenceType type); + ISceneAgent AddNewAgent(IClientAPI client, PresenceType type); /// - /// Remove the given client from the scene. + /// Tell a single agent to disconnect from the region. /// /// - /// Close the neighbour child agents associated with this client. - void RemoveClient(UUID agentID, bool closeChildAgents); + /// + /// Force the agent to close even if it might be in the middle of some other operation. You do not want to + /// force unless you are absolutely sure that the agent is dead and a normal close is not working. + /// + bool CloseAgent(UUID agentID, bool force); void Restart(); - //RegionInfo OtherRegionUp(RegionInfo thisRegion); string GetSimulatorVersion(); @@ -136,5 +138,10 @@ namespace OpenSim.Framework ISceneObject DeserializeObject(string representation); bool CheckClient(UUID agentID, System.Net.IPEndPoint ep); + + /// + /// Start the scene and associated scripts within it. + /// + void Start(); } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/ISceneAgent.cs b/OpenSim/Framework/ISceneAgent.cs index 563d906..ca1399c 100644 --- a/OpenSim/Framework/ISceneAgent.cs +++ b/OpenSim/Framework/ISceneAgent.cs @@ -66,12 +66,17 @@ namespace OpenSim.Framework AvatarAppearance Appearance { get; set; } /// + /// Set if initial data about the scene (avatars, objects) has been sent to the client. + /// + bool SentInitialDataToClient { get; } + + /// /// Send initial scene data to the client controlling this agent /// /// /// This includes scene object data and the appearance data of other avatars. /// - void SendInitialDataToMe(); + void SendInitialDataToClient(); /// /// Direction in which the scene presence is looking. diff --git a/OpenSim/Framework/ISceneObject.cs b/OpenSim/Framework/ISceneObject.cs index afac9b8..754b77b 100644 --- a/OpenSim/Framework/ISceneObject.cs +++ b/OpenSim/Framework/ISceneObject.cs @@ -32,6 +32,8 @@ namespace OpenSim.Framework { public interface ISceneObject { + string Name { get; } + UUID UUID { get; } /// diff --git a/OpenSim/Framework/InventoryCollection.cs b/OpenSim/Framework/InventoryCollection.cs index 7049902..59655eb 100644 --- a/OpenSim/Framework/InventoryCollection.cs +++ b/OpenSim/Framework/InventoryCollection.cs @@ -37,6 +37,8 @@ namespace OpenSim.Framework { public List Folders; public List Items; - public UUID UserID; + public UUID OwnerID; + public UUID FolderID; + public int Version; } } diff --git a/OpenSim/Framework/InventoryFolderBase.cs b/OpenSim/Framework/InventoryFolderBase.cs index b3457a6..fb66056 100644 --- a/OpenSim/Framework/InventoryFolderBase.cs +++ b/OpenSim/Framework/InventoryFolderBase.cs @@ -34,6 +34,9 @@ namespace OpenSim.Framework /// public class InventoryFolderBase : InventoryNodeBase { + public static readonly string ROOT_FOLDER_NAME = "My Inventory"; + public static readonly string SUITCASE_FOLDER_NAME = "My Suitcase"; + /// /// The folder this folder is contained in /// diff --git a/OpenSim/Framework/InventoryItemBase.cs b/OpenSim/Framework/InventoryItemBase.cs index 3d45e76..f9fd752 100644 --- a/OpenSim/Framework/InventoryItemBase.cs +++ b/OpenSim/Framework/InventoryItemBase.cs @@ -34,7 +34,7 @@ namespace OpenSim.Framework /// Inventory Item - contains all the properties associated with an individual inventory piece. /// public class InventoryItemBase : InventoryNodeBase, ICloneable - { + { /// /// The inventory type of the item. This is slightly different from the asset type in some situations. /// @@ -82,12 +82,15 @@ namespace OpenSim.Framework set { m_creatorId = value; + + if ((m_creatorId == null) || !UUID.TryParse(m_creatorId, out m_creatorIdAsUuid)) + m_creatorIdAsUuid = UUID.Zero; } } protected string m_creatorId; /// - /// The CreatorId expressed as a UUID.tely + /// The CreatorId expressed as a UUID. /// public UUID CreatorIdAsUuid { @@ -122,7 +125,7 @@ namespace OpenSim.Framework { get { - if (m_creatorData != null && m_creatorData != string.Empty) + if (!string.IsNullOrEmpty(m_creatorData)) return m_creatorId + ';' + m_creatorData; else return m_creatorId; diff --git a/OpenSim/Framework/Location.cs b/OpenSim/Framework/Location.cs index 9504e03..0b88834 100644 --- a/OpenSim/Framework/Location.cs +++ b/OpenSim/Framework/Location.cs @@ -33,10 +33,10 @@ namespace OpenSim.Framework [Serializable] public class Location : ICloneable { - private readonly int m_x; - private readonly int m_y; + private readonly uint m_x; + private readonly uint m_y; - public Location(int x, int y) + public Location(uint x, uint y) { m_x = x; m_y = y; @@ -44,21 +44,21 @@ namespace OpenSim.Framework public Location(ulong regionHandle) { - m_x = (int) regionHandle; - m_y = (int) (regionHandle >> 32); + m_x = (uint)(regionHandle >> 32); + m_y = (uint)(regionHandle & (ulong)uint.MaxValue); } public ulong RegionHandle { - get { return Utils.UIntsToLong((uint)m_x, (uint)m_y); } + get { return Utils.UIntsToLong(m_x, m_y); } } - public int X + public uint X { get { return m_x; } } - public int Y + public uint Y { get { return m_y; } } diff --git a/OpenSim/Framework/LogWriter.cs b/OpenSim/Framework/LogWriter.cs new file mode 100755 index 0000000..2e0bf4a --- /dev/null +++ b/OpenSim/Framework/LogWriter.cs @@ -0,0 +1,181 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Text; +using log4net; + +namespace OpenSim.Framework +{ + /// + /// Class for writing a high performance, high volume log file. + /// Sometimes, to debug, one has a high volume logging to do and the regular + /// log file output is not appropriate. + /// Create a new instance with the parameters needed and + /// call Write() to output a line. Call Close() when finished. + /// If created with no parameters, it will not log anything. + /// + public class LogWriter : IDisposable + { + public bool Enabled { get; private set; } + + private string m_logDirectory = "."; + private int m_logMaxFileTimeMin = 5; // 5 minutes + public String LogFileHeader { get; set; } + + private StreamWriter m_logFile = null; + private TimeSpan m_logFileLife; + private DateTime m_logFileEndTime; + private Object m_logFileWriteLock = new Object(); + private bool m_flushWrite; + + // set externally when debugging. If let 'null', this does not write any error messages. + public ILog ErrorLogger = null; + private string LogHeader = "[LOG WRITER]"; + + /// + /// Create a log writer that will not write anything. Good for when not enabled + /// but the write statements are still in the code. + /// + public LogWriter() + { + Enabled = false; + m_logFile = null; + } + + /// + /// Create a log writer instance. + /// + /// The directory to create the log file in. May be 'null' for default. + /// The characters that begin the log file name. May be 'null' for default. + /// Maximum age of a log file in minutes. If zero, will set default. + /// Whether to do a flush after every log write. Best left off but + /// if one is looking for a crash, this is a good thing to turn on. + public LogWriter(string dir, string headr, int maxFileTime, bool flushWrite) + { + m_logDirectory = dir == null ? "." : dir; + + LogFileHeader = headr == null ? "log-" : headr; + + m_logMaxFileTimeMin = maxFileTime; + if (m_logMaxFileTimeMin < 1) + m_logMaxFileTimeMin = 5; + + m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0); + m_logFileEndTime = DateTime.Now + m_logFileLife; + + m_flushWrite = flushWrite; + + Enabled = true; + } + // Constructor that assumes flushWrite is off. + public LogWriter(string dir, string headr, int maxFileTime) : this(dir, headr, maxFileTime, false) + { + } + + public void Dispose() + { + this.Close(); + } + + public void Close() + { + Enabled = false; + if (m_logFile != null) + { + m_logFile.Close(); + m_logFile.Dispose(); + m_logFile = null; + } + } + + public void Write(string line, params object[] args) + { + if (!Enabled) return; + Write(String.Format(line, args)); + } + + public void Flush() + { + if (!Enabled) return; + if (m_logFile != null) + { + m_logFile.Flush(); + } + } + + public void Write(string line) + { + if (!Enabled) return; + try + { + lock (m_logFileWriteLock) + { + DateTime now = DateTime.UtcNow; + if (m_logFile == null || now > m_logFileEndTime) + { + if (m_logFile != null) + { + m_logFile.Close(); + m_logFile.Dispose(); + m_logFile = null; + } + + // First log file or time has expired, start writing to a new log file + m_logFileEndTime = now + m_logFileLife; + string path = (m_logDirectory.Length > 0 ? m_logDirectory + + System.IO.Path.DirectorySeparatorChar.ToString() : "") + + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss")); + m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)); + } + if (m_logFile != null) + { + StringBuilder buff = new StringBuilder(line.Length + 25); + buff.Append(now.ToString("yyyyMMddHHmmssfff")); + // buff.Append(now.ToString("yyyyMMddHHmmss")); + buff.Append(","); + buff.Append(line); + buff.Append("\r\n"); + m_logFile.Write(buff.ToString()); + if (m_flushWrite) + m_logFile.Flush(); + } + } + } + catch (Exception e) + { + if (ErrorLogger != null) + { + ErrorLogger.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e); + } + Enabled = false; + } + return; + } + } +} diff --git a/OpenSim/Framework/MapBlockData.cs b/OpenSim/Framework/MapBlockData.cs index 2298ac5..4bee499 100644 --- a/OpenSim/Framework/MapBlockData.cs +++ b/OpenSim/Framework/MapBlockData.cs @@ -27,6 +27,7 @@ using System; using OpenMetaverse; +using OpenMetaverse.StructuredData; namespace OpenSim.Framework { @@ -40,9 +41,26 @@ namespace OpenSim.Framework public byte WaterHeight; public ushort X; public ushort Y; + public ushort SizeX; + public ushort SizeY; public MapBlockData() { } + + public OSDMap ToOSD() + { + OSDMap map = new OSDMap(); + map["X"] = X; + map["Y"] = Y; + map["SizeX"] = SizeX; + map["SizeY"] = SizeY; + map["Name"] = Name; + map["Access"] = Access; + map["RegionFlags"] = RegionFlags; + map["WaterHeight"] = WaterHeight; + map["MapImageID"] = MapImageId; + return map; + } } } diff --git a/OpenSim/Framework/MapItemReplyStruct.cs b/OpenSim/Framework/MapItemReplyStruct.cs index 58011bd..c8693ae 100644 --- a/OpenSim/Framework/MapItemReplyStruct.cs +++ b/OpenSim/Framework/MapItemReplyStruct.cs @@ -26,6 +26,7 @@ */ using OpenMetaverse; +using OpenMetaverse.StructuredData; namespace OpenSim.Framework { @@ -37,5 +38,37 @@ namespace OpenSim.Framework public int Extra; public int Extra2; public string name; + + public mapItemReply(uint pX, uint pY, UUID pId, string pName, int pExt1, int pExt2) + { + x = pX; + y = pY; + id = pId; + name = pName; + Extra = pExt1; + Extra2 = pExt2; + } + + public OSDMap ToOSD() + { + OSDMap map = new OSDMap(); + map["X"] = OSD.FromInteger((int)x); + map["Y"] = OSD.FromInteger((int)y); + map["ID"] = OSD.FromUUID(id); + map["Name"] = OSD.FromString(name); + map["Extra"] = OSD.FromInteger(Extra); + map["Extra2"] = OSD.FromInteger(Extra2); + return map; + } + + public void FromOSD(OSDMap map) + { + x = (uint) map["X"].AsInteger(); + y = (uint) map["Y"].AsInteger(); + id = map["ID"].AsUUID(); + Extra = map["Extra"].AsInteger(); + Extra2 = map["Extra2"].AsInteger(); + name = map["Name"].AsString(); + } } } diff --git a/OpenSim/Framework/MetricsCollector.cs b/OpenSim/Framework/MetricsCollector.cs new file mode 100644 index 0000000..c8f4a33 --- /dev/null +++ b/OpenSim/Framework/MetricsCollector.cs @@ -0,0 +1,223 @@ +using System; +using System.Diagnostics; + +namespace OpenSim.Framework +{ + /// + /// A MetricsCollector for 'long' values. + /// + public class MetricsCollectorLong : MetricsCollector + { + public MetricsCollectorLong(int windowSize, int numBuckets) + : base(windowSize, numBuckets) + { + } + + protected override long GetZero() { return 0; } + + protected override long Add(long a, long b) { return a + b; } + } + + + /// + /// A MetricsCollector for time spans. + /// + public class MetricsCollectorTime : MetricsCollectorLong + { + public MetricsCollectorTime(int windowSize, int numBuckets) + : base(windowSize, numBuckets) + { + } + + public void AddSample(Stopwatch timer) + { + long ticks = timer.ElapsedTicks; + if (ticks > 0) + AddSample(ticks); + } + + public TimeSpan GetSumTime() + { + return TimeSpan.FromMilliseconds((GetSum() * 1000) / Stopwatch.Frequency); + } + } + + + struct MetricsBucket + { + public T value; + public int count; + } + + + /// + /// Collects metrics in a sliding window. + /// + /// + /// MetricsCollector provides the current Sum of the metrics that it collects. It can easily be extended + /// to provide the Average, too. It uses a sliding window to keep these values current. + /// + /// This class is not thread-safe. + /// + /// Subclass MetricsCollector to have it use a concrete value type. Override the abstract methods. + /// + public abstract class MetricsCollector + { + private int bucketSize; // e.g. 3,000 ms + + private MetricsBucket[] buckets; + + private int NumBuckets { get { return buckets.Length; } } + + + // The number of the current bucket, if we had an infinite number of buckets and didn't have to wrap around + long curBucketGlobal; + + // The total of all the buckets + T totalSum; + int totalCount; + + + /// + /// Returns the default (zero) value. + /// + /// + protected abstract T GetZero(); + + /// + /// Adds two values. + /// + protected abstract T Add(T a, T b); + + + /// + /// Creates a MetricsCollector. + /// + /// The period of time over which to collect the metrics, in ms. E.g.: 30,000. + /// The number of buckets to divide the samples into. E.g.: 10. Using more buckets + /// smooths the jarring that occurs whenever we drop an old bucket, but uses more memory. + public MetricsCollector(int windowSize, int numBuckets) + { + bucketSize = windowSize / numBuckets; + buckets = new MetricsBucket[numBuckets]; + Reset(); + } + + public void Reset() + { + ZeroBuckets(0, NumBuckets); + curBucketGlobal = GetNow() / bucketSize; + totalSum = GetZero(); + totalCount = 0; + } + + public void AddSample(T sample) + { + MoveWindow(); + + int curBucket = (int)(curBucketGlobal % NumBuckets); + buckets[curBucket].value = Add(buckets[curBucket].value, sample); + buckets[curBucket].count++; + + totalSum = Add(totalSum, sample); + totalCount++; + } + + /// + /// Returns the total values in the collection window. + /// + public T GetSum() + { + // It might have been a while since we last added a sample, so we may need to adjust the window + MoveWindow(); + + return totalSum; + } + + /// + /// Returns the current time in ms. + /// + private long GetNow() + { + return DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + } + + /// + /// Clears the values in buckets [offset, offset+num) + /// + private void ZeroBuckets(int offset, int num) + { + for (int i = 0; i < num; i++) + { + buckets[offset + i].value = GetZero(); + buckets[offset + i].count = 0; + } + } + + /// + /// Adjusts the buckets so that the "current bucket" corresponds to the current time. + /// This may require dropping old buckets. + /// + /// + /// This method allows for the possibility that we don't get new samples for each bucket, so the + /// new bucket may be some distance away from the last used bucket. + /// + private void MoveWindow() + { + long newBucketGlobal = GetNow() / bucketSize; + long bucketsDistance = newBucketGlobal - curBucketGlobal; + + if (bucketsDistance == 0) + { + // We're still on the same bucket as before + return; + } + + if (bucketsDistance >= NumBuckets) + { + // Discard everything + Reset(); + return; + } + + int curBucket = (int)(curBucketGlobal % NumBuckets); + int newBucket = (int)(newBucketGlobal % NumBuckets); + + + // Clear all the buckets in this range: (cur, new] + int numToClear = (int)bucketsDistance; + + if (curBucket < NumBuckets - 1) + { + // Clear buckets at the end of the window + int num = Math.Min((int)bucketsDistance, NumBuckets - (curBucket + 1)); + ZeroBuckets(curBucket + 1, num); + numToClear -= num; + } + + if (numToClear > 0) + { + // Clear buckets at the beginning of the window + ZeroBuckets(0, numToClear); + } + + // Move the "current bucket" pointer + curBucketGlobal = newBucketGlobal; + + RecalcTotal(); + } + + private void RecalcTotal() + { + totalSum = GetZero(); + totalCount = 0; + + for (int i = 0; i < NumBuckets; i++) + { + totalSum = Add(totalSum, buckets[i].value); + totalCount += buckets[i].count; + } + } + + } +} 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 @@ using System; using System.Timers; +using OpenMetaverse.StructuredData; + namespace OpenSim.Framework.Monitoring { /// @@ -100,5 +102,29 @@ Asset requests yesterday : {3} ({4} per hour) of which {5} were not found", AssetRequestsToday, assetRequestsTodayPerHour, AssetRequestsNotFoundToday, AssetRequestsYesterday, assetRequestsYesterdayPerHour, AssetRequestsNotFoundYesterday); } + + public override string XReport(string uptime, string version) + { + return OSDParser.SerializeJsonString(OReport(uptime, version)); + } + + public override OSDMap OReport(string uptime, string version) + { + double elapsedHours = (DateTime.Now - startTime).TotalHours; + if (elapsedHours <= 0) { elapsedHours = 1; } // prevent divide by zero + + long assetRequestsTodayPerHour = (long)Math.Round(AssetRequestsToday / elapsedHours); + long assetRequestsYesterdayPerHour = (long)Math.Round(AssetRequestsYesterday / 24.0); + + OSDMap ret = new OSDMap(); + ret.Add("AssetRequestsToday", OSD.FromLong(AssetRequestsToday)); + ret.Add("AssetRequestsTodayPerHour", OSD.FromLong(assetRequestsTodayPerHour)); + ret.Add("AssetRequestsNotFoundToday", OSD.FromLong(AssetRequestsNotFoundToday)); + ret.Add("AssetRequestsYesterday", OSD.FromLong(AssetRequestsYesterday)); + ret.Add("AssetRequestsYesterdayPerHour", OSD.FromLong(assetRequestsYesterdayPerHour)); + ret.Add("AssetRequestsNotFoundYesterday", OSD.FromLong(assetRequestsNotFoundYesterday)); + + return ret; + } } } diff --git a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs index 2903b6e..20495f6 100644 --- a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -45,16 +45,16 @@ namespace OpenSim.Framework.Monitoring sb.Append(Environment.NewLine); sb.AppendFormat( - "Allocated to OpenSim objects: {0} MB\n", + "Heap allocated to OpenSim : {0} MB\n", Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0)); sb.AppendFormat( - "OpenSim last object memory churn : {0} MB/s\n", - Math.Round((MemoryWatchdog.LastMemoryChurn * 1000) / 1024.0 / 1024, 3)); + "Last heap allocation rate : {0} MB/s\n", + Math.Round((MemoryWatchdog.LastHeapAllocationRate * 1000) / 1024.0 / 1024, 3)); sb.AppendFormat( - "OpenSim average object memory churn : {0} MB/s\n", - Math.Round((MemoryWatchdog.AverageMemoryChurn * 1000) / 1024.0 / 1024, 3)); + "Average heap allocation rate: {0} MB/s\n", + Math.Round((MemoryWatchdog.AverageHeapAllocationRate * 1000) / 1024.0 / 1024, 3)); sb.AppendFormat( "Process memory : {0} MB\n", @@ -67,5 +67,12 @@ namespace OpenSim.Framework.Monitoring { return (string) Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0).ToString() ; } + + public virtual OSDMap OReport(string uptime, string version) + { + OSDMap ret = new OSDMap(); + ret.Add("TotalMemory", new OSDReal(Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0))); + return ret; + } } } diff --git a/OpenSim/Framework/Monitoring/Checks/Check.cs b/OpenSim/Framework/Monitoring/Checks/Check.cs new file mode 100644 index 0000000..594386a --- /dev/null +++ b/OpenSim/Framework/Monitoring/Checks/Check.cs @@ -0,0 +1,118 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Text; + +namespace OpenSim.Framework.Monitoring +{ + public class Check + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public static readonly char[] DisallowedShortNameCharacters = { '.' }; + + /// + /// Category of this stat (e.g. cache, scene, etc). + /// + public string Category { get; private set; } + + /// + /// Containing name for this stat. + /// FIXME: In the case of a scene, this is currently the scene name (though this leaves + /// us with a to-be-resolved problem of non-unique region names). + /// + /// + /// The container. + /// + public string Container { get; private set; } + + /// + /// Action used to check whether alert should go off. + /// + /// + /// Should return true if check passes. False otherwise. + /// + public Func CheckFunc { get; private set; } + + /// + /// Message from the last failure, if any. If there is no message or no failure then will be null. + /// + /// + /// Should be set by the CheckFunc when applicable. + /// + public string LastFailureMessage { get; set; } + + public StatVerbosity Verbosity { get; private set; } + public string ShortName { get; private set; } + public string Name { get; private set; } + public string Description { get; private set; } + + public Check( + string shortName, + string name, + string description, + string category, + string container, + Func checkFunc, + StatVerbosity verbosity) + { + if (ChecksManager.SubCommands.Contains(category)) + throw new Exception( + string.Format("Alert cannot be in category '{0}' since this is reserved for a subcommand", category)); + + foreach (char c in DisallowedShortNameCharacters) + { + if (shortName.IndexOf(c) != -1) + throw new Exception(string.Format("Alert name {0} cannot contain character {1}", shortName, c)); + } + + ShortName = shortName; + Name = name; + Description = description; + Category = category; + Container = container; + CheckFunc = checkFunc; + Verbosity = verbosity; + } + + public bool CheckIt() + { + return CheckFunc(this); + } + + public virtual string ToConsoleString() + { + return string.Format( + "{0}.{1}.{2} - {3}", + Category, + Container, + ShortName, + Description); + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/Monitoring/ChecksManager.cs b/OpenSim/Framework/Monitoring/ChecksManager.cs new file mode 100644 index 0000000..e4a7f8c --- /dev/null +++ b/OpenSim/Framework/Monitoring/ChecksManager.cs @@ -0,0 +1,262 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using log4net; + +namespace OpenSim.Framework.Monitoring +{ + /// + /// Static class used to register/deregister checks on runtime conditions. + /// + public static class ChecksManager + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // Subcommand used to list other stats. + public const string ListSubCommand = "list"; + + // All subcommands + public static HashSet SubCommands = new HashSet { ListSubCommand }; + + /// + /// Checks categorized by category/container/shortname + /// + /// + /// Do not add or remove directly from this dictionary. + /// + public static SortedDictionary>> RegisteredChecks + = new SortedDictionary>>(); + + public static void RegisterConsoleCommands(ICommandConsole console) + { + console.Commands.AddCommand( + "General", + false, + "show checks", + "show checks", + "Show checks configured for this server", + "If no argument is specified then info on all checks will be shown.\n" + + "'list' argument will show check categories.\n" + + "THIS FACILITY IS EXPERIMENTAL", + HandleShowchecksCommand); + } + + public static void HandleShowchecksCommand(string module, string[] cmd) + { + ICommandConsole con = MainConsole.Instance; + + if (cmd.Length > 2) + { + foreach (string name in cmd.Skip(2)) + { + string[] components = name.Split('.'); + + string categoryName = components[0]; +// string containerName = components.Length > 1 ? components[1] : null; + + if (categoryName == ListSubCommand) + { + con.Output("check categories available are:"); + + foreach (string category in RegisteredChecks.Keys) + con.OutputFormat(" {0}", category); + } +// else +// { +// SortedDictionary> category; +// if (!Registeredchecks.TryGetValue(categoryName, out category)) +// { +// con.OutputFormat("No such category as {0}", categoryName); +// } +// else +// { +// if (String.IsNullOrEmpty(containerName)) +// { +// OutputConfiguredToConsole(con, category); +// } +// else +// { +// SortedDictionary container; +// if (category.TryGetValue(containerName, out container)) +// { +// OutputContainerChecksToConsole(con, container); +// } +// else +// { +// con.OutputFormat("No such container {0} in category {1}", containerName, categoryName); +// } +// } +// } +// } + } + } + else + { + OutputAllChecksToConsole(con); + } + } + + /// + /// Registers a statistic. + /// + /// + /// + public static bool RegisterCheck(Check check) + { + SortedDictionary> category = null, newCategory; + SortedDictionary container = null, newContainer; + + lock (RegisteredChecks) + { + // Check name is not unique across category/container/shortname key. + // XXX: For now just return false. This is to avoid problems in regression tests where all tests + // in a class are run in the same instance of the VM. + if (TryGetCheckParents(check, out category, out container)) + return false; + + // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed. + // This means that we don't need to lock or copy them on iteration, which will be a much more + // common operation after startup. + if (container != null) + newContainer = new SortedDictionary(container); + else + newContainer = new SortedDictionary(); + + if (category != null) + newCategory = new SortedDictionary>(category); + else + newCategory = new SortedDictionary>(); + + newContainer[check.ShortName] = check; + newCategory[check.Container] = newContainer; + RegisteredChecks[check.Category] = newCategory; + } + + return true; + } + + /// + /// Deregister an check + /// > + /// + /// + public static bool DeregisterCheck(Check check) + { + SortedDictionary> category = null, newCategory; + SortedDictionary container = null, newContainer; + + lock (RegisteredChecks) + { + if (!TryGetCheckParents(check, out category, out container)) + return false; + + newContainer = new SortedDictionary(container); + newContainer.Remove(check.ShortName); + + newCategory = new SortedDictionary>(category); + newCategory.Remove(check.Container); + + newCategory[check.Container] = newContainer; + RegisteredChecks[check.Category] = newCategory; + + return true; + } + } + + public static bool TryGetCheckParents( + Check check, + out SortedDictionary> category, + out SortedDictionary container) + { + category = null; + container = null; + + lock (RegisteredChecks) + { + if (RegisteredChecks.TryGetValue(check.Category, out category)) + { + if (category.TryGetValue(check.Container, out container)) + { + if (container.ContainsKey(check.ShortName)) + return true; + } + } + } + + return false; + } + + public static void CheckChecks() + { + lock (RegisteredChecks) + { + foreach (SortedDictionary> category in RegisteredChecks.Values) + { + foreach (SortedDictionary container in category.Values) + { + foreach (Check check in container.Values) + { + if (!check.CheckIt()) + m_log.WarnFormat( + "[CHECKS MANAGER]: Check {0}.{1}.{2} failed with message {3}", check.Category, check.Container, check.ShortName, check.LastFailureMessage); + } + } + } + } + } + + private static void OutputAllChecksToConsole(ICommandConsole con) + { + foreach (var category in RegisteredChecks.Values) + { + OutputCategoryChecksToConsole(con, category); + } + } + + private static void OutputCategoryChecksToConsole( + ICommandConsole con, SortedDictionary> category) + { + foreach (var container in category.Values) + { + OutputContainerChecksToConsole(con, container); + } + } + + private static void OutputContainerChecksToConsole(ICommandConsole con, SortedDictionary container) + { + foreach (Check check in container.Values) + { + con.Output(check.ToConsoleString()); + } + } + } +} \ No newline at end of file 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 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using OpenMetaverse.StructuredData; + namespace OpenSim.Framework.Monitoring { /// @@ -45,5 +47,12 @@ namespace OpenSim.Framework.Monitoring /// A /// string XReport(string uptime, string version); + + /// + /// Report back collected statistical information as an OSDMap of key/values + /// + /// + /// + OSDMap OReport(string uptime, string version); } } diff --git a/OpenSim/Framework/Monitoring/JobEngine.cs b/OpenSim/Framework/Monitoring/JobEngine.cs new file mode 100644 index 0000000..6db9a67 --- /dev/null +++ b/OpenSim/Framework/Monitoring/JobEngine.cs @@ -0,0 +1,341 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Concurrent; +using System.Reflection; +using System.Threading; +using log4net; +using OpenSim.Framework; + +namespace OpenSim.Framework.Monitoring +{ + public class JobEngine + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public int LogLevel { get; set; } + + public string Name { get; private set; } + + public string LoggingName { get; private set; } + + /// + /// Is this engine running? + /// + public bool IsRunning { get; private set; } + + /// + /// The current job that the engine is running. + /// + /// + /// Will be null if no job is currently running. + /// + public Job CurrentJob { get; private set; } + + /// + /// Number of jobs waiting to be processed. + /// + public int JobsWaiting { get { return m_jobQueue.Count; } } + + /// + /// The timeout in milliseconds to wait for at least one event to be written when the recorder is stopping. + /// + public int RequestProcessTimeoutOnStop { get; set; } + + /// + /// Controls whether we need to warn in the log about exceeding the max queue size. + /// + /// + /// This is flipped to false once queue max has been exceeded and back to true when it falls below max, in + /// order to avoid spamming the log with lots of warnings. + /// + private bool m_warnOverMaxQueue = true; + + private BlockingCollection m_jobQueue; + + private CancellationTokenSource m_cancelSource; + + /// + /// Used to signal that we are ready to complete stop. + /// + private ManualResetEvent m_finishedProcessingAfterStop = new ManualResetEvent(false); + + public JobEngine(string name, string loggingName) + { + Name = name; + LoggingName = loggingName; + + RequestProcessTimeoutOnStop = 5000; + } + + public void Start() + { + lock (this) + { + if (IsRunning) + return; + + IsRunning = true; + + m_finishedProcessingAfterStop.Reset(); + + m_jobQueue = new BlockingCollection(new ConcurrentQueue(), 5000); + m_cancelSource = new CancellationTokenSource(); + + WorkManager.StartThread( + ProcessRequests, + Name, + ThreadPriority.Normal, + false, + true, + null, + int.MaxValue); + } + } + + public void Stop() + { + lock (this) + { + try + { + if (!IsRunning) + return; + + IsRunning = false; + + int requestsLeft = m_jobQueue.Count; + + if (requestsLeft <= 0) + { + m_cancelSource.Cancel(); + } + else + { + m_log.InfoFormat("[{0}]: Waiting to write {1} events after stop.", LoggingName, requestsLeft); + + while (requestsLeft > 0) + { + if (!m_finishedProcessingAfterStop.WaitOne(RequestProcessTimeoutOnStop)) + { + // After timeout no events have been written + if (requestsLeft == m_jobQueue.Count) + { + m_log.WarnFormat( + "[{0}]: No requests processed after {1} ms wait. Discarding remaining {2} requests", + LoggingName, RequestProcessTimeoutOnStop, requestsLeft); + + break; + } + } + + requestsLeft = m_jobQueue.Count; + } + } + } + finally + { + m_cancelSource.Dispose(); + } + } + } + + /// + /// Make a job. + /// + /// + /// We provide this method to replace the constructor so that we can later pool job objects if necessary to + /// reduce memory churn. Normally one would directly call QueueJob() with parameters anyway. + /// + /// + /// Name. + /// Action. + /// Common identifier. + public static Job MakeJob(string name, Action action, string commonId = null) + { + return Job.MakeJob(name, action, commonId); + } + + /// + /// Remove the next job queued for processing. + /// + /// + /// Returns null if there is no next job. + /// Will not remove a job currently being performed. + /// + public Job RemoveNextJob() + { + Job nextJob; + m_jobQueue.TryTake(out nextJob); + + return nextJob; + } + + /// + /// Queue the job for processing. + /// + /// true, if job was queued, false otherwise. + /// Name of job. This appears on the console and in logging. + /// Action to perform. + /// + /// Common identifier for a set of jobs. This is allows a set of jobs to be removed + /// if required (e.g. all jobs for a given agent. Optional. + /// + public bool QueueJob(string name, Action action, string commonId = null) + { + return QueueJob(MakeJob(name, action, commonId)); + } + + /// + /// Queue the job for processing. + /// + /// true, if job was queued, false otherwise. + /// The job + /// + public bool QueueJob(Job job) + { + if (m_jobQueue.Count < m_jobQueue.BoundedCapacity) + { + m_jobQueue.Add(job); + + if (!m_warnOverMaxQueue) + m_warnOverMaxQueue = true; + + return true; + } + else + { + if (m_warnOverMaxQueue) + { + m_log.WarnFormat( + "[{0}]: Job queue at maximum capacity, not recording job from {1} in {2}", + LoggingName, job.Name, Name); + + m_warnOverMaxQueue = false; + } + + return false; + } + } + + private void ProcessRequests() + { + try + { + while (IsRunning || m_jobQueue.Count > 0) + { + try + { + CurrentJob = m_jobQueue.Take(m_cancelSource.Token); + } + catch (ObjectDisposedException e) + { + // If we see this whilst not running then it may be due to a race where this thread checks + // IsRunning after the stopping thread sets it to false and disposes of the cancellation source. + if (IsRunning) + throw e; + else + break; + } + + if (LogLevel >= 1) + m_log.DebugFormat("[{0}]: Processing job {1}", LoggingName, CurrentJob.Name); + + try + { + CurrentJob.Action(); + } + catch (Exception e) + { + m_log.Error( + string.Format( + "[{0}]: Job {1} failed, continuing. Exception ", LoggingName, CurrentJob.Name), e); + } + + if (LogLevel >= 1) + m_log.DebugFormat("[{0}]: Processed job {1}", LoggingName, CurrentJob.Name); + + CurrentJob = null; + } + } + catch (OperationCanceledException) + { + } + + m_finishedProcessingAfterStop.Set(); + } + + public class Job + { + /// + /// Name of the job. + /// + /// + /// This appears on console and debug output. + /// + public string Name { get; private set; } + + /// + /// Common ID for this job. + /// + /// + /// This allows all jobs with a certain common ID (e.g. a client UUID) to be removed en-masse if required. + /// Can be null if this is not required. + /// + public string CommonId { get; private set; } + + /// + /// Action to perform when this job is processed. + /// + public Action Action { get; private set; } + + private Job(string name, string commonId, Action action) + { + Name = name; + CommonId = commonId; + Action = action; + } + + /// + /// Make a job. It needs to be separately queued. + /// + /// + /// We provide this method to replace the constructor so that we can pool job objects if necessary to + /// to reduce memory churn. Normally one would directly call JobEngine.QueueJob() with parameters anyway. + /// + /// + /// Name. + /// Action. + /// Common identifier. + public static Job MakeJob(string name, Action action, string commonId = null) + { + return new Job(name, commonId, action); + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs index c6010cd..c474622 100644 --- a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs +++ b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs @@ -60,17 +60,17 @@ namespace OpenSim.Framework.Monitoring private static bool m_enabled; /// - /// Last memory churn in bytes per millisecond. + /// Average heap allocation rate in bytes per millisecond. /// - public static double AverageMemoryChurn + public static double AverageHeapAllocationRate { get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; } } /// - /// Average memory churn in bytes per millisecond. + /// Last heap allocation in bytes /// - public static double LastMemoryChurn + public static double LastHeapAllocationRate { get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; } } diff --git a/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs index 1f2bb40..a617b93 100644 --- a/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs new file mode 100644 index 0000000..77315bb --- /dev/null +++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs @@ -0,0 +1,346 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net.NetworkInformation; +using System.Text; +using System.Threading; +using log4net; +using Nini.Config; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; + +namespace OpenSim.Framework.Monitoring +{ + public class ServerStatsCollector + { + private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private readonly string LogHeader = "[SERVER STATS]"; + + public bool Enabled = false; + private static Dictionary RegisteredStats = new Dictionary(); + + public readonly string CategoryServer = "server"; + + public readonly string ContainerThreadpool = "threadpool"; + public readonly string ContainerProcessor = "processor"; + public readonly string ContainerMemory = "memory"; + public readonly string ContainerNetwork = "network"; + public readonly string ContainerProcess = "process"; + + public string NetworkInterfaceTypes = "Ethernet"; + + readonly int performanceCounterSampleInterval = 500; +// int lastperformanceCounterSampleTime = 0; + + private class PerfCounterControl + { + public PerformanceCounter perfCounter; + public int lastFetch; + public string name; + public PerfCounterControl(PerformanceCounter pPc) + : this(pPc, String.Empty) + { + } + public PerfCounterControl(PerformanceCounter pPc, string pName) + { + perfCounter = pPc; + lastFetch = 0; + name = pName; + } + } + + PerfCounterControl processorPercentPerfCounter = null; + + // IRegionModuleBase.Initialize + public void Initialise(IConfigSource source) + { + if (source == null) + return; + + IConfig cfg = source.Configs["Monitoring"]; + + if (cfg != null) + Enabled = cfg.GetBoolean("ServerStatsEnabled", true); + + if (Enabled) + { + NetworkInterfaceTypes = cfg.GetString("NetworkInterfaceTypes", "Ethernet"); + } + } + + public void Start() + { + if (RegisteredStats.Count == 0) + RegisterServerStats(); + } + + public void Close() + { + if (RegisteredStats.Count > 0) + { + foreach (Stat stat in RegisteredStats.Values) + { + StatsManager.DeregisterStat(stat); + stat.Dispose(); + } + RegisteredStats.Clear(); + } + } + + private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action act) + { + MakeStat(pName, pDesc, pUnit, pContainer, act, MeasuresOfInterest.None); + } + + private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action act, MeasuresOfInterest moi) + { + string desc = pDesc; + if (desc == null) + desc = pName; + Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, moi, act, StatVerbosity.Debug); + StatsManager.RegisterStat(stat); + RegisteredStats.Add(pName, stat); + } + + public void RegisterServerStats() + { +// lastperformanceCounterSampleTime = Util.EnvironmentTickCount(); + PerformanceCounter tempPC; + Stat tempStat; + string tempName; + + try + { + tempName = "CPUPercent"; + tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total"); + processorPercentPerfCounter = new PerfCounterControl(tempPC); + // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy. + tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor, + StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter); }, + StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor, + (s) => { s.Value = Math.Round(Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds, 3); }); + + MakeStat("UserProcessorTime", null, "sec", ContainerProcessor, + (s) => { s.Value = Math.Round(Process.GetCurrentProcess().UserProcessorTime.TotalSeconds, 3); }); + + MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor, + (s) => { s.Value = Math.Round(Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds, 3); }); + + MakeStat("Threads", null, "threads", ContainerProcessor, + (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; }); + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e); + } + + MakeStat("BuiltinThreadpoolWorkerThreadsAvailable", null, "threads", ContainerThreadpool, + s => + { + int workerThreads, iocpThreads; + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + s.Value = workerThreads; + }); + + MakeStat("BuiltinThreadpoolIOCPThreadsAvailable", null, "threads", ContainerThreadpool, + s => + { + int workerThreads, iocpThreads; + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + s.Value = iocpThreads; + }); + + if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool && Util.GetSmartThreadPoolInfo() != null) + { + MakeStat("STPMaxThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxThreads); + MakeStat("STPMinThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MinThreads); + MakeStat("STPConcurrency", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxConcurrentWorkItems); + MakeStat("STPActiveThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().ActiveThreads); + MakeStat("STPInUseThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().InUseThreads); + MakeStat("STPWorkItemsWaiting", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().WaitingCallbacks); + } + + MakeStat( + "HTTPRequestsMade", + "Number of outbound HTTP requests made", + "requests", + ContainerNetwork, + s => s.Value = WebUtil.RequestNumber, + MeasuresOfInterest.AverageChangeOverTime); + + try + { + List okInterfaceTypes = new List(NetworkInterfaceTypes.Split(',')); + + IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces(); + foreach (NetworkInterface nic in nics) + { + if (nic.OperationalStatus != OperationalStatus.Up) + continue; + + string nicInterfaceType = nic.NetworkInterfaceType.ToString(); + if (!okInterfaceTypes.Contains(nicInterfaceType)) + { + m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.", + LogHeader, nic.Name, nicInterfaceType); + m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}", + LogHeader, NetworkInterfaceTypes); + continue; + } + + if (nic.Supports(NetworkInterfaceComponent.IPv4)) + { + IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics(); + if (nicStats != null) + { + MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork, + (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); }); + MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork, + (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); }); + MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork, + (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); }); + } + } + // TODO: add IPv6 (it may actually happen someday) + } + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e); + } + + MakeStat("ProcessMemory", null, "MB", ContainerMemory, + (s) => { s.Value = Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d, 3); }); + MakeStat("HeapMemory", null, "MB", ContainerMemory, + (s) => { s.Value = Math.Round(GC.GetTotalMemory(false) / 1024d / 1024d, 3); }); + MakeStat("LastHeapAllocationRate", null, "MB/sec", ContainerMemory, + (s) => { s.Value = Math.Round(MemoryWatchdog.LastHeapAllocationRate * 1000d / 1024d / 1024d, 3); }); + MakeStat("AverageHeapAllocationRate", null, "MB/sec", ContainerMemory, + (s) => { s.Value = Math.Round(MemoryWatchdog.AverageHeapAllocationRate * 1000d / 1024d / 1024d, 3); }); + } + + // Notes on performance counters: + // "How To Read Performance Counters": http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx + // "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c + // "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters + private delegate double PerfCounterNextValue(); + + private void GetNextValue(Stat stat, PerfCounterControl perfControl) + { + if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval) + { + if (perfControl != null && perfControl.perfCounter != null) + { + try + { + stat.Value = Math.Round(perfControl.perfCounter.NextValue(), 3); + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e); + } + + perfControl.lastFetch = Util.EnvironmentTickCount(); + } + } + } + + // Lookup the nic that goes with this stat and set the value by using a fetch action. + // Not sure about closure with delegates inside delegates. + private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat); + private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor) + { + // Get the one nic that has the name of this stat + IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces().Where( + (network) => network.Name == stat.Description); + try + { + foreach (NetworkInterface nic in nics) + { + IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics(); + if (intrStats != null) + { + double newVal = Math.Round(getter(intrStats) / factor, 3); + stat.Value = newVal; + } + break; + } + } + catch + { + // There are times interfaces go away so we just won't update the stat for this + m_log.ErrorFormat("{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description); + } + } + } + + public class ServerStatsAggregator : Stat + { + public ServerStatsAggregator( + string shortName, + string name, + string description, + string unitName, + string category, + string container + ) + : base( + shortName, + name, + description, + unitName, + category, + container, + StatType.Push, + MeasuresOfInterest.None, + null, + StatVerbosity.Info) + { + } + public override string ToConsoleString() + { + StringBuilder sb = new StringBuilder(); + + return sb.ToString(); + } + + public override OSDMap ToOSDMap() + { + OSDMap ret = new OSDMap(); + + return ret; + } + } +} diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs old mode 100644 new mode 100755 index aa86202..e4df7ee --- a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs @@ -27,6 +27,8 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; using System.Text; using OpenMetaverse; using OpenMetaverse.StructuredData; @@ -39,8 +41,6 @@ namespace OpenSim.Framework.Monitoring /// public class SimExtraStatsCollector : BaseStatsCollector { - private long abnormalClientThreadTerminations; - // private long assetsInCache; // private long texturesInCache; // private long assetCacheMemoryUsage; @@ -72,11 +72,11 @@ namespace OpenSim.Framework.Monitoring private volatile float pendingUploads; private volatile float activeScripts; private volatile float scriptLinesPerSecond; - - /// - /// Number of times that a client thread terminated because of an exception - /// - public long AbnormalClientThreadTerminations { get { return abnormalClientThreadTerminations; } } + private volatile float m_frameDilation; + private volatile float m_usersLoggingIn; + private volatile float m_totalGeoPrims; + private volatile float m_totalMeshes; + private volatile float m_inUseThreads; // /// // /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the @@ -166,11 +166,6 @@ namespace OpenSim.Framework.Monitoring private IDictionary packetQueueStatsCollectors = new Dictionary(); - public void AddAbnormalClientThreadTermination() - { - abnormalClientThreadTerminations++; - } - // public void AddAsset(AssetBase asset) // { // assetsInCache++; @@ -260,6 +255,10 @@ namespace OpenSim.Framework.Monitoring { // FIXME: SimStats shouldn't allow an arbitrary stat packing order (which is inherited from the original // SimStatsPacket that was being used). + + // For an unknown reason the original designers decided not to + // include the spare MS statistic inside of this class, this is + // located inside the StatsBlock at location 21, thus it is skipped timeDilation = stats.StatsBlock[0].StatValue; simFps = stats.StatsBlock[1].StatValue; physicsFps = stats.StatsBlock[2].StatValue; @@ -281,6 +280,11 @@ namespace OpenSim.Framework.Monitoring pendingUploads = stats.StatsBlock[18].StatValue; activeScripts = stats.StatsBlock[19].StatValue; scriptLinesPerSecond = stats.StatsBlock[20].StatValue; + m_frameDilation = stats.StatsBlock[22].StatValue; + m_usersLoggingIn = stats.StatsBlock[23].StatValue; + m_totalGeoPrims = stats.StatsBlock[24].StatValue; + m_totalMeshes = stats.StatsBlock[25].StatValue; + m_inUseThreads = stats.StatsBlock[26].StatValue; } /// @@ -324,10 +328,12 @@ Asset service request failures: {3}" + Environment.NewLine, sb.Append(Environment.NewLine); sb.Append("CONNECTION STATISTICS"); sb.Append(Environment.NewLine); - sb.Append( - string.Format( - "Abnormal client thread terminations: {0}" + Environment.NewLine, - abnormalClientThreadTerminations)); + + List stats = StatsManager.GetStatsFromEachContainer("clientstack", "ClientLogoutsDueToNoReceives"); + + sb.AppendFormat( + "Client logouts due to no data receive timeout: {0}\n\n", + stats != null ? stats.Sum(s => s.Value).ToString() : "unknown"); // sb.Append(Environment.NewLine); // sb.Append("INVENTORY STATISTICS"); @@ -338,7 +344,7 @@ Asset service request failures: {3}" + Environment.NewLine, // InventoryServiceRetrievalFailures)); sb.Append(Environment.NewLine); - sb.Append("FRAME STATISTICS"); + sb.Append("SAMPLE FRAME STATISTICS"); sb.Append(Environment.NewLine); sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS"); sb.Append(Environment.NewLine); @@ -359,11 +365,12 @@ Asset service request failures: {3}" + Environment.NewLine, inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime, netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime)); - Dictionary> sceneStats; - + /* 20130319 RA: For the moment, disable the dump of 'scene' catagory as they are mostly output by + * the two formatted printouts above. + SortedDictionary> sceneStats; if (StatsManager.TryGetStats("scene", out sceneStats)) { - foreach (KeyValuePair> kvp in sceneStats) + foreach (KeyValuePair> kvp in sceneStats) { foreach (Stat stat in kvp.Value.Values) { @@ -374,6 +381,7 @@ Asset service request failures: {3}" + Environment.NewLine, } } } + */ /* sb.Append(Environment.NewLine); @@ -405,6 +413,36 @@ Asset service request failures: {3}" + Environment.NewLine, /// public override string XReport(string uptime, string version) { + return OSDParser.SerializeJsonString(OReport(uptime, version)); + } + + /// + /// Report back collected statistical information as an OSDMap + /// + /// + public override OSDMap OReport(string uptime, string version) + { + // Get the amount of physical memory, allocated with the instance of this program, in kilobytes; + // the working set is the set of memory pages currently visible to this program in physical RAM + // memory and includes both shared (e.g. system libraries) and private data + double memUsage = Process.GetCurrentProcess().WorkingSet64 / 1024.0; + + // Get the number of threads from the system that are currently + // running + int numberThreadsRunning = 0; + foreach (ProcessThread currentThread in + Process.GetCurrentProcess().Threads) + { + // A known issue with the current process .Threads property is + // that it can return null threads, thus don't count those as + // running threads and prevent the program function from failing + if (currentThread != null && + currentThread.ThreadState == ThreadState.Running) + { + numberThreadsRunning++; + } + } + OSDMap args = new OSDMap(30); // args["AssetsInCache"] = OSD.FromString (String.Format ("{0:0.##}", AssetsInCache)); // args["TimeAfterCacheMiss"] = OSD.FromString (String.Format ("{0:0.##}", @@ -441,14 +479,28 @@ Asset service request failures: {3}" + Environment.NewLine, args["Memory"] = OSD.FromString (base.XReport (uptime, version)); args["Uptime"] = OSD.FromString (uptime); args["Version"] = OSD.FromString (version); - - string strBuffer = ""; - strBuffer = OSDParser.SerializeJsonString(args); - return strBuffer; + args["FrameDilatn"] = OSD.FromString(String.Format("{0:0.##}", m_frameDilation)); + args["Logging in Users"] = OSD.FromString(String.Format("{0:0.##}", + m_usersLoggingIn)); + args["GeoPrims"] = OSD.FromString(String.Format("{0:0.##}", + m_totalGeoPrims)); + args["Mesh Objects"] = OSD.FromString(String.Format("{0:0.##}", + m_totalMeshes)); + args["XEngine Thread Count"] = OSD.FromString(String.Format("{0:0.##}", + m_inUseThreads)); + args["Util Thread Count"] = OSD.FromString(String.Format("{0:0.##}", + Util.GetSmartThreadPoolInfo().InUseThreads)); + args["System Thread Count"] = OSD.FromString(String.Format( + "{0:0.##}", numberThreadsRunning)); + args["ProcMem"] = OSD.FromString(String.Format("{0:#,###,###.##}", + memUsage)); + + return args; } } + /// /// Pull packet queue stats from packet queues and report /// @@ -474,5 +526,11 @@ Asset service request failures: {3}" + Environment.NewLine, { return ""; } + + public OSDMap OReport(string uptime, string version) + { + OSDMap ret = new OSDMap(); + return ret; + } } } diff --git a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs new file mode 100755 index 0000000..318cf1c --- /dev/null +++ b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs @@ -0,0 +1,119 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework.Monitoring +{ +// A statistic that wraps a counter. +// Built this way mostly so histograms and history can be created. +public class CounterStat : Stat +{ + private SortedDictionary m_histograms; + private object counterLock = new object(); + + public CounterStat( + string shortName, + string name, + string description, + string unitName, + string category, + string container, + StatVerbosity verbosity) + : base(shortName, name, description, unitName, category, container, StatType.Push, null, verbosity) + { + m_histograms = new SortedDictionary(); + } + + // Histograms are presumably added at intialization time and the list does not change thereafter. + // Thus no locking of the histogram list. + public void AddHistogram(string histoName, EventHistogram histo) + { + m_histograms.Add(histoName, histo); + } + + public delegate void ProcessHistogram(string name, EventHistogram histo); + public void ForEachHistogram(ProcessHistogram process) + { + foreach (KeyValuePair kvp in m_histograms) + { + process(kvp.Key, kvp.Value); + } + } + + public void Event() + { + this.Event(1); + } + + // Count the underlying counter. + public void Event(int cnt) + { + lock (counterLock) + { + base.Value += cnt; + + foreach (EventHistogram histo in m_histograms.Values) + { + histo.Event(cnt); + } + } + } + + // CounterStat is a basic stat plus histograms + public override OSDMap ToOSDMap() + { + // Get the foundational instance + OSDMap map = base.ToOSDMap(); + + map["StatType"] = "CounterStat"; + + // If there are any histograms, add a new field that is an array of histograms as OSDMaps + if (m_histograms.Count > 0) + { + lock (counterLock) + { + if (m_histograms.Count > 0) + { + OSDArray histos = new OSDArray(); + foreach (EventHistogram histo in m_histograms.Values) + { + histos.Add(histo.GetHistogramAsOSDMap()); + } + map.Add("Histograms", histos); + } + } + } + return map; + } +} +} diff --git a/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs b/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs new file mode 100755 index 0000000..f51f322 --- /dev/null +++ b/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs @@ -0,0 +1,173 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework.Monitoring +{ +// Create a time histogram of events. The histogram is built in a wrap-around +// array of equally distributed buckets. +// For instance, a minute long histogram of second sized buckets would be: +// new EventHistogram(60, 1000) +public class EventHistogram +{ + private int m_timeBase; + private int m_numBuckets; + private int m_bucketMilliseconds; + private int m_lastBucket; + private int m_totalHistogramMilliseconds; + private long[] m_histogram; + private object histoLock = new object(); + + public EventHistogram(int numberOfBuckets, int millisecondsPerBucket) + { + m_numBuckets = numberOfBuckets; + m_bucketMilliseconds = millisecondsPerBucket; + m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds; + + m_histogram = new long[m_numBuckets]; + Zero(); + m_lastBucket = 0; + m_timeBase = Util.EnvironmentTickCount(); + } + + public void Event() + { + this.Event(1); + } + + // Record an event at time 'now' in the histogram. + public void Event(int cnt) + { + lock (histoLock) + { + // The time as displaced from the base of the histogram + int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase); + + // If more than the total time of the histogram, we just start over + if (bucketTime > m_totalHistogramMilliseconds) + { + Zero(); + m_lastBucket = 0; + m_timeBase = Util.EnvironmentTickCount(); + } + else + { + // To which bucket should we add this event? + int bucket = bucketTime / m_bucketMilliseconds; + + // Advance m_lastBucket to the new bucket. Zero any buckets skipped over. + while (bucket != m_lastBucket) + { + // Zero from just after the last bucket to the new bucket or the end + for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++) + { + m_histogram[jj] = 0; + } + m_lastBucket = bucket; + // If the new bucket is off the end, wrap around to the beginning + if (bucket > m_numBuckets) + { + bucket -= m_numBuckets; + m_lastBucket = 0; + m_histogram[m_lastBucket] = 0; + m_timeBase += m_totalHistogramMilliseconds; + } + } + } + m_histogram[m_lastBucket] += cnt; + } + } + + // Get a copy of the current histogram + public long[] GetHistogram() + { + long[] ret = new long[m_numBuckets]; + lock (histoLock) + { + int indx = m_lastBucket + 1; + for (int ii = 0; ii < m_numBuckets; ii++, indx++) + { + if (indx >= m_numBuckets) + indx = 0; + ret[ii] = m_histogram[indx]; + } + } + return ret; + } + + public OSDMap GetHistogramAsOSDMap() + { + OSDMap ret = new OSDMap(); + + ret.Add("Buckets", OSD.FromInteger(m_numBuckets)); + ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds)); + ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds)); + + // Compute a number for the first bucket in the histogram. + // This will allow readers to know how this histogram relates to any previously read histogram. + int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1; + ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum)); + + ret.Add("Values", GetHistogramAsOSDArray()); + + return ret; + } + // Get a copy of the current histogram + public OSDArray GetHistogramAsOSDArray() + { + OSDArray ret = new OSDArray(m_numBuckets); + lock (histoLock) + { + int indx = m_lastBucket + 1; + for (int ii = 0; ii < m_numBuckets; ii++, indx++) + { + if (indx >= m_numBuckets) + indx = 0; + ret[ii] = OSD.FromLong(m_histogram[indx]); + } + } + return ret; + } + + // Zero out the histogram + public void Zero() + { + lock (histoLock) + { + for (int ii = 0; ii < m_numBuckets; ii++) + m_histogram[ii] = 0; + } + } +} + +} diff --git a/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs index 60bed55..55ddf06 100644 --- a/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs +++ b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs @@ -29,6 +29,8 @@ using System; using System.Collections.Generic; using System.Text; +using OpenMetaverse.StructuredData; + namespace OpenSim.Framework.Monitoring { public class PercentageStat : Stat @@ -84,5 +86,19 @@ namespace OpenSim.Framework.Monitoring return sb.ToString(); } + + // PercentageStat is a basic stat plus percent calc + public override OSDMap ToOSDMap() + { + // Get the foundational instance + OSDMap map = base.ToOSDMap(); + + map["StatType"] = "PercentageStat"; + + map.Add("Antecedent", OSD.FromLong(Antecedent)); + map.Add("Consequent", OSD.FromLong(Consequent)); + + return map; + } } } \ No newline at end of file diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index f91251b..a7cb2a6 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -27,15 +27,23 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Reflection; using System.Text; +using log4net; +using OpenMetaverse.StructuredData; namespace OpenSim.Framework.Monitoring { /// /// Holds individual statistic details /// - public class Stat + public class Stat : IDisposable { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public static readonly char[] DisallowedShortNameCharacters = { '.' }; + /// /// Category of this stat (e.g. cache, scene, etc). /// @@ -93,7 +101,7 @@ namespace OpenSim.Framework.Monitoring /// /// Will be null if no measures of interest require samples. /// - private static Queue m_samples; + private Queue m_samples; /// /// Maximum number of statistical samples. @@ -160,6 +168,13 @@ namespace OpenSim.Framework.Monitoring throw new Exception( string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category)); + foreach (char c in DisallowedShortNameCharacters) + { + if (shortName.IndexOf(c) != -1) + shortName = shortName.Replace(c, '#'); +// throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c)); + } + ShortName = shortName; Name = name; Description = description; @@ -181,6 +196,12 @@ namespace OpenSim.Framework.Monitoring Verbosity = verbosity; } + // IDisposable.Dispose() + public virtual void Dispose() + { + return; + } + /// /// Record a value in the sample set. /// @@ -196,6 +217,8 @@ namespace OpenSim.Framework.Monitoring if (m_samples.Count >= m_maxSamples) m_samples.Dequeue(); +// m_log.DebugFormat("[STAT]: Recording value {0} for {1}", newValue, Name); + m_samples.Enqueue(newValue); } } @@ -203,35 +226,100 @@ namespace OpenSim.Framework.Monitoring public virtual string ToConsoleString() { StringBuilder sb = new StringBuilder(); - sb.AppendFormat("{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName); + sb.AppendFormat( + "{0}.{1}.{2} : {3}{4}", + Category, + Container, + ShortName, + Value, + string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName)); AppendMeasuresOfInterest(sb); return sb.ToString(); } - protected void AppendMeasuresOfInterest(StringBuilder sb) + public virtual OSDMap ToOSDMap() { - if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) - == MeasuresOfInterest.AverageChangeOverTime) + OSDMap ret = new OSDMap(); + ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat + + ret.Add("Category", OSD.FromString(Category)); + ret.Add("Container", OSD.FromString(Container)); + ret.Add("ShortName", OSD.FromString(ShortName)); + ret.Add("Name", OSD.FromString(Name)); + ret.Add("Description", OSD.FromString(Description)); + ret.Add("UnitName", OSD.FromString(UnitName)); + ret.Add("Value", OSD.FromReal(Value)); + + double lastChangeOverTime, averageChangeOverTime; + if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime)) + { + ret.Add("LastChangeOverTime", OSD.FromReal(lastChangeOverTime)); + ret.Add("AverageChangeOverTime", OSD.FromReal(averageChangeOverTime)); + } + + return ret; + } + + // Compute the averages over time and return same. + // Return 'true' if averages were actually computed. 'false' if no average info. + public bool ComputeMeasuresOfInterest(out double lastChangeOverTime, out double averageChangeOverTime) + { + bool ret = false; + lastChangeOverTime = 0; + averageChangeOverTime = 0; + + if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime) { double totalChange = 0; + double? penultimateSample = null; double? lastSample = null; lock (m_samples) { + // m_log.DebugFormat( + // "[STAT]: Samples for {0} are {1}", + // Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray())); + foreach (double s in m_samples) { if (lastSample != null) totalChange += s - (double)lastSample; + penultimateSample = lastSample; lastSample = s; } } + if (lastSample != null && penultimateSample != null) + { + lastChangeOverTime + = ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); + } + int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; - sb.AppendFormat(", {0:0.##}{1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName); + averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); + ret = true; + } + + return ret; + } + + protected void AppendMeasuresOfInterest(StringBuilder sb) + { + double lastChangeOverTime = 0; + double averageChangeOverTime = 0; + + if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime)) + { + sb.AppendFormat( + ", {0:0.##}{1}/s, {2:0.##}{3}/s", + lastChangeOverTime, + string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName), + averageChangeOverTime, + string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName)); } } } diff --git a/OpenSim/Framework/Monitoring/StatsLogger.cs b/OpenSim/Framework/Monitoring/StatsLogger.cs new file mode 100644 index 0000000..15a37aa --- /dev/null +++ b/OpenSim/Framework/Monitoring/StatsLogger.cs @@ -0,0 +1,151 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using System.Timers; +using log4net; + +namespace OpenSim.Framework.Monitoring +{ + /// + /// Provides a means to continuously log stats for debugging purposes. + /// + public static class StatsLogger + { + private static readonly ILog m_statsLog = LogManager.GetLogger("special.StatsLogger"); + + private static Timer m_loggingTimer; + private static int m_statsLogIntervalMs = 5000; + + public static void RegisterConsoleCommands(ICommandConsole console) + { + console.Commands.AddCommand( + "General", + false, + "stats record", + "stats record start|stop", + "Control whether stats are being regularly recorded to a separate file.", + "For debug purposes. Experimental.", + HandleStatsRecordCommand); + + console.Commands.AddCommand( + "General", + false, + "stats save", + "stats save ", + "Save stats snapshot to a file. If the file already exists, then the report is appended.", + "For debug purposes. Experimental.", + HandleStatsSaveCommand); + } + + public static void HandleStatsRecordCommand(string module, string[] cmd) + { + ICommandConsole con = MainConsole.Instance; + + if (cmd.Length != 3) + { + con.Output("Usage: stats record start|stop"); + return; + } + + if (cmd[2] == "start") + { + Start(); + con.OutputFormat("Now recording all stats to file every {0}ms", m_statsLogIntervalMs); + } + else if (cmd[2] == "stop") + { + Stop(); + con.Output("Stopped recording stats to file."); + } + } + + public static void HandleStatsSaveCommand(string module, string[] cmd) + { + ICommandConsole con = MainConsole.Instance; + + if (cmd.Length != 3) + { + con.Output("Usage: stats save "); + return; + } + + string path = cmd[2]; + + using (StreamWriter sw = new StreamWriter(path, true)) + { + foreach (string line in GetReport()) + sw.WriteLine(line); + } + + MainConsole.Instance.OutputFormat("Stats saved to file {0}", path); + } + + public static void Start() + { + if (m_loggingTimer != null) + Stop(); + + m_loggingTimer = new Timer(m_statsLogIntervalMs); + m_loggingTimer.AutoReset = false; + m_loggingTimer.Elapsed += Log; + m_loggingTimer.Start(); + } + + public static void Stop() + { + if (m_loggingTimer != null) + { + m_loggingTimer.Stop(); + } + } + + private static void Log(object sender, ElapsedEventArgs e) + { + foreach (string line in GetReport()) + m_statsLog.Info(line); + + m_loggingTimer.Start(); + } + + private static List GetReport() + { + List lines = new List(); + + lines.Add(string.Format("*** STATS REPORT AT {0} ***", DateTime.Now)); + + foreach (string report in StatsManager.GetAllStatsReports()) + lines.Add(report); + + return lines; + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 0762b01..3136ee8 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -26,15 +26,20 @@ */ using System; +using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Text; +using OpenSim.Framework; +using OpenMetaverse.StructuredData; + namespace OpenSim.Framework.Monitoring { /// - /// Singleton used to provide access to statistics reporters + /// Static class used to register/deregister/fetch statistics /// - public class StatsManager + public static class StatsManager { // Subcommand used to list other stats. public const string AllSubCommand = "all"; @@ -51,31 +56,43 @@ namespace OpenSim.Framework.Monitoring /// /// Do not add or remove directly from this dictionary. /// - public static Dictionary>> RegisteredStats - = new Dictionary>>(); + public static SortedDictionary>> RegisteredStats + = new SortedDictionary>>(); - private static AssetStatsCollector assetStats; - private static UserStatsCollector userStats; - private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); +// private static AssetStatsCollector assetStats; +// private static UserStatsCollector userStats; +// private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); - public static AssetStatsCollector AssetStats { get { return assetStats; } } - public static UserStatsCollector UserStats { get { return userStats; } } - public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } +// public static AssetStatsCollector AssetStats { get { return assetStats; } } +// public static UserStatsCollector UserStats { get { return userStats; } } + public static SimExtraStatsCollector SimExtraStats { get; set; } public static void RegisterConsoleCommands(ICommandConsole console) { console.Commands.AddCommand( "General", false, - "show stats", - "show stats [list|all|]", + "stats show", + "stats show [list|all|([.])+", "Show statistical information for this server", "If no final argument is specified then legacy statistics information is currently shown.\n" - + "If list is specified then statistic categories are shown.\n" - + "If all is specified then all registered statistics are shown.\n" - + "If a category name is specified then only statistics from that category are shown.\n" + + "'list' argument will show statistic categories.\n" + + "'all' will show all statistics.\n" + + "A name will show statistics from that category.\n" + + "A . name will show statistics from that category in that container.\n" + + "More than one name can be given separated by spaces.\n" + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS", HandleShowStatsCommand); + + console.Commands.AddCommand( + "General", + false, + "show stats", + "show stats [list|all|([.])+", + "Alias for 'stats show' command", + HandleShowStatsCommand); + + StatsLogger.RegisterConsoleCommands(console); } public static void HandleShowStatsCommand(string module, string[] cmd) @@ -84,105 +101,286 @@ namespace OpenSim.Framework.Monitoring if (cmd.Length > 2) { - var categoryName = cmd[2]; - - if (categoryName == AllSubCommand) + foreach (string name in cmd.Skip(2)) { - foreach (var category in RegisteredStats.Values) + string[] components = name.Split('.'); + + string categoryName = components[0]; + string containerName = components.Length > 1 ? components[1] : null; + string statName = components.Length > 2 ? components[2] : null; + + if (categoryName == AllSubCommand) { - OutputCategoryStatsToConsole(con, category); + OutputAllStatsToConsole(con); } - } - else if (categoryName == ListSubCommand) - { - con.Output("Statistic categories available are:"); - foreach (string category in RegisteredStats.Keys) - con.OutputFormat(" {0}", category); - } - else - { - Dictionary> category; - if (!RegisteredStats.TryGetValue(categoryName, out category)) + else if (categoryName == ListSubCommand) { - con.OutputFormat("No such category as {0}", categoryName); + con.Output("Statistic categories available are:"); + foreach (string category in RegisteredStats.Keys) + con.OutputFormat(" {0}", category); } else { - OutputCategoryStatsToConsole(con, category); + SortedDictionary> category; + if (!RegisteredStats.TryGetValue(categoryName, out category)) + { + con.OutputFormat("No such category as {0}", categoryName); + } + else + { + if (String.IsNullOrEmpty(containerName)) + { + OutputCategoryStatsToConsole(con, category); + } + else + { + SortedDictionary container; + if (category.TryGetValue(containerName, out container)) + { + if (String.IsNullOrEmpty(statName)) + { + OutputContainerStatsToConsole(con, container); + } + else + { + Stat stat; + if (container.TryGetValue(statName, out stat)) + { + OutputStatToConsole(con, stat); + } + else + { + con.OutputFormat( + "No such stat {0} in {1}.{2}", statName, categoryName, containerName); + } + } + } + else + { + con.OutputFormat("No such container {0} in category {1}", containerName, categoryName); + } + } + } } } } else { // Legacy - con.Output(SimExtraStats.Report()); + if (SimExtraStats != null) + con.Output(SimExtraStats.Report()); + else + OutputAllStatsToConsole(con); } } - private static void OutputCategoryStatsToConsole( - ICommandConsole con, Dictionary> category) + public static List GetAllStatsReports() + { + List reports = new List(); + + foreach (var category in RegisteredStats.Values) + reports.AddRange(GetCategoryStatsReports(category)); + + return reports; + } + + private static void OutputAllStatsToConsole(ICommandConsole con) { + foreach (string report in GetAllStatsReports()) + con.Output(report); + } + + private static List GetCategoryStatsReports( + SortedDictionary> category) + { + List reports = new List(); + foreach (var container in category.Values) + reports.AddRange(GetContainerStatsReports(container)); + + return reports; + } + + private static void OutputCategoryStatsToConsole( + ICommandConsole con, SortedDictionary> category) + { + foreach (string report in GetCategoryStatsReports(category)) + con.Output(report); + } + + private static List GetContainerStatsReports(SortedDictionary container) + { + List reports = new List(); + + foreach (Stat stat in container.Values) + reports.Add(stat.ToConsoleString()); + + return reports; + } + + private static void OutputContainerStatsToConsole( + ICommandConsole con, SortedDictionary container) + { + foreach (string report in GetContainerStatsReports(container)) + con.Output(report); + } + + private static void OutputStatToConsole(ICommandConsole con, Stat stat) + { + con.Output(stat.ToConsoleString()); + } + + // Creates an OSDMap of the format: + // { categoryName: { + // containerName: { + // statName: { + // "Name": name, + // "ShortName": shortName, + // ... + // }, + // statName: { + // "Name": name, + // "ShortName": shortName, + // ... + // }, + // ... + // }, + // containerName: { + // ... + // }, + // ... + // }, + // categoryName: { + // ... + // }, + // ... + // } + // The passed in parameters will filter the categories, containers and stats returned. If any of the + // parameters are either EmptyOrNull or the AllSubCommand value, all of that type will be returned. + // Case matters. + public static OSDMap GetStatsAsOSDMap(string pCategoryName, string pContainerName, string pStatName) + { + OSDMap map = new OSDMap(); + + foreach (string catName in RegisteredStats.Keys) { - foreach (Stat stat in container.Values) + // Do this category if null spec, "all" subcommand or category name matches passed parameter. + // Skip category if none of the above. + if (!(String.IsNullOrEmpty(pCategoryName) || pCategoryName == AllSubCommand || pCategoryName == catName)) + continue; + + OSDMap contMap = new OSDMap(); + foreach (string contName in RegisteredStats[catName].Keys) { - con.Output(stat.ToConsoleString()); + if (!(string.IsNullOrEmpty(pContainerName) || pContainerName == AllSubCommand || pContainerName == contName)) + continue; + + OSDMap statMap = new OSDMap(); + + SortedDictionary theStats = RegisteredStats[catName][contName]; + foreach (string statName in theStats.Keys) + { + if (!(String.IsNullOrEmpty(pStatName) || pStatName == AllSubCommand || pStatName == statName)) + continue; + + statMap.Add(statName, theStats[statName].ToOSDMap()); + } + + contMap.Add(contName, statMap); } + map.Add(catName, contMap); } + + return map; } - /// - /// Start collecting statistics related to assets. - /// Should only be called once. - /// - public static AssetStatsCollector StartCollectingAssetStats() + public static Hashtable HandleStatsRequest(Hashtable request) { - assetStats = new AssetStatsCollector(); + Hashtable responsedata = new Hashtable(); +// string regpath = request["uri"].ToString(); + int response_code = 200; + string contenttype = "text/json"; - return assetStats; - } + string pCategoryName = StatsManager.AllSubCommand; + string pContainerName = StatsManager.AllSubCommand; + string pStatName = StatsManager.AllSubCommand; - /// - /// Start collecting statistics related to users. - /// Should only be called once. - /// - public static UserStatsCollector StartCollectingUserStats() - { - userStats = new UserStatsCollector(); + if (request.ContainsKey("cat")) pCategoryName = request["cat"].ToString(); + if (request.ContainsKey("cont")) pContainerName = request["cat"].ToString(); + if (request.ContainsKey("stat")) pStatName = request["stat"].ToString(); - return userStats; + string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString(); + + // If requestor wants it as a callback function, build response as a function rather than just the JSON string. + if (request.ContainsKey("callback")) + { + strOut = request["callback"].ToString() + "(" + strOut + ");"; + } + + // m_log.DebugFormat("{0} StatFetch: uri={1}, cat={2}, cont={3}, stat={4}, resp={5}", + // LogHeader, regpath, pCategoryName, pContainerName, pStatName, strOut); + + responsedata["int_response_code"] = response_code; + responsedata["content_type"] = contenttype; + responsedata["keepalive"] = false; + responsedata["str_response_string"] = strOut; + responsedata["access_control_allow_origin"] = "*"; + + return responsedata; } +// /// +// /// Start collecting statistics related to assets. +// /// Should only be called once. +// /// +// public static AssetStatsCollector StartCollectingAssetStats() +// { +// assetStats = new AssetStatsCollector(); +// +// return assetStats; +// } +// +// /// +// /// Start collecting statistics related to users. +// /// Should only be called once. +// /// +// public static UserStatsCollector StartCollectingUserStats() +// { +// userStats = new UserStatsCollector(); +// +// return userStats; +// } + /// - /// Registers a statistic. + /// Register a statistic. /// /// /// public static bool RegisterStat(Stat stat) { - Dictionary> category = null, newCategory; - Dictionary container = null, newContainer; + SortedDictionary> category = null, newCategory; + SortedDictionary container = null, newContainer; lock (RegisteredStats) { // Stat name is not unique across category/container/shortname key. // XXX: For now just return false. This is to avoid problems in regression tests where all tests // in a class are run in the same instance of the VM. - if (TryGetStat(stat, out category, out container)) + if (TryGetStatParents(stat, out category, out container)) return false; // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed. // This means that we don't need to lock or copy them on iteration, which will be a much more // common operation after startup. if (container != null) - newContainer = new Dictionary(container); + newContainer = new SortedDictionary(container); else - newContainer = new Dictionary(); + newContainer = new SortedDictionary(); if (category != null) - newCategory = new Dictionary>(category); + newCategory = new SortedDictionary>(category); else - newCategory = new Dictionary>(); + newCategory = new SortedDictionary>(); newContainer[stat.ShortName] = stat; newCategory[stat.Container] = newContainer; @@ -196,21 +394,21 @@ namespace OpenSim.Framework.Monitoring /// Deregister a statistic /// > /// - /// public static bool DeregisterStat(Stat stat) { - Dictionary> category = null, newCategory; - Dictionary container = null, newContainer; + SortedDictionary> category = null, newCategory; + SortedDictionary container = null, newContainer; lock (RegisteredStats) { - if (!TryGetStat(stat, out category, out container)) + if (!TryGetStatParents(stat, out category, out container)) return false; - newContainer = new Dictionary(container); + newContainer = new SortedDictionary(container); newContainer.Remove(stat.ShortName); - newCategory = new Dictionary>(category); + newCategory = new SortedDictionary>(category); newCategory.Remove(stat.Container); newCategory[stat.Container] = newContainer; @@ -220,15 +418,70 @@ namespace OpenSim.Framework.Monitoring } } - public static bool TryGetStats(string category, out Dictionary> stats) + public static bool TryGetStat(string category, string container, string statShortName, out Stat stat) { - return RegisteredStats.TryGetValue(category, out stats); + stat = null; + SortedDictionary> categoryStats; + + lock (RegisteredStats) + { + if (!TryGetStatsForCategory(category, out categoryStats)) + return false; + + SortedDictionary containerStats; + + if (!categoryStats.TryGetValue(container, out containerStats)) + return false; + + return containerStats.TryGetValue(statShortName, out stat); + } + } + + public static bool TryGetStatsForCategory( + string category, out SortedDictionary> stats) + { + lock (RegisteredStats) + return RegisteredStats.TryGetValue(category, out stats); + } + + /// + /// Get the same stat for each container in a given category. + /// + /// + /// The stats if there were any to fetch. Otherwise null. + /// + /// + /// + public static List GetStatsFromEachContainer(string category, string statShortName) + { + SortedDictionary> categoryStats; + + lock (RegisteredStats) + { + if (!RegisteredStats.TryGetValue(category, out categoryStats)) + return null; + + List stats = null; + + foreach (SortedDictionary containerStats in categoryStats.Values) + { + if (containerStats.ContainsKey(statShortName)) + { + if (stats == null) + stats = new List(); + + stats.Add(containerStats[statShortName]); + } + } + + return stats; + } } - public static bool TryGetStat( + public static bool TryGetStatParents( Stat stat, - out Dictionary> category, - out Dictionary container) + out SortedDictionary> category, + out SortedDictionary container) { category = null; container = null; @@ -252,9 +505,9 @@ namespace OpenSim.Framework.Monitoring { lock (RegisteredStats) { - foreach (Dictionary> category in RegisteredStats.Values) + foreach (SortedDictionary> category in RegisteredStats.Values) { - foreach (Dictionary container in category.Values) + foreach (SortedDictionary container in category.Values) { foreach (Stat stat in container.Values) { 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 @@ using System.Timers; +using OpenMetaverse.StructuredData; + namespace OpenSim.Framework.Monitoring { /// @@ -88,5 +90,21 @@ namespace OpenSim.Framework.Monitoring Logouts total : {3}", SuccessfulLogins, SuccessfulLoginsToday, SuccessfulLoginsYesterday, Logouts); } + + public override string XReport(string uptime, string version) + { + return OSDParser.SerializeJsonString(OReport(uptime, version)); + } + + public override OSDMap OReport(string uptime, string version) + { + OSDMap ret = new OSDMap(); + ret.Add("SuccessfulLogins", OSD.FromInteger(SuccessfulLogins)); + ret.Add("SuccessfulLoginsToday", OSD.FromInteger(SuccessfulLoginsToday)); + ret.Add("SuccessfulLoginsYesterday", OSD.FromInteger(SuccessfulLoginsYesterday)); + ret.Add("Logouts", OSD.FromInteger(Logouts)); + + return ret; + } } } diff --git a/OpenSim/Framework/Monitoring/Watchdog.cs b/OpenSim/Framework/Monitoring/Watchdog.cs index 3f992b1..a644fa5 100644 --- a/OpenSim/Framework/Monitoring/Watchdog.cs +++ b/OpenSim/Framework/Monitoring/Watchdog.cs @@ -38,6 +38,8 @@ namespace OpenSim.Framework.Monitoring /// public static class Watchdog { + private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + /// Timer interval in milliseconds for the watchdog timer public const double WATCHDOG_INTERVAL_MS = 2500.0d; @@ -82,12 +84,32 @@ namespace OpenSim.Framework.Monitoring /// public Func AlarmMethod { get; set; } - public ThreadWatchdogInfo(Thread thread, int timeout) + /// + /// Stat structure associated with this thread. + /// + public Stat Stat { get; set; } + + public ThreadWatchdogInfo(Thread thread, int timeout, string name) { Thread = thread; Timeout = timeout; FirstTick = Environment.TickCount & Int32.MaxValue; LastTick = FirstTick; + + Stat + = new Stat( + name, + string.Format("Last update of thread {0}", name), + "", + "ms", + "server", + "thread", + StatType.Pull, + MeasuresOfInterest.None, + stat => stat.Value = Environment.TickCount & Int32.MaxValue - LastTick, + StatVerbosity.Debug); + + StatsManager.RegisterStat(Stat); } public ThreadWatchdogInfo(ThreadWatchdogInfo previousTwi) @@ -100,6 +122,11 @@ namespace OpenSim.Framework.Monitoring AlarmIfTimeout = previousTwi.AlarmIfTimeout; AlarmMethod = previousTwi.AlarmMethod; } + + public void Cleanup() + { + StatsManager.DeregisterStat(Stat); + } } /// @@ -116,7 +143,7 @@ namespace OpenSim.Framework.Monitoring get { return m_enabled; } set { -// m_log.DebugFormat("[MEMORY WATCHDOG]: Setting MemoryWatchdog.Enabled to {0}", value); + // m_log.DebugFormat("[MEMORY WATCHDOG]: Setting MemoryWatchdog.Enabled to {0}", value); if (value == m_enabled) return; @@ -132,9 +159,8 @@ namespace OpenSim.Framework.Monitoring m_watchdogTimer.Enabled = m_enabled; } } - private static bool m_enabled; - private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private static bool m_enabled; private static Dictionary m_threads; private static System.Timers.Timer m_watchdogTimer; @@ -155,57 +181,19 @@ namespace OpenSim.Framework.Monitoring } /// - /// Start a new thread that is tracked by the watchdog timer. - /// - /// The method that will be executed in a new thread - /// A name to give to the new thread - /// Priority to run the thread at - /// True to run this thread as a background thread, otherwise false - /// Trigger an alarm function is we have timed out - /// The newly created Thread object - public static Thread StartThread( - ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout) - { - return StartThread(start, name, priority, isBackground, alarmIfTimeout, null, DEFAULT_WATCHDOG_TIMEOUT_MS); - } - - /// - /// Start a new thread that is tracked by the watchdog timer + /// Add a thread to the watchdog tracker. /// - /// The method that will be executed in a new thread - /// A name to give to the new thread - /// Priority to run the thread at - /// True to run this thread as a background - /// thread, otherwise false - /// Trigger an alarm function is we have timed out - /// - /// Alarm method to call if alarmIfTimeout is true and there is a timeout. - /// Normally, this will just return some useful debugging information. - /// - /// Number of milliseconds to wait until we issue a warning about timeout. - /// The newly created Thread object - public static Thread StartThread( - ThreadStart start, string name, ThreadPriority priority, bool isBackground, - bool alarmIfTimeout, Func alarmMethod, int timeout) + /// Information about the thread. + /// Name of the thread. + /// If true then creation of thread is logged. + public static void AddThread(ThreadWatchdogInfo info, string name, bool log = true) { - Thread thread = new Thread(start); - thread.Name = name; - thread.Priority = priority; - thread.IsBackground = isBackground; - - ThreadWatchdogInfo twi - = new ThreadWatchdogInfo(thread, timeout) - { AlarmIfTimeout = alarmIfTimeout, AlarmMethod = alarmMethod }; - - m_log.DebugFormat( - "[WATCHDOG]: Started tracking thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId); + if (log) + m_log.DebugFormat( + "[WATCHDOG]: Started tracking thread {0}, ID {1}", name, info.Thread.ManagedThreadId); lock (m_threads) - m_threads.Add(twi.Thread.ManagedThreadId, twi); - - thread.Start(); - - return thread; + m_threads.Add(info.Thread.ManagedThreadId, info); } /// @@ -219,25 +207,28 @@ namespace OpenSim.Framework.Monitoring /// /// Stops watchdog tracking on the current thread /// + /// If true then normal events in thread removal are not logged. /// /// True if the thread was removed from the list of tracked /// threads, otherwise false /// - public static bool RemoveThread() + public static bool RemoveThread(bool log = true) { - return RemoveThread(Thread.CurrentThread.ManagedThreadId); + return RemoveThread(Thread.CurrentThread.ManagedThreadId, log); } - private static bool RemoveThread(int threadID) + private static bool RemoveThread(int threadID, bool log = true) { lock (m_threads) { ThreadWatchdogInfo twi; if (m_threads.TryGetValue(threadID, out twi)) { - m_log.DebugFormat( - "[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId); + if (log) + m_log.DebugFormat( + "[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId); + twi.Cleanup(); m_threads.Remove(threadID); return true; @@ -293,7 +284,7 @@ namespace OpenSim.Framework.Monitoring } catch { } } - + /// /// Get currently watched threads for diagnostic purposes /// @@ -380,6 +371,7 @@ namespace OpenSim.Framework.Monitoring if (MemoryWatchdog.Enabled) MemoryWatchdog.Update(); + ChecksManager.CheckChecks(); StatsManager.RecordStats(); m_watchdogTimer.Start(); diff --git a/OpenSim/Framework/Monitoring/WorkManager.cs b/OpenSim/Framework/Monitoring/WorkManager.cs new file mode 100644 index 0000000..d1a74ce --- /dev/null +++ b/OpenSim/Framework/Monitoring/WorkManager.cs @@ -0,0 +1,290 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using System.Threading; +using log4net; + +namespace OpenSim.Framework.Monitoring +{ + /// + /// Manages various work items in the simulator. + /// + /// + /// Currently, here work can be started + /// * As a long-running and monitored thread. + /// * In a thread that will never timeout but where the job is expected to eventually complete. + /// * In a threadpool thread that will timeout if it takes a very long time to complete (> 10 mins). + /// * As a job which will be run in a single-threaded job engine. Such jobs must not incorporate delays (sleeps, + /// network waits, etc.). + /// + /// This is an evolving approach to better manage the work that OpenSimulator is asked to do from a very diverse + /// range of sources (client actions, incoming network, outgoing network calls, etc.). + /// + /// Util.FireAndForget is still available to insert jobs in the threadpool, though this is equivalent to + /// WorkManager.RunInThreadPool(). + /// + public static class WorkManager + { + private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + public static JobEngine JobEngine { get; private set; } + + static WorkManager() + { + JobEngine = new JobEngine("Non-blocking non-critical job engine", "JOB ENGINE"); + + StatsManager.RegisterStat( + new Stat( + "JobsWaiting", + "Number of jobs waiting for processing.", + "", + "", + "server", + "jobengine", + StatType.Pull, + MeasuresOfInterest.None, + stat => stat.Value = JobEngine.JobsWaiting, + StatVerbosity.Debug)); + + MainConsole.Instance.Commands.AddCommand( + "Debug", + false, + "debug jobengine", + "debug jobengine ", + "Start, stop, get status or set logging level of the job engine.", + "If stopped then all outstanding jobs are processed immediately.", + HandleControlCommand); + } + + /// + /// Start a new long-lived thread. + /// + /// The method that will be executed in a new thread + /// A name to give to the new thread + /// Priority to run the thread at + /// True to run this thread as a background thread, otherwise false + /// Trigger an alarm function is we have timed out + /// If true then creation of thread is logged. + /// The newly created Thread object + public static Thread StartThread( + ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout, bool log = true) + { + return StartThread(start, name, priority, isBackground, alarmIfTimeout, null, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS, log); + } + + /// + /// Start a new thread that is tracked by the watchdog + /// + /// The method that will be executed in a new thread + /// A name to give to the new thread + /// Priority to run the thread at + /// True to run this thread as a background + /// thread, otherwise false + /// Trigger an alarm function is we have timed out + /// + /// Alarm method to call if alarmIfTimeout is true and there is a timeout. + /// Normally, this will just return some useful debugging information. + /// + /// Number of milliseconds to wait until we issue a warning about timeout. + /// If true then creation of thread is logged. + /// The newly created Thread object + public static Thread StartThread( + ThreadStart start, string name, ThreadPriority priority, bool isBackground, + bool alarmIfTimeout, Func alarmMethod, int timeout, bool log = true) + { + Thread thread = new Thread(start); + thread.Priority = priority; + thread.IsBackground = isBackground; + + Watchdog.ThreadWatchdogInfo twi + = new Watchdog.ThreadWatchdogInfo(thread, timeout, name) + { AlarmIfTimeout = alarmIfTimeout, AlarmMethod = alarmMethod }; + + Watchdog.AddThread(twi, name, log:log); + + thread.Start(); + thread.Name = name; + + return thread; + } + + /// + /// Run the callback in a new thread immediately. If the thread exits with an exception log it but do + /// not propogate it. + /// + /// Code for the thread to execute. + /// Object to pass to the thread. + /// Name of the thread + public static void RunInThread(WaitCallback callback, object obj, string name, bool log = false) + { + if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest) + { + Culture.SetCurrentCulture(); + callback(obj); + return; + } + + ThreadStart ts = new ThreadStart(delegate() + { + try + { + Culture.SetCurrentCulture(); + callback(obj); + Watchdog.RemoveThread(log:false); + } + catch (Exception e) + { + m_log.Error(string.Format("[WATCHDOG]: Exception in thread {0}.", name), e); + } + }); + + StartThread(ts, name, ThreadPriority.Normal, true, false, log:log); + } + + /// + /// Run the callback via a threadpool thread. + /// + /// + /// Such jobs may run after some delay but must always complete. + /// + /// + /// + /// The name of the job. This is used in monitoring and debugging. + public static void RunInThreadPool(System.Threading.WaitCallback callback, object obj, string name) + { + Util.FireAndForget(callback, obj, name); + } + + /// + /// Run a job. + /// + /// + /// This differs from direct scheduling (e.g. Util.FireAndForget) in that a job can be run in the job + /// engine if it is running, where all jobs are currently performed in sequence on a single thread. This is + /// to prevent observed overload and server freeze problems when there are hundreds of connections which all attempt to + /// perform work at once (e.g. in conference situations). With lower numbers of connections, the small + /// delay in performing jobs in sequence rather than concurrently has not been notiecable in testing, though a future more + /// sophisticated implementation could perform jobs concurrently when the server is under low load. + /// + /// However, be advised that some callers of this function rely on all jobs being performed in sequence if any + /// jobs are performed in sequence (i.e. if jobengine is active or not). Therefore, expanding the jobengine + /// beyond a single thread will require considerable thought. + /// + /// Also, any jobs submitted must be guaranteed to complete within a reasonable timeframe (e.g. they cannot + /// incorporate a network delay with a long timeout). At the moment, work that could suffer such issues + /// should still be run directly with RunInThread(), Util.FireAndForget(), etc. This is another area where + /// the job engine could be improved and so CPU utilization improved by better management of concurrency within + /// OpenSimulator. + /// + /// General classification for the job (e.g. "RezAttachments"). + /// Callback for job. + /// Object to pass to callback when run + /// Specific name of job (e.g. "RezAttachments for Joe Bloggs" + /// If set to true then the job may be run in ths calling thread. + /// If the true then the job must never timeout. + /// If set to true then extra logging is performed. + public static void RunJob( + string jobType, WaitCallback callback, object obj, string name, + bool canRunInThisThread = false, bool mustNotTimeout = false, + bool log = false) + { + if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest) + { + Culture.SetCurrentCulture(); + callback(obj); + return; + } + + if (JobEngine.IsRunning) + JobEngine.QueueJob(name, () => callback(obj)); + else if (canRunInThisThread) + callback(obj); + else if (mustNotTimeout) + RunInThread(callback, obj, name, log); + else + Util.FireAndForget(callback, obj, name); + } + + private static void HandleControlCommand(string module, string[] args) + { + // if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) + // return; + + if (args.Length < 3) + { + MainConsole.Instance.Output("Usage: debug jobengine "); + return; + } + + string subCommand = args[2]; + + if (subCommand == "stop") + { + JobEngine.Stop(); + MainConsole.Instance.OutputFormat("Stopped job engine."); + } + else if (subCommand == "start") + { + JobEngine.Start(); + MainConsole.Instance.OutputFormat("Started job engine."); + } + else if (subCommand == "status") + { + MainConsole.Instance.OutputFormat("Job engine running: {0}", JobEngine.IsRunning); + + JobEngine.Job job = JobEngine.CurrentJob; + MainConsole.Instance.OutputFormat("Current job {0}", job != null ? job.Name : "none"); + + MainConsole.Instance.OutputFormat( + "Jobs waiting: {0}", JobEngine.IsRunning ? JobEngine.JobsWaiting.ToString() : "n/a"); + MainConsole.Instance.OutputFormat("Log Level: {0}", JobEngine.LogLevel); + } + else if (subCommand == "log") + { + if (args.Length < 4) + { + MainConsole.Instance.Output("Usage: debug jobengine log "); + return; + } + + // int logLevel; + int logLevel = int.Parse(args[3]); + // if (ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out logLevel)) + // { + JobEngine.LogLevel = logLevel; + MainConsole.Instance.OutputFormat("Set debug log level to {0}", JobEngine.LogLevel); + // } + } + else + { + MainConsole.Instance.OutputFormat("Unrecognized job engine subcommand {0}", subCommand); + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/OutboundUrlFilter.cs b/OpenSim/Framework/OutboundUrlFilter.cs new file mode 100644 index 0000000..baa3647 --- /dev/null +++ b/OpenSim/Framework/OutboundUrlFilter.cs @@ -0,0 +1,256 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Reflection; +using log4net; +using LukeSkywalker.IPNetwork; +using Nini.Config; + +namespace OpenSim.Framework +{ + public class OutboundUrlFilter + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public string Name { get; private set; } + + private List m_blacklistNetworks; + private List m_blacklistEndPoints; + + private List m_blacklistExceptionNetworks; + private List m_blacklistExceptionEndPoints; + + public OutboundUrlFilter( + string name, + List blacklistNetworks, List blacklistEndPoints, + List blacklistExceptionNetworks, List blacklistExceptionEndPoints) + { + Name = name; + + m_blacklistNetworks = blacklistNetworks; + m_blacklistEndPoints = blacklistEndPoints; + m_blacklistExceptionNetworks = blacklistExceptionNetworks; + m_blacklistExceptionEndPoints = blacklistExceptionEndPoints; + } + + /// + /// Initializes a new instance of the class. + /// + /// Name of the filter for logging purposes. + /// Filter configuration + public OutboundUrlFilter(string name, IConfigSource config) + { + Name = name; + + string configBlacklist + = "0.0.0.0/8|10.0.0.0/8|100.64.0.0/10|127.0.0.0/8|169.254.0.0/16|172.16.0.0/12|192.0.0.0/24|192.0.2.0/24|192.88.99.0/24|192.168.0.0/16|198.18.0.0/15|198.51.100.0/24|203.0.113.0/24|224.0.0.0/4|240.0.0.0/4|255.255.255.255/32"; + string configBlacklistExceptions = ""; + + IConfig networkConfig = config.Configs["Network"]; + + if (networkConfig != null) + { + configBlacklist = networkConfig.GetString("OutboundDisallowForUserScripts", configBlacklist); + configBlacklistExceptions + = networkConfig.GetString("OutboundDisallowForUserScriptsExcept", configBlacklistExceptions); + } + + m_log.DebugFormat( + "[OUTBOUND URL FILTER]: OutboundDisallowForUserScripts for {0} is [{1}]", Name, configBlacklist); + m_log.DebugFormat( + "[OUTBOUND URL FILTER]: OutboundDisallowForUserScriptsExcept for {0} is [{1}]", Name, configBlacklistExceptions); + + OutboundUrlFilter.ParseConfigList( + configBlacklist, Name, out m_blacklistNetworks, out m_blacklistEndPoints); + OutboundUrlFilter.ParseConfigList( + configBlacklistExceptions, Name, out m_blacklistExceptionNetworks, out m_blacklistExceptionEndPoints); + } + + private static void ParseConfigList( + string fullConfigEntry, string filterName, out List networks, out List endPoints) + { + // Parse blacklist + string[] configBlacklistEntries + = fullConfigEntry.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries); + + configBlacklistEntries = configBlacklistEntries.Select(e => e.Trim()).ToArray(); + + networks = new List(); + endPoints = new List(); + + foreach (string configEntry in configBlacklistEntries) + { + if (configEntry.Contains("/")) + { + IPNetwork network; + + if (!IPNetwork.TryParse(configEntry, out network)) + { + m_log.ErrorFormat( + "[OUTBOUND URL FILTER]: Entry [{0}] is invalid network for {1}", configEntry, filterName); + + continue; + } + + networks.Add(network); + } + else + { + Uri configEntryUri; + + if (!Uri.TryCreate("http://" + configEntry, UriKind.Absolute, out configEntryUri)) + { + m_log.ErrorFormat( + "[OUTBOUND URL FILTER]: EndPoint entry [{0}] is invalid endpoint for {1}", + configEntry, filterName); + + continue; + } + + IPAddress[] addresses = Dns.GetHostAddresses(configEntryUri.Host); + + foreach (IPAddress addr in addresses) + { + if (addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) + { + // m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}] in config", addr); + + IPEndPoint configEntryEp = new IPEndPoint(addr, configEntryUri.Port); + endPoints.Add(configEntryEp); + + // m_log.DebugFormat("[OUTBOUND URL FILTER]: Added blacklist exception [{0}]", configEntryEp); + } + } + } + } + } + + /// + /// Determines if an url is in a list of networks and endpoints. + /// + /// + /// IP address + /// + /// Networks. + /// End points. + /// Filter name. + private static bool IsInNetwork( + IPAddress addr, int port, List networks, List endPoints, string filterName) + { + foreach (IPNetwork ipn in networks) + { +// m_log.DebugFormat( +// "[OUTBOUND URL FILTER]: Checking [{0}] against network [{1}]", addr, ipn); + + if (IPNetwork.Contains(ipn, addr)) + { +// m_log.DebugFormat( +// "[OUTBOUND URL FILTER]: Found [{0}] in network [{1}]", addr, ipn); + + return true; + } + } + + // m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}]", addr); + + foreach (IPEndPoint ep in endPoints) + { +// m_log.DebugFormat( +// "[OUTBOUND URL FILTER]: Checking [{0}:{1}] against endpoint [{2}]", +// addr, port, ep); + + if (addr.Equals(ep.Address) && port == ep.Port) + { +// m_log.DebugFormat( +// "[OUTBOUND URL FILTER]: Found [{0}:{1}] in endpoint [{2}]", addr, port, ep); + + return true; + } + } + +// m_log.DebugFormat("[OUTBOUND URL FILTER]: Did not find [{0}:{1}] in list", addr, port); + + return false; + } + + /// + /// Checks whether the given url is allowed by the filter. + /// + /// + public bool CheckAllowed(Uri url) + { + bool allowed = true; + + // Check that we are permitted to make calls to this endpoint. + bool foundIpv4Address = false; + + IPAddress[] addresses = Dns.GetHostAddresses(url.Host); + + foreach (IPAddress addr in addresses) + { + if (addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) + { +// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}]", addr); + + foundIpv4Address = true; + + // Check blacklist + if (OutboundUrlFilter.IsInNetwork(addr, url.Port, m_blacklistNetworks, m_blacklistEndPoints, Name)) + { +// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found [{0}] in blacklist for {1}", url, Name); + + // Check blacklist exceptions + allowed + = OutboundUrlFilter.IsInNetwork( + addr, url.Port, m_blacklistExceptionNetworks, m_blacklistExceptionEndPoints, Name); + +// if (allowed) +// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found [{0}] in whitelist for {1}", url, Name); + } + } + + // Found at least one address in a blacklist and not a blacklist exception + if (!allowed) + return false; +// else +// m_log.DebugFormat("[OUTBOUND URL FILTER]: URL [{0}] not in blacklist for {1}", url, Name); + } + + // We do not know how to handle IPv6 securely yet. + if (!foundIpv4Address) + return false; + +// m_log.DebugFormat("[OUTBOUND URL FILTER]: Allowing request [{0}]", url); + + return allowed; + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/PermissionsUtil.cs b/OpenSim/Framework/PermissionsUtil.cs new file mode 100644 index 0000000..d785a78 --- /dev/null +++ b/OpenSim/Framework/PermissionsUtil.cs @@ -0,0 +1,87 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using log4net; + +namespace OpenSim.Framework +{ + public static class PermissionsUtil + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Logs permissions flags. Useful when debugging permission problems. + /// + /// + public static void LogPermissions(String name, String message, uint basePerm, uint curPerm, uint nextPerm) + { + m_log.DebugFormat("Permissions of \"{0}\" at \"{1}\": Base {2} ({3:X4}), Current {4} ({5:X4}), NextOwner {6} ({7:X4})", + name, message, + PermissionsToString(basePerm), basePerm, PermissionsToString(curPerm), curPerm, PermissionsToString(nextPerm), nextPerm); + } + + /// + /// Converts a permissions bit-mask to a string (e.g., "MCT"). + /// + private static string PermissionsToString(uint perms) + { + string str = ""; + if ((perms & (int)PermissionMask.Modify) != 0) + str += "M"; + if ((perms & (int)PermissionMask.Copy) != 0) + str += "C"; + if ((perms & (int)PermissionMask.Transfer) != 0) + str += "T"; + if (str == "") + str = "."; + return str; + } + + /// + /// Applies an object's folded permissions to its regular permissions. + /// + /// The folded permissions. Only the lowest 7 bits are examined. + /// The permissions variable to modify. + public static void ApplyFoldedPermissions(uint foldedPerms, ref uint mainPerms) + { + if ((foldedPerms & 7) == 0) + return; // assume that if the folded permissions are 0 then this means that they weren't actually recorded + + if ((foldedPerms & ((uint)PermissionMask.Copy >> 13)) == 0) + mainPerms &= ~(uint)PermissionMask.Copy; + if ((foldedPerms & ((uint)PermissionMask.Transfer >> 13)) == 0) + mainPerms &= ~(uint)PermissionMask.Transfer; + if ((foldedPerms & ((uint)PermissionMask.Modify >> 13)) == 0) + mainPerms &= ~(uint)PermissionMask.Modify; + } + + } +} diff --git a/OpenSim/Framework/PluginLoader.cs b/OpenSim/Framework/PluginLoader.cs index 819cb7b..d12aa61 100644 --- a/OpenSim/Framework/PluginLoader.cs +++ b/OpenSim/Framework/PluginLoader.cs @@ -215,12 +215,12 @@ namespace OpenSim.Framework AddinManager.AddinLoadError += on_addinloaderror_; AddinManager.AddinLoaded += on_addinloaded_; - clear_registry_(); + //clear_registry_(dir); - suppress_console_output_(true); + //suppress_console_output_(true); AddinManager.Initialize(dir); AddinManager.Registry.Update(null); - suppress_console_output_(false); + //suppress_console_output_(false); } private void on_addinloaded_(object sender, AddinEventArgs args) @@ -239,18 +239,19 @@ namespace OpenSim.Framework + args.Exception.StackTrace); } - private void clear_registry_() + private void clear_registry_(string dir) { // The Mono addin manager (in Mono.Addins.dll version 0.2.0.0) // occasionally seems to corrupt its addin cache // Hence, as a temporary solution we'll remove it before each startup + try { - if (Directory.Exists("addin-db-000")) - Directory.Delete("addin-db-000", true); + if (Directory.Exists(dir + "/addin-db-000")) + Directory.Delete(dir + "/addin-db-000", true); - if (Directory.Exists("addin-db-001")) - Directory.Delete("addin-db-001", true); + if (Directory.Exists(dir + "/addin-db-001")) + Directory.Delete(dir + "/addin-db-001", true); } catch (IOException) { diff --git a/OpenSim/Framework/PluginManager.cs b/OpenSim/Framework/PluginManager.cs index 00263f5..0117096 100644 --- a/OpenSim/Framework/PluginManager.cs +++ b/OpenSim/Framework/PluginManager.cs @@ -218,7 +218,7 @@ namespace OpenSim.Framework Console.WriteLine ("Looking for updates..."); Repositories.UpdateAllRepositories (ps); Console.WriteLine ("Available add-in updates:"); - bool found = false; + AddinRepositoryEntry[] entries = Repositories.GetAvailableUpdates(); foreach (AddinRepositoryEntry entry in entries) @@ -541,7 +541,7 @@ namespace OpenSim.Framework { list.AddRange(PluginRegistry.GetAddins()); } - catch(Exception e) + catch (Exception) { Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[]; return x; diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs index 4c36819..c8a5376 100644 --- a/OpenSim/Framework/PrimitiveBaseShape.cs +++ b/OpenSim/Framework/PrimitiveBaseShape.cs @@ -105,6 +105,7 @@ namespace OpenSim.Framework private ushort _profileHollow; private Vector3 _scale; private byte _state; + private byte _lastattach; private ProfileShape _profileShape; private HollowShape _hollowShape; @@ -207,6 +208,7 @@ namespace OpenSim.Framework PCode = (byte)prim.PrimData.PCode; State = prim.PrimData.State; + LastAttachPoint = prim.PrimData.State; PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin); PathEnd = Primitive.PackEndCut(prim.PrimData.PathEnd); PathScaleX = Primitive.PackPathScale(prim.PrimData.PathScaleX); @@ -583,6 +585,15 @@ namespace OpenSim.Framework } } + public byte LastAttachPoint { + get { + return _lastattach; + } + set { + _lastattach = value; + } + } + public ProfileShape ProfileShape { get { return _profileShape; @@ -622,6 +633,8 @@ namespace OpenSim.Framework } } + // This is only used at runtime. For sculpties this holds the texture data, and for meshes + // the mesh data. public byte[] SculptData { get @@ -1147,14 +1160,13 @@ namespace OpenSim.Framework public void ReadSculptData(byte[] data, int pos) { - byte[] SculptTextureUUID = new byte[16]; - UUID SculptUUID = UUID.Zero; - byte SculptTypel = data[16+pos]; + UUID SculptUUID; + byte SculptTypel; - if (data.Length+pos >= 17) + if (data.Length-pos >= 17) { _sculptEntry = true; - SculptTextureUUID = new byte[16]; + byte[] SculptTextureUUID = new byte[16]; SculptTypel = data[16 + pos]; Array.Copy(data, pos, SculptTextureUUID,0, 16); SculptUUID = new UUID(SculptTextureUUID, 0); diff --git a/OpenSim/Framework/RegionFlags.cs b/OpenSim/Framework/RegionFlags.cs index a3089b0..7c6569e 100644 --- a/OpenSim/Framework/RegionFlags.cs +++ b/OpenSim/Framework/RegionFlags.cs @@ -48,6 +48,7 @@ namespace OpenSim.Framework NoMove = 64, // Don't allow moving this region Reservation = 128, // This is an inactive reservation Authenticate = 256, // Require authentication - Hyperlink = 512 // Record represents a HG link + Hyperlink = 512, // Record represents a HG link + DefaultHGRegion = 1024 // Record represents a default region for hypergrid teleports only. } } \ No newline at end of file diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index 016f2a6..79fbd96 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -99,9 +99,8 @@ namespace OpenSim.Framework public class RegionInfo { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly string LogHeader = "[REGION INFO]"; - public bool commFailTF = false; - public ConfigurationMember configMember; public string RegionFile = String.Empty; public bool isSandbox = false; public bool Persistent = true; @@ -126,8 +125,8 @@ namespace OpenSim.Framework private int m_physPrimMax = 0; private bool m_clampPrimSize = false; private int m_objectCapacity = 0; + private int m_maxPrimsPerUser = -1; private int m_linksetCapacity = 0; - private int m_agentCapacity = 0; private string m_regionType = String.Empty; private RegionLightShareData m_windlight = new RegionLightShareData(); protected uint m_httpPort; @@ -137,15 +136,41 @@ namespace OpenSim.Framework public bool m_allow_alternate_ports; protected string m_externalHostName; protected IPEndPoint m_internalEndPoint; - protected uint? m_regionLocX; - protected uint? m_regionLocY; protected uint m_remotingPort; public UUID RegionID = UUID.Zero; public string RemotingAddress; public UUID ScopeID = UUID.Zero; + private UUID m_maptileStaticUUID = UUID.Zero; - private Dictionary m_otherSettings = new Dictionary(); + public uint WorldLocX = 0; + public uint WorldLocY = 0; + public uint WorldLocZ = 0; + /// + /// X dimension of the region. + /// + /// + /// If this is a varregion then the default size set here will be replaced when we load the region config. + /// + public uint RegionSizeX = Constants.RegionSize; + + /// + /// X dimension of the region. + /// + /// + /// If this is a varregion then the default size set here will be replaced when we load the region config. + /// + public uint RegionSizeY = Constants.RegionSize; + + /// + /// Z dimension of the region. + /// + /// + /// XXX: Unknown if this accounts for regions with negative Z. + /// + public uint RegionSizeZ = Constants.RegionHeight; + + private Dictionary m_extraSettings = new Dictionary(); // Apparently, we're applying the same estatesettings regardless of whether it's local or remote. @@ -197,7 +222,6 @@ namespace OpenSim.Framework try { // This will throw if it's not legal Nini XML format - // and thereby toss it to the legacy loader // IConfigSource xmlsource = new XmlConfigSource(filename); @@ -210,29 +234,27 @@ namespace OpenSim.Framework catch (Exception) { } - - configMember = - new ConfigurationMember(filename, description, loadConfigurationOptions, handleIncomingConfiguration, !skipConsoleConfig); - configMember.performConfigurationRetrieve(); - RegionFile = filename; } // The web loader uses this // public RegionInfo(string description, XmlNode xmlNode, bool skipConsoleConfig, IConfigSource configSource) { - // m_configSource = configSource; - configMember = - new ConfigurationMember(xmlNode, description, loadConfigurationOptions, handleIncomingConfiguration, !skipConsoleConfig); - configMember.performConfigurationRetrieve(); + XmlElement elem = (XmlElement)xmlNode; + string name = elem.GetAttribute("Name"); + string xmlstr = "" + xmlNode.OuterXml + ""; + XmlConfigSource source = new XmlConfigSource(XmlReader.Create(new StringReader(xmlstr))); + ReadNiniConfig(source, name); + m_serverURI = string.Empty; } - public RegionInfo(uint regionLocX, uint regionLocY, IPEndPoint internalEndPoint, string externalUri) + public RegionInfo(uint legacyRegionLocX, uint legacyRegionLocY, IPEndPoint internalEndPoint, string externalUri) { - m_regionLocX = regionLocX; - m_regionLocY = regionLocY; - + RegionLocX = legacyRegionLocX; + RegionLocY = legacyRegionLocY; + RegionSizeX = Constants.RegionSize; + RegionSizeY = Constants.RegionSize; m_internalEndPoint = internalEndPoint; m_externalHostName = externalUri; m_serverURI = string.Empty; @@ -318,16 +340,18 @@ namespace OpenSim.Framework get { return m_objectCapacity; } } - public int LinksetCapacity + public int MaxPrimsPerUser { - get { return m_linksetCapacity; } + get { return m_maxPrimsPerUser; } } - public int AgentCapacity + public int LinksetCapacity { - get { return m_agentCapacity; } + get { return m_linksetCapacity; } } + public int AgentCapacity { get; set; } + public byte AccessLevel { get { return (byte)Util.ConvertMaturityToAccessLevel((uint)RegionSettings.Maturity); } @@ -338,6 +362,13 @@ namespace OpenSim.Framework get { return m_regionType; } } + public UUID MaptileStaticUUID + { + get { return m_maptileStaticUUID; } + } + + public string MaptileStaticFile { get; private set; } + /// /// The port by which http communication occurs with the region (most noticeably, CAPS communication) /// @@ -441,25 +472,42 @@ namespace OpenSim.Framework /// /// The x co-ordinate of this region in map tiles (e.g. 1000). + /// Coordinate is scaled as world coordinates divided by the legacy region size + /// and is thus is the number of legacy regions. /// public uint RegionLocX { - get { return m_regionLocX.Value; } - set { m_regionLocX = value; } + get { return WorldLocX / Constants.RegionSize; } + set { WorldLocX = value * Constants.RegionSize; } } /// /// The y co-ordinate of this region in map tiles (e.g. 1000). + /// Coordinate is scaled as world coordinates divided by the legacy region size + /// and is thus is the number of legacy regions. /// public uint RegionLocY { - get { return m_regionLocY.Value; } - set { m_regionLocY = value; } + get { return WorldLocY / Constants.RegionSize; } + set { WorldLocY = value * Constants.RegionSize; } + } + + public void SetDefaultRegionSize() + { + WorldLocX = 0; + WorldLocY = 0; + WorldLocZ = 0; + RegionSizeX = Constants.RegionSize; + RegionSizeY = Constants.RegionSize; + RegionSizeZ = Constants.RegionHeight; } + // A unique region handle is created from the region's world coordinates. + // This cannot be changed because some code expects to receive the region handle and then + // compute the region coordinates from it. public ulong RegionHandle { - get { return Util.UIntsToLong((RegionLocX * (uint) Constants.RegionSize), (RegionLocY * (uint) Constants.RegionSize)); } + get { return Util.UIntsToLong(WorldLocX, WorldLocY); } } public void SetEndPoint(string ipaddr, int port) @@ -469,20 +517,20 @@ namespace OpenSim.Framework m_internalEndPoint = tmpEPE; } - public string GetOtherSetting(string key) + public string GetSetting(string key) { string val; string keylower = key.ToLower(); - if (m_otherSettings.TryGetValue(keylower, out val)) + if (m_extraSettings.TryGetValue(keylower, out val)) return val; m_log.DebugFormat("[RegionInfo] Could not locate value for parameter {0}", key); return null; } - public void SetOtherSetting(string key, string value) + private void SetExtraSetting(string key, string value) { string keylower = key.ToLower(); - m_otherSettings[keylower] = value; + m_extraSettings[keylower] = value; } private void ReadNiniConfig(IConfigSource source, string name) @@ -566,8 +614,25 @@ namespace OpenSim.Framework string[] locationElements = location.Split(new char[] {','}); - m_regionLocX = Convert.ToUInt32(locationElements[0]); - m_regionLocY = Convert.ToUInt32(locationElements[1]); + RegionLocX = Convert.ToUInt32(locationElements[0]); + RegionLocY = Convert.ToUInt32(locationElements[1]); + + // Region size + // Default to legacy region size if not specified. + allKeys.Remove("SizeX"); + string configSizeX = config.GetString("SizeX", Constants.RegionSize.ToString()); + config.Set("SizeX", configSizeX); + RegionSizeX = Convert.ToUInt32(configSizeX); + allKeys.Remove("SizeY"); + string configSizeY = config.GetString("SizeY", Constants.RegionSize.ToString()); + config.Set("SizeY", configSizeX); + RegionSizeY = Convert.ToUInt32(configSizeY); + allKeys.Remove("SizeZ"); + string configSizeZ = config.GetString("SizeZ", Constants.RegionHeight.ToString()); + config.Set("SizeZ", configSizeX); + RegionSizeZ = Convert.ToUInt32(configSizeZ); + + DoRegionSizeSanityChecks(); // InternalAddress // @@ -641,7 +706,7 @@ namespace OpenSim.Framework m_regionType = config.GetString("RegionType", String.Empty); allKeys.Remove("RegionType"); - #region Prim stuff + #region Prim and map stuff m_nonphysPrimMin = config.GetFloat("NonPhysicalPrimMin", 0); allKeys.Remove("NonPhysicalPrimMin"); @@ -661,12 +726,25 @@ namespace OpenSim.Framework m_objectCapacity = config.GetInt("MaxPrims", 15000); allKeys.Remove("MaxPrims"); + m_maxPrimsPerUser = config.GetInt("MaxPrimsPerUser", -1); + allKeys.Remove("MaxPrimsPerUser"); + m_linksetCapacity = config.GetInt("LinksetPrims", 0); allKeys.Remove("LinksetPrims"); + + allKeys.Remove("MaptileStaticUUID"); + string mapTileStaticUUID = config.GetString("MaptileStaticUUID", UUID.Zero.ToString()); + if (UUID.TryParse(mapTileStaticUUID.Trim(), out m_maptileStaticUUID)) + { + config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString()); + } + + MaptileStaticFile = config.GetString("MaptileStaticFile", String.Empty); + allKeys.Remove("MaptileStaticFile"); #endregion - m_agentCapacity = config.GetInt("MaxAgents", 100); + AgentCapacity = config.GetInt("MaxAgents", 100); allKeys.Remove("MaxAgents"); // Multi-tenancy @@ -676,7 +754,58 @@ namespace OpenSim.Framework foreach (String s in allKeys) { - SetOtherSetting(s, config.GetString(s)); + SetExtraSetting(s, config.GetString(s)); + } + } + + // Make sure user specified region sizes are sane. + // Must be multiples of legacy region size (256). + private void DoRegionSizeSanityChecks() + { + if (RegionSizeX != Constants.RegionSize || RegionSizeY != Constants.RegionSize) + { + // Doing non-legacy region sizes. + // Enforce region size to be multiples of the legacy region size (256) + uint partial = RegionSizeX % Constants.RegionSize; + if (partial != 0) + { + RegionSizeX -= partial; + if (RegionSizeX == 0) + RegionSizeX = Constants.RegionSize; + m_log.ErrorFormat("{0} Region size must be multiple of {1}. Enforcing {2}.RegionSizeX={3} instead of specified {4}", + LogHeader, Constants.RegionSize, m_regionName, RegionSizeX, RegionSizeX + partial); + } + partial = RegionSizeY % Constants.RegionSize; + if (partial != 0) + { + RegionSizeY -= partial; + if (RegionSizeY == 0) + RegionSizeY = Constants.RegionSize; + m_log.ErrorFormat("{0} Region size must be multiple of {1}. Enforcing {2}.RegionSizeY={3} instead of specified {4}", + LogHeader, Constants.RegionSize, m_regionName, RegionSizeY, RegionSizeY + partial); + } + + // Because of things in the viewer, regions MUST be square. + // Remove this check when viewers have been updated. + if (RegionSizeX != RegionSizeY) + { + uint minSize = Math.Min(RegionSizeX, RegionSizeY); + RegionSizeX = minSize; + RegionSizeY = minSize; + m_log.ErrorFormat("{0} Regions must be square until viewers are updated. Forcing region {1} size to <{2},{3}>", + LogHeader, m_regionName, RegionSizeX, RegionSizeY); + } + + // There is a practical limit to region size. + if (RegionSizeX > Constants.MaximumRegionSize || RegionSizeY > Constants.MaximumRegionSize) + { + RegionSizeX = Util.Clamp(RegionSizeX, Constants.RegionSize, Constants.MaximumRegionSize); + RegionSizeY = Util.Clamp(RegionSizeY, Constants.RegionSize, Constants.MaximumRegionSize); + m_log.ErrorFormat("{0} Region dimensions must be less than {1}. Clamping {2}'s size to <{3},{4}>", + LogHeader, Constants.MaximumRegionSize, m_regionName, RegionSizeX, RegionSizeY); + } + + m_log.InfoFormat("{0} Region {1} size set to <{2},{3}>", LogHeader, m_regionName, RegionSizeX, RegionSizeY); } } @@ -691,9 +820,18 @@ namespace OpenSim.Framework config.Set("RegionUUID", RegionID.ToString()); - string location = String.Format("{0},{1}", m_regionLocX, m_regionLocY); + string location = String.Format("{0},{1}", RegionLocX, RegionLocY); config.Set("Location", location); + if (RegionSizeX > 0) + config.Set("SizeX", RegionSizeX); + + if (RegionSizeY > 0) + config.Set("SizeY", RegionSizeY); + +// if (RegionSizeZ > 0) +// config.Set("SizeZ", RegionSizeZ); + config.Set("InternalAddress", m_internalEndPoint.Address.ToString()); config.Set("InternalPort", m_internalEndPoint.Port); @@ -718,22 +856,26 @@ namespace OpenSim.Framework if (m_objectCapacity > 0) config.Set("MaxPrims", m_objectCapacity); + if (m_maxPrimsPerUser > -1) + config.Set("MaxPrimsPerUser", m_maxPrimsPerUser); + if (m_linksetCapacity > 0) config.Set("LinksetPrims", m_linksetCapacity); - if (m_agentCapacity > 0) - config.Set("MaxAgents", m_agentCapacity); + if (AgentCapacity > 0) + config.Set("MaxAgents", AgentCapacity); if (ScopeID != UUID.Zero) config.Set("ScopeID", ScopeID.ToString()); if (RegionType != String.Empty) config.Set("RegionType", RegionType); - } - public bool ignoreIncomingConfiguration(string configuration_key, object configuration_result) - { - return true; + if (m_maptileStaticUUID != UUID.Zero) + config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString()); + + if (MaptileStaticFile != null && MaptileStaticFile != String.Empty) + config.Set("MaptileStaticFile", MaptileStaticFile); } public void SaveRegionToFile(string description, string filename) @@ -755,215 +897,14 @@ namespace OpenSim.Framework return; } - else if (filename.ToLower().EndsWith(".xml")) - { - configMember = new ConfigurationMember(filename, description, loadConfigurationOptionsFromMe, - ignoreIncomingConfiguration, false); - configMember.performConfigurationRetrieve(); - RegionFile = filename; - } else throw new Exception("Invalid file type for region persistence."); } - public void loadConfigurationOptionsFromMe() - { - configMember.addConfigurationOption("sim_UUID", ConfigurationOption.ConfigurationTypes.TYPE_UUID_NULL_FREE, - "UUID of Region (Default is recommended, random UUID)", - RegionID.ToString(), true); - configMember.addConfigurationOption("sim_name", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, - "Region Name", RegionName, true); - configMember.addConfigurationOption("sim_location_x", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, - "Grid Location (X Axis)", m_regionLocX.ToString(), true); - configMember.addConfigurationOption("sim_location_y", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, - "Grid Location (Y Axis)", m_regionLocY.ToString(), true); - //m_configMember.addConfigurationOption("datastore", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, "Filename for local storage", "OpenSim.db", false); - configMember.addConfigurationOption("internal_ip_address", - ConfigurationOption.ConfigurationTypes.TYPE_IP_ADDRESS, - "Internal IP Address for incoming UDP client connections", - m_internalEndPoint.Address.ToString(), - true); - configMember.addConfigurationOption("internal_ip_port", ConfigurationOption.ConfigurationTypes.TYPE_INT32, - "Internal IP Port for incoming UDP client connections", - m_internalEndPoint.Port.ToString(), true); - configMember.addConfigurationOption("allow_alternate_ports", - ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN, - "Allow sim to find alternate UDP ports when ports are in use?", - m_allow_alternate_ports.ToString(), true); - configMember.addConfigurationOption("external_host_name", - ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, - "External Host Name", m_externalHostName, true); - configMember.addConfigurationOption("lastmap_uuid", ConfigurationOption.ConfigurationTypes.TYPE_UUID, - "Last Map UUID", lastMapUUID.ToString(), true); - configMember.addConfigurationOption("lastmap_refresh", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, - "Last Map Refresh", Util.UnixTimeSinceEpoch().ToString(), true); - - configMember.addConfigurationOption("nonphysical_prim_min", ConfigurationOption.ConfigurationTypes.TYPE_FLOAT, - "Minimum size for nonphysical prims", m_nonphysPrimMin.ToString(), true); - - configMember.addConfigurationOption("nonphysical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32, - "Maximum size for nonphysical prims", m_nonphysPrimMax.ToString(), true); - - configMember.addConfigurationOption("physical_prim_min", ConfigurationOption.ConfigurationTypes.TYPE_FLOAT, - "Minimum size for nonphysical prims", m_physPrimMin.ToString(), true); - - configMember.addConfigurationOption("physical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32, - "Maximum size for physical prims", m_physPrimMax.ToString(), true); - - configMember.addConfigurationOption("clamp_prim_size", ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN, - "Clamp prims to max size", m_clampPrimSize.ToString(), true); - - configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32, - "Max objects this sim will hold", m_objectCapacity.ToString(), true); - - configMember.addConfigurationOption("linkset_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32, - "Max prims an object will hold", m_linksetCapacity.ToString(), true); - - configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32, - "Max avatars this sim will hold", m_agentCapacity.ToString(), true); - - configMember.addConfigurationOption("scope_id", ConfigurationOption.ConfigurationTypes.TYPE_UUID, - "Scope ID for this region", ScopeID.ToString(), true); - - configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING, - "Free form string describing the type of region", String.Empty, true); - } - - public void loadConfigurationOptions() - { - configMember.addConfigurationOption("sim_UUID", ConfigurationOption.ConfigurationTypes.TYPE_UUID, - "UUID of Region (Default is recommended, random UUID)", - UUID.Random().ToString(), true); - configMember.addConfigurationOption("sim_name", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, - "Region Name", "OpenSim Test", false); - configMember.addConfigurationOption("sim_location_x", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, - "Grid Location (X Axis)", "1000", false); - configMember.addConfigurationOption("sim_location_y", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, - "Grid Location (Y Axis)", "1000", false); - //m_configMember.addConfigurationOption("datastore", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, "Filename for local storage", "OpenSim.db", false); - configMember.addConfigurationOption("internal_ip_address", - ConfigurationOption.ConfigurationTypes.TYPE_IP_ADDRESS, - "Internal IP Address for incoming UDP client connections", "0.0.0.0", - false); - configMember.addConfigurationOption("internal_ip_port", ConfigurationOption.ConfigurationTypes.TYPE_INT32, - "Internal IP Port for incoming UDP client connections", - ConfigSettings.DefaultRegionHttpPort.ToString(), false); - configMember.addConfigurationOption("allow_alternate_ports", ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN, - "Allow sim to find alternate UDP ports when ports are in use?", - "false", true); - configMember.addConfigurationOption("external_host_name", - ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, - "External Host Name", "127.0.0.1", false); - configMember.addConfigurationOption("lastmap_uuid", ConfigurationOption.ConfigurationTypes.TYPE_UUID, - "Last Map UUID", lastMapUUID.ToString(), true); - - configMember.addConfigurationOption("lastmap_refresh", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, - "Last Map Refresh", Util.UnixTimeSinceEpoch().ToString(), true); - - configMember.addConfigurationOption("nonphysical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32, - "Maximum size for nonphysical prims", "0", true); - - configMember.addConfigurationOption("physical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32, - "Maximum size for physical prims", "0", true); - - configMember.addConfigurationOption("clamp_prim_size", ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN, - "Clamp prims to max size", "false", true); - - configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32, - "Max objects this sim will hold", "15000", true); - - configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32, - "Max avatars this sim will hold", "100", true); - - configMember.addConfigurationOption("scope_id", ConfigurationOption.ConfigurationTypes.TYPE_UUID, - "Scope ID for this region", UUID.Zero.ToString(), true); - - configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING, - "Region Type", String.Empty, true); - } - - public bool handleIncomingConfiguration(string configuration_key, object configuration_result) - { - switch (configuration_key) - { - case "sim_UUID": - RegionID = (UUID) configuration_result; - originRegionID = (UUID) configuration_result; - break; - case "sim_name": - RegionName = (string) configuration_result; - break; - case "sim_location_x": - m_regionLocX = (uint) configuration_result; - break; - case "sim_location_y": - m_regionLocY = (uint) configuration_result; - break; - case "internal_ip_address": - IPAddress address = (IPAddress) configuration_result; - m_internalEndPoint = new IPEndPoint(address, 0); - break; - case "internal_ip_port": - m_internalEndPoint.Port = (int) configuration_result; - break; - case "allow_alternate_ports": - m_allow_alternate_ports = (bool) configuration_result; - break; - case "external_host_name": - if ((string) configuration_result != "SYSTEMIP") - { - m_externalHostName = (string) configuration_result; - } - else - { - m_externalHostName = Util.GetLocalHost().ToString(); - } - break; - case "lastmap_uuid": - lastMapUUID = (UUID)configuration_result; - break; - case "lastmap_refresh": - lastMapRefresh = (string)configuration_result; - break; - case "nonphysical_prim_max": - m_nonphysPrimMax = (int)configuration_result; - break; - case "physical_prim_max": - m_physPrimMax = (int)configuration_result; - break; - case "clamp_prim_size": - m_clampPrimSize = (bool)configuration_result; - break; - case "object_capacity": - m_objectCapacity = (int)configuration_result; - break; - case "linkset_capacity": - m_linksetCapacity = (int)configuration_result; - break; - case "agent_capacity": - m_agentCapacity = (int)configuration_result; - break; - case "scope_id": - ScopeID = (UUID)configuration_result; - break; - case "region_type": - m_regionType = (string)configuration_result; - break; - } - - return true; - } - public void SaveLastMapUUID(UUID mapUUID) { lastMapUUID = mapUUID; lastMapRefresh = Util.UnixTimeSinceEpoch().ToString(); - - if (configMember == null) - return; - - configMember.forceSetConfigurationOption("lastmap_uuid", mapUUID.ToString()); - configMember.forceSetConfigurationOption("lastmap_refresh", lastMapRefresh); } public OSDMap PackRegionInfoData() @@ -975,8 +916,13 @@ namespace OpenSim.Framework args["external_host_name"] = OSD.FromString(ExternalHostName); args["http_port"] = OSD.FromString(HttpPort.ToString()); args["server_uri"] = OSD.FromString(ServerURI); + args["region_xloc"] = OSD.FromString(RegionLocX.ToString()); args["region_yloc"] = OSD.FromString(RegionLocY.ToString()); + args["region_size_x"] = OSD.FromString(RegionSizeX.ToString()); + args["region_size_y"] = OSD.FromString(RegionSizeY.ToString()); + args["region_size_z"] = OSD.FromString(RegionSizeZ.ToString()); + args["internal_ep_address"] = OSD.FromString(InternalEndPoint.Address.ToString()); args["internal_ep_port"] = OSD.FromString(InternalEndPoint.Port.ToString()); if ((RemotingAddress != null) && !RemotingAddress.Equals("")) @@ -1015,6 +961,13 @@ namespace OpenSim.Framework UInt32.TryParse(args["region_yloc"].AsString(), out locy); RegionLocY = locy; } + if (args.ContainsKey("region_size_x")) + RegionSizeX = (uint)args["region_size_x"].AsInteger(); + if (args.ContainsKey("region_size_y")) + RegionSizeY = (uint)args["region_size_y"].AsInteger(); + if (args.ContainsKey("region_size_z")) + RegionSizeZ = (uint)args["region_size_z"].AsInteger(); + IPAddress ip_addr = null; if (args["internal_ep_address"] != null) { @@ -1051,23 +1004,5 @@ namespace OpenSim.Framework regionInfo.ServerURI = serverURI; return regionInfo; } - - public Dictionary ToKeyValuePairs() - { - Dictionary kvp = new Dictionary(); - kvp["uuid"] = RegionID.ToString(); - kvp["locX"] = RegionLocX.ToString(); - kvp["locY"] = RegionLocY.ToString(); - kvp["external_ip_address"] = ExternalEndPoint.Address.ToString(); - kvp["external_port"] = ExternalEndPoint.Port.ToString(); - kvp["external_host_name"] = ExternalHostName; - kvp["http_port"] = HttpPort.ToString(); - kvp["internal_ip_address"] = InternalEndPoint.Address.ToString(); - kvp["internal_port"] = InternalEndPoint.Port.ToString(); - kvp["alternate_ports"] = m_allow_alternate_ports.ToString(); - kvp["server_uri"] = ServerURI; - - return kvp; - } } } diff --git a/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs b/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs deleted file mode 100644 index d670f2f..0000000 --- a/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenSim.Framework.RegionLoader.Filesystem")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("http://opensimulator.org")] -[assembly: AssemblyProduct("OpenSim")] -[assembly: AssemblyCopyright("OpenSimulator developers")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("4ab5c74b-e886-40a1-b67d-a04df285e706")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs b/OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs deleted file mode 100644 index 8332c14..0000000 --- a/OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using log4net; -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using Nini.Config; - -namespace OpenSim.Framework.RegionLoader.Filesystem -{ - public class RegionLoaderFileSystem : IRegionLoader - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private IConfigSource m_configSource; - - public void SetIniConfigSource(IConfigSource configSource) - { - m_configSource = configSource; - } - - public RegionInfo[] LoadRegions() - { - string regionConfigPath = Path.Combine(Util.configDir(), "Regions"); - bool allowRegionless = false; - - try - { - IConfig startupConfig = (IConfig)m_configSource.Configs["Startup"]; - regionConfigPath = startupConfig.GetString("regionload_regionsdir", regionConfigPath).Trim(); - allowRegionless = startupConfig.GetBoolean("allow_regionless", false); - } - catch (Exception) - { - // No INI setting recorded. - } - - if (!Directory.Exists(regionConfigPath)) - { - Directory.CreateDirectory(regionConfigPath); - } - - string[] configFiles = Directory.GetFiles(regionConfigPath, "*.xml"); - string[] iniFiles = Directory.GetFiles(regionConfigPath, "*.ini"); - - // Create an empty Regions.ini if there are no existing config files. - if (!allowRegionless && configFiles.Length == 0 && iniFiles.Length == 0) - { - new RegionInfo("DEFAULT REGION CONFIG", Path.Combine(regionConfigPath, "Regions.ini"), false, m_configSource); - iniFiles = Directory.GetFiles(regionConfigPath, "*.ini"); - } - - m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config files from {0}", regionConfigPath); - - List regionInfos = new List(); - - int i = 0; - foreach (string file in iniFiles) - { - m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config file {0}", file); - - IConfigSource source = new IniConfigSource(file); - - foreach (IConfig config in source.Configs) - { - RegionInfo regionInfo = new RegionInfo("REGION CONFIG #" + (i + 1), file, false, m_configSource, config.Name); - regionInfos.Add(regionInfo); - - m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loaded config for region {0}", regionInfo.RegionName); - - i++; - } - } - - foreach (string file in configFiles) - { - m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config file {0}", file); - - RegionInfo regionInfo = new RegionInfo("REGION CONFIG #" + (i + 1), file, false, m_configSource); - regionInfos.Add(regionInfo); - - m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loaded config for region {0}", regionInfo.RegionName); - - i++; - } - - return regionInfos.ToArray(); - } - } -} \ No newline at end of file diff --git a/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs b/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs deleted file mode 100644 index 7309a12..0000000 --- a/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenSim.Framework.RegionLoader.Web")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("http://opensimulator.org")] -[assembly: AssemblyProduct("OpenSim")] -[assembly: AssemblyCopyright("OpenSimulator developers")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("985afff8-e7ed-4056-acce-39abf7a43d33")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs b/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs deleted file mode 100644 index a2f5d9c..0000000 --- a/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Net; -using System.Reflection; -using System.Xml; -using log4net; -using Nini.Config; - -namespace OpenSim.Framework.RegionLoader.Web -{ - public class RegionLoaderWebServer : IRegionLoader - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private IConfigSource m_configSource; - - public void SetIniConfigSource(IConfigSource configSource) - { - m_configSource = configSource; - } - - public RegionInfo[] LoadRegions() - { - if (m_configSource == null) - { - m_log.Error("[WEBLOADER]: Unable to load configuration source!"); - return null; - } - else - { - IConfig startupConfig = (IConfig) m_configSource.Configs["Startup"]; - string url = startupConfig.GetString("regionload_webserver_url", String.Empty).Trim(); - bool allowRegionless = startupConfig.GetBoolean("allow_regionless", false); - - if (url == String.Empty) - { - m_log.Error("[WEBLOADER]: Unable to load webserver URL - URL was empty."); - return null; - } - else - { - RegionInfo[] regionInfos = new RegionInfo[] {}; - int regionCount = 0; - HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create(url); - webRequest.Timeout = 30000; //30 Second Timeout - m_log.DebugFormat("[WEBLOADER]: Sending download request to {0}", url); - - try - { - HttpWebResponse webResponse = (HttpWebResponse) webRequest.GetResponse(); - m_log.Debug("[WEBLOADER]: Downloading region information..."); - StreamReader reader = new StreamReader(webResponse.GetResponseStream()); - string xmlSource = String.Empty; - string tempStr = reader.ReadLine(); - while (tempStr != null) - { - xmlSource = xmlSource + tempStr; - tempStr = reader.ReadLine(); - } - m_log.Debug("[WEBLOADER]: Done downloading region information from server. Total Bytes: " + - xmlSource.Length); - XmlDocument xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(xmlSource); - if (xmlDoc.FirstChild.Name == "Regions") - { - regionCount = xmlDoc.FirstChild.ChildNodes.Count; - - if (regionCount > 0) - { - regionInfos = new RegionInfo[regionCount]; - int i; - for (i = 0; i < xmlDoc.FirstChild.ChildNodes.Count; i++) - { - m_log.Debug(xmlDoc.FirstChild.ChildNodes[i].OuterXml); - regionInfos[i] = - new RegionInfo("REGION CONFIG #" + (i + 1), xmlDoc.FirstChild.ChildNodes[i],false,m_configSource); - } - } - } - } - catch (WebException ex) - { - if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.NotFound) - { - if (!allowRegionless) - throw ex; - } - else - throw ex; - } - - if (regionCount > 0 | allowRegionless) - return regionInfos; - else - { - m_log.Error("[WEBLOADER]: No region configs were available."); - return null; - } - } - } - } - } -} diff --git a/OpenSim/Framework/RegionSettings.cs b/OpenSim/Framework/RegionSettings.cs index 47dbcec..a895c40 100644 --- a/OpenSim/Framework/RegionSettings.cs +++ b/OpenSim/Framework/RegionSettings.cs @@ -200,7 +200,7 @@ namespace OpenSim.Framework set { m_ObjectBonus = value; } } - private int m_Maturity = 1; + private int m_Maturity = 0; public int Maturity { @@ -482,21 +482,14 @@ namespace OpenSim.Framework set { m_LoadedCreationID = value; } } - // Connected Telehub object - private UUID m_TelehubObject = UUID.Zero; - public UUID TelehubObject - { - get - { - return m_TelehubObject; - } - set - { - m_TelehubObject = value; - } - } + /// + /// Connected Telehub object + /// + public UUID TelehubObject { get; set; } - // Our Connected Telehub's SpawnPoints + /// + /// Our connected Telehub's SpawnPoints + /// public List l_SpawnPoints = new List(); // Add a SpawnPoint diff --git a/OpenSim/Framework/RestClient.cs b/OpenSim/Framework/RestClient.cs new file mode 100644 index 0000000..7080ca5 --- /dev/null +++ b/OpenSim/Framework/RestClient.cs @@ -0,0 +1,676 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Web; +using log4net; + +using OpenSim.Framework.ServiceAuth; + +namespace OpenSim.Framework +{ + /// + /// Implementation of a generic REST client + /// + /// + /// This class is a generic implementation of a REST (Representational State Transfer) web service. This + /// class is designed to execute both synchronously and asynchronously. + /// + /// Internally the implementation works as a two stage asynchronous web-client. + /// When the request is initiated, RestClient will query asynchronously for for a web-response, + /// sleeping until the initial response is returned by the server. Once the initial response is retrieved + /// the second stage of asynchronous requests will be triggered, in an attempt to read of the response + /// object into a memorystream as a sequence of asynchronous reads. + /// + /// The asynchronisity of RestClient is designed to move as much processing into the back-ground, allowing + /// other threads to execute, while it waits for a response from the web-service. RestClient itself can be + /// invoked by the caller in either synchronous mode or asynchronous modes. + /// + public class RestClient : IDisposable + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // private string realuri; + + #region member variables + + /// + /// The base Uri of the web-service e.g. http://www.google.com + /// + private string _url; + + /// + /// Path elements of the query + /// + private List _pathElements = new List(); + + /// + /// Parameter elements of the query, e.g. min=34 + /// + private Dictionary _parameterElements = new Dictionary(); + + /// + /// Request method. E.g. GET, POST, PUT or DELETE + /// + private string _method; + + /// + /// Temporary buffer used to store bytes temporarily as they come in from the server + /// + private byte[] _readbuf; + + /// + /// MemoryStream representing the resulting resource + /// + private Stream _resource; + + /// + /// WebRequest object, held as a member variable + /// + private HttpWebRequest _request; + + /// + /// WebResponse object, held as a member variable, so we can close it + /// + private HttpWebResponse _response; + + /// + /// This flag will help block the main synchroneous method, in case we run in synchroneous mode + /// + //public static ManualResetEvent _allDone = new ManualResetEvent(false); + + /// + /// Default time out period + /// + //private const int DefaultTimeout = 10*1000; // 10 seconds timeout + + /// + /// Default Buffer size of a block requested from the web-server + /// + private const int BufferSize = 4096; // Read blocks of 4 KB. + + + /// + /// if an exception occours during async processing, we need to save it, so it can be + /// rethrown on the primary thread; + /// + private Exception _asyncException; + + #endregion member variables + + #region constructors + + /// + /// Instantiate a new RestClient + /// + /// Web-service to query, e.g. http://osgrid.org:8003 + public RestClient(string url) + { + _url = url; + _readbuf = new byte[BufferSize]; + _resource = new MemoryStream(); + _request = null; + _response = null; + _lock = new object(); + } + + private object _lock; + + #endregion constructors + + + #region Dispose + + private bool disposed = false; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) + { + _resource.Dispose(); + } + + disposed = true; + } + + #endregion Dispose + + + /// + /// Add a path element to the query, e.g. assets + /// + /// path entry + public void AddResourcePath(string element) + { + if (isSlashed(element)) + _pathElements.Add(element.Substring(0, element.Length - 1)); + else + _pathElements.Add(element); + } + + /// + /// Add a query parameter to the Url + /// + /// Name of the parameter, e.g. min + /// Value of the parameter, e.g. 42 + public void AddQueryParameter(string name, string value) + { + try + { + _parameterElements.Add(HttpUtility.UrlEncode(name), HttpUtility.UrlEncode(value)); + } + catch (ArgumentException) + { + m_log.Error("[REST]: Query parameter " + name + " is already added."); + } + catch (Exception e) + { + m_log.Error("[REST]: An exception was raised adding query parameter to dictionary. Exception: {0}",e); + } + } + + /// + /// Add a query parameter to the Url + /// + /// Name of the parameter, e.g. min + public void AddQueryParameter(string name) + { + try + { + _parameterElements.Add(HttpUtility.UrlEncode(name), null); + } + catch (ArgumentException) + { + m_log.Error("[REST]: Query parameter " + name + " is already added."); + } + catch (Exception e) + { + m_log.Error("[REST]: An exception was raised adding query parameter to dictionary. Exception: {0}",e); + } + } + + /// + /// Web-Request method, e.g. GET, PUT, POST, DELETE + /// + public string RequestMethod + { + get { return _method; } + set { _method = value; } + } + + /// + /// True if string contains a trailing slash '/' + /// + /// string to be examined + /// true if slash is present + private static bool isSlashed(string s) + { + return s.Substring(s.Length - 1, 1) == "/"; + } + + /// + /// Build a Uri based on the initial Url, path elements and parameters + /// + /// fully constructed Uri + private Uri buildUri() + { + StringBuilder sb = new StringBuilder(); + sb.Append(_url); + + foreach (string e in _pathElements) + { + sb.Append("/"); + sb.Append(e); + } + + bool firstElement = true; + foreach (KeyValuePair kv in _parameterElements) + { + if (firstElement) + { + sb.Append("?"); + firstElement = false; + } + else + sb.Append("&"); + + sb.Append(kv.Key); + if (!string.IsNullOrEmpty(kv.Value)) + { + sb.Append("="); + sb.Append(kv.Value); + } + } + // realuri = sb.ToString(); + //m_log.InfoFormat("[REST CLIENT]: RestURL: {0}", realuri); + return new Uri(sb.ToString()); + } + + #region Async communications with server + + /// + /// Async method, invoked when a block of data has been received from the service + /// + /// + private void StreamIsReadyDelegate(IAsyncResult ar) + { + try + { + Stream s = (Stream) ar.AsyncState; + int read = s.EndRead(ar); + + if (read > 0) + { + _resource.Write(_readbuf, 0, read); + // IAsyncResult asynchronousResult = + // s.BeginRead(_readbuf, 0, BufferSize, new AsyncCallback(StreamIsReadyDelegate), s); + s.BeginRead(_readbuf, 0, BufferSize, new AsyncCallback(StreamIsReadyDelegate), s); + + // TODO! Implement timeout, without killing the server + //ThreadPool.RegisterWaitForSingleObject(asynchronousResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); + } + else + { + s.Close(); + //_allDone.Set(); + } + } + catch (Exception e) + { + //_allDone.Set(); + _asyncException = e; + } + } + + #endregion Async communications with server + + /// + /// Perform a synchronous request + /// + public Stream Request() + { + return Request(null); + } + + /// + /// Perform a synchronous request + /// + public Stream Request(IServiceAuth auth) + { + lock (_lock) + { + _request = (HttpWebRequest) WebRequest.Create(buildUri()); + _request.KeepAlive = false; + _request.ContentType = "application/xml"; + _request.Timeout = 200000; + _request.Method = RequestMethod; + _asyncException = null; + if (auth != null) + auth.AddAuthorization(_request.Headers); + + int reqnum = WebUtil.RequestNumber++; + if (WebUtil.DebugLevel >= 3) + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} REST {1} to {2}", reqnum, _request.Method, _request.RequestUri); + +// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request); + + try + { + using (_response = (HttpWebResponse) _request.GetResponse()) + { + using (Stream src = _response.GetResponseStream()) + { + int length = src.Read(_readbuf, 0, BufferSize); + while (length > 0) + { + _resource.Write(_readbuf, 0, length); + length = src.Read(_readbuf, 0, BufferSize); + } + + // TODO! Implement timeout, without killing the server + // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted + //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); + + // _allDone.WaitOne(); + } + } + } + catch (WebException e) + { + using (HttpWebResponse errorResponse = e.Response as HttpWebResponse) + { + if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode) + { + // This is often benign. E.g., requesting a missing asset will return 404. + m_log.DebugFormat("[REST CLIENT] Resource not found (404): {0}", _request.Address.ToString()); + } + else + { + m_log.Error(string.Format("[REST CLIENT] Error fetching resource from server: {0} ", _request.Address.ToString()), e); + } + } + + return null; + } + + if (_asyncException != null) + throw _asyncException; + + if (_resource != null) + { + _resource.Flush(); + _resource.Seek(0, SeekOrigin.Begin); + } + + if (WebUtil.DebugLevel >= 5) + WebUtil.LogResponseDetail(reqnum, _resource); + + return _resource; + } + } + + public Stream Request(Stream src, IServiceAuth auth) + { + _request = (HttpWebRequest) WebRequest.Create(buildUri()); + _request.KeepAlive = false; + _request.ContentType = "application/xml"; + _request.Timeout = 900000; + _request.Method = RequestMethod; + _asyncException = null; + _request.ContentLength = src.Length; + if (auth != null) + auth.AddAuthorization(_request.Headers); + + src.Seek(0, SeekOrigin.Begin); + + int reqnum = WebUtil.RequestNumber++; + if (WebUtil.DebugLevel >= 3) + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} REST {1} to {2}", reqnum, _request.Method, _request.RequestUri); + if (WebUtil.DebugLevel >= 5) + WebUtil.LogOutgoingDetail(string.Format("SEND {0}: ", reqnum), src); + + Stream dst = _request.GetRequestStream(); + + byte[] buf = new byte[1024]; + int length = src.Read(buf, 0, 1024); + while (length > 0) + { + dst.Write(buf, 0, length); + length = src.Read(buf, 0, 1024); + } + + try + { + _response = (HttpWebResponse)_request.GetResponse(); + } + catch (WebException e) + { + m_log.WarnFormat("[REST]: Request {0} {1} failed with status {2} and message {3}", + RequestMethod, _request.RequestUri, e.Status, e.Message); + return null; + } + catch (Exception e) + { + m_log.WarnFormat( + "[REST]: Request {0} {1} failed with exception {2} {3}", + RequestMethod, _request.RequestUri, e.Message, e.StackTrace); + return null; + } + + if (WebUtil.DebugLevel >= 5) + { + using (Stream responseStream = _response.GetResponseStream()) + { + using (StreamReader reader = new StreamReader(responseStream)) + { + string responseStr = reader.ReadToEnd(); + WebUtil.LogResponseDetail(reqnum, responseStr); + } + } + } + + _response.Close(); + +// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request); + + // TODO! Implement timeout, without killing the server + // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted + //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); + + return null; + } + + #region Async Invocation + + public IAsyncResult BeginRequest(AsyncCallback callback, object state) + { + /// + /// In case, we are invoked asynchroneously this object will keep track of the state + /// + AsyncResult ar = new AsyncResult(callback, state); + Util.FireAndForget(RequestHelper, ar, "RestClient.BeginRequest"); + return ar; + } + + public Stream EndRequest(IAsyncResult asyncResult) + { + AsyncResult ar = (AsyncResult) asyncResult; + + // Wait for operation to complete, then return result or + // throw exception + return ar.EndInvoke(); + } + + private void RequestHelper(Object asyncResult) + { + // We know that it's really an AsyncResult object + AsyncResult ar = (AsyncResult) asyncResult; + try + { + // Perform the operation; if sucessful set the result + Stream s = Request(null); + ar.SetAsCompleted(s, false); + } + catch (Exception e) + { + // If operation fails, set the exception + ar.HandleException(e, false); + } + } + + #endregion Async Invocation + } + + internal class SimpleAsyncResult : IAsyncResult + { + private readonly AsyncCallback m_callback; + + /// + /// Is process completed? + /// + /// Should really be boolean, but VolatileRead has no boolean method + private byte m_completed; + + /// + /// Did process complete synchronously? + /// + /// I have a hard time imagining a scenario where this is the case, again, same issue about + /// booleans and VolatileRead as m_completed + /// + private byte m_completedSynchronously; + + private readonly object m_asyncState; + private ManualResetEvent m_waitHandle; + private Exception m_exception; + + internal SimpleAsyncResult(AsyncCallback cb, object state) + { + m_callback = cb; + m_asyncState = state; + m_completed = 0; + m_completedSynchronously = 1; + } + + #region IAsyncResult Members + + public object AsyncState + { + get { return m_asyncState; } + } + + public WaitHandle AsyncWaitHandle + { + get + { + if (m_waitHandle == null) + { + bool done = IsCompleted; + ManualResetEvent mre = new ManualResetEvent(done); + if (Interlocked.CompareExchange(ref m_waitHandle, mre, null) != null) + { + mre.Close(); + } + else + { + if (!done && IsCompleted) + { + m_waitHandle.Set(); + } + } + } + + return m_waitHandle; + } + } + + + public bool CompletedSynchronously + { + get { return Thread.VolatileRead(ref m_completedSynchronously) == 1; } + } + + + public bool IsCompleted + { + get { return Thread.VolatileRead(ref m_completed) == 1; } + } + + #endregion + + #region class Methods + + internal void SetAsCompleted(bool completedSynchronously) + { + m_completed = 1; + if (completedSynchronously) + m_completedSynchronously = 1; + else + m_completedSynchronously = 0; + + SignalCompletion(); + } + + internal void HandleException(Exception e, bool completedSynchronously) + { + m_completed = 1; + if (completedSynchronously) + m_completedSynchronously = 1; + else + m_completedSynchronously = 0; + m_exception = e; + + SignalCompletion(); + } + + private void SignalCompletion() + { + if (m_waitHandle != null) m_waitHandle.Set(); + + if (m_callback != null) m_callback(this); + } + + public void EndInvoke() + { + // This method assumes that only 1 thread calls EndInvoke + if (!IsCompleted) + { + // If the operation isn't done, wait for it + AsyncWaitHandle.WaitOne(); + AsyncWaitHandle.Close(); + m_waitHandle.Close(); + m_waitHandle = null; // Allow early GC + } + + // Operation is done: if an exception occured, throw it + if (m_exception != null) throw m_exception; + } + + #endregion + } + + internal class AsyncResult : SimpleAsyncResult + { + private T m_result = default(T); + + public AsyncResult(AsyncCallback asyncCallback, Object state) : + base(asyncCallback, state) + { + } + + public void SetAsCompleted(T result, bool completedSynchronously) + { + // Save the asynchronous operation's result + m_result = result; + + // Tell the base class that the operation completed + // sucessfully (no exception) + base.SetAsCompleted(completedSynchronously); + } + + public new T EndInvoke() + { + base.EndInvoke(); + return m_result; + } + } + +} \ No newline at end of file diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs index 537de7a..e66d5be 100644 --- a/OpenSim/Framework/SLUtil.cs +++ b/OpenSim/Framework/SLUtil.cs @@ -25,13 +25,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using OpenMetaverse; using System; using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Xml; -using log4net; -using OpenMetaverse; namespace OpenSim.Framework { @@ -39,12 +35,36 @@ namespace OpenSim.Framework { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Asset types used only in OpenSim. + /// To avoid clashing with the code numbers used in Second Life, use only negative numbers here. + /// + public enum OpenSimAssetType : sbyte + { + Material = -2 + } + + #region SL / file extension / content-type conversions + /// + /// Returns the Enum entry corresponding to the given code, regardless of whether it belongs + /// to the AssetType or OpenSimAssetType enums. + /// + public static object AssetTypeFromCode(sbyte assetType) + { + if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType)) + return (OpenMetaverse.AssetType)assetType; + else if (Enum.IsDefined(typeof(OpenSimAssetType), assetType)) + return (OpenSimAssetType)assetType; + else + return OpenMetaverse.AssetType.Unknown; + } + private class TypeMapping { private sbyte assetType; - private InventoryType inventoryType; + private sbyte inventoryType; private string contentType; private string contentType2; private string extension; @@ -56,15 +76,10 @@ namespace OpenSim.Framework public object AssetType { - get { - if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType)) - return (OpenMetaverse.AssetType)assetType; - else - return OpenMetaverse.AssetType.Unknown; - } + get { return AssetTypeFromCode(assetType); } } - public InventoryType InventoryType + public sbyte InventoryType { get { return inventoryType; } } @@ -84,7 +99,7 @@ namespace OpenSim.Framework get { return extension; } } - private TypeMapping(sbyte assetType, InventoryType inventoryType, string contentType, string contentType2, string extension) + private TypeMapping(sbyte assetType, sbyte inventoryType, string contentType, string contentType2, string extension) { this.assetType = assetType; this.inventoryType = inventoryType; @@ -93,13 +108,28 @@ namespace OpenSim.Framework this.extension = extension; } - public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string contentType2, string extension) + public TypeMapping(AssetType assetType, sbyte inventoryType, string contentType, string contentType2, string extension) : this((sbyte)assetType, inventoryType, contentType, contentType2, extension) { } + public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string contentType2, string extension) + : this((sbyte)assetType, (sbyte)inventoryType, contentType, contentType2, extension) + { + } + public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string extension) - : this((sbyte)assetType, inventoryType, contentType, null, extension) + : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension) + { + } + + public TypeMapping(AssetType assetType, FolderType inventoryType, string contentType, string extension) + : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension) + { + } + + public TypeMapping(OpenSimAssetType assetType, InventoryType inventoryType, string contentType, string extension) + : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension) { } } @@ -125,51 +155,65 @@ namespace OpenSim.Framework new TypeMapping(AssetType.Object, InventoryType.Object, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"), new TypeMapping(AssetType.Object, InventoryType.Attachment, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"), new TypeMapping(AssetType.Notecard, InventoryType.Notecard, "application/vnd.ll.notecard", "application/x-metaverse-notecard", "notecard"), - new TypeMapping(AssetType.Folder, InventoryType.Folder, "application/vnd.ll.folder", "folder"), - new TypeMapping(AssetType.RootFolder, InventoryType.RootCategory, "application/vnd.ll.rootfolder", "rootfolder"), new TypeMapping(AssetType.LSLText, InventoryType.LSL, "application/vnd.ll.lsltext", "application/x-metaverse-lsl", "lsl"), new TypeMapping(AssetType.LSLBytecode, InventoryType.LSL, "application/vnd.ll.lslbyte", "application/x-metaverse-lso", "lso"), new TypeMapping(AssetType.Bodypart, InventoryType.Wearable, "application/vnd.ll.bodypart", "application/x-metaverse-bodypart", "bodypart"), - new TypeMapping(AssetType.TrashFolder, InventoryType.Folder, "application/vnd.ll.trashfolder", "trashfolder"), - new TypeMapping(AssetType.SnapshotFolder, InventoryType.Folder, "application/vnd.ll.snapshotfolder", "snapshotfolder"), - new TypeMapping(AssetType.LostAndFoundFolder, InventoryType.Folder, "application/vnd.ll.lostandfoundfolder", "lostandfoundfolder"), new TypeMapping(AssetType.Animation, InventoryType.Animation, "application/vnd.ll.animation", "application/x-metaverse-animation", "animation"), new TypeMapping(AssetType.Gesture, InventoryType.Gesture, "application/vnd.ll.gesture", "application/x-metaverse-gesture", "gesture"), new TypeMapping(AssetType.Simstate, InventoryType.Snapshot, "application/x-metaverse-simstate", "simstate"), - new TypeMapping(AssetType.FavoriteFolder, InventoryType.Unknown, "application/vnd.ll.favoritefolder", "favoritefolder"), new TypeMapping(AssetType.Link, InventoryType.Unknown, "application/vnd.ll.link", "link"), new TypeMapping(AssetType.LinkFolder, InventoryType.Unknown, "application/vnd.ll.linkfolder", "linkfolder"), - new TypeMapping(AssetType.CurrentOutfitFolder, InventoryType.Unknown, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"), - new TypeMapping(AssetType.OutfitFolder, InventoryType.Unknown, "application/vnd.ll.outfitfolder", "outfitfolder"), - new TypeMapping(AssetType.MyOutfitsFolder, InventoryType.Unknown, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"), - new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm") + new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm"), + + // The next few items are about inventory folders + new TypeMapping(AssetType.Folder, FolderType.None, "application/vnd.ll.folder", "folder"), + new TypeMapping(AssetType.Folder, FolderType.Root, "application/vnd.ll.rootfolder", "rootfolder"), + new TypeMapping(AssetType.Folder, FolderType.Trash, "application/vnd.ll.trashfolder", "trashfolder"), + new TypeMapping(AssetType.Folder, FolderType.Snapshot, "application/vnd.ll.snapshotfolder", "snapshotfolder"), + new TypeMapping(AssetType.Folder, FolderType.LostAndFound, "application/vnd.ll.lostandfoundfolder", "lostandfoundfolder"), + new TypeMapping(AssetType.Folder, FolderType.Favorites, "application/vnd.ll.favoritefolder", "favoritefolder"), + new TypeMapping(AssetType.Folder, FolderType.CurrentOutfit, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"), + new TypeMapping(AssetType.Folder, FolderType.Outfit, "application/vnd.ll.outfitfolder", "outfitfolder"), + new TypeMapping(AssetType.Folder, FolderType.MyOutfits, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"), + + // This next mappping is an asset to inventory item mapping. + // Note: LL stores folders as assets of type Folder = 8, and it has a corresponding InventoryType = 8 + // OpenSim doesn't store folders as assets, so this mapping should only be used when parsing things from the viewer to the server + new TypeMapping(AssetType.Folder, InventoryType.Folder, "application/vnd.ll.folder", "folder"), + + // OpenSim specific + new TypeMapping(OpenSimAssetType.Material, InventoryType.Unknown, "application/llsd+xml", "material") }; private static Dictionary asset2Content; private static Dictionary asset2Extension; - private static Dictionary inventory2Content; + private static Dictionary inventory2Content; private static Dictionary content2Asset; - private static Dictionary content2Inventory; + private static Dictionary content2Inventory; static SLUtil() { asset2Content = new Dictionary(); asset2Extension = new Dictionary(); - inventory2Content = new Dictionary(); + inventory2Content = new Dictionary(); content2Asset = new Dictionary(); - content2Inventory = new Dictionary(); + content2Inventory = new Dictionary(); foreach (TypeMapping mapping in MAPPINGS) { sbyte assetType = mapping.AssetTypeCode; if (!asset2Content.ContainsKey(assetType)) asset2Content.Add(assetType, mapping.ContentType); + if (!asset2Extension.ContainsKey(assetType)) asset2Extension.Add(assetType, mapping.Extension); + if (!inventory2Content.ContainsKey(mapping.InventoryType)) inventory2Content.Add(mapping.InventoryType, mapping.ContentType); + if (!content2Asset.ContainsKey(mapping.ContentType)) content2Asset.Add(mapping.ContentType, assetType); + if (!content2Inventory.ContainsKey(mapping.ContentType)) content2Inventory.Add(mapping.ContentType, mapping.InventoryType); @@ -194,8 +238,8 @@ namespace OpenSim.Framework public static string SLInvTypeToContentType(int invType) { string contentType; - if (!inventory2Content.TryGetValue((InventoryType)invType, out contentType)) - contentType = inventory2Content[InventoryType.Unknown]; + if (!inventory2Content.TryGetValue((sbyte)invType, out contentType)) + contentType = inventory2Content[(sbyte)InventoryType.Unknown]; return contentType; } @@ -209,9 +253,9 @@ namespace OpenSim.Framework public static sbyte ContentTypeToSLInvType(string contentType) { - InventoryType invType; + sbyte invType; if (!content2Inventory.TryGetValue(contentType, out invType)) - invType = InventoryType.Unknown; + invType = (sbyte)InventoryType.Unknown; return (sbyte)invType; } @@ -225,106 +269,270 @@ namespace OpenSim.Framework #endregion SL / file extension / content-type conversions - /// - /// Parse a notecard in Linden format to a string of ordinary text. - /// - /// - /// - public static string ParseNotecardToString(string rawInput) + private class NotecardReader { - string[] output = ParseNotecardToList(rawInput).ToArray(); + private string rawInput; + private int lineNumber; -// foreach (string line in output) -// m_log.DebugFormat("[PARSE NOTECARD]: ParseNotecardToString got line {0}", line); - - return string.Join("\n", output); + public int LineNumber + { + get + { + return lineNumber; + } + } + + public NotecardReader(string _rawInput) + { + rawInput = (string)_rawInput.Clone(); + lineNumber = 0; + } + + public string getLine() + { + if(rawInput.Length == 0) + { + throw new NotANotecardFormatException(lineNumber + 1); + } + + int pos = rawInput.IndexOf('\n'); + if(pos < 0) + { + pos = rawInput.Length; + } + + /* cut line from rest */ + ++lineNumber; + string line = rawInput.Substring(0, pos); + if (pos + 1 >= rawInput.Length) + { + rawInput = string.Empty; + } + else + { + rawInput = rawInput.Substring(pos + 1); + } + /* clean up line from double spaces and tabs */ + line = line.Replace("\t", " "); + while(line.IndexOf(" ") >= 0) + { + line = line.Replace(" ", " "); + } + return line.Replace("\r", "").Trim(); + } + + public string getBlock(int length) + { + /* cut line from rest */ + if(length > rawInput.Length) + { + throw new NotANotecardFormatException(lineNumber); + } + string line = rawInput.Substring(0, length); + rawInput = rawInput.Substring(length); + return line; + } } - - /// - /// Parse a notecard in Linden format to a list of ordinary lines. - /// - /// - /// - public static List ParseNotecardToList(string rawInput) + + public class NotANotecardFormatException : Exception + { + public int lineNumber; + public NotANotecardFormatException(int _lineNumber) + : base() + { + lineNumber = _lineNumber; + } + } + + private static void skipSection(NotecardReader reader) { - string[] input = rawInput.Replace("\r", "").Split('\n'); - int idx = 0; - int level = 0; - List output = new List(); - string[] words; + if (reader.getLine() != "{") + throw new NotANotecardFormatException(reader.LineNumber); - while (idx < input.Length) + string line; + while ((line = reader.getLine()) != "}") { - if (input[idx] == "{") + if(line.IndexOf('{')>=0) + { + throw new NotANotecardFormatException(reader.LineNumber); + } + } + } + + private static void skipInventoryItem(NotecardReader reader) + { + if (reader.getLine() != "{") + throw new NotANotecardFormatException(reader.LineNumber); + + string line; + while((line = reader.getLine()) != "}") + { + string[] data = line.Split(' '); + if(data.Length == 0) { - level++; - idx++; continue; } + if(data[0] == "permissions") + { + skipSection(reader); + } + else if(data[0] == "sale_info") + { + skipSection(reader); + } + else if (line.IndexOf('{') >= 0) + { + throw new NotANotecardFormatException(reader.LineNumber); + } + } + } + + private static void skipInventoryItems(NotecardReader reader) + { + if(reader.getLine() != "{") + { + throw new NotANotecardFormatException(reader.LineNumber); + } - if (input[idx]== "}") + string line; + while((line = reader.getLine()) != "}") + { + string[] data = line.Split(' '); + if(data.Length == 0) { - level--; - idx++; continue; } - switch (level) + if(data[0] == "inv_item") + { + skipInventoryItem(reader); + } + else if (line.IndexOf('{') >= 0) + { + throw new NotANotecardFormatException(reader.LineNumber); + } + + } + } + + private static void skipInventory(NotecardReader reader) + { + if (reader.getLine() != "{") + throw new NotANotecardFormatException(reader.LineNumber); + + string line; + while((line = reader.getLine()) != "}") + { + string[] data = line.Split(' '); + if(data[0] == "count") { - case 0: - words = input[idx].Split(' '); // Linden text ver - // Notecards are created *really* empty. Treat that as "no text" (just like after saving an empty notecard) - if (words.Length < 3) - return output; - - int version = int.Parse(words[3]); - if (version != 2) - return output; - break; - case 1: - words = input[idx].Split(' '); - if (words[0] == "LLEmbeddedItems") - break; - if (words[0] == "Text") + int count = Int32.Parse(data[1]); + for(int i = 0; i < count; ++i) { - int len = int.Parse(words[2]); - idx++; + skipInventoryItems(reader); + } + } + else if (line.IndexOf('{') >= 0) + { + throw new NotANotecardFormatException(reader.LineNumber); + } + } + } + + private static string readNotecardText(NotecardReader reader) + { + if (reader.getLine() != "{") + throw new NotANotecardFormatException(reader.LineNumber); + + string notecardString = string.Empty; + string line; + while((line = reader.getLine()) != "}") + { + string[] data = line.Split(' '); + if (data.Length == 0) + { + continue; + } - int count = -1; + if (data[0] == "LLEmbeddedItems") + { + skipInventory(reader); + } + else if(data[0] == "Text" && data.Length == 3) + { + int length = Int32.Parse(data[2]); + notecardString = reader.getBlock(length); + } + else if (line.IndexOf('{') >= 0) + { + throw new NotANotecardFormatException(reader.LineNumber); + } - while (count < len && idx < input.Length) - { - // int l = input[idx].Length; - string ln = input[idx]; + } + return notecardString; + } - int need = len-count-1; - if (ln.Length > need) - ln = ln.Substring(0, need); + private static string readNotecard(byte[] rawInput) + { + string rawIntermedInput = string.Empty; -// m_log.DebugFormat("[PARSE NOTECARD]: Adding line {0}", ln); - output.Add(ln); - count += ln.Length + 1; - idx++; - } + /* make up a Raw Encoding here */ + foreach(byte c in rawInput) + { + char d = (char)c; + rawIntermedInput += d; + } - return output; - } - break; - case 2: - words = input[idx].Split(' '); // count - if (words[0] == "count") - { - int c = int.Parse(words[1]); - if (c > 0) - return output; - break; - } - break; + NotecardReader reader = new NotecardReader(rawIntermedInput); + string line; + try + { + line = reader.getLine(); + } + catch(Exception) + { + return System.Text.Encoding.UTF8.GetString(rawInput); + } + string[] versioninfo = line.Split(' '); + if(versioninfo.Length < 3) + { + return System.Text.Encoding.UTF8.GetString(rawInput); + } + else if(versioninfo[0] != "Linden" || versioninfo[1] != "text") + { + return System.Text.Encoding.UTF8.GetString(rawInput); + } + else + { + /* now we actually decode the Encoding, before we needed it in raw */ + string o = readNotecardText(reader); + byte[] a = new byte[o.Length]; + for(int i = 0; i < o.Length; ++i) + { + a[i] = (byte)o[i]; } - idx++; + return System.Text.Encoding.UTF8.GetString(a); } - - return output; + } + + /// + /// Parse a notecard in Linden format to a string of ordinary text. + /// + /// + /// + public static string ParseNotecardToString(byte[] rawInput) + { + return readNotecard(rawInput); + } + + /// + /// Parse a notecard in Linden format to a list of ordinary lines. + /// + /// + /// + public static string[] ParseNotecardToArray(byte[] rawInput) + { + return readNotecard(rawInput).Replace("\r", "").Split('\n'); } } } diff --git a/OpenSim/Framework/Serialization/ArchiveConstants.cs b/OpenSim/Framework/Serialization/ArchiveConstants.cs index 0c12787..ab3c285 100644 --- a/OpenSim/Framework/Serialization/ArchiveConstants.cs +++ b/OpenSim/Framework/Serialization/ArchiveConstants.cs @@ -29,6 +29,7 @@ using System; using System.Collections.Generic; using System.Text; using OpenMetaverse; +using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType; namespace OpenSim.Framework.Serialization { @@ -114,20 +115,17 @@ namespace OpenSim.Framework.Serialization ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.ImageJPEG] = ASSET_EXTENSION_SEPARATOR + "image.jpg"; ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.ImageTGA] = ASSET_EXTENSION_SEPARATOR + "image.tga"; ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Landmark] = ASSET_EXTENSION_SEPARATOR + "landmark.txt"; - ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LostAndFoundFolder] = ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"; // Not sure if we'll ever see this ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LSLBytecode] = ASSET_EXTENSION_SEPARATOR + "bytecode.lso"; ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LSLText] = ASSET_EXTENSION_SEPARATOR + "script.lsl"; ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Mesh] = ASSET_EXTENSION_SEPARATOR + "mesh.llmesh"; ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Notecard] = ASSET_EXTENSION_SEPARATOR + "notecard.txt"; ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Object] = ASSET_EXTENSION_SEPARATOR + "object.xml"; - ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.RootFolder] = ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"; // Not sure if we'll ever see this ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Simstate] = ASSET_EXTENSION_SEPARATOR + "simstate.bin"; // Not sure if we'll ever see this - ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SnapshotFolder] = ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"; // Not sure if we'll ever see this ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Sound] = ASSET_EXTENSION_SEPARATOR + "sound.ogg"; ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV] = ASSET_EXTENSION_SEPARATOR + "sound.wav"; ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Texture] = ASSET_EXTENSION_SEPARATOR + "texture.jp2"; ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TextureTGA] = ASSET_EXTENSION_SEPARATOR + "texture.tga"; - ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TrashFolder] = ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"; // Not sure if we'll ever see this + ASSET_TYPE_TO_EXTENSION[(sbyte)OpenSimAssetType.Material] = ASSET_EXTENSION_SEPARATOR + "material.xml"; // Not sure if we'll ever see this EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "animation.bvh"] = (sbyte)AssetType.Animation; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bodypart.txt"] = (sbyte)AssetType.Bodypart; @@ -138,20 +136,17 @@ namespace OpenSim.Framework.Serialization EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.jpg"] = (sbyte)AssetType.ImageJPEG; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.tga"] = (sbyte)AssetType.ImageTGA; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "landmark.txt"] = (sbyte)AssetType.Landmark; - EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"] = (sbyte)AssetType.LostAndFoundFolder; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bytecode.lso"] = (sbyte)AssetType.LSLBytecode; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "script.lsl"] = (sbyte)AssetType.LSLText; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "mesh.llmesh"] = (sbyte)AssetType.Mesh; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "notecard.txt"] = (sbyte)AssetType.Notecard; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "object.xml"] = (sbyte)AssetType.Object; - EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"] = (sbyte)AssetType.RootFolder; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "simstate.bin"] = (sbyte)AssetType.Simstate; - EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"] = (sbyte)AssetType.SnapshotFolder; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.ogg"] = (sbyte)AssetType.Sound; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.wav"] = (sbyte)AssetType.SoundWAV; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.jp2"] = (sbyte)AssetType.Texture; EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.tga"] = (sbyte)AssetType.TextureTGA; - EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder; + EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "material.xml"] = (sbyte)OpenSimAssetType.Material; } public static string CreateOarLandDataPath(LandData ld) diff --git a/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs b/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs index c56f213..55640ac 100644 --- a/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs +++ b/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Reflection; using System.Xml; @@ -47,20 +48,20 @@ namespace OpenSim.Framework.Serialization.External /// Populate a node with data read from xml using a dictinoary of processors /// /// - /// /param> + /// /// /// true on successful, false if there were any processing failures public static bool ExecuteReadProcessors( - NodeType nodeToFill, Dictionary> processors, XmlTextReader xtr) + NodeType nodeToFill, Dictionary> processors, XmlReader xtr) { return ExecuteReadProcessors( nodeToFill, processors, xtr, - (o, name, e) - => m_log.DebugFormat( - "[ExternalRepresentationUtils]: Exception while parsing element {0}, continuing. Exception {1}{2}", - name, e.Message, e.StackTrace)); + (o, nodeName, e) => { + m_log.Debug(string.Format("[ExternalRepresentationUtils]: Error while parsing element {0} ", + nodeName), e); + }); } /// @@ -75,23 +76,27 @@ namespace OpenSim.Framework.Serialization.External /// true on successful, false if there were any processing failures public static bool ExecuteReadProcessors( NodeType nodeToFill, - Dictionary> processors, - XmlTextReader xtr, + Dictionary> processors, + XmlReader xtr, Action parseExceptionAction) { bool errors = false; + int numErrors = 0; + + Stopwatch timer = new Stopwatch(); + timer.Start(); string nodeName = string.Empty; while (xtr.NodeType != XmlNodeType.EndElement) { nodeName = xtr.Name; -// m_log.DebugFormat("[ExternalRepresentationUtils]: Processing: {0}", nodeName); + // m_log.DebugFormat("[ExternalRepresentationUtils]: Processing node: {0}", nodeName); - Action p = null; + Action p = null; if (processors.TryGetValue(xtr.Name, out p)) { -// m_log.DebugFormat("[ExternalRepresentationUtils]: Found {0} processor, nodeName); + // m_log.DebugFormat("[ExternalRepresentationUtils]: Found processor for {0}", nodeName); try { @@ -101,6 +106,18 @@ namespace OpenSim.Framework.Serialization.External { errors = true; parseExceptionAction(nodeToFill, nodeName, e); + + if (xtr.EOF) + { + m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to unexpected end of XML"); + break; + } + + if (++numErrors == 10) + { + m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to too many parsing errors"); + break; + } if (xtr.NodeType == XmlNodeType.EndElement) xtr.Read(); @@ -108,9 +125,16 @@ namespace OpenSim.Framework.Serialization.External } else { - // m_log.DebugFormat("[LandDataSerializer]: caught unknown element {0}", nodeName); + // m_log.DebugFormat("[ExternalRepresentationUtils]: found unknown element \"{0}\"", nodeName); xtr.ReadOuterXml(); // ignore } + + if (timer.Elapsed.TotalSeconds >= 60) + { + m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to timeout"); + errors = true; + break; + } } return errors; @@ -125,7 +149,8 @@ namespace OpenSim.Framework.Serialization.External /// The service for retrieving user account information /// The scope of the user account information (Grid ID) /// The SceneObjectPart represented in XML2 - public static string RewriteSOP(string xml, string homeURL, IUserAccountService userService, UUID scopeID) + [Obsolete("This method is deprecated. Use RewriteSOP instead.")] + public static string RewriteSOP_Old(string xml, string homeURL, IUserAccountService userService, UUID scopeID) { if (xml == string.Empty || homeURL == string.Empty || userService == null) return xml; @@ -161,7 +186,7 @@ namespace OpenSim.Framework.Serialization.External if (!hasCreatorData && creator != null) { XmlElement creatorData = doc.CreateElement("CreatorData"); - creatorData.InnerText = homeURL + ";" + creator.FirstName + " " + creator.LastName; + creatorData.InnerText = CalcCreatorData(homeURL, creator.FirstName + " " + creator.LastName); sop.AppendChild(creatorData); } } @@ -172,5 +197,215 @@ namespace OpenSim.Framework.Serialization.External return wr.ToString(); } } + + /// + /// Takes a XML representation of a SceneObjectPart and returns another XML representation + /// with creator data added to it. + /// + /// The SceneObjectPart represented in XML2 + /// An identifier for the component that's calling this function + /// The URL of the user agents service (home) for the creator + /// The service for retrieving user account information + /// The scope of the user account information (Grid ID) + /// The SceneObjectPart represented in XML2 + public static string RewriteSOP(string xmlData, string sceneName, string homeURL, IUserAccountService userService, UUID scopeID) + { + // Console.WriteLine("Input XML [{0}]", xmlData); + if (xmlData == string.Empty || homeURL == string.Empty || userService == null) + return xmlData; + + // Deal with bug + xmlData = ExternalRepresentationUtils.SanitizeXml(xmlData); + + using (StringWriter sw = new StringWriter()) + using (XmlTextWriter writer = new XmlTextWriter(sw)) + using (XmlTextReader wrappedReader = new XmlTextReader(xmlData, XmlNodeType.Element, null)) + using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment })) + { + TransformXml(reader, writer, sceneName, homeURL, userService, scopeID); + + // Console.WriteLine("Output: [{0}]", sw.ToString()); + + return sw.ToString(); + } + } + + protected static void TransformXml(XmlReader reader, XmlWriter writer, string sceneName, string homeURI, IUserAccountService userAccountService, UUID scopeID) + { + // m_log.DebugFormat("[HG ASSET MAPPER]: Transforming XML"); + + int sopDepth = -1; + UserAccount creator = null; + bool hasCreatorData = false; + + while (reader.Read()) + { + // Console.WriteLine("Depth: {0}, name {1}", reader.Depth, reader.Name); + + switch (reader.NodeType) + { + case XmlNodeType.Attribute: + // Console.WriteLine("FOUND ATTRIBUTE {0}", reader.Name); + writer.WriteAttributeString(reader.Name, reader.Value); + break; + + case XmlNodeType.CDATA: + writer.WriteCData(reader.Value); + break; + + case XmlNodeType.Comment: + writer.WriteComment(reader.Value); + break; + + case XmlNodeType.DocumentType: + writer.WriteDocType(reader.Name, reader.Value, null, null); + break; + + case XmlNodeType.Element: + // m_log.DebugFormat("Depth {0} at element {1}", reader.Depth, reader.Name); + + writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI); + + if (reader.HasAttributes) + { + while (reader.MoveToNextAttribute()) + writer.WriteAttributeString(reader.Name, reader.Value); + + reader.MoveToElement(); + } + + if (reader.LocalName == "SceneObjectPart") + { + if (sopDepth < 0) + { + sopDepth = reader.Depth; + // m_log.DebugFormat("[HG ASSET MAPPER]: Set sopDepth to {0}", sopDepth); + } + } + else + { + if (sopDepth >= 0 && reader.Depth == sopDepth + 1) + { + if (reader.Name == "CreatorID") + { + reader.Read(); + if (reader.NodeType == XmlNodeType.Element && reader.Name == "Guid" || reader.Name == "UUID") + { + reader.Read(); + + if (reader.NodeType == XmlNodeType.Text) + { + UUID uuid = UUID.Zero; + UUID.TryParse(reader.Value, out uuid); + creator = userAccountService.GetUserAccount(scopeID, uuid); + writer.WriteElementString("UUID", reader.Value); + reader.Read(); + } + else + { + // If we unexpected run across mixed content in this node, still carry on + // transforming the subtree (this replicates earlier behaviour). + TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID); + } + } + else + { + // If we unexpected run across mixed content in this node, still carry on + // transforming the subtree (this replicates earlier behaviour). + TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID); + } + } + else if (reader.Name == "CreatorData") + { + reader.Read(); + if (reader.NodeType == XmlNodeType.Text) + { + hasCreatorData = true; + writer.WriteString(reader.Value); + } + else + { + // If we unexpected run across mixed content in this node, still carry on + // transforming the subtree (this replicates earlier behaviour). + TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID); + } + } + } + } + + if (reader.IsEmptyElement) + { + // m_log.DebugFormat("[HG ASSET MAPPER]: Writing end for empty element {0}", reader.Name); + writer.WriteEndElement(); + } + + break; + + case XmlNodeType.EndElement: + // m_log.DebugFormat("Depth {0} at EndElement", reader.Depth); + if (sopDepth == reader.Depth) + { + if (!hasCreatorData && creator != null) + writer.WriteElementString(reader.Prefix, "CreatorData", reader.NamespaceURI, string.Format("{0};{1} {2}", homeURI, creator.FirstName, creator.LastName)); + + // m_log.DebugFormat("[HG ASSET MAPPER]: Reset sopDepth"); + sopDepth = -1; + creator = null; + hasCreatorData = false; + } + writer.WriteEndElement(); + break; + + case XmlNodeType.EntityReference: + writer.WriteEntityRef(reader.Name); + break; + + case XmlNodeType.ProcessingInstruction: + writer.WriteProcessingInstruction(reader.Name, reader.Value); + break; + + case XmlNodeType.Text: + writer.WriteString(reader.Value); + break; + + case XmlNodeType.XmlDeclaration: + // For various reasons, not all serializations have xml declarations (or consistent ones) + // and as it's embedded inside a byte stream we don't need it anyway, so ignore. + break; + + default: + m_log.WarnFormat( + "[HG ASSET MAPPER]: Unrecognized node {0} in asset XML transform in {1}", + reader.NodeType, sceneName); + break; + } + } + } + + public static string CalcCreatorData(string homeURL, string name) + { + return homeURL + ";" + name; + } + + internal static string CalcCreatorData(string homeURL, UUID uuid, string name) + { + return homeURL + "/" + uuid + ";" + name; + } + + /// + /// Sanitation for bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) + /// + /// + /// + public static string SanitizeXml(string xmlData) + { + string fixedData = xmlData; + if (fixedData != null) + // Loop, because it may contain multiple + while (fixedData.Contains("xmlns:xmlns:")) + fixedData = fixedData.Replace("xmlns:xmlns:", "xmlns:"); + return fixedData; + } + } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/Serialization/External/LandDataSerializer.cs b/OpenSim/Framework/Serialization/External/LandDataSerializer.cs index 709b516..e42d56f 100644 --- a/OpenSim/Framework/Serialization/External/LandDataSerializer.cs +++ b/OpenSim/Framework/Serialization/External/LandDataSerializer.cs @@ -44,11 +44,11 @@ namespace OpenSim.Framework.Serialization.External { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static Dictionary> m_ldProcessors - = new Dictionary>(); + private static Dictionary> m_ldProcessors + = new Dictionary>(); - private static Dictionary> m_laeProcessors - = new Dictionary>(); + private static Dictionary> m_laeProcessors + = new Dictionary>(); static LandDataSerializer() { @@ -134,7 +134,7 @@ namespace OpenSim.Framework.Serialization.External "AccessList", (lae, xtr) => lae.Flags = (AccessList)Convert.ToUInt32(xtr.ReadElementString("AccessList"))); } - public static void ProcessParcelAccessList(LandData ld, XmlTextReader xtr) + public static void ProcessParcelAccessList(LandData ld, XmlReader xtr) { if (!xtr.IsEmptyElement) { @@ -213,8 +213,13 @@ namespace OpenSim.Framework.Serialization.External xtw.WriteElementString("ClaimDate", Convert.ToString(landData.ClaimDate)); xtw.WriteElementString("ClaimPrice", Convert.ToString(landData.ClaimPrice)); xtw.WriteElementString("GlobalID", landData.GlobalID.ToString()); - xtw.WriteElementString("GroupID", landData.GroupID.ToString()); - xtw.WriteElementString("IsGroupOwned", Convert.ToString(landData.IsGroupOwned)); + + UUID groupID = options.ContainsKey("wipe-owners") ? UUID.Zero : landData.GroupID; + xtw.WriteElementString("GroupID", groupID.ToString()); + + bool isGroupOwned = options.ContainsKey("wipe-owners") ? false : landData.IsGroupOwned; + xtw.WriteElementString("IsGroupOwned", Convert.ToString(isGroupOwned)); + xtw.WriteElementString("Bitmap", Convert.ToBase64String(landData.Bitmap)); xtw.WriteElementString("Description", landData.Description); xtw.WriteElementString("Flags", Convert.ToString((uint)landData.Flags)); @@ -227,13 +232,8 @@ namespace OpenSim.Framework.Serialization.External xtw.WriteElementString("MediaURL", landData.MediaURL); xtw.WriteElementString("MusicURL", landData.MusicURL); - UUID ownerIdToWrite; - if (options != null && options.ContainsKey("wipe-owners")) - ownerIdToWrite = UUID.Zero; - else - ownerIdToWrite = landData.OwnerID; - - xtw.WriteElementString("OwnerID", ownerIdToWrite.ToString()); + UUID ownerID = options.ContainsKey("wipe-owners") ? UUID.Zero : landData.OwnerID; + xtw.WriteElementString("OwnerID", ownerID.ToString()); xtw.WriteStartElement("ParcelAccessList"); foreach (LandAccessEntry pal in landData.ParcelAccessList) diff --git a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs index 88f9581..994cede 100644 --- a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs +++ b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs @@ -46,8 +46,8 @@ namespace OpenSim.Framework.Serialization.External { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static Dictionary> m_InventoryItemXmlProcessors - = new Dictionary>(); + private static Dictionary> m_InventoryItemXmlProcessors + = new Dictionary>(); #region InventoryItemBase Processor initialization static UserInventoryItemSerializer() @@ -76,103 +76,103 @@ namespace OpenSim.Framework.Serialization.External #endregion #region InventoryItemBase Processors - private static void ProcessName(InventoryItemBase item, XmlTextReader reader) + private static void ProcessName(InventoryItemBase item, XmlReader reader) { item.Name = reader.ReadElementContentAsString("Name", String.Empty); } - private static void ProcessID(InventoryItemBase item, XmlTextReader reader) + private static void ProcessID(InventoryItemBase item, XmlReader reader) { item.ID = Util.ReadUUID(reader, "ID"); } - private static void ProcessInvType(InventoryItemBase item, XmlTextReader reader) + private static void ProcessInvType(InventoryItemBase item, XmlReader reader) { item.InvType = reader.ReadElementContentAsInt("InvType", String.Empty); } - private static void ProcessCreatorUUID(InventoryItemBase item, XmlTextReader reader) + private static void ProcessCreatorUUID(InventoryItemBase item, XmlReader reader) { item.CreatorId = reader.ReadElementContentAsString("CreatorUUID", String.Empty); } - private static void ProcessCreatorID(InventoryItemBase item, XmlTextReader reader) + private static void ProcessCreatorID(InventoryItemBase item, XmlReader reader) { // when it exists, this overrides the previous item.CreatorId = reader.ReadElementContentAsString("CreatorID", String.Empty); } - private static void ProcessCreationDate(InventoryItemBase item, XmlTextReader reader) + private static void ProcessCreationDate(InventoryItemBase item, XmlReader reader) { item.CreationDate = reader.ReadElementContentAsInt("CreationDate", String.Empty); } - private static void ProcessOwner(InventoryItemBase item, XmlTextReader reader) + private static void ProcessOwner(InventoryItemBase item, XmlReader reader) { item.Owner = Util.ReadUUID(reader, "Owner"); } - private static void ProcessDescription(InventoryItemBase item, XmlTextReader reader) + private static void ProcessDescription(InventoryItemBase item, XmlReader reader) { item.Description = reader.ReadElementContentAsString("Description", String.Empty); } - private static void ProcessAssetType(InventoryItemBase item, XmlTextReader reader) + private static void ProcessAssetType(InventoryItemBase item, XmlReader reader) { item.AssetType = reader.ReadElementContentAsInt("AssetType", String.Empty); } - private static void ProcessAssetID(InventoryItemBase item, XmlTextReader reader) + private static void ProcessAssetID(InventoryItemBase item, XmlReader reader) { item.AssetID = Util.ReadUUID(reader, "AssetID"); } - private static void ProcessSaleType(InventoryItemBase item, XmlTextReader reader) + private static void ProcessSaleType(InventoryItemBase item, XmlReader reader) { item.SaleType = (byte)reader.ReadElementContentAsInt("SaleType", String.Empty); } - private static void ProcessSalePrice(InventoryItemBase item, XmlTextReader reader) + private static void ProcessSalePrice(InventoryItemBase item, XmlReader reader) { item.SalePrice = reader.ReadElementContentAsInt("SalePrice", String.Empty); } - private static void ProcessBasePermissions(InventoryItemBase item, XmlTextReader reader) + private static void ProcessBasePermissions(InventoryItemBase item, XmlReader reader) { item.BasePermissions = (uint)reader.ReadElementContentAsInt("BasePermissions", String.Empty); } - private static void ProcessCurrentPermissions(InventoryItemBase item, XmlTextReader reader) + private static void ProcessCurrentPermissions(InventoryItemBase item, XmlReader reader) { item.CurrentPermissions = (uint)reader.ReadElementContentAsInt("CurrentPermissions", String.Empty); } - private static void ProcessEveryOnePermissions(InventoryItemBase item, XmlTextReader reader) + private static void ProcessEveryOnePermissions(InventoryItemBase item, XmlReader reader) { item.EveryOnePermissions = (uint)reader.ReadElementContentAsInt("EveryOnePermissions", String.Empty); } - private static void ProcessNextPermissions(InventoryItemBase item, XmlTextReader reader) + private static void ProcessNextPermissions(InventoryItemBase item, XmlReader reader) { item.NextPermissions = (uint)reader.ReadElementContentAsInt("NextPermissions", String.Empty); } - private static void ProcessFlags(InventoryItemBase item, XmlTextReader reader) + private static void ProcessFlags(InventoryItemBase item, XmlReader reader) { item.Flags = (uint)reader.ReadElementContentAsInt("Flags", String.Empty); } - private static void ProcessGroupID(InventoryItemBase item, XmlTextReader reader) + private static void ProcessGroupID(InventoryItemBase item, XmlReader reader) { item.GroupID = Util.ReadUUID(reader, "GroupID"); } - private static void ProcessGroupOwned(InventoryItemBase item, XmlTextReader reader) + private static void ProcessGroupOwned(InventoryItemBase item, XmlReader reader) { item.GroupOwned = Util.ReadBoolean(reader); } - private static void ProcessCreatorData(InventoryItemBase item, XmlTextReader reader) + private static void ProcessCreatorData(InventoryItemBase item, XmlReader reader) { item.CreatorData = reader.ReadElementContentAsString("CreatorData", String.Empty); } @@ -277,7 +277,7 @@ namespace OpenSim.Framework.Serialization.External writer.WriteStartElement("GroupOwned"); writer.WriteString(inventoryItem.GroupOwned.ToString()); writer.WriteEndElement(); - if (options.ContainsKey("creators") && inventoryItem.CreatorData != null && inventoryItem.CreatorData != string.Empty) + if (options.ContainsKey("creators") && !string.IsNullOrEmpty(inventoryItem.CreatorData)) writer.WriteElementString("CreatorData", inventoryItem.CreatorData); else if (options.ContainsKey("home")) { @@ -286,7 +286,8 @@ namespace OpenSim.Framework.Serialization.External UserAccount account = userAccountService.GetUserAccount(UUID.Zero, inventoryItem.CreatorIdAsUuid); if (account != null) { - writer.WriteElementString("CreatorData", (string)options["home"] + "/" + inventoryItem.CreatorIdAsUuid + ";" + account.FirstName + " " + account.LastName); + string creatorData = ExternalRepresentationUtils.CalcCreatorData((string)options["home"], inventoryItem.CreatorIdAsUuid, account.FirstName + " " + account.LastName); + writer.WriteElementString("CreatorData", creatorData); } writer.WriteElementString("CreatorID", inventoryItem.CreatorId); } diff --git a/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs b/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs index 11efa4b..acec20f 100644 --- a/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs b/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs index ea100ee..e81cb78 100644 --- a/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs +++ b/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs @@ -121,7 +121,8 @@ namespace OpenSim.Framework.Serialization.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - LandData ld = LandDataSerializer.Deserialize(LandDataSerializer.Serialize(this.land, null)); + Dictionary options = new Dictionary(); + LandData ld = LandDataSerializer.Deserialize(LandDataSerializer.Serialize(this.land, options)); Assert.That(ld, Is.Not.Null, "Deserialize(string) returned null"); // Assert.That(ld.AABBMax, Is.EqualTo(land.AABBMax)); // Assert.That(ld.AABBMin, Is.EqualTo(land.AABBMin)); diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index c0dc907..828a852 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -45,6 +45,7 @@ using OpenSim.Framework.Monitoring; using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; using Timer=System.Timers.Timer; +using Nini.Config; namespace OpenSim.Framework.Servers { @@ -56,9 +57,15 @@ namespace OpenSim.Framework.Servers private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// + /// Used by tests to suppress Environment.Exit(0) so that post-run operations are possible. + /// + public bool SuppressExit { get; set; } + + /// /// This will control a periodic log printout of the current 'show stats' (if they are active) for this /// server. /// + private int m_periodDiagnosticTimerMS = 60 * 60 * 1000; private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000); /// @@ -77,8 +84,6 @@ namespace OpenSim.Framework.Servers // Random uuid for private data m_osSecret = UUID.Random().ToString(); - m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics); - m_periodicDiagnosticsTimer.Enabled = true; } /// @@ -86,26 +91,34 @@ namespace OpenSim.Framework.Servers /// protected virtual void StartupSpecific() { - if (m_console == null) - return; - + StatsManager.SimExtraStats = new SimExtraStatsCollector(); RegisterCommonCommands(); - - m_console.Commands.AddCommand("General", false, "quit", - "quit", - "Quit the application", HandleQuit); + RegisterCommonComponents(Config); + + IConfig startupConfig = Config.Configs["Startup"]; + int logShowStatsSeconds = startupConfig.GetInt("LogShowStatsSeconds", m_periodDiagnosticTimerMS / 1000); + m_periodDiagnosticTimerMS = logShowStatsSeconds * 1000; + m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics); + if (m_periodDiagnosticTimerMS != 0) + { + m_periodicDiagnosticsTimer.Interval = m_periodDiagnosticTimerMS; + m_periodicDiagnosticsTimer.Enabled = true; + } + } + + protected override void ShutdownSpecific() + { + m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); - m_console.Commands.AddCommand("General", false, "shutdown", - "shutdown", - "Quit the application", HandleQuit); + RemovePIDFile(); + + base.ShutdownSpecific(); + + if (!SuppressExit) + Environment.Exit(0); } /// - /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing - /// - public virtual void ShutdownSpecific() {} - - /// /// Provides a list of help topics that are available. Overriding classes should append their topics to the /// information returned when the base method is called. /// @@ -133,45 +146,18 @@ namespace OpenSim.Framework.Servers /// Performs initialisation of the scene, such as loading configuration from disk. /// public virtual void Startup() - { - m_log.Info("[STARTUP]: Beginning startup processing"); - - m_log.Info("[STARTUP]: OpenSimulator version: " + m_version + Environment.NewLine); - // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and - // the clr version number doesn't match the project version number under Mono. - //m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine); - m_log.InfoFormat( - "[STARTUP]: Operating system version: {0}, .NET platform {1}, {2}-bit\n", - Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32"); - + { StartupSpecific(); TimeSpan timeTaken = DateTime.Now - m_startuptime; - m_log.InfoFormat( - "[STARTUP]: Non-script portion of startup took {0}m {1}s. PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED.", + MainConsole.Instance.OutputFormat( + "PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED. Non-script portion of startup took {0}m {1}s.", timeTaken.Minutes, timeTaken.Seconds); } - /// - /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing - /// - public virtual void Shutdown() + public string osSecret { - ShutdownSpecific(); - - m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); - RemovePIDFile(); - - Environment.Exit(0); - } - - private void HandleQuit(string module, string[] args) - { - Shutdown(); - } - - public string osSecret { // Secret uuid for the simulator get { return m_osSecret; } } diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index aa49343..f252bd5 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -46,6 +46,7 @@ using CoolHTTPListener = HttpServer.HttpListener; using HttpListener=System.Net.HttpListener; using LogPrio=HttpServer.LogPrio; using OpenSim.Framework.Monitoring; +using System.IO.Compression; namespace OpenSim.Framework.Servers.HttpServer { @@ -53,6 +54,16 @@ namespace OpenSim.Framework.Servers.HttpServer { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); + private static Encoding UTF8NoBOM = new System.Text.UTF8Encoding(false); + + /// + /// This is a pending websocket request before it got an sucessful upgrade response. + /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to + /// start the connection and optionally provide an origin authentication method. + /// + /// + /// + public delegate void WebSocketRequestDelegate(string servicepath, WebSocketHttpServerHandler handler); /// /// Gets or sets the debug level. @@ -71,12 +82,18 @@ namespace OpenSim.Framework.Servers.HttpServer /// public int RequestNumber { get; private set; } + /// + /// Statistic for holding number of requests processed. + /// + private Stat m_requestsProcessedStat; + private volatile int NotSocketErrors = 0; public volatile bool HTTPDRunning = false; // protected HttpListener m_httpListener; protected CoolHTTPListener m_httpListener2; protected Dictionary m_rpcHandlers = new Dictionary(); + protected Dictionary jsonRpcHandlers = new Dictionary(); protected Dictionary m_rpcHandlersKeepAlive = new Dictionary(); protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/ protected Dictionary m_llsdHandlers = new Dictionary(); @@ -86,6 +103,9 @@ namespace OpenSim.Framework.Servers.HttpServer protected Dictionary m_pollHandlers = new Dictionary(); + protected Dictionary m_WebSocketHandlers = + new Dictionary(); + protected uint m_port; protected uint m_sslport; protected bool m_ssl; @@ -95,7 +115,7 @@ namespace OpenSim.Framework.Servers.HttpServer protected IPAddress m_listenIPAddress = IPAddress.Any; - private PollServiceRequestManager m_PollServiceManager; + public PollServiceRequestManager PollServiceRequestManager { get; private set; } public uint SSLPort { @@ -169,6 +189,22 @@ namespace OpenSim.Framework.Servers.HttpServer } } + public void AddWebSocketHandler(string servicepath, WebSocketRequestDelegate handler) + { + lock (m_WebSocketHandlers) + { + if (!m_WebSocketHandlers.ContainsKey(servicepath)) + m_WebSocketHandlers.Add(servicepath, handler); + } + } + + public void RemoveWebSocketHandler(string servicepath) + { + lock (m_WebSocketHandlers) + if (m_WebSocketHandlers.ContainsKey(servicepath)) + m_WebSocketHandlers.Remove(servicepath); + } + public List GetStreamHandlerKeys() { lock (m_streamHandlers) @@ -217,6 +253,37 @@ namespace OpenSim.Framework.Servers.HttpServer return new List(m_rpcHandlers.Keys); } + // JsonRPC + public bool AddJsonRPCHandler(string method, JsonRPCMethod handler) + { + lock(jsonRpcHandlers) + { + jsonRpcHandlers.Add(method, handler); + } + return true; + } + + public JsonRPCMethod GetJsonRPCHandler(string method) + { + lock (jsonRpcHandlers) + { + if (jsonRpcHandlers.ContainsKey(method)) + { + return jsonRpcHandlers[method]; + } + else + { + return null; + } + } + } + + public List GetJsonRpcHandlerKeys() + { + lock (jsonRpcHandlers) + return new List(jsonRpcHandlers.Keys); + } + public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler) { //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName); @@ -309,7 +376,7 @@ namespace OpenSim.Framework.Servers.HttpServer return true; } - private void OnRequest(object source, RequestEventArgs args) + public void OnRequest(object source, RequestEventArgs args) { RequestNumber++; @@ -322,6 +389,8 @@ namespace OpenSim.Framework.Servers.HttpServer if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs)) { + psEvArgs.RequestsReceived++; + PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request); if (psEvArgs.Request != null) @@ -362,7 +431,7 @@ namespace OpenSim.Framework.Servers.HttpServer psEvArgs.Request(psreq.RequestID, keysvals); } - m_PollServiceManager.Enqueue(psreq); + PollServiceRequestManager.Enqueue(psreq); } else { @@ -375,11 +444,24 @@ namespace OpenSim.Framework.Servers.HttpServer } } - public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) + private void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) { OSHttpRequest req = new OSHttpRequest(context, request); + WebSocketRequestDelegate dWebSocketRequestDelegate = null; + lock (m_WebSocketHandlers) + { + if (m_WebSocketHandlers.ContainsKey(req.RawUrl)) + dWebSocketRequestDelegate = m_WebSocketHandlers[req.RawUrl]; + } + if (dWebSocketRequestDelegate != null) + { + dWebSocketRequestDelegate(req.Url.AbsolutePath, new WebSocketHttpServerHandler(req, context, 8192)); + return; + } + OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); - HandleRequest(req, resp); + resp.ReuseContext = true; + HandleRequest(req, resp); // !!!HACK ALERT!!! // There seems to be a bug in the underlying http code that makes subsequent requests @@ -410,7 +492,9 @@ namespace OpenSim.Framework.Servers.HttpServer { try { - SendHTML500(response); + byte[] buffer500 = SendHTML500(response); + response.OutputStream.Write(buffer500, 0, buffer500.Length); + response.Send(); } catch { @@ -468,7 +552,7 @@ namespace OpenSim.Framework.Servers.HttpServer LogIncomingToStreamHandler(request, requestHandler); response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. - + if (requestHandler is IStreamedRequestHandler) { IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; @@ -556,10 +640,18 @@ namespace OpenSim.Framework.Servers.HttpServer buffer = HandleLLSDRequests(request, response); break; + + case "application/json-rpc": + if (DebugLevel >= 3) + LogIncomingToContentTypeHandler(request); + + buffer = HandleJsonRpcRequests(request, response); + break; case "text/xml": case "application/xml": case "application/json": + default: //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); // Point of note.. the DoWeHaveA methods check for an EXACT path @@ -600,7 +692,24 @@ namespace OpenSim.Framework.Servers.HttpServer if (buffer != null) { - if (!response.SendChunked) + if (WebUtil.DebugLevel >= 5) + { + string output = System.Text.Encoding.UTF8.GetString(buffer); + + if (WebUtil.DebugLevel >= 6) + { + // Always truncate binary blobs. We don't have a ContentType, so detect them using the request name. + if ((requestHandler != null && requestHandler.Name == "GetMesh")) + { + if (output.Length > WebUtil.MaxRequestDiagLength) + output = output.Substring(0, WebUtil.MaxRequestDiagLength) + "..."; + } + } + + WebUtil.LogResponseDetail(RequestNumber, output); + } + + if (!response.SendChunked && response.ContentLength64 <= 0) response.ContentLength64 = buffer.LongLength; response.OutputStream.Write(buffer, 0, buffer.Length); @@ -630,12 +739,20 @@ namespace OpenSim.Framework.Servers.HttpServer } catch (IOException e) { - m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e); + m_log.Error("[BASE HTTP SERVER]: HandleRequest() threw exception ", e); } catch (Exception e) { - m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e); - SendHTML500(response); + m_log.Error("[BASE HTTP SERVER]: HandleRequest() threw exception ", e); + try + { + byte[] buffer500 = SendHTML500(response); + response.OutputStream.Write(buffer500, 0, buffer500.Length); + response.Send(); + } + catch + { + } } finally { @@ -645,7 +762,7 @@ namespace OpenSim.Framework.Servers.HttpServer if (tickdiff > 3000 && requestHandler != null && requestHandler.Name != "GetTexture") { m_log.InfoFormat( - "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms", + "[LOGHTTP] Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms", RequestNumber, requestMethod, uriString, @@ -657,7 +774,7 @@ namespace OpenSim.Framework.Servers.HttpServer else if (DebugLevel >= 4) { m_log.DebugFormat( - "[BASE HTTP SERVER]: HTTP IN {0} :{1} took {2}ms", + "[LOGHTTP] HTTP IN {0} :{1} took {2}ms", RequestNumber, Port, tickdiff); @@ -668,7 +785,7 @@ namespace OpenSim.Framework.Servers.HttpServer private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler) { m_log.DebugFormat( - "[BASE HTTP SERVER]: HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}", + "[LOGHTTP] HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}", RequestNumber, Port, request.HttpMethod, @@ -684,10 +801,10 @@ namespace OpenSim.Framework.Servers.HttpServer private void LogIncomingToContentTypeHandler(OSHttpRequest request) { m_log.DebugFormat( - "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", + "[LOGHTTP] HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", RequestNumber, Port, - (request.ContentType == null || request.ContentType == "") ? "not set" : request.ContentType, + string.IsNullOrEmpty(request.ContentType) ? "not set" : request.ContentType, request.HttpMethod, request.Url.PathAndQuery, request.RemoteIPEndPoint); @@ -699,7 +816,7 @@ namespace OpenSim.Framework.Servers.HttpServer private void LogIncomingToXmlRpcHandler(OSHttpRequest request) { m_log.DebugFormat( - "[BASE HTTP SERVER]: HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}", + "[LOGHTTP] HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}", RequestNumber, Port, request.HttpMethod, @@ -712,29 +829,49 @@ namespace OpenSim.Framework.Servers.HttpServer private void LogIncomingInDetail(OSHttpRequest request) { - using (StreamReader reader = new StreamReader(Util.Copy(request.InputStream), Encoding.UTF8)) - { - string output; + if (request.ContentType == "application/octet-stream") + return; // never log these; they're just binary data - if (DebugLevel == 5) + Stream inputStream = Util.Copy(request.InputStream); + Stream innerStream = null; + try + { + if ((request.Headers["Content-Encoding"] == "gzip") || (request.Headers["X-Content-Encoding"] == "gzip")) { - const int sampleLength = 80; - char[] sampleChars = new char[sampleLength + 3]; - reader.Read(sampleChars, 0, sampleLength); - sampleChars[80] = '.'; - sampleChars[81] = '.'; - sampleChars[82] = '.'; - output = new string(sampleChars); + innerStream = inputStream; + inputStream = new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress); } - else + + using (StreamReader reader = new StreamReader(inputStream, Encoding.UTF8)) { - output = reader.ReadToEnd(); - } + string output; - m_log.DebugFormat("[BASE HTTP SERVER]: {0}", output.Replace("\n", @"\n")); + if (DebugLevel == 5) + { + char[] chars = new char[WebUtil.MaxRequestDiagLength + 1]; // +1 so we know to add "..." only if needed + int len = reader.Read(chars, 0, WebUtil.MaxRequestDiagLength + 1); + output = new string(chars, 0, Math.Min(len, WebUtil.MaxRequestDiagLength)); + if (len > WebUtil.MaxRequestDiagLength) + output += "..."; + } + else + { + output = reader.ReadToEnd(); + } + + m_log.DebugFormat("[LOGHTTP] {0}", Util.BinaryToASCII(output)); + } + } + finally + { + if (innerStream != null) + innerStream.Dispose(); + inputStream.Dispose(); } } + private readonly string HANDLER_SEPARATORS = "/?&#-"; + private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler) { string bestMatch = null; @@ -743,7 +880,8 @@ namespace OpenSim.Framework.Servers.HttpServer { foreach (string pattern in m_streamHandlers.Keys) { - if (handlerKey.StartsWith(pattern)) + if ((handlerKey == pattern) + || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0))) { if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) { @@ -773,7 +911,8 @@ namespace OpenSim.Framework.Servers.HttpServer { foreach (string pattern in m_pollHandlers.Keys) { - if (handlerKey.StartsWith(pattern)) + if ((handlerKey == pattern) + || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0))) { if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) { @@ -805,7 +944,8 @@ namespace OpenSim.Framework.Servers.HttpServer { foreach (string pattern in m_HTTPHandlers.Keys) { - if (handlerKey.StartsWith(pattern)) + if ((handlerKey == pattern) + || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0))) { if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) { @@ -854,16 +994,33 @@ namespace OpenSim.Framework.Servers.HttpServer /// private byte[] HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response) { + String requestBody; + Stream requestStream = request.InputStream; + Stream innerStream = null; + try + { + if ((request.Headers["Content-Encoding"] == "gzip") || (request.Headers["X-Content-Encoding"] == "gzip")) + { + innerStream = requestStream; + requestStream = new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress); + } - Encoding encoding = Encoding.UTF8; - StreamReader reader = new StreamReader(requestStream, encoding); + using (StreamReader reader = new StreamReader(requestStream, Encoding.UTF8)) + { + requestBody = reader.ReadToEnd(); + } + } + finally + { + if (innerStream != null) + innerStream.Dispose(); + requestStream.Dispose(); + } - string requestBody = reader.ReadToEnd(); - reader.Close(); - requestStream.Close(); //m_log.Debug(requestBody); requestBody = requestBody.Replace("", ""); + string responseString = String.Empty; XmlRpcRequest xmlRprcRequest = null; @@ -958,7 +1115,19 @@ namespace OpenSim.Framework.Servers.HttpServer } response.ContentType = "text/xml"; - responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); + using (MemoryStream outs = new MemoryStream()) + using (XmlTextWriter writer = new XmlTextWriter(outs, UTF8NoBOM)) + { + writer.Formatting = Formatting.None; + XmlRpcResponseSerializer.Singleton.Serialize(writer, xmlRpcResponse); + writer.Flush(); + outs.Flush(); + outs.Position = 0; + using (StreamReader sr = new StreamReader(outs)) + { + responseString = sr.ReadToEnd(); + } + } } else { @@ -985,6 +1154,93 @@ namespace OpenSim.Framework.Servers.HttpServer return buffer; } + // JsonRpc (v2.0 only) + // Batch requests not yet supported + private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response) + { + Stream requestStream = request.InputStream; + JsonRpcResponse jsonRpcResponse = new JsonRpcResponse(); + OSDMap jsonRpcRequest = null; + + try + { + jsonRpcRequest = (OSDMap)OSDParser.DeserializeJson(requestStream); + } + catch (LitJson.JsonException e) + { + jsonRpcResponse.Error.Code = ErrorCode.InternalError; + jsonRpcResponse.Error.Message = e.Message; + } + + requestStream.Close(); + + if (jsonRpcRequest != null) + { + if (jsonRpcRequest.ContainsKey("jsonrpc") || jsonRpcRequest["jsonrpc"].AsString() == "2.0") + { + jsonRpcResponse.JsonRpc = "2.0"; + + // If we have no id, then it's a "notification" + if (jsonRpcRequest.ContainsKey("id")) + { + jsonRpcResponse.Id = jsonRpcRequest["id"].AsString(); + } + + string methodname = jsonRpcRequest["method"]; + JsonRPCMethod method; + + if (jsonRpcHandlers.ContainsKey(methodname)) + { + lock(jsonRpcHandlers) + { + jsonRpcHandlers.TryGetValue(methodname, out method); + } + bool res = false; + try + { + res = method(jsonRpcRequest, ref jsonRpcResponse); + if(!res) + { + // The handler sent back an unspecified error + if(jsonRpcResponse.Error.Code == 0) + { + jsonRpcResponse.Error.Code = ErrorCode.InternalError; + } + } + } + catch (Exception e) + { + string ErrorMessage = string.Format("[BASE HTTP SERVER]: Json-Rpc Handler Error method {0} - {1}", methodname, e.Message); + m_log.Error(ErrorMessage); + jsonRpcResponse.Error.Code = ErrorCode.InternalError; + jsonRpcResponse.Error.Message = ErrorMessage; + } + } + else // Error no hanlder defined for requested method + { + jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest; + jsonRpcResponse.Error.Message = string.Format ("No handler defined for {0}", methodname); + } + } + else // not json-rpc 2.0 could be v1 + { + jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest; + jsonRpcResponse.Error.Message = "Must be valid json-rpc 2.0 see: http://www.jsonrpc.org/specification"; + + if (jsonRpcRequest.ContainsKey("id")) + jsonRpcResponse.Id = jsonRpcRequest["id"].AsString(); + } + } + + response.KeepAlive = true; + string responseData = string.Empty; + + responseData = jsonRpcResponse.Serialize(); + + byte[] buffer = Encoding.UTF8.GetBytes(responseData); + return buffer; + } + private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) { //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); @@ -1575,16 +1831,24 @@ namespace OpenSim.Framework.Servers.HttpServer response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; - + + return buffer; } public void Start() { - StartHTTP(); + Start(true); } - private void StartHTTP() + /// + /// Start the http server + /// + /// + /// If true then poll responses are performed asynchronsly. + /// Option exists to allow regression tests to perform processing synchronously. + /// + public void Start(bool performPollResponsesAsync) { m_log.InfoFormat( "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port); @@ -1622,8 +1886,9 @@ namespace OpenSim.Framework.Servers.HttpServer m_httpListener2.Start(64); // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events - m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000); - m_PollServiceManager.Start(); + PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 3, 25000); + PollServiceRequestManager.Start(); + HTTPDRunning = true; //HttpListenerContext context; @@ -1642,6 +1907,21 @@ namespace OpenSim.Framework.Servers.HttpServer // useful without inbound HTTP. throw e; } + + m_requestsProcessedStat + = new Stat( + "HTTPRequestsServed", + "Number of inbound HTTP requests processed", + "", + "requests", + "httpserver", + Port.ToString(), + StatType.Pull, + MeasuresOfInterest.AverageChangeOverTime, + stat => stat.Value = RequestNumber, + StatVerbosity.Debug); + + StatsManager.RegisterStat(m_requestsProcessedStat); } public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) @@ -1672,9 +1952,12 @@ namespace OpenSim.Framework.Servers.HttpServer public void Stop() { HTTPDRunning = false; + + StatsManager.DeregisterStat(m_requestsProcessedStat); + try { - m_PollServiceManager.Stop(); + PollServiceRequestManager.Stop(); m_httpListener2.ExceptionThrown -= httpServerException; //m_httpListener2.DisconnectHandler = null; @@ -1741,6 +2024,12 @@ namespace OpenSim.Framework.Servers.HttpServer m_rpcHandlers.Remove(method); } + public void RemoveJsonRPCHandler(string method) + { + lock(jsonRpcHandlers) + jsonRpcHandlers.Remove(method); + } + public bool RemoveLLSDHandler(string path, LLSDMethod handler) { lock (m_llsdHandlers) diff --git a/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs new file mode 100644 index 0000000..72b3065 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs @@ -0,0 +1,60 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.IO; + +namespace OpenSim.Framework.Servers.HttpServer +{ + /// + /// Base handler for writing to an output stream + /// + /// + /// Inheriting classes should override ProcessRequest() rather than Handle() + /// + public abstract class BaseOutputStreamHandler : BaseRequestHandler, IRequestHandler + { + protected BaseOutputStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} + + protected BaseOutputStreamHandler(string httpMethod, string path, string name, string description) + : base(httpMethod, path, name, description) {} + + public virtual void Handle( + string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + RequestsReceived++; + + ProcessRequest(path, request, response, httpRequest, httpResponse); + + RequestsHandled++; + } + + protected virtual void ProcessRequest( + string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs index ae7aaf2..d4a1ec3 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs @@ -26,11 +26,16 @@ */ using System; +using OpenSim.Framework.Monitoring; namespace OpenSim.Framework.Servers.HttpServer { public abstract class BaseRequestHandler { + public int RequestsReceived { get; protected set; } + + public int RequestsHandled { get; protected set; } + public virtual string ContentType { get { return "application/xml"; } @@ -57,6 +62,24 @@ namespace OpenSim.Framework.Servers.HttpServer Description = description; m_httpMethod = httpMethod; m_path = path; + + // FIXME: A very temporary measure to stop the simulator stats being overwhelmed with user CAPS info. + // Needs to be fixed properly in stats display + if (!path.StartsWith("/CAPS/")) + { + StatsManager.RegisterStat( + new Stat( + "requests", + "requests", + "Number of requests received by this service endpoint", + "requests", + "service", + string.Format("{0}:{1}", httpMethod, path), + StatType.Pull, + MeasuresOfInterest.AverageChangeOverTime, + s => s.Value = RequestsReceived, + StatVerbosity.Debug)); + } } public virtual string Path diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs index 6342983..41aa19b 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs @@ -26,17 +26,60 @@ */ using System.IO; +using System.Net; +using OpenSim.Framework.ServiceAuth; namespace OpenSim.Framework.Servers.HttpServer { + /// + /// Base streamed request handler. + /// + /// + /// Inheriting classes should override ProcessRequest() rather than Handle() + /// public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler { - public abstract byte[] Handle(string path, Stream request, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse); + protected IServiceAuth m_Auth; - protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} + protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) { } protected BaseStreamHandler(string httpMethod, string path, string name, string description) : base(httpMethod, path, name, description) {} + + protected BaseStreamHandler(string httpMethod, string path, IServiceAuth auth) + : base(httpMethod, path, null, null) + { + m_Auth = auth; + } + + public virtual byte[] Handle( + string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + RequestsReceived++; + + if (m_Auth != null) + { + HttpStatusCode statusCode; + + if (!m_Auth.Authenticate(httpRequest.Headers, httpResponse.AddHeader, out statusCode)) + { + httpResponse.StatusCode = (int)statusCode; + httpResponse.ContentType = "text/plain"; + return new byte[0]; + } + } + + byte[] result = ProcessRequest(path, request, httpRequest, httpResponse); + + RequestsHandled++; + + return result; + } + + protected virtual byte[] ProcessRequest( + string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + return null; + } } } \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs new file mode 100644 index 0000000..1b88545 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs @@ -0,0 +1,107 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using OpenSim.Framework; +using System.IO; + +namespace OpenSim.Framework.Servers.HttpServer +{ + /// + /// BaseStreamHandlerBasicDOSProtector Base streamed request handler. + /// + /// + /// Inheriting classes should override ProcessRequest() rather than Handle() + /// + public abstract class BaseStreamHandlerBasicDOSProtector : BaseRequestHandler, IStreamedRequestHandler + { + + private readonly BasicDosProtectorOptions _options; + private readonly BasicDOSProtector _dosProtector; + + protected BaseStreamHandlerBasicDOSProtector(string httpMethod, string path, BasicDosProtectorOptions options) : this(httpMethod, path, null, null, options) {} + + protected BaseStreamHandlerBasicDOSProtector(string httpMethod, string path, string name, string description, BasicDosProtectorOptions options) + : base(httpMethod, path, name, description) + { + _options = options; + _dosProtector = new BasicDOSProtector(_options); + } + + public virtual byte[] Handle( + string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + byte[] result; + RequestsReceived++; + string clientstring = GetClientString(httpRequest); + string endpoint = GetRemoteAddr(httpRequest); + if (_dosProtector.Process(clientstring, endpoint)) + result = ProcessRequest(path, request, httpRequest, httpResponse); + else + result = ThrottledRequest(path, request, httpRequest, httpResponse); + if (_options.MaxConcurrentSessions > 0) + _dosProtector.ProcessEnd(clientstring, endpoint); + + RequestsHandled++; + + return result; + } + + protected virtual byte[] ProcessRequest( + string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + return null; + } + + protected virtual byte[] ThrottledRequest( + string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + return new byte[0]; + } + + + private string GetRemoteAddr(IOSHttpRequest httpRequest) + { + string remoteaddr = string.Empty; + if (httpRequest.Headers["remote_addr"] != null) + remoteaddr = httpRequest.Headers["remote_addr"]; + + return remoteaddr; + } + + private string GetClientString(IOSHttpRequest httpRequest) + { + string clientstring = string.Empty; + + if (_options.AllowXForwardedFor && httpRequest.Headers["x-forwarded-for"] != null) + clientstring = httpRequest.Headers["x-forwarded-for"]; + else + clientstring = GetRemoteAddr(httpRequest); + + return clientstring; + + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs index b94bfb4..1b03f54 100644 --- a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs @@ -45,7 +45,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_method = binaryMethod; } - public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { byte[] data = ReadFully(request); string param = GetParam(path); diff --git a/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs new file mode 100644 index 0000000..cd4b8ff --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs @@ -0,0 +1,119 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Collections; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public class GenericHTTPDOSProtector + { + private readonly GenericHTTPMethod _normalMethod; + private readonly GenericHTTPMethod _throttledMethod; + + private readonly BasicDosProtectorOptions _options; + private readonly BasicDOSProtector _dosProtector; + + public GenericHTTPDOSProtector(GenericHTTPMethod normalMethod, GenericHTTPMethod throttledMethod, BasicDosProtectorOptions options) + { + _normalMethod = normalMethod; + _throttledMethod = throttledMethod; + + _options = options; + _dosProtector = new BasicDOSProtector(_options); + } + public Hashtable Process(Hashtable request) + { + Hashtable process = null; + string clientstring= GetClientString(request); + string endpoint = GetRemoteAddr(request); + if (_dosProtector.Process(clientstring, endpoint)) + process = _normalMethod(request); + else + process = _throttledMethod(request); + + if (_options.MaxConcurrentSessions>0) + _dosProtector.ProcessEnd(clientstring, endpoint); + + return process; + } + + private string GetRemoteAddr(Hashtable request) + { + string remoteaddr = ""; + if (!request.ContainsKey("headers")) + return remoteaddr; + Hashtable requestinfo = (Hashtable)request["headers"]; + if (!requestinfo.ContainsKey("remote_addr")) + return remoteaddr; + object remote_addrobj = requestinfo["remote_addr"]; + if (remote_addrobj != null) + { + if (!string.IsNullOrEmpty(remote_addrobj.ToString())) + { + remoteaddr = remote_addrobj.ToString(); + } + + } + return remoteaddr; + } + + private string GetClientString(Hashtable request) + { + string clientstring = ""; + if (!request.ContainsKey("headers")) + return clientstring; + + Hashtable requestinfo = (Hashtable)request["headers"]; + if (_options.AllowXForwardedFor && requestinfo.ContainsKey("x-forwarded-for")) + { + object str = requestinfo["x-forwarded-for"]; + if (str != null) + { + if (!string.IsNullOrEmpty(str.ToString())) + { + return str.ToString(); + } + } + } + if (!requestinfo.ContainsKey("remote_addr")) + return clientstring; + + object remote_addrobj = requestinfo["remote_addr"]; + if (remote_addrobj != null) + { + if (!string.IsNullOrEmpty(remote_addrobj.ToString())) + { + clientstring = remote_addrobj.ToString(); + } + } + + return clientstring; + + } + + } +} 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 bool AddXmlRPCHandler(string method, XmlRpcMethod handler); bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive); + bool AddJsonRPCHandler(string method, JsonRPCMethod handler); + + /// + /// Websocket HTTP server handlers. + /// + /// + /// + void AddWebSocketHandler(string servicepath, BaseHttpServer.WebSocketRequestDelegate handler); + + + void RemoveWebSocketHandler(string servicepath); + /// /// Gets the XML RPC handler for given method name /// @@ -128,6 +140,8 @@ namespace OpenSim.Framework.Servers.HttpServer void RemoveStreamHandler(string httpMethod, string path); void RemoveXmlRPCHandler(string method); + + void RemoveJsonRPCHandler(string method); string GetHTTP404(string host); diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs index cb5cce5..b8541cb 100644 --- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs @@ -32,7 +32,6 @@ namespace OpenSim.Framework.Servers.HttpServer { public interface IRequestHandler { - /// /// Name for this handler. /// @@ -59,6 +58,19 @@ namespace OpenSim.Framework.Servers.HttpServer // Return path string Path { get; } + + /// + /// Number of requests received by this handler + /// + int RequestsReceived { get; } + + /// + /// Number of requests handled. + /// + /// + /// Should be equal to RequestsReceived unless requested are being handled slowly or there is deadlock. + /// + int RequestsHandled { get; } } public interface IStreamedRequestHandler : IRequestHandler @@ -69,7 +81,6 @@ namespace OpenSim.Framework.Servers.HttpServer public interface IStreamHandler : IRequestHandler { - // Handle request stream, return byte array void Handle(string path, Stream request, Stream response, IOSHttpRequest httpReqbuest, IOSHttpResponse httpResponse); } diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs new file mode 100644 index 0000000..5bab508 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs @@ -0,0 +1,34 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Net; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public delegate bool JsonRPCMethod(OSDMap jsonRpcRequest, ref JsonRpcResponse response); +} diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs new file mode 100644 index 0000000..2fe1a7d --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs @@ -0,0 +1,190 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Text; +using System.IO; +using OpenMetaverse.StructuredData; +using OpenMetaverse; +using log4net; + +namespace OpenSim.Framework.Servers.HttpServer +{ + /// + /// Json rpc request manager. + /// + public class JsonRpcRequestManager + { + static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public JsonRpcRequestManager() + { + } + + /// + /// Sends json-rpc request with a serializable type. + /// + /// + /// OSD Map. + /// + /// + /// Serializable type . + /// + /// + /// Json-rpc method to call. + /// + /// + /// URI of json-rpc service. + /// + /// + /// Id for our call. + /// + public bool JsonRpcRequest(ref object parameters, string method, string uri, string jsonId) + { + if (jsonId == null) + throw new ArgumentNullException("jsonId"); + if (uri == null) + throw new ArgumentNullException("uri"); + if (method == null) + throw new ArgumentNullException("method"); + if (parameters == null) + throw new ArgumentNullException("parameters"); + + OSDMap request = new OSDMap(); + request.Add("jsonrpc", OSD.FromString("2.0")); + request.Add("id", OSD.FromString(jsonId)); + request.Add("method", OSD.FromString(method)); + request.Add("params", OSD.SerializeMembers(parameters)); + + OSDMap response; + try + { + response = WebUtil.PostToService(uri, request, 10000, true); + } + catch (Exception e) + { + m_log.Debug(string.Format("JsonRpc request '{0}' to {1} failed", method, uri), e); + return false; + } + + if (!response.ContainsKey("_Result")) + { + m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an invalid response: {2}", + method, uri, OSDParser.SerializeJsonString(response)); + return false; + } + response = (OSDMap)response["_Result"]; + + OSD data; + + if (response.ContainsKey("error")) + { + data = response["error"]; + m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an error: {2}", + method, uri, OSDParser.SerializeJsonString(data)); + return false; + } + + if (!response.ContainsKey("result")) + { + m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an invalid response: {2}", + method, uri, OSDParser.SerializeJsonString(response)); + return false; + } + + data = response["result"]; + OSD.DeserializeMembers(ref parameters, (OSDMap)data); + + return true; + } + + /// + /// Sends json-rpc request with OSD parameter. + /// + /// + /// The rpc request. + /// + /// + /// data - incoming as parameters, outgoing as result/error + /// + /// + /// Json-rpc method to call. + /// + /// + /// URI of json-rpc service. + /// + /// + /// If set to true json identifier. + /// + public bool JsonRpcRequest(ref OSD data, string method, string uri, string jsonId) + { + if (string.IsNullOrEmpty(jsonId)) + jsonId = UUID.Random().ToString(); + + OSDMap request = new OSDMap(); + request.Add("jsonrpc", OSD.FromString("2.0")); + request.Add("id", OSD.FromString(jsonId)); + request.Add("method", OSD.FromString(method)); + request.Add("params", data); + + OSDMap response; + try + { + response = WebUtil.PostToService(uri, request, 10000, true); + } + catch (Exception e) + { + m_log.Debug(string.Format("JsonRpc request '{0}' to {1} failed", method, uri), e); + return false; + } + + if (!response.ContainsKey("_Result")) + { + m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an invalid response: {2}", + method, uri, OSDParser.SerializeJsonString(response)); + return false; + } + response = (OSDMap)response["_Result"]; + + if (response.ContainsKey("error")) + { + data = response["error"]; + m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an error: {2}", + method, uri, OSDParser.SerializeJsonString(data)); + return false; + } + + data = response; + + return true; + } + + } +} 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 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Net; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public sealed class ErrorCode + { + private ErrorCode() {} + + public const int ParseError = -32700; + public const int InvalidRequest = -32600; + public const int MethodNotFound = -32601; + public const int InvalidParams = -32602; + public const int InternalError = -32604; + + } + + public class JsonRpcError + { + internal OSDMap Error = new OSDMap(); + + public int Code + { + get + { + if (Error.ContainsKey("code")) + return Error["code"].AsInteger(); + else + return 0; + } + set + { + Error["code"] = OSD.FromInteger(value); + } + } + + public string Message + { + get + { + if (Error.ContainsKey("message")) + return Error["message"].AsString(); + else + return null; + } + set + { + Error["message"] = OSD.FromString(value); + } + } + + public OSD Data + { + get; set; + } + } + + public class JsonRpcResponse + { + public string JsonRpc + { + get + { + return Reply["jsonrpc"].AsString(); + } + set + { + Reply["jsonrpc"] = OSD.FromString(value); + } + } + + public string Id + { + get + { + return Reply["id"].AsString(); + } + set + { + Reply["id"] = OSD.FromString(value); + } + } + + public OSD Result + { + get; set; + } + + public JsonRpcError Error + { + get; set; + } + + public OSDMap Reply = new OSDMap(); + + public JsonRpcResponse() + { + Error = new JsonRpcError(); + } + + public string Serialize() + { + if (Result != null) + Reply["result"] = Result; + + if (Error.Code != 0) + { + Reply["error"] = (OSD)Error.Error; + } + + string result = string.Empty; + try + { + result = OSDParser.SerializeJsonString(Reply); + } + catch + { + + } + return result; + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs index 3171759..05ec6dc 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs @@ -182,11 +182,22 @@ namespace OpenSim.Framework.Servers.HttpServer _context = context; if (null != req.Headers["content-encoding"]) - _contentEncoding = Encoding.GetEncoding(_request.Headers["content-encoding"]); + { + try + { + _contentEncoding = Encoding.GetEncoding(_request.Headers["content-encoding"]); + } + catch (Exception) + { + // ignore + } + } + if (null != req.Headers["content-type"]) _contentType = _request.Headers["content-type"]; if (null != req.Headers["user-agent"]) _userAgent = req.Headers["user-agent"]; + if (null != req.Headers["remote_addr"]) { try diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs index 77cfb7e..bdea278 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs @@ -70,9 +70,9 @@ namespace OpenSim.Framework.Servers.HttpServer _id = id; _engine = new Thread(new ThreadStart(Engine)); - _engine.Name = EngineID; _engine.IsBackground = true; _engine.Start(); + _engine.Name = string.Format ("Engine:{0}",EngineID); ThreadTracker.Add(_engine); } @@ -91,9 +91,9 @@ namespace OpenSim.Framework.Servers.HttpServer public void Start() { _engine = new Thread(new ThreadStart(Engine)); - _engine.Name = EngineID; _engine.IsBackground = true; _engine.Start(); + _engine.Name = string.Format ("Engine:{0}",EngineID); ThreadTracker.Add(_engine); } diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs index 84aa31b..cd62842 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs @@ -150,9 +150,9 @@ namespace OpenSim.Framework.Servers.HttpServer public void Start() { _engine = new Thread(new ThreadStart(Engine)); - _engine.Name = _engineId; _engine.IsBackground = true; _engine.Start(); + _engine.Name = string.Format ("Engine:{0}",_engineId); ThreadTracker.Add(_engine); diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 3089351..9477100 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -34,7 +34,7 @@ namespace OpenSim.Framework.Servers.HttpServer public delegate void RequestMethod(UUID requestID, Hashtable request); public delegate bool HasEventsMethod(UUID requestID, UUID pId); - public delegate Hashtable GetEventsMethod(UUID requestID, UUID pId, string request); + public delegate Hashtable GetEventsMethod(UUID requestID, UUID pId); public delegate Hashtable NoEventsMethod(UUID requestID, UUID pId); @@ -45,17 +45,42 @@ namespace OpenSim.Framework.Servers.HttpServer public NoEventsMethod NoEvents; public RequestMethod Request; public UUID Id; + public int TimeOutms; + public EventType Type; + + public enum EventType : int + { + LongPoll = 0, + LslHttp = 1, + Inventory = 2 + } + + public string Url { get; set; } + + /// + /// Number of requests received for this poll service. + /// + public int RequestsReceived { get; set; } + + /// + /// Number of requests handled by this poll service. + /// + public int RequestsHandled { get; set; } public PollServiceEventArgs( RequestMethod pRequest, + string pUrl, HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, - UUID pId) + UUID pId, int pTimeOutms) { Request = pRequest; + Url = pUrl; HasEvents = pHasEvents; GetEvents = pGetEvents; NoEvents = pNoEvents; Id = pId; + TimeOutms = pTimeOutms; + Type = EventType.LongPoll; } } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs index 723530a..caf0e98 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs @@ -26,13 +26,19 @@ */ using System; +using System.Collections; +using System.Reflection; +using System.Text; using HttpServer; +using log4net; using OpenMetaverse; namespace OpenSim.Framework.Servers.HttpServer { public class PollServiceHttpRequest { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public readonly PollServiceEventArgs PollServiceArgs; public readonly IHttpClientContext HttpContext; public readonly IHttpRequest Request; @@ -48,5 +54,44 @@ namespace OpenSim.Framework.Servers.HttpServer RequestTime = System.Environment.TickCount; RequestID = UUID.Random(); } + + internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata) + { + OSHttpResponse response + = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext); + + byte[] buffer = server.DoHTTPGruntWork(responsedata, response); + + response.SendChunked = false; + response.ContentLength64 = buffer.Length; + response.ContentEncoding = Encoding.UTF8; + + try + { + response.OutputStream.Write(buffer, 0, buffer.Length); + } + catch (Exception ex) + { + m_log.Warn("[POLL SERVICE WORKER THREAD]: Error ", ex); + } + finally + { + //response.OutputStream.Close(); + try + { + response.OutputStream.Flush(); + response.Send(); + + //if (!response.KeepAlive && response.ReuseContext) + // response.FreeContext(); + } + catch (Exception e) + { + m_log.Warn("[POLL SERVICE WORKER THREAD]: Error ", e); + } + + PollServiceArgs.RequestsHandled++; + } + } } } \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 3e84c55..28bba70 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -33,132 +33,298 @@ using log4net; using HttpServer; using OpenSim.Framework; using OpenSim.Framework.Monitoring; +using Amib.Threading; +using System.IO; +using System.Text; +using System.Collections.Generic; namespace OpenSim.Framework.Servers.HttpServer { public class PollServiceRequestManager { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Is the poll service request manager running? + /// + /// + /// Can be running either synchronously or asynchronously + /// + public bool IsRunning { get; private set; } + + /// + /// Is the poll service performing responses asynchronously (with its own threads) or synchronously (via + /// external calls)? + /// + public bool PerformResponsesAsync { get; private set; } + + /// + /// Number of responses actually processed and sent to viewer (or aborted due to error). + /// + public int ResponsesProcessed { get; private set; } private readonly BaseHttpServer m_server; - private static Queue m_requests = Queue.Synchronized(new Queue()); + + private BlockingQueue m_requests = new BlockingQueue(); + private static List m_longPollRequests = new List(); + private uint m_WorkerThreadCount = 0; private Thread[] m_workerThreads; - private PollServiceWorkerThread[] m_PollServiceWorkerThreads; - private volatile bool m_running = true; - private int m_pollTimeout; - public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout) + private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2); + +// private int m_timeout = 1000; // increase timeout 250; now use the event one + + public PollServiceRequestManager( + BaseHttpServer pSrv, bool performResponsesAsync, uint pWorkerThreadCount, int pTimeout) { m_server = pSrv; + PerformResponsesAsync = performResponsesAsync; m_WorkerThreadCount = pWorkerThreadCount; - m_pollTimeout = pTimeout; + m_workerThreads = new Thread[m_WorkerThreadCount]; + + StatsManager.RegisterStat( + new Stat( + "QueuedPollResponses", + "Number of poll responses queued for processing.", + "", + "", + "httpserver", + m_server.Port.ToString(), + StatType.Pull, + MeasuresOfInterest.AverageChangeOverTime, + stat => stat.Value = m_requests.Count(), + StatVerbosity.Debug)); + + StatsManager.RegisterStat( + new Stat( + "ProcessedPollResponses", + "Number of poll responses processed.", + "", + "", + "httpserver", + m_server.Port.ToString(), + StatType.Pull, + MeasuresOfInterest.AverageChangeOverTime, + stat => stat.Value = ResponsesProcessed, + StatVerbosity.Debug)); } public void Start() { - m_running = true; - m_workerThreads = new Thread[m_WorkerThreadCount]; - m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount]; + IsRunning = true; - //startup worker threads - for (uint i = 0; i < m_WorkerThreadCount; i++) + if (PerformResponsesAsync) { - m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, m_pollTimeout); - m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent; - - m_workerThreads[i] - = Watchdog.StartThread( - m_PollServiceWorkerThreads[i].ThreadStart, - String.Format("PollServiceWorkerThread{0}", i), - ThreadPriority.Normal, - false, - true, - null, - int.MaxValue); - } + //startup worker threads + for (uint i = 0; i < m_WorkerThreadCount; i++) + { + m_workerThreads[i] + = WorkManager.StartThread( + PoolWorkerJob, + string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port), + ThreadPriority.Normal, + false, + false, + null, + int.MaxValue); + } - Watchdog.StartThread( - this.ThreadStart, - "PollServiceWatcherThread", - ThreadPriority.Normal, - false, - true, - null, - 1000 * 60 * 10); + WorkManager.StartThread( + this.CheckLongPollThreads, + string.Format("LongPollServiceWatcherThread:{0}", m_server.Port), + ThreadPriority.Normal, + false, + true, + null, + 1000 * 60 * 10); + } } - internal void ReQueueEvent(PollServiceHttpRequest req) + private void ReQueueEvent(PollServiceHttpRequest req) { - // Do accounting stuff here - Enqueue(req); - } + if (IsRunning) + { + // delay the enqueueing for 100ms. There's no need to have the event + // actively on the queue + Timer t = new Timer(self => { + ((Timer)self).Dispose(); + m_requests.Enqueue(req); + }); - public void Enqueue(PollServiceHttpRequest req) - { - lock (m_requests) - m_requests.Enqueue(req); + t.Change(100, Timeout.Infinite); + + } } - public void ThreadStart() + public void Enqueue(PollServiceHttpRequest req) { - while (m_running) + if (IsRunning) { - Watchdog.UpdateThread(); - ProcessQueuedRequests(); - Thread.Sleep(1000); + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) + { + lock (m_longPollRequests) + m_longPollRequests.Add(req); + } + else + m_requests.Enqueue(req); } } - private void ProcessQueuedRequests() + private void CheckLongPollThreads() { - lock (m_requests) + // The only purpose of this thread is to check the EQs for events. + // If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests. + // If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests. + // All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature, + // so if they aren't ready to be served by a worker thread (no events), they are placed + // directly back in the "ready-to-serve" queue by the worker thread. + while (IsRunning) { - if (m_requests.Count == 0) - return; - -// m_log.DebugFormat("[POLL SERVICE REQUEST MANAGER]: Processing {0} requests", m_requests.Count); - - int reqperthread = (int) (m_requests.Count/m_WorkerThreadCount) + 1; + Thread.Sleep(500); + Watchdog.UpdateThread(); - // For Each WorkerThread - for (int tc = 0; tc < m_WorkerThreadCount && m_requests.Count > 0; tc++) +// List not_ready = new List(); + lock (m_longPollRequests) { - //Loop over number of requests each thread handles. - for (int i = 0; i < reqperthread && m_requests.Count > 0; i++) + if (m_longPollRequests.Count > 0 && IsRunning) { - try - { - m_PollServiceWorkerThreads[tc].Enqueue((PollServiceHttpRequest)m_requests.Dequeue()); - } - catch (InvalidOperationException) - { - // The queue is empty, we did our calculations wrong! - return; - } - + List ready = m_longPollRequests.FindAll(req => + (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ + (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout + ); + + ready.ForEach(req => + { + m_requests.Enqueue(req); + m_longPollRequests.Remove(req); + }); + } + } } - } public void Stop() { - m_running = false; + IsRunning = false; +// m_timeout = -10000; // cause all to expire + Thread.Sleep(1000); // let the world move + + foreach (Thread t in m_workerThreads) + Watchdog.AbortThread(t.ManagedThreadId); + + PollServiceHttpRequest wreq; - foreach (object o in m_requests) + lock (m_longPollRequests) { - PollServiceHttpRequest req = (PollServiceHttpRequest) o; - PollServiceWorkerThread.DoHTTPGruntWork( - m_server, req, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + if (m_longPollRequests.Count > 0 && IsRunning) + m_longPollRequests.ForEach(req => m_requests.Enqueue(req)); } + while (m_requests.Count() > 0) + { + try + { + wreq = m_requests.Dequeue(0); + ResponsesProcessed++; + wreq.DoHTTPGruntWork( + m_server, wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id)); + } + catch + { + } + } + + m_longPollRequests.Clear(); m_requests.Clear(); + } - foreach (Thread t in m_workerThreads) + // work threads + + private void PoolWorkerJob() + { + while (IsRunning) { - t.Abort(); + Watchdog.UpdateThread(); + WaitPerformResponse(); + } + } + + public void WaitPerformResponse() + { + PollServiceHttpRequest req = m_requests.Dequeue(5000); +// m_log.DebugFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); + + if (req != null) + { + try + { + if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) + { + Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); + + if (responsedata == null) + return; + + // This is the event queue. + // Even if we're not running we can still perform responses by explicit request. + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll + || !PerformResponsesAsync) + { + try + { + ResponsesProcessed++; + req.DoHTTPGruntWork(m_server, responsedata); + } + catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream + { + // Ignore it, no need to reply + m_log.Error(e); + } + } + else + { + m_threadPool.QueueWorkItem(x => + { + try + { + ResponsesProcessed++; + req.DoHTTPGruntWork(m_server, responsedata); + } + catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream + { + // Ignore it, no need to reply + m_log.Error(e); + } + catch (Exception e) + { + m_log.Error(e); + } + + return null; + }, null); + } + } + else + { + if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) + { + ResponsesProcessed++; + req.DoHTTPGruntWork( + m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + } + else + { + ReQueueEvent(req); + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); + } } } } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs deleted file mode 100644 index 5adbcd1..0000000 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Text; -using HttpServer; -using OpenMetaverse; -using System.Reflection; -using log4net; -using OpenSim.Framework.Monitoring; - -namespace OpenSim.Framework.Servers.HttpServer -{ - public delegate void ReQueuePollServiceItem(PollServiceHttpRequest req); - - public class PollServiceWorkerThread - { - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); - - public event ReQueuePollServiceItem ReQueue; - - private readonly BaseHttpServer m_server; - private BlockingQueue m_request; - private bool m_running = true; - private int m_timeout = 250; - - public PollServiceWorkerThread(BaseHttpServer pSrv, int pTimeout) - { - m_request = new BlockingQueue(); - m_server = pSrv; - m_timeout = pTimeout; - } - - public void ThreadStart() - { - Run(); - } - - public void Run() - { - while (m_running) - { - PollServiceHttpRequest req = m_request.Dequeue(); - - Watchdog.UpdateThread(); - - try - { - if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) - { - StreamReader str; - try - { - str = new StreamReader(req.Request.Body); - } - catch (System.ArgumentException) - { - // Stream was not readable means a child agent - // was closed due to logout, leaving the - // Event Queue request orphaned. - continue; - } - - Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id, str.ReadToEnd()); - DoHTTPGruntWork(m_server, req, responsedata); - } - else - { - if ((Environment.TickCount - req.RequestTime) > m_timeout) - { - DoHTTPGruntWork( - m_server, - req, - req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); - } - else - { - ReQueuePollServiceItem reQueueItem = ReQueue; - if (reQueueItem != null) - reQueueItem(req); - } - } - } - catch (Exception e) - { - m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); - } - } - } - - internal void Enqueue(PollServiceHttpRequest pPollServiceHttpRequest) - { - m_request.Enqueue(pPollServiceHttpRequest); - } - - /// - /// FIXME: This should be part of BaseHttpServer - /// - internal static void DoHTTPGruntWork(BaseHttpServer server, PollServiceHttpRequest req, Hashtable responsedata) - { - OSHttpResponse response - = new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext); - - byte[] buffer = server.DoHTTPGruntWork(responsedata, response); - - response.SendChunked = false; - response.ContentLength64 = buffer.Length; - response.ContentEncoding = Encoding.UTF8; - - try - { - response.OutputStream.Write(buffer, 0, buffer.Length); - } - catch (Exception ex) - { - m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex)); - } - finally - { - //response.OutputStream.Close(); - try - { - response.OutputStream.Flush(); - response.Send(); - - //if (!response.KeepAlive && response.ReuseContext) - // response.FreeContext(); - } - catch (Exception e) - { - m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e)); - } - } - } - } -} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs index 02ecc25..5e630dc 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; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs index 07082a8..bd55657 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs @@ -33,7 +33,7 @@ namespace OpenSim.Framework.Servers.HttpServer { public delegate TResponse RestDeserialiseMethod(TRequest request); - public class RestDeserialiseHandler : BaseRequestHandler, IStreamHandler + public class RestDeserialiseHandler : BaseOutputStreamHandler, IStreamHandler where TRequest : new() { private RestDeserialiseMethod m_method; @@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_method = method; } - public void Handle(string path, Stream request, Stream responseStream, + protected override void ProcessRequest(string path, Stream request, Stream responseStream, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { TRequest deserial; diff --git a/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs b/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs index 48ced19..afe052f 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs @@ -52,23 +52,25 @@ namespace OpenSim.Framework.Servers.HttpServer request.Method = verb; request.ContentType = "text/xml"; - MemoryStream buffer = new MemoryStream(); + using (MemoryStream buffer = new MemoryStream()) + { + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; - XmlWriterSettings settings = new XmlWriterSettings(); - settings.Encoding = Encoding.UTF8; + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, obj); + writer.Flush(); + } - using (XmlWriter writer = XmlWriter.Create(buffer, settings)) - { - XmlSerializer serializer = new XmlSerializer(type); - serializer.Serialize(writer, obj); - writer.Flush(); - } + int length = (int)buffer.Length; + request.ContentLength = length; - int length = (int) buffer.Length; - request.ContentLength = length; + using (Stream requestStream = request.GetRequestStream()) + requestStream.Write(buffer.ToArray(), 0, length); + } - Stream requestStream = request.GetRequestStream(); - requestStream.Write(buffer.ToArray(), 0, length); // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); request.BeginGetResponse(AsyncCallback, request); } diff --git a/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs b/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs index 451745c..a911b9f 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs @@ -60,24 +60,25 @@ namespace OpenSim.Framework.Servers.HttpServer request.ContentType = "text/xml"; request.Timeout = 10000; - MemoryStream buffer = new MemoryStream(); + using (MemoryStream buffer = new MemoryStream()) + { + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; + + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, obj); + writer.Flush(); + } - XmlWriterSettings settings = new XmlWriterSettings(); - settings.Encoding = Encoding.UTF8; + int length = (int)buffer.Length; + request.ContentLength = length; - using (XmlWriter writer = XmlWriter.Create(buffer, settings)) - { - XmlSerializer serializer = new XmlSerializer(type); - serializer.Serialize(writer, obj); - writer.Flush(); + using (Stream requestStream = request.GetRequestStream()) + requestStream.Write(buffer.ToArray(), 0, length); } - int length = (int) buffer.Length; - request.ContentLength = length; - - Stream requestStream = request.GetRequestStream(); - requestStream.Write(buffer.ToArray(), 0, length); - requestStream.Close(); // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); request.BeginGetResponse(AsyncCallback, request); } diff --git a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs index 19c03a8..ad69cd2 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs @@ -77,44 +77,34 @@ namespace OpenSim.Framework.Servers.HttpServer request.ContentType = "text/xml"; request.Timeout = 20000; - MemoryStream buffer = new MemoryStream(); - - XmlWriterSettings settings = new XmlWriterSettings(); - settings.Encoding = Encoding.UTF8; - - using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + using (MemoryStream buffer = new MemoryStream()) { - XmlSerializer serializer = new XmlSerializer(type); - serializer.Serialize(writer, sobj); - writer.Flush(); - } + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; - int length = (int)buffer.Length; - request.ContentLength = length; + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, sobj); + writer.Flush(); + } - Stream requestStream = request.GetRequestStream(); - requestStream.Write(buffer.ToArray(), 0, length); - buffer.Close(); - requestStream.Close(); + int length = (int)buffer.Length; + request.ContentLength = length; + + using (Stream requestStream = request.GetRequestStream()) + requestStream.Write(buffer.ToArray(), 0, length); + } TResponse deserial = default(TResponse); using (WebResponse resp = request.GetResponse()) { XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); - Stream respStream = null; - try - { - respStream = resp.GetResponseStream(); + + using (Stream respStream = resp.GetResponseStream()) deserial = (TResponse)deserializer.Deserialize(respStream); - } - catch { } - finally - { - if (respStream != null) - respStream.Close(); - resp.Close(); - } } + return deserial; } } @@ -142,25 +132,25 @@ namespace OpenSim.Framework.Servers.HttpServer request.ContentType = "text/xml"; request.Timeout = 10000; - MemoryStream buffer = new MemoryStream(); + using (MemoryStream buffer = new MemoryStream()) + { + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; - XmlWriterSettings settings = new XmlWriterSettings(); - settings.Encoding = Encoding.UTF8; + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, sobj); + writer.Flush(); + } - using (XmlWriter writer = XmlWriter.Create(buffer, settings)) - { - XmlSerializer serializer = new XmlSerializer(type); - serializer.Serialize(writer, sobj); - writer.Flush(); - } - buffer.Close(); + int length = (int)buffer.Length; + request.ContentLength = length; - int length = (int)buffer.Length; - request.ContentLength = length; + using (Stream requestStream = request.GetRequestStream()) + requestStream.Write(buffer.ToArray(), 0, length); + } - Stream requestStream = request.GetRequestStream(); - requestStream.Write(buffer.ToArray(), 0, length); - requestStream.Close(); // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); request.BeginGetResponse(AsyncCallback, request); } @@ -192,7 +182,7 @@ namespace OpenSim.Framework.Servers.HttpServer public delegate bool CheckIdentityMethod(string sid, string aid); - public class RestDeserialiseSecureHandler : BaseRequestHandler, IStreamHandler + public class RestDeserialiseSecureHandler : BaseOutputStreamHandler, IStreamHandler where TRequest : new() { private static readonly ILog m_log @@ -210,7 +200,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_method = method; } - public void Handle(string path, Stream request, Stream responseStream, + protected override void ProcessRequest(string path, Stream request, Stream responseStream, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { RestSessionObject deserial = default(RestSessionObject); @@ -246,7 +236,7 @@ namespace OpenSim.Framework.Servers.HttpServer public delegate bool CheckTrustedSourceMethod(IPEndPoint peer); - public class RestDeserialiseTrustedHandler : BaseRequestHandler, IStreamHandler + public class RestDeserialiseTrustedHandler : BaseOutputStreamHandler, IStreamHandler where TRequest : new() { private static readonly ILog m_log @@ -269,7 +259,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_method = method; } - public void Handle(string path, Stream request, Stream responseStream, + protected override void ProcessRequest(string path, Stream request, Stream responseStream, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { TRequest deserial = default(TRequest); @@ -301,6 +291,5 @@ namespace OpenSim.Framework.Servers.HttpServer serializer.Serialize(xmlWriter, response); } } - } - -} + } +} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs index 1f17fee..0305dee 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs @@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_restMethod = restMethod; } - public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { Encoding encoding = Encoding.UTF8; StreamReader streamReader = new StreamReader(request, encoding); diff --git a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs new file mode 100644 index 0000000..c2925e3 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs @@ -0,0 +1,1159 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using HttpServer; + +namespace OpenSim.Framework.Servers.HttpServer +{ + // Sealed class. If you're going to unseal it, implement IDisposable. + /// + /// This class implements websockets. It grabs the network context from C#Webserver and utilizes it directly as a tcp streaming service + /// + public sealed class WebSocketHttpServerHandler : BaseRequestHandler + { + + private class WebSocketState + { + public List ReceivedBytes; + public int ExpectedBytes; + public WebsocketFrameHeader Header; + public bool FrameComplete; + public WebSocketFrame ContinuationFrame; + } + + /// + /// Binary Data will trigger this event + /// + public event DataDelegate OnData; + + /// + /// Textual Data will trigger this event + /// + public event TextDelegate OnText; + + /// + /// A ping request form the other side will trigger this event. + /// This class responds to the ping automatically. You shouldn't send a pong. + /// it's informational. + /// + public event PingDelegate OnPing; + + /// + /// This is a response to a ping you sent. + /// + public event PongDelegate OnPong; + + /// + /// This is a regular HTTP Request... This may be removed in the future. + /// +// public event RegularHttpRequestDelegate OnRegularHttpRequest; + + /// + /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired + /// + public event UpgradeCompletedDelegate OnUpgradeCompleted; + + /// + /// If the upgrade failed, this will be fired + /// + public event UpgradeFailedDelegate OnUpgradeFailed; + + /// + /// When the websocket is closed, this will be fired. + /// + public event CloseDelegate OnClose; + + /// + /// Set this delegate to allow your module to validate the origin of the + /// Websocket request. Primary line of defense against cross site scripting + /// + public ValidateHandshake HandshakeValidateMethodOverride = null; + + private ManualResetEvent _receiveDone = new ManualResetEvent(false); + + private OSHttpRequest _request; + private HTTPNetworkContext _networkContext; + private IHttpClientContext _clientContext; + + private int _pingtime = 0; + private byte[] _buffer; + private int _bufferPosition; + private int _bufferLength; + private bool _closing; + private bool _upgraded; + private int _maxPayloadBytes = 41943040; + private int _initialMsgTimeout = 0; + private int _defaultReadTimeout = 10000; + + private const string HandshakeAcceptText = + "HTTP/1.1 101 Switching Protocols\r\n" + + "upgrade: websocket\r\n" + + "Connection: Upgrade\r\n" + + "sec-websocket-accept: {0}\r\n\r\n";// + + //"{1}"; + + private const string HandshakeDeclineText = + "HTTP/1.1 {0} {1}\r\n" + + "Connection: close\r\n\r\n"; + + /// + /// Mysterious constant defined in RFC6455 to append to the client provided security key + /// + private const string WebsocketHandshakeAcceptHashConstant = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + + public WebSocketHttpServerHandler(OSHttpRequest preq, IHttpClientContext pContext, int bufferlen) + : base(preq.HttpMethod, preq.Url.OriginalString) + { + _request = preq; + _networkContext = pContext.GiveMeTheNetworkStreamIKnowWhatImDoing(); + _networkContext.Stream.ReadTimeout = _defaultReadTimeout; + _clientContext = pContext; + _bufferLength = bufferlen; + _buffer = new byte[_bufferLength]; + } + + // Sealed class implments destructor and an internal dispose method. complies with C# unmanaged resource best practices. + ~WebSocketHttpServerHandler() + { + Dispose(); + + } + + /// + /// Sets the length of the stream buffer + /// + /// Byte length. + public void SetChunksize(int pChunk) + { + if (!_upgraded) + { + _buffer = new byte[pChunk]; + } + else + { + throw new InvalidOperationException("You must set the chunksize before the connection is upgraded"); + } + } + + /// + /// This is the famous nagle. + /// + public bool NoDelay_TCP_Nagle + { + get + { + if (_networkContext != null && _networkContext.Socket != null) + { + return _networkContext.Socket.NoDelay; + } + else + { + throw new InvalidOperationException("The socket has been shutdown"); + } + } + set + { + if (_networkContext != null && _networkContext.Socket != null) + _networkContext.Socket.NoDelay = value; + else + { + throw new InvalidOperationException("The socket has been shutdown"); + } + } + } + + /// + /// This triggers the websocket to start the upgrade process... + /// This is a Generalized Networking 'common sense' helper method. Some people expect to call Start() instead + /// of the more context appropriate HandshakeAndUpgrade() + /// + public void Start() + { + HandshakeAndUpgrade(); + } + + /// + /// Max Payload Size in bytes. Defaults to 40MB, but could be set upon connection before calling handshake and upgrade. + /// + public int MaxPayloadSize + { + get { return _maxPayloadBytes; } + set { _maxPayloadBytes = value; } + } + + /// + /// Set this to the maximum amount of milliseconds to wait for the first complete message to be sent or received on the websocket after upgrading + /// Default, it waits forever. Use this when your Websocket consuming code opens a connection and waits for a message from the other side to avoid a Denial of Service vector. + /// + public int InitialMsgTimeout + { + get { return _initialMsgTimeout; } + set { _initialMsgTimeout = value; } + } + + /// + /// This triggers the websocket start the upgrade process + /// + public void HandshakeAndUpgrade() + { + string webOrigin = string.Empty; + string websocketKey = string.Empty; + string acceptKey = string.Empty; + string accepthost = string.Empty; + if (!string.IsNullOrEmpty(_request.Headers["origin"])) + webOrigin = _request.Headers["origin"]; + + if (!string.IsNullOrEmpty(_request.Headers["sec-websocket-key"])) + websocketKey = _request.Headers["sec-websocket-key"]; + + if (!string.IsNullOrEmpty(_request.Headers["host"])) + accepthost = _request.Headers["host"]; + + if (string.IsNullOrEmpty(_request.Headers["upgrade"])) + { + FailUpgrade(OSHttpStatusCode.ClientErrorBadRequest, "no upgrade request submitted"); + } + + string connectionheader = _request.Headers["upgrade"]; + if (connectionheader.ToLower() != "websocket") + { + FailUpgrade(OSHttpStatusCode.ClientErrorBadRequest, "no connection upgrade request submitted"); + } + + // If the object consumer provided a method to validate the origin, we should call it and give the client a success or fail. + // If not.. we should accept any. The assumption here is that there would be no Websocket handlers registered in baseHTTPServer unless + // Something asked for it... + if (HandshakeValidateMethodOverride != null) + { + if (HandshakeValidateMethodOverride(webOrigin, websocketKey, accepthost)) + { + acceptKey = GenerateAcceptKey(websocketKey); + string rawaccept = string.Format(HandshakeAcceptText, acceptKey); + SendUpgradeSuccess(rawaccept); + + + } + else + { + FailUpgrade(OSHttpStatusCode.ClientErrorForbidden, "Origin Validation Failed"); + } + } + else + { + acceptKey = GenerateAcceptKey(websocketKey); + string rawaccept = string.Format(HandshakeAcceptText, acceptKey); + SendUpgradeSuccess(rawaccept); + } + } + public IPEndPoint GetRemoteIPEndpoint() + { + return _request.RemoteIPEndPoint; + } + + /// + /// Generates a handshake response key string based on the client's + /// provided key to prove to the client that we're allowing the Websocket + /// upgrade of our own free will and we were not coerced into doing it. + /// + /// Client provided security key + /// + private static string GenerateAcceptKey(string key) + { + if (string.IsNullOrEmpty(key)) + return string.Empty; + + string acceptkey = key + WebsocketHandshakeAcceptHashConstant; + + SHA1 hashobj = SHA1.Create(); + string ret = Convert.ToBase64String(hashobj.ComputeHash(Encoding.UTF8.GetBytes(acceptkey))); + hashobj.Clear(); + + return ret; + } + + /// + /// Informs the otherside that we accepted their upgrade request + /// + /// The HTTP 1.1 101 response that says Yay \o/ + private void SendUpgradeSuccess(string pHandshakeResponse) + { + // Create a new websocket state so we can keep track of data in between network reads. + WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true}; + + byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse); + + + + + try + { + if (_initialMsgTimeout > 0) + { + _receiveDone.Reset(); + } + // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream. + _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState); + + // Write the upgrade handshake success message + _networkContext.Stream.Write(bhandshakeResponse, 0, bhandshakeResponse.Length); + _networkContext.Stream.Flush(); + _upgraded = true; + UpgradeCompletedDelegate d = OnUpgradeCompleted; + if (d != null) + d(this, new UpgradeCompletedEventArgs()); + if (_initialMsgTimeout > 0) + { + if (!_receiveDone.WaitOne(TimeSpan.FromMilliseconds(_initialMsgTimeout))) + Close(string.Empty); + } + } + catch (IOException) + { + Close(string.Empty); + } + catch (ObjectDisposedException) + { + Close(string.Empty); + } + } + + /// + /// The server has decided not to allow the upgrade to a websocket for some reason. The Http 1.1 response that says Nay >:( + /// + /// HTTP Status reflecting the reason why + /// Textual reason for the upgrade fail + private void FailUpgrade(OSHttpStatusCode pCode, string pMessage ) + { + string handshakeResponse = string.Format(HandshakeDeclineText, (int)pCode, pMessage.Replace("\n", string.Empty).Replace("\r", string.Empty)); + byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(handshakeResponse); + _networkContext.Stream.Write(bhandshakeResponse, 0, bhandshakeResponse.Length); + _networkContext.Stream.Flush(); + _networkContext.Stream.Dispose(); + + UpgradeFailedDelegate d = OnUpgradeFailed; + if (d != null) + d(this,new UpgradeFailedEventArgs()); + } + + + /// + /// This is our ugly Async OnReceive event handler. + /// This chunks the input stream based on the length of the provided buffer and processes out + /// as many frames as it can. It then moves the unprocessed data to the beginning of the buffer. + /// + /// Our Async State from beginread + private void OnReceive(IAsyncResult ar) + { + WebSocketState _socketState = ar.AsyncState as WebSocketState; + try + { + int bytesRead = _networkContext.Stream.EndRead(ar); + if (bytesRead == 0) + { + // Do Disconnect + _networkContext.Stream.Dispose(); + _networkContext = null; + return; + } + _bufferPosition += bytesRead; + + if (_bufferPosition > _bufferLength) + { + // Message too big for chunksize.. not sure how this happened... + //Close(string.Empty); + } + + int offset = 0; + bool headerread = true; + int headerforwardposition = 0; + while (headerread && offset < bytesRead) + { + if (_socketState.FrameComplete) + { + WebsocketFrameHeader pheader = WebsocketFrameHeader.ZeroHeader; + + headerread = WebSocketReader.TryReadHeader(_buffer, offset, _bufferPosition - offset, out pheader, + out headerforwardposition); + offset += headerforwardposition; + + if (headerread) + { + _socketState.FrameComplete = false; + if (pheader.PayloadLen > (ulong) _maxPayloadBytes) + { + Close("Invalid Payload size"); + + return; + } + if (pheader.PayloadLen > 0) + { + if ((int) pheader.PayloadLen > _bufferPosition - offset) + { + byte[] writebytes = new byte[_bufferPosition - offset]; + + Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition - offset); + _socketState.ExpectedBytes = (int) pheader.PayloadLen; + _socketState.ReceivedBytes.AddRange(writebytes); + _socketState.Header = pheader; // We need to add the header so that we can unmask it + offset += (int) _bufferPosition - offset; + } + else + { + byte[] writebytes = new byte[pheader.PayloadLen]; + Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) pheader.PayloadLen); + WebSocketReader.Mask(pheader.Mask, writebytes); + pheader.IsMasked = false; + _socketState.FrameComplete = true; + _socketState.ReceivedBytes.AddRange(writebytes); + _socketState.Header = pheader; + offset += (int) pheader.PayloadLen; + } + } + else + { + pheader.Mask = 0; + _socketState.FrameComplete = true; + _socketState.Header = pheader; + } + + if (_socketState.FrameComplete) + { + ProcessFrame(_socketState); + _socketState.Header.SetDefault(); + _socketState.ReceivedBytes.Clear(); + _socketState.ExpectedBytes = 0; + + } + } + } + else + { + WebsocketFrameHeader frameHeader = _socketState.Header; + int bytesleft = _socketState.ExpectedBytes - _socketState.ReceivedBytes.Count; + + if (bytesleft > _bufferPosition) + { + byte[] writebytes = new byte[_bufferPosition]; + + Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition); + _socketState.ReceivedBytes.AddRange(writebytes); + _socketState.Header = frameHeader; // We need to add the header so that we can unmask it + offset += (int) _bufferPosition; + } + else + { + byte[] writebytes = new byte[_bufferPosition]; + Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition); + _socketState.FrameComplete = true; + _socketState.ReceivedBytes.AddRange(writebytes); + _socketState.Header = frameHeader; + offset += (int) _bufferPosition; + } + if (_socketState.FrameComplete) + { + ProcessFrame(_socketState); + _socketState.Header.SetDefault(); + _socketState.ReceivedBytes.Clear(); + _socketState.ExpectedBytes = 0; + // do some processing + } + } + } + if (offset > 0) + { + // If the buffer is maxed out.. we can just move the cursor. Nothing to move to the beginning. + if (offset <_buffer.Length) + Buffer.BlockCopy(_buffer, offset, _buffer, 0, _bufferPosition - offset); + _bufferPosition -= offset; + } + if (_networkContext.Stream != null && _networkContext.Stream.CanRead && !_closing) + { + _networkContext.Stream.BeginRead(_buffer, _bufferPosition, _bufferLength - _bufferPosition, OnReceive, + _socketState); + } + else + { + // We can't read the stream anymore... + } + } + catch (IOException) + { + Close(string.Empty); + } + catch (ObjectDisposedException) + { + Close(string.Empty); + } + } + + /// + /// Sends a string to the other side + /// + /// the string message that is to be sent + public void SendMessage(string message) + { + if (_initialMsgTimeout > 0) + { + _receiveDone.Set(); + _initialMsgTimeout = 0; + } + byte[] messagedata = Encoding.UTF8.GetBytes(message); + WebSocketFrame textMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata }; + textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text; + textMessageFrame.Header.IsEnd = true; + SendSocket(textMessageFrame.ToBytes()); + + } + + public void SendData(byte[] data) + { + if (_initialMsgTimeout > 0) + { + _receiveDone.Set(); + _initialMsgTimeout = 0; + } + WebSocketFrame dataMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data}; + dataMessageFrame.Header.IsEnd = true; + dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary; + SendSocket(dataMessageFrame.ToBytes()); + + } + + /// + /// Writes raw bytes to the websocket. Unframed data will cause disconnection + /// + /// + private void SendSocket(byte[] data) + { + if (!_closing) + { + try + { + + _networkContext.Stream.Write(data, 0, data.Length); + } + catch (IOException) + { + + } + } + } + + /// + /// 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. + /// + public void SendPingCheck() + { + if (_initialMsgTimeout > 0) + { + _receiveDone.Set(); + _initialMsgTimeout = 0; + } + WebSocketFrame pingFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0] }; + pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping; + pingFrame.Header.IsEnd = true; + _pingtime = Util.EnvironmentTickCount(); + SendSocket(pingFrame.ToBytes()); + } + + /// + /// Closes the websocket connection. Sends a close message to the other side if it hasn't already done so. + /// + /// + public void Close(string message) + { + if (_initialMsgTimeout > 0) + { + _receiveDone.Set(); + _initialMsgTimeout = 0; + } + if (_networkContext == null) + return; + if (_networkContext.Stream != null) + { + if (_networkContext.Stream.CanWrite) + { + byte[] messagedata = Encoding.UTF8.GetBytes(message); + WebSocketFrame closeResponseFrame = new WebSocketFrame() + { + Header = WebsocketFrameHeader.HeaderDefault(), + WebSocketPayload = messagedata + }; + closeResponseFrame.Header.Opcode = WebSocketReader.OpCode.Close; + closeResponseFrame.Header.PayloadLen = (ulong) messagedata.Length; + closeResponseFrame.Header.IsEnd = true; + SendSocket(closeResponseFrame.ToBytes()); + } + } + CloseDelegate closeD = OnClose; + if (closeD != null) + { + closeD(this, new CloseEventArgs()); + } + + _closing = true; + } + + /// + /// Processes a websocket frame and triggers consumer events + /// + /// We need to modify the websocket state here depending on the frame + private void ProcessFrame(WebSocketState psocketState) + { + if (psocketState.Header.IsMasked) + { + byte[] unmask = psocketState.ReceivedBytes.ToArray(); + WebSocketReader.Mask(psocketState.Header.Mask, unmask); + psocketState.ReceivedBytes = new List(unmask); + } + if (psocketState.Header.Opcode != WebSocketReader.OpCode.Continue && _initialMsgTimeout > 0) + { + _receiveDone.Set(); + _initialMsgTimeout = 0; + } + switch (psocketState.Header.Opcode) + { + case WebSocketReader.OpCode.Ping: + PingDelegate pingD = OnPing; + if (pingD != null) + { + pingD(this, new PingEventArgs()); + } + + WebSocketFrame pongFrame = new WebSocketFrame(){Header = WebsocketFrameHeader.HeaderDefault(),WebSocketPayload = new byte[0]}; + pongFrame.Header.Opcode = WebSocketReader.OpCode.Pong; + pongFrame.Header.IsEnd = true; + SendSocket(pongFrame.ToBytes()); + break; + case WebSocketReader.OpCode.Pong: + + PongDelegate pongD = OnPong; + if (pongD != null) + { + pongD(this, new PongEventArgs(){PingResponseMS = Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(),_pingtime)}); + } + break; + case WebSocketReader.OpCode.Binary: + if (!psocketState.Header.IsEnd) // Not done, so we need to store this and wait for the end frame. + { + psocketState.ContinuationFrame = new WebSocketFrame + { + Header = psocketState.Header, + WebSocketPayload = + psocketState.ReceivedBytes.ToArray() + }; + } + else + { + // Send Done Event! + DataDelegate dataD = OnData; + if (dataD != null) + { + dataD(this,new WebsocketDataEventArgs(){Data = psocketState.ReceivedBytes.ToArray()}); + } + } + break; + case WebSocketReader.OpCode.Text: + if (!psocketState.Header.IsEnd) // Not done, so we need to store this and wait for the end frame. + { + psocketState.ContinuationFrame = new WebSocketFrame + { + Header = psocketState.Header, + WebSocketPayload = + psocketState.ReceivedBytes.ToArray() + }; + } + else + { + TextDelegate textD = OnText; + if (textD != null) + { + textD(this, new WebsocketTextEventArgs() { Data = Encoding.UTF8.GetString(psocketState.ReceivedBytes.ToArray()) }); + } + + // Send Done Event! + } + break; + case WebSocketReader.OpCode.Continue: // Continuation. Multiple frames worth of data for one message. Only valid when not using Control Opcodes + //Console.WriteLine("currhead " + psocketState.Header.IsEnd); + //Console.WriteLine("Continuation! " + psocketState.ContinuationFrame.Header.IsEnd); + byte[] combineddata = new byte[psocketState.ReceivedBytes.Count+psocketState.ContinuationFrame.WebSocketPayload.Length]; + byte[] newdata = psocketState.ReceivedBytes.ToArray(); + Buffer.BlockCopy(psocketState.ContinuationFrame.WebSocketPayload, 0, combineddata, 0, psocketState.ContinuationFrame.WebSocketPayload.Length); + Buffer.BlockCopy(newdata, 0, combineddata, + psocketState.ContinuationFrame.WebSocketPayload.Length, newdata.Length); + psocketState.ContinuationFrame.WebSocketPayload = combineddata; + psocketState.Header.PayloadLen = (ulong)combineddata.Length; + if (psocketState.Header.IsEnd) + { + if (psocketState.ContinuationFrame.Header.Opcode == WebSocketReader.OpCode.Text) + { + // Send Done event + TextDelegate textD = OnText; + if (textD != null) + { + textD(this, new WebsocketTextEventArgs() { Data = Encoding.UTF8.GetString(combineddata) }); + } + } + else if (psocketState.ContinuationFrame.Header.Opcode == WebSocketReader.OpCode.Binary) + { + // Send Done event + DataDelegate dataD = OnData; + if (dataD != null) + { + dataD(this, new WebsocketDataEventArgs() { Data = combineddata }); + } + } + else + { + // protocol violation + } + psocketState.ContinuationFrame = null; + } + break; + case WebSocketReader.OpCode.Close: + Close(string.Empty); + + break; + + } + psocketState.Header.SetDefault(); + psocketState.ReceivedBytes.Clear(); + psocketState.ExpectedBytes = 0; + } + public void Dispose() + { + if (_initialMsgTimeout > 0) + { + _receiveDone.Set(); + _initialMsgTimeout = 0; + } + if (_networkContext != null && _networkContext.Stream != null) + { + if (_networkContext.Stream.CanWrite) + _networkContext.Stream.Flush(); + _networkContext.Stream.Close(); + _networkContext.Stream.Dispose(); + _networkContext.Stream = null; + } + + if (_request != null && _request.InputStream != null) + { + _request.InputStream.Close(); + _request.InputStream.Dispose(); + _request = null; + } + + if (_clientContext != null) + { + _clientContext.Close(); + _clientContext = null; + } + } + } + + /// + /// Reads a byte stream and returns Websocket frames. + /// + public class WebSocketReader + { + /// + /// Bit to determine if the frame read on the stream is the last frame in a sequence of fragmented frames + /// + private const byte EndBit = 0x80; + + /// + /// These are the Frame Opcodes + /// + public enum OpCode + { + // Data Opcodes + Continue = 0x0, + Text = 0x1, + Binary = 0x2, + + // Control flow Opcodes + Close = 0x8, + Ping = 0x9, + Pong = 0xA + } + + /// + /// Masks and Unmasks data using the frame mask. Mask is applied per octal + /// Note: Frames from clients MUST be masked + /// Note: Frames from servers MUST NOT be masked + /// + /// Int representing 32 bytes of mask data. Mask is applied per octal + /// + public static void Mask(int pMask, byte[] pBuffer) + { + byte[] maskKey = BitConverter.GetBytes(pMask); + int currentMaskIndex = 0; + for (int i = 0; i < pBuffer.Length; i++) + { + pBuffer[i] = (byte)(pBuffer[i] ^ maskKey[currentMaskIndex]); + if (currentMaskIndex == 3) + { + currentMaskIndex = 0; + } + else + { + currentMaskIndex++; + + } + + } + } + + /// + /// Attempts to read a header off the provided buffer. Returns true, exports a WebSocketFrameheader, + /// and an int to move the buffer forward when it reads a header. False when it can't read a header + /// + /// Bytes read from the stream + /// Starting place in the stream to begin trying to read from + /// Lenth in the stream to try and read from. Provided for cases where the + /// buffer's length is larger then the data in it + /// Outputs the read WebSocket frame header + /// Informs the calling stream to move the buffer forward + /// True if it got a header, False if it didn't get a header + public static bool TryReadHeader(byte[] pBuffer, int pOffset, int length, out WebsocketFrameHeader oHeader, + out int moveBuffer) + { + oHeader = WebsocketFrameHeader.ZeroHeader; + int minumheadersize = 2; + if (length > pBuffer.Length - pOffset) + throw new ArgumentOutOfRangeException("The Length specified was larger the byte array supplied"); + if (length < minumheadersize) + { + moveBuffer = 0; + return false; + } + + byte nibble1 = (byte)(pBuffer[pOffset] & 0xF0); //FIN/RSV1/RSV2/RSV3 + byte nibble2 = (byte)(pBuffer[pOffset] & 0x0F); // Opcode block + + oHeader = new WebsocketFrameHeader(); + oHeader.SetDefault(); + + if ((nibble1 & WebSocketReader.EndBit) == WebSocketReader.EndBit) + { + oHeader.IsEnd = true; + } + else + { + oHeader.IsEnd = false; + } + //Opcode + oHeader.Opcode = (WebSocketReader.OpCode)nibble2; + //Mask + oHeader.IsMasked = Convert.ToBoolean((pBuffer[pOffset + 1] & 0x80) >> 7); + + // Payload length + oHeader.PayloadLen = (byte)(pBuffer[pOffset + 1] & 0x7F); + + int index = 2; // LargerPayload length starts at byte 3 + + switch (oHeader.PayloadLen) + { + case 126: + minumheadersize += 2; + if (length < minumheadersize) + { + moveBuffer = 0; + return false; + } + Array.Reverse(pBuffer, pOffset + index, 2); // two bytes + oHeader.PayloadLen = BitConverter.ToUInt16(pBuffer, pOffset + index); + index += 2; + break; + case 127: // we got more this is a bigger frame + // 8 bytes - uint64 - most significant bit 0 network byte order + minumheadersize += 8; + if (length < minumheadersize) + { + moveBuffer = 0; + return false; + } + Array.Reverse(pBuffer, pOffset + index, 8); + oHeader.PayloadLen = BitConverter.ToUInt64(pBuffer, pOffset + index); + index += 8; + break; + + } + //oHeader.PayloadLeft = oHeader.PayloadLen; // Start the count in case it's chunked over the network. This is different then frame fragmentation + if (oHeader.IsMasked) + { + minumheadersize += 4; + if (length < minumheadersize) + { + moveBuffer = 0; + return false; + } + oHeader.Mask = BitConverter.ToInt32(pBuffer, pOffset + index); + index += 4; + } + moveBuffer = index; + return true; + + } + } + + /// + /// RFC6455 Websocket Frame + /// + public class WebSocketFrame + { + /* + * RFC6455 +nib 0 1 2 3 4 5 6 7 +byt 0 1 2 3 +dec 0 1 2 3 + 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 + +-+-+-+-+-------+-+-------------+-------------------------------+ + |F|R|R|R| opcode|M| Payload len | Extended payload length | + |I|S|S|S| (4) |A| (7) | (16/64) + + |N|V|V|V| |S| | (if payload len==126/127) | + | |1|2|3| |K| | + + +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + | Extended payload length continued, if payload len == 127 | + + - - - - - - - - - - - - - - - +-------------------------------+ + | |Masking-key, if MASK set to 1 | + +-------------------------------+-------------------------------+ + | Masking-key (continued) | Payload Data | + +-------------------------------- - - - - - - - - - - - - - - - + + : Payload Data continued ... : + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + | Payload Data continued ... | + +---------------------------------------------------------------+ + + * When reading these, the frames are possibly fragmented and interleaved with control frames + * the fragmented frames are not interleaved with data frames. Just control frames + */ + public static readonly WebSocketFrame DefaultFrame = new WebSocketFrame(){Header = new WebsocketFrameHeader(),WebSocketPayload = new byte[0]}; + public WebsocketFrameHeader Header; + public byte[] WebSocketPayload; + + public byte[] ToBytes() + { + Header.PayloadLen = (ulong)WebSocketPayload.Length; + return Header.ToBytes(WebSocketPayload); + } + + } + + public struct WebsocketFrameHeader + { + //public byte CurrentMaskIndex; + /// + /// The last frame in a sequence of fragmented frames or the one and only frame for this message. + /// + public bool IsEnd; + + /// + /// Returns whether the payload data is masked or not. Data from Clients MUST be masked, Data from Servers MUST NOT be masked + /// + public bool IsMasked; + + /// + /// A set of cryptologically sound random bytes XoR-ed against the payload octally. Looped + /// + public int Mask; + /* +byt 0 1 2 3 + 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 + +---------------+---------------+---------------+---------------+ + | Octal 1 | Octal 2 | Octal 3 | Octal 4 | + +---------------+---------------+---------------+---------------+ +*/ + + + public WebSocketReader.OpCode Opcode; + + public UInt64 PayloadLen; + //public UInt64 PayloadLeft; + // Payload is X + Y + //public UInt64 ExtensionDataLength; + //public UInt64 ApplicationDataLength; + public static readonly WebsocketFrameHeader ZeroHeader = WebsocketFrameHeader.HeaderDefault(); + + public void SetDefault() + { + + //CurrentMaskIndex = 0; + IsEnd = true; + IsMasked = true; + Mask = 0; + Opcode = WebSocketReader.OpCode.Close; + // PayloadLeft = 0; + PayloadLen = 0; + // ExtensionDataLength = 0; + // ApplicationDataLength = 0; + + } + + /// + /// Returns a byte array representing the Frame header + /// + /// This is the frame data payload. The header describes the size of the payload. + /// If payload is null, a Zero sized payload is assumed + /// Returns a byte array representing the frame header + public byte[] ToBytes(byte[] payload) + { + List result = new List(); + + // Squeeze in our opcode and our ending bit. + result.Add((byte)((byte)Opcode | (IsEnd?0x80:0x00) )); + + // Again with the three different byte interpretations of size.. + + //bytesize + if (PayloadLen <= 125) + { + result.Add((byte) PayloadLen); + } //Uint16 + else if (PayloadLen <= ushort.MaxValue) + { + result.Add(126); + byte[] payloadLengthByte = BitConverter.GetBytes(Convert.ToUInt16(PayloadLen)); + Array.Reverse(payloadLengthByte); + result.AddRange(payloadLengthByte); + } //UInt64 + else + { + result.Add(127); + byte[] payloadLengthByte = BitConverter.GetBytes(PayloadLen); + Array.Reverse(payloadLengthByte); + result.AddRange(payloadLengthByte); + } + + // Only add a payload if it's not null + if (payload != null) + { + result.AddRange(payload); + } + return result.ToArray(); + } + + /// + /// A Helper method to define the defaults + /// + /// + + public static WebsocketFrameHeader HeaderDefault() + { + return new WebsocketFrameHeader + { + //CurrentMaskIndex = 0, + IsEnd = false, + IsMasked = true, + Mask = 0, + Opcode = WebSocketReader.OpCode.Close, + //PayloadLeft = 0, + PayloadLen = 0, + // ExtensionDataLength = 0, + // ApplicationDataLength = 0 + }; + } + } + + public delegate void DataDelegate(object sender, WebsocketDataEventArgs data); + + public delegate void TextDelegate(object sender, WebsocketTextEventArgs text); + + public delegate void PingDelegate(object sender, PingEventArgs pingdata); + + public delegate void PongDelegate(object sender, PongEventArgs pongdata); + + public delegate void RegularHttpRequestDelegate(object sender, RegularHttpRequestEvnetArgs request); + + public delegate void UpgradeCompletedDelegate(object sender, UpgradeCompletedEventArgs completeddata); + + public delegate void UpgradeFailedDelegate(object sender, UpgradeFailedEventArgs faileddata); + + public delegate void CloseDelegate(object sender, CloseEventArgs closedata); + + public delegate bool ValidateHandshake(string pWebOrigin, string pWebSocketKey, string pHost); + + + public class WebsocketDataEventArgs : EventArgs + { + public byte[] Data; + } + + public class WebsocketTextEventArgs : EventArgs + { + public string Data; + } + + public class PingEventArgs : EventArgs + { + /// + /// The ping event can arbitrarily contain data + /// + public byte[] Data; + } + + public class PongEventArgs : EventArgs + { + /// + /// The pong event can arbitrarily contain data + /// + public byte[] Data; + + public int PingResponseMS; + + } + + public class RegularHttpRequestEvnetArgs : EventArgs + { + + } + + public class UpgradeCompletedEventArgs : EventArgs + { + + } + + public class UpgradeFailedEventArgs : EventArgs + { + + } + + public class CloseEventArgs : EventArgs + { + + } + + +} diff --git a/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs new file mode 100644 index 0000000..f212208 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs @@ -0,0 +1,91 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Net; +using Nwc.XmlRpc; +using OpenSim.Framework; + + +namespace OpenSim.Framework.Servers.HttpServer +{ + public class XmlRpcBasicDOSProtector + { + private readonly XmlRpcMethod _normalMethod; + private readonly XmlRpcMethod _throttledMethod; + + private readonly BasicDosProtectorOptions _options; + private readonly BasicDOSProtector _dosProtector; + + public XmlRpcBasicDOSProtector(XmlRpcMethod normalMethod, XmlRpcMethod throttledMethod,BasicDosProtectorOptions options) + { + _normalMethod = normalMethod; + _throttledMethod = throttledMethod; + + _options = options; + _dosProtector = new BasicDOSProtector(_options); + + } + public XmlRpcResponse Process(XmlRpcRequest request, IPEndPoint client) + { + + XmlRpcResponse resp = null; + string clientstring = GetClientString(request, client); + string endpoint = GetEndPoint(request, client); + if (_dosProtector.Process(clientstring, endpoint)) + resp = _normalMethod(request, client); + else + resp = _throttledMethod(request, client); + if (_options.MaxConcurrentSessions > 0) + _dosProtector.ProcessEnd(clientstring, endpoint); + return resp; + } + + private string GetClientString(XmlRpcRequest request, IPEndPoint client) + { + string clientstring; + if (_options.AllowXForwardedFor && request.Params.Count > 3) + { + object headerstr = request.Params[3]; + if (headerstr != null && !string.IsNullOrEmpty(headerstr.ToString())) + clientstring = request.Params[3].ToString(); + else + clientstring = client.Address.ToString(); + } + else + clientstring = client.Address.ToString(); + return clientstring; + } + + private string GetEndPoint(XmlRpcRequest request, IPEndPoint client) + { + return client.Address.ToString(); + } + + } + + +} diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs index ae7d515..57931d4 100644 --- a/OpenSim/Framework/Servers/MainServer.cs +++ b/OpenSim/Framework/Servers/MainServer.cs @@ -121,12 +121,14 @@ namespace OpenSim.Framework.Servers + " level >= 2 then long warnings are logged when receiving bad input data.\n" + " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n" + " level >= 4 then the time taken to fulfill the request is logged.\n" - + " level >= 5 then a sample from the beginning of the incoming data is logged.\n" - + " level >= 6 then the entire incoming data is logged.\n" + + " level >= 5 then a sample from the beginning of the data is logged.\n" + + " level >= 6 then the entire data is logged.\n" + " no level is specified then the current level is returned.\n\n" + "If out or all and\n" + " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n" - + " level >= 4 then the time taken to fulfill the request is logged.\n", + + " level >= 4 then the time taken to fulfill the request is logged.\n" + + " level >= 5 then a sample from the beginning of the data is logged.\n" + + " level >= 6 then the entire data is logged.\n", HandleDebugHttpCommand); } @@ -227,9 +229,16 @@ namespace OpenSim.Framework.Servers handlers.AppendFormat("\t{0}\n", s); handlers.AppendFormat("* HTTP:\n"); - List poll = httpServer.GetPollServiceHandlerKeys(); foreach (String s in httpServer.GetHTTPHandlerKeys()) - handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty)); + handlers.AppendFormat("\t{0}\n", s); + + handlers.AppendFormat("* HTTP (poll):\n"); + foreach (String s in httpServer.GetPollServiceHandlerKeys()) + handlers.AppendFormat("\t{0}\n", s); + + handlers.AppendFormat("* JSONRPC:\n"); + foreach (String s in httpServer.GetJsonRpcHandlerKeys()) + handlers.AppendFormat("\t{0}\n", s); // handlers.AppendFormat("* Agent:\n"); // foreach (String s in httpServer.GetAgentHandlerKeys()) @@ -276,7 +285,12 @@ namespace OpenSim.Framework.Servers public static bool RemoveHttpServer(uint port) { lock (m_Servers) + { + if (instance != null && instance.Port == port) + instance = null; + return m_Servers.Remove(port); + } } /// 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; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] +[assembly: AssemblyVersion("0.7.6.*")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 47baac8..07a09e6 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -29,6 +29,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; @@ -62,6 +63,8 @@ namespace OpenSim.Framework.Servers protected string m_pidFile = String.Empty; + protected ServerStatsCollector m_serverStatsCollector; + /// /// Server version information. Usually VersionInfo + information about git commit, operating system, etc. /// @@ -76,6 +79,11 @@ namespace OpenSim.Framework.Servers protected void CreatePIDFile(string path) { + if (File.Exists(path)) + m_log.ErrorFormat( + "[SERVER BASE]: Previous pid file {0} still exists on startup. Possibly previously unclean shutdown.", + path); + try { string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); @@ -113,6 +121,26 @@ namespace OpenSim.Framework.Servers } } + /// + /// Log information about the circumstances in which we're running (OpenSimulator version number, CLR details, + /// etc.). + /// + public void LogEnvironmentInformation() + { + // FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net + // XmlConfigurator calls first accross servers. + m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory); + + m_log.InfoFormat("[SERVER BASE]: OpenSimulator version: {0}", m_version); + + // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and + // the clr version number doesn't match the project version number under Mono. + //m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine); + m_log.InfoFormat( + "[SERVER BASE]: Operating system version: {0}, .NET platform {1}, {2}-bit", + Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32"); + } + public void RegisterCommonAppenders(IConfig startupConfig) { ILoggerRepository repository = LogManager.GetRepository(); @@ -219,7 +247,7 @@ namespace OpenSim.Framework.Servers "Show thread status", HandleShow); m_console.Commands.AddCommand( - "General", false, "threads abort", + "Debug", false, "threads abort", "threads abort ", "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort); @@ -229,11 +257,281 @@ namespace OpenSim.Framework.Servers "Show thread status. Synonym for \"show threads\"", (string module, string[] args) => Notice(GetThreadsReport())); + m_console.Commands.AddCommand ( + "Debug", false, "debug comms set", + "debug comms set serialosdreq true|false", + "Set comms parameters. For debug purposes.", + HandleDebugCommsSet); + + m_console.Commands.AddCommand ( + "Debug", false, "debug comms status", + "debug comms status", + "Show current debug comms parameters.", + HandleDebugCommsStatus); + + m_console.Commands.AddCommand ( + "Debug", false, "debug threadpool set", + "debug threadpool set worker|iocp min|max ", + "Set threadpool parameters. For debug purposes.", + HandleDebugThreadpoolSet); + + m_console.Commands.AddCommand ( + "Debug", false, "debug threadpool status", + "debug threadpool status", + "Show current debug threadpool parameters.", + HandleDebugThreadpoolStatus); + + m_console.Commands.AddCommand( + "Debug", false, "debug threadpool level", + "debug threadpool level 0.." + Util.MAX_THREADPOOL_LEVEL, + "Turn on logging of activity in the main thread pool.", + "Log levels:\n" + + " 0 = no logging\n" + + " 1 = only first line of stack trace; don't log common threads\n" + + " 2 = full stack trace; don't log common threads\n" + + " 3 = full stack trace, including common threads\n", + HandleDebugThreadpoolLevel); + +// m_console.Commands.AddCommand( +// "Debug", false, "show threadpool calls active", +// "show threadpool calls active", +// "Show details about threadpool calls that are still active (currently waiting or in progress)", +// HandleShowThreadpoolCallsActive); + m_console.Commands.AddCommand( - "General", false, "force gc", + "Debug", false, "show threadpool calls complete", + "show threadpool calls complete", + "Show details about threadpool calls that have been completed.", + HandleShowThreadpoolCallsComplete); + + m_console.Commands.AddCommand( + "Debug", false, "force gc", "force gc", "Manually invoke runtime garbage collection. For debugging purposes", HandleForceGc); + + m_console.Commands.AddCommand( + "General", false, "quit", + "quit", + "Quit the application", (mod, args) => Shutdown()); + + m_console.Commands.AddCommand( + "General", false, "shutdown", + "shutdown", + "Quit the application", (mod, args) => Shutdown()); + + ChecksManager.RegisterConsoleCommands(m_console); + StatsManager.RegisterConsoleCommands(m_console); + } + + public void RegisterCommonComponents(IConfigSource configSource) + { + IConfig networkConfig = configSource.Configs["Network"]; + + if (networkConfig != null) + { + WebUtil.SerializeOSDRequestsPerEndpoint = networkConfig.GetBoolean("SerializeOSDRequests", false); + } + + m_serverStatsCollector = new ServerStatsCollector(); + m_serverStatsCollector.Initialise(configSource); + m_serverStatsCollector.Start(); + } + + private void HandleDebugCommsStatus(string module, string[] args) + { + Notice("serialosdreq is {0}", WebUtil.SerializeOSDRequestsPerEndpoint); + } + + private void HandleDebugCommsSet(string module, string[] args) + { + if (args.Length != 5) + { + Notice("Usage: debug comms set serialosdreq true|false"); + return; + } + + if (args[3] != "serialosdreq") + { + Notice("Usage: debug comms set serialosdreq true|false"); + return; + } + + bool setSerializeOsdRequests; + + if (!ConsoleUtil.TryParseConsoleBool(m_console, args[4], out setSerializeOsdRequests)) + return; + + WebUtil.SerializeOSDRequestsPerEndpoint = setSerializeOsdRequests; + + Notice("serialosdreq is now {0}", setSerializeOsdRequests); + } + + private void HandleShowThreadpoolCallsActive(string module, string[] args) + { + List> calls = Util.GetFireAndForgetCallsInProgress().ToList(); + calls.Sort((kvp1, kvp2) => kvp2.Value.CompareTo(kvp1.Value)); + int namedCalls = 0; + + ConsoleDisplayList cdl = new ConsoleDisplayList(); + foreach (KeyValuePair kvp in calls) + { + if (kvp.Value > 0) + { + cdl.AddRow(kvp.Key, kvp.Value); + namedCalls += kvp.Value; + } + } + + cdl.AddRow("TOTAL NAMED", namedCalls); + + long allQueuedCalls = Util.TotalQueuedFireAndForgetCalls; + long allRunningCalls = Util.TotalRunningFireAndForgetCalls; + + cdl.AddRow("TOTAL QUEUED", allQueuedCalls); + cdl.AddRow("TOTAL RUNNING", allRunningCalls); + cdl.AddRow("TOTAL ANONYMOUS", allQueuedCalls + allRunningCalls - namedCalls); + cdl.AddRow("TOTAL ALL", allQueuedCalls + allRunningCalls); + + MainConsole.Instance.Output(cdl.ToString()); + } + + private void HandleShowThreadpoolCallsComplete(string module, string[] args) + { + List> calls = Util.GetFireAndForgetCallsMade().ToList(); + calls.Sort((kvp1, kvp2) => kvp2.Value.CompareTo(kvp1.Value)); + int namedCallsMade = 0; + + ConsoleDisplayList cdl = new ConsoleDisplayList(); + foreach (KeyValuePair kvp in calls) + { + cdl.AddRow(kvp.Key, kvp.Value); + namedCallsMade += kvp.Value; + } + + cdl.AddRow("TOTAL NAMED", namedCallsMade); + + long allCallsMade = Util.TotalFireAndForgetCallsMade; + cdl.AddRow("TOTAL ANONYMOUS", allCallsMade - namedCallsMade); + cdl.AddRow("TOTAL ALL", allCallsMade); + + MainConsole.Instance.Output(cdl.ToString()); + } + + private void HandleDebugThreadpoolStatus(string module, string[] args) + { + int workerThreads, iocpThreads; + + ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); + Notice("Min worker threads: {0}", workerThreads); + Notice("Min IOCP threads: {0}", iocpThreads); + + ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); + Notice("Max worker threads: {0}", workerThreads); + Notice("Max IOCP threads: {0}", iocpThreads); + + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + Notice("Available worker threads: {0}", workerThreads); + Notice("Available IOCP threads: {0}", iocpThreads); + } + + private void HandleDebugThreadpoolSet(string module, string[] args) + { + if (args.Length != 6) + { + Notice("Usage: debug threadpool set worker|iocp min|max "); + return; + } + + int newThreads; + + if (!ConsoleUtil.TryParseConsoleInt(m_console, args[5], out newThreads)) + return; + + string poolType = args[3]; + string bound = args[4]; + + bool fail = false; + int workerThreads, iocpThreads; + + if (poolType == "worker") + { + if (bound == "min") + { + ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); + + if (!ThreadPool.SetMinThreads(newThreads, iocpThreads)) + fail = true; + } + else + { + ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); + + if (!ThreadPool.SetMaxThreads(newThreads, iocpThreads)) + fail = true; + } + } + else + { + if (bound == "min") + { + ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); + + if (!ThreadPool.SetMinThreads(workerThreads, newThreads)) + fail = true; + } + else + { + ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); + + if (!ThreadPool.SetMaxThreads(workerThreads, newThreads)) + fail = true; + } + } + + if (fail) + { + Notice("ERROR: Could not set {0} {1} threads to {2}", poolType, bound, newThreads); + } + else + { + int minWorkerThreads, maxWorkerThreads, minIocpThreads, maxIocpThreads; + + ThreadPool.GetMinThreads(out minWorkerThreads, out minIocpThreads); + ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxIocpThreads); + + Notice("Min worker threads now {0}", minWorkerThreads); + Notice("Min IOCP threads now {0}", minIocpThreads); + Notice("Max worker threads now {0}", maxWorkerThreads); + Notice("Max IOCP threads now {0}", maxIocpThreads); + } + } + + private static void HandleDebugThreadpoolLevel(string module, string[] cmdparams) + { + if (cmdparams.Length < 4) + { + MainConsole.Instance.Output("Usage: debug threadpool level 0.." + Util.MAX_THREADPOOL_LEVEL); + return; + } + + string rawLevel = cmdparams[3]; + int newLevel; + + if (!int.TryParse(rawLevel, out newLevel)) + { + MainConsole.Instance.OutputFormat("{0} is not a valid debug level", rawLevel); + return; + } + + if (newLevel < 0 || newLevel > Util.MAX_THREADPOOL_LEVEL) + { + MainConsole.Instance.OutputFormat("{0} is outside the valid debug level range of 0.." + Util.MAX_THREADPOOL_LEVEL, newLevel); + return; + } + + Util.LogThreadPool = newLevel; + MainConsole.Instance.OutputFormat("LogThreadPool set to {0}", newLevel); } private void HandleForceGc(string module, string[] args) @@ -575,7 +873,8 @@ namespace OpenSim.Framework.Servers protected string GetVersionText() { - return String.Format("Version: {0} (interface version {1})", m_version, VersionInfo.MajorInterfaceVersion); + return String.Format("Version: {0} (SIMULATION/{1} - SIMULATION/{2})", + m_version, VersionInfo.SimulationServiceVersionSupportedMin, VersionInfo.SimulationServiceVersionSupportedMax); } /// @@ -621,7 +920,68 @@ namespace OpenSim.Framework.Servers sb.AppendFormat("Total threads active: {0}\n\n", totalThreads); sb.Append("Main threadpool (excluding script engine pools)\n"); - sb.Append(Util.GetThreadPoolReport()); + sb.Append(GetThreadPoolReport()); + + return sb.ToString(); + } + + /// + /// Get a thread pool report. + /// + /// + public static string GetThreadPoolReport() + { + string threadPoolUsed = null; + int maxThreads = 0; + int minThreads = 0; + int allocatedThreads = 0; + int inUseThreads = 0; + int waitingCallbacks = 0; + int completionPortThreads = 0; + + StringBuilder sb = new StringBuilder(); + if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) + { + STPInfo stpi = Util.GetSmartThreadPoolInfo(); + + // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. + if (stpi != null) + { + threadPoolUsed = "SmartThreadPool"; + maxThreads = stpi.MaxThreads; + minThreads = stpi.MinThreads; + inUseThreads = stpi.InUseThreads; + allocatedThreads = stpi.ActiveThreads; + waitingCallbacks = stpi.WaitingCallbacks; + } + } + else if ( + Util.FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem + || Util.FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) + { + threadPoolUsed = "BuiltInThreadPool"; + ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); + ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); + int availableThreads; + ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); + inUseThreads = maxThreads - availableThreads; + allocatedThreads = -1; + waitingCallbacks = -1; + } + + if (threadPoolUsed != null) + { + sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); + sb.AppendFormat("Max threads : {0}\n", maxThreads); + sb.AppendFormat("Min threads : {0}\n", minThreads); + sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); + sb.AppendFormat("In use threads : {0}\n", inUseThreads); + sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); + } + else + { + sb.AppendFormat("Thread pool not used\n"); + } return sb.ToString(); } @@ -673,5 +1033,16 @@ namespace OpenSim.Framework.Servers if (m_console != null) m_console.OutputFormat(format, components); } + + public virtual void Shutdown() + { + m_serverStatsCollector.Close(); + ShutdownSpecific(); + } + + /// + /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing + /// + protected virtual void ShutdownSpecific() {} } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs index 3412e0f..5c0e0df 100644 --- a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs +++ b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs @@ -41,318 +41,7 @@ namespace OpenSim.Framework.Servers.Tests { [TestFixture] public class OSHttpTests : OpenSimTestCase - { - // we need an IHttpClientContext for our tests - public class TestHttpClientContext: IHttpClientContext - { - private bool _secured; - public bool IsSecured - { - get { return _secured; } - } - public bool Secured - { - get { return _secured; } - } - - public TestHttpClientContext(bool secured) - { - _secured = secured; - } - - public void Disconnect(SocketError error) {} - public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {} - public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {} - public void Respond(string body) {} - public void Send(byte[] buffer) {} - public void Send(byte[] buffer, int offset, int size) {} - public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) {} - public void Close() { } - public bool EndWhenDone { get { return false;} set { return;}} - - public event EventHandler Disconnected = delegate { }; - /// - /// A request have been received in the context. - /// - public event EventHandler RequestReceived = delegate { }; - - } - - public class TestHttpRequest: IHttpRequest - { - private string _uriPath; - public bool BodyIsComplete - { - get { return true; } - } - public string[] AcceptTypes - { - get {return _acceptTypes; } - } - private string[] _acceptTypes; - public Stream Body - { - get { return _body; } - set { _body = value;} - } - private Stream _body; - public ConnectionType Connection - { - get { return _connection; } - set { _connection = value; } - } - private ConnectionType _connection; - public int ContentLength - { - get { return _contentLength; } - set { _contentLength = value; } - } - private int _contentLength; - public NameValueCollection Headers - { - get { return _headers; } - } - private NameValueCollection _headers = new NameValueCollection(); - public string HttpVersion - { - get { return _httpVersion; } - set { _httpVersion = value; } - } - private string _httpVersion = null; - public string Method - { - get { return _method; } - set { _method = value; } - } - private string _method = null; - public HttpInput QueryString - { - get { return _queryString; } - } - private HttpInput _queryString = null; - public Uri Uri - { - get { return _uri; } - set { _uri = value; } - } - private Uri _uri = null; - public string[] UriParts - { - get { return _uri.Segments; } - } - public HttpParam Param - { - get { return null; } - } - public HttpForm Form - { - get { return null; } - } - public bool IsAjax - { - get { return false; } - } - public RequestCookies Cookies - { - get { return null; } - } - - public TestHttpRequest() {} - - public TestHttpRequest(string contentEncoding, string contentType, string userAgent, - string remoteAddr, string remotePort, string[] acceptTypes, - ConnectionType connectionType, int contentLength, Uri uri) - { - _headers["content-encoding"] = contentEncoding; - _headers["content-type"] = contentType; - _headers["user-agent"] = userAgent; - _headers["remote_addr"] = remoteAddr; - _headers["remote_port"] = remotePort; - - _acceptTypes = acceptTypes; - _connection = connectionType; - _contentLength = contentLength; - _uri = uri; - } - - public void DecodeBody(FormDecoderProvider providers) {} - public void SetCookies(RequestCookies cookies) {} - public void AddHeader(string name, string value) - { - _headers.Add(name, value); - } - public int AddToBody(byte[] bytes, int offset, int length) - { - return 0; - } - public void Clear() {} - - public object Clone() - { - TestHttpRequest clone = new TestHttpRequest(); - clone._acceptTypes = _acceptTypes; - clone._connection = _connection; - clone._contentLength = _contentLength; - clone._uri = _uri; - clone._headers = new NameValueCollection(_headers); - - return clone; - } - public IHttpResponse CreateResponse(IHttpClientContext context) - { - return new HttpResponse(context, this); - } - /// - /// Path and query (will be merged with the host header) and put in Uri - /// - /// - public string UriPath - { - get { return _uriPath; } - set - { - _uriPath = value; - - } - } - - } - - public class TestHttpResponse: IHttpResponse - { - public Stream Body - { - get { return _body; } - - set { _body = value; } - } - private Stream _body; - - public string ProtocolVersion - { - get { return _protocolVersion; } - set { _protocolVersion = value; } - } - private string _protocolVersion; - - public bool Chunked - { - get { return _chunked; } - - set { _chunked = value; } - } - private bool _chunked; - - public ConnectionType Connection - { - get { return _connection; } - - set { _connection = value; } - } - private ConnectionType _connection; - - public Encoding Encoding - { - get { return _encoding; } - - set { _encoding = value; } - } - private Encoding _encoding; - - public int KeepAlive - { - get { return _keepAlive; } - - set { _keepAlive = value; } - } - private int _keepAlive; - - public HttpStatusCode Status - { - get { return _status; } - - set { _status = value; } - } - private HttpStatusCode _status; - - public string Reason - { - get { return _reason; } - - set { _reason = value; } - } - private string _reason; - - public long ContentLength - { - get { return _contentLength; } - - set { _contentLength = value; } - } - private long _contentLength; - - public string ContentType - { - get { return _contentType; } - - set { _contentType = value; } - } - private string _contentType; - - public bool HeadersSent - { - get { return _headersSent; } - } - private bool _headersSent; - - public bool Sent - { - get { return _sent; } - } - private bool _sent; - - public ResponseCookies Cookies - { - get { return _cookies; } - } - private ResponseCookies _cookies = null; - - public TestHttpResponse() - { - _headersSent = false; - _sent = false; - } - - public void AddHeader(string name, string value) {} - public void Send() - { - if (!_headersSent) SendHeaders(); - if (_sent) throw new InvalidOperationException("stuff already sent"); - _sent = true; - } - - public void SendBody(byte[] buffer, int offset, int count) - { - if (!_headersSent) SendHeaders(); - _sent = true; - } - public void SendBody(byte[] buffer) - { - if (!_headersSent) SendHeaders(); - _sent = true; - } - - public void SendHeaders() - { - if (_headersSent) throw new InvalidOperationException("headers already sent"); - _headersSent = true; - } - - public void Redirect(Uri uri) {} - public void Redirect(string url) {} - } - - + { public OSHttpRequest req0; public OSHttpRequest req1; @@ -424,4 +113,4 @@ namespace OpenSim.Framework.Servers.Tests Assert.That(rsp0.ContentType, Is.EqualTo("text/xml")); } } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs b/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs index 2d72cb8..480f2bb 100644 --- a/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs +++ b/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs @@ -47,7 +47,7 @@ namespace OpenSim.Framework.Servers.Tests { foreach (VersionInfo.Flavour flavour in Enum.GetValues(typeof(VersionInfo.Flavour))) { - Assert.AreEqual(VersionInfo.VERSIONINFO_VERSION_LENGTH, VersionInfo.GetVersionString("0.0.0", "0", flavour).Length, "0.0.0/" + flavour + " failed"); + Assert.AreEqual(VersionInfo.VERSIONINFO_VERSION_LENGTH, VersionInfo.GetVersionString("0.0.0", flavour).Length, "0.0.0/" + flavour + " failed"); } } } diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs deleted file mode 100644 index 54af95e..0000000 --- a/OpenSim/Framework/Servers/VersionInfo.cs +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -namespace OpenSim -{ - public class VersionInfo - { - private const string VERSION_NUMBER = "0.7.5"; - private const string IG_BUILD_NUMBER = "4"; - private const Flavour VERSION_FLAVOUR = Flavour.IG; - - public enum Flavour - { - Unknown, - Dev, - RC1, - RC2, - Release, - Post_Fixes, - Extended, - IG - } - - public static string Version - { - get { return GetVersionString(VERSION_NUMBER, IG_BUILD_NUMBER, VERSION_FLAVOUR); } - } - - public static string GetVersionString(string versionNumber, string buildNumber, Flavour flavour) - { - string versionString = "OpenSim " + versionNumber + " " + flavour + " build " + buildNumber; - return versionString.PadRight(VERSIONINFO_VERSION_LENGTH); - } - - public const int VERSIONINFO_VERSION_LENGTH = 39; - - /// - /// This is the external interface version. It is separate from the OpenSimulator project version. - /// - /// This version number should be - /// increased by 1 every time a code change makes the previous OpenSimulator revision incompatible - /// with the new revision. This will usually be due to interregion or grid facing interface changes. - /// - /// Changes which are compatible with an older revision (e.g. older revisions experience degraded functionality - /// but not outright failure) do not need a version number increment. - /// - /// Having this version number allows the grid service to reject connections from regions running a version - /// of the code that is too old. - /// - /// - public readonly static int MajorInterfaceVersion = 7; - } -} diff --git a/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs b/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs new file mode 100644 index 0000000..512ac4f --- /dev/null +++ b/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs @@ -0,0 +1,113 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Net; +using System.Reflection; + +using Nini.Config; +using log4net; + +namespace OpenSim.Framework.ServiceAuth +{ + public class BasicHttpAuthentication : IServiceAuth + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public string Name { get { return "BasicHttp"; } } + + private string m_Username, m_Password; + private string m_CredentialsB64; + +// private string remove_me; + + public string Credentials + { + get { return m_CredentialsB64; } + } + + public BasicHttpAuthentication(IConfigSource config, string section) + { +// remove_me = section; + m_Username = Util.GetConfigVarFromSections(config, "HttpAuthUsername", new string[] { "Network", section }, string.Empty); + m_Password = Util.GetConfigVarFromSections(config, "HttpAuthPassword", new string[] { "Network", section }, string.Empty); + string str = m_Username + ":" + m_Password; + byte[] encData_byte = Util.UTF8.GetBytes(str); + + m_CredentialsB64 = Convert.ToBase64String(encData_byte); +// m_log.DebugFormat("[HTTP BASIC AUTH]: {0} {1} [{2}]", m_Username, m_Password, section); + } + + public void AddAuthorization(NameValueCollection headers) + { + //m_log.DebugFormat("[HTTP BASIC AUTH]: Adding authorization for {0}", remove_me); + headers["Authorization"] = "Basic " + m_CredentialsB64; + } + + public bool Authenticate(string data) + { + string recovered = Util.Base64ToString(data); + if (!String.IsNullOrEmpty(recovered)) + { + string[] parts = recovered.Split(new char[] { ':' }); + if (parts.Length >= 2) + { + return m_Username.Equals(parts[0]) && m_Password.Equals(parts[1]); + } + } + + return false; + } + + public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode) + { +// m_log.DebugFormat("[HTTP BASIC AUTH]: Authenticate in {0}", "BasicHttpAuthentication"); + + string value = requestHeaders.Get("Authorization"); + if (value != null) + { + value = value.Trim(); + if (value.StartsWith("Basic ")) + { + value = value.Replace("Basic ", string.Empty); + if (Authenticate(value)) + { + statusCode = HttpStatusCode.OK; + return true; + } + } + } + + d("WWW-Authenticate", "Basic realm = \"Asset Server\""); + + statusCode = HttpStatusCode.Unauthorized; + return false; + } + } +} diff --git a/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs new file mode 100644 index 0000000..a49952c --- /dev/null +++ b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs @@ -0,0 +1,82 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Net; + +namespace OpenSim.Framework.ServiceAuth +{ + public class CompoundAuthentication : IServiceAuth + { + public string Name { get { return "Compound"; } } + + private List m_authentications = new List(); + + public int Count { get { return m_authentications.Count; } } + + public List GetAuthentors() + { + return new List(m_authentications); + } + + public void AddAuthenticator(IServiceAuth auth) + { + m_authentications.Add(auth); + } + + public void RemoveAuthenticator(IServiceAuth auth) + { + m_authentications.Remove(auth); + } + + public void AddAuthorization(NameValueCollection headers) + { + foreach (IServiceAuth auth in m_authentications) + auth.AddAuthorization(headers); + } + + public bool Authenticate(string data) + { + return m_authentications.TrueForAll(a => a.Authenticate(data)); + } + + public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode) + { + foreach (IServiceAuth auth in m_authentications) + { + if (!auth.Authenticate(requestHeaders, d, out statusCode)) + return false; + } + + statusCode = HttpStatusCode.OK; + return true; + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs b/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs new file mode 100644 index 0000000..e0c413b --- /dev/null +++ b/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs @@ -0,0 +1,59 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Specialized; +using System.Net; + +namespace OpenSim.Framework.ServiceAuth +{ + public class DisallowLlHttpRequest : IServiceAuth + { + public string Name { get { return "DisallowllHTTPRequest"; } } + + public void AddAuthorization(NameValueCollection headers) {} + + public bool Authenticate(string data) + { + return false; + } + + public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode) + { +// Console.WriteLine("DisallowLlHttpRequest"); + + if (requestHeaders["X-SecondLife-Shard"] != null) + { + statusCode = HttpStatusCode.Forbidden; + return false; + } + + statusCode = HttpStatusCode.OK; + return true; + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/ServiceAuth/IServiceAuth.cs b/OpenSim/Framework/ServiceAuth/IServiceAuth.cs new file mode 100644 index 0000000..5f744cb --- /dev/null +++ b/OpenSim/Framework/ServiceAuth/IServiceAuth.cs @@ -0,0 +1,48 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; +using System.Collections.Generic; +using System.Collections.Specialized; + +namespace OpenSim.Framework.ServiceAuth +{ + public delegate void AddHeaderDelegate(string key, string value); + + public interface IServiceAuth + { + /// + /// Name of this authenticator. + /// + string Name { get; } + + bool Authenticate(string data); + bool Authenticate(NameValueCollection headers, AddHeaderDelegate d, out HttpStatusCode statusCode); + void AddAuthorization(NameValueCollection headers); + } +} diff --git a/OpenSim/Framework/ServiceAuth/ServiceAuth.cs b/OpenSim/Framework/ServiceAuth/ServiceAuth.cs new file mode 100644 index 0000000..51012e3 --- /dev/null +++ b/OpenSim/Framework/ServiceAuth/ServiceAuth.cs @@ -0,0 +1,68 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using log4net; +using Nini.Config; + +namespace OpenSim.Framework.ServiceAuth +{ + public class ServiceAuth + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public static IServiceAuth Create(IConfigSource config, string section) + { + CompoundAuthentication compoundAuth = new CompoundAuthentication(); + + bool allowLlHttpRequestIn + = Util.GetConfigVarFromSections(config, "AllowllHTTPRequestIn", new string[] { "Network", section }, false); + + if (!allowLlHttpRequestIn) + compoundAuth.AddAuthenticator(new DisallowLlHttpRequest()); + + string authType = Util.GetConfigVarFromSections(config, "AuthType", new string[] { "Network", section }, "None"); + + switch (authType) + { + case "BasicHttpAuthentication": + compoundAuth.AddAuthenticator(new BasicHttpAuthentication(config, section)); + break; + } + +// foreach (IServiceAuth auth in compoundAuth.GetAuthentors()) +// m_log.DebugFormat("[SERVICE AUTH]: Configured authenticator {0}", auth.Name); + + if (compoundAuth.Count > 0) + return compoundAuth; + else + return null; + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/TaskInventoryItem.cs b/OpenSim/Framework/TaskInventoryItem.cs index a06f8e7..307cb75 100644 --- a/OpenSim/Framework/TaskInventoryItem.cs +++ b/OpenSim/Framework/TaskInventoryItem.cs @@ -124,7 +124,7 @@ namespace OpenSim.Framework { get { - if (_creatorData != null && _creatorData != string.Empty) + if (!string.IsNullOrEmpty(_creatorData)) return _creatorID.ToString() + ';' + _creatorData; else return _creatorID.ToString(); diff --git a/OpenSim/Framework/TerrainData.cs b/OpenSim/Framework/TerrainData.cs new file mode 100644 index 0000000..6b1be4e --- /dev/null +++ b/OpenSim/Framework/TerrainData.cs @@ -0,0 +1,464 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; + +using OpenMetaverse; + +using log4net; + +namespace OpenSim.Framework +{ + public abstract class TerrainData + { + // Terrain always is a square + public int SizeX { get; protected set; } + public int SizeY { get; protected set; } + public int SizeZ { get; protected set; } + + // A height used when the user doesn't specify anything + public const float DefaultTerrainHeight = 21f; + + public abstract float this[int x, int y] { get; set; } + // Someday terrain will have caves + public abstract float this[int x, int y, int z] { get; set; } + + public abstract bool IsTaintedAt(int xx, int yy); + public abstract bool IsTaintedAt(int xx, int yy, bool clearOnTest); + public abstract void TaintAllTerrain(); + public abstract void ClearTaint(); + + public abstract void ClearLand(); + public abstract void ClearLand(float height); + + // Return a representation of this terrain for storing as a blob in the database. + // Returns 'true' to say blob was stored in the 'out' locations. + public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob); + + // Given a revision code and a blob from the database, create and return the right type of TerrainData. + // The sizes passed are the expected size of the region. The database info will be used to + // initialize the heightmap of that sized region with as much data is in the blob. + // Return created TerrainData or 'null' if unsuccessful. + public static TerrainData CreateFromDatabaseBlobFactory(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) + { + // For the moment, there is only one implementation class + return new HeightmapTerrainData(pSizeX, pSizeY, pSizeZ, pFormatCode, pBlob); + } + + // return a special compressed representation of the heightmap in ints + public abstract int[] GetCompressedMap(); + public abstract float CompressionFactor { get; } + + public abstract float[] GetFloatsSerialized(); + public abstract double[,] GetDoubles(); + public abstract TerrainData Clone(); + } + + // The terrain is stored in the database as a blob with a 'revision' field. + // Some implementations of terrain storage would fill the revision field with + // the time the terrain was stored. When real revisions were added and this + // feature removed, that left some old entries with the time in the revision + // field. + // Thus, if revision is greater than 'RevisionHigh' then terrain db entry is + // left over and it is presumed to be 'Legacy256'. + // Numbers are arbitrary and are chosen to to reduce possible mis-interpretation. + // If a revision does not match any of these, it is assumed to be Legacy256. + public enum DBTerrainRevision + { + // Terrain is 'double[256,256]' + Legacy256 = 11, + // Terrain is 'int32, int32, float[,]' where the ints are X and Y dimensions + // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256. + Variable2D = 22, + // Terrain is 'int32, int32, int32, int16[]' where the ints are X and Y dimensions + // and third int is the 'compression factor'. The heights are compressed as + // "int compressedHeight = (int)(height * compressionFactor);" + // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256. + Compressed2D = 27, + // A revision that is not listed above or any revision greater than this value is 'Legacy256'. + RevisionHigh = 1234 + } + + // Version of terrain that is a heightmap. + // This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge + // of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer. + // The heighmap is kept as an array of integers. The integer values are converted to + // and from floats by TerrainCompressionFactor. + public class HeightmapTerrainData : TerrainData + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static string LogHeader = "[HEIGHTMAP TERRAIN DATA]"; + + // TerrainData.this[x, y] + public override float this[int x, int y] + { + get { return FromCompressedHeight(m_heightmap[x, y]); } + set { + int newVal = ToCompressedHeight(value); + if (m_heightmap[x, y] != newVal) + { + m_heightmap[x, y] = newVal; + m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true; + } + } + } + + // TerrainData.this[x, y, z] + public override float this[int x, int y, int z] + { + get { return this[x, y]; } + set { this[x, y] = value; } + } + + // TerrainData.ClearTaint + public override void ClearTaint() + { + SetAllTaint(false); + } + + // TerrainData.TaintAllTerrain + public override void TaintAllTerrain() + { + SetAllTaint(true); + } + + private void SetAllTaint(bool setting) + { + for (int ii = 0; ii < m_taint.GetLength(0); ii++) + for (int jj = 0; jj < m_taint.GetLength(1); jj++) + m_taint[ii, jj] = setting; + } + + // TerrainData.ClearLand + public override void ClearLand() + { + ClearLand(DefaultTerrainHeight); + } + // TerrainData.ClearLand(float) + public override void ClearLand(float pHeight) + { + int flatHeight = ToCompressedHeight(pHeight); + for (int xx = 0; xx < SizeX; xx++) + for (int yy = 0; yy < SizeY; yy++) + m_heightmap[xx, yy] = flatHeight; + } + + // Return 'true' of the patch that contains these region coordinates has been modified. + // Note that checking the taint clears it. + // There is existing code that relies on this feature. + public override bool IsTaintedAt(int xx, int yy, bool clearOnTest) + { + int tx = xx / Constants.TerrainPatchSize; + int ty = yy / Constants.TerrainPatchSize; + bool ret = m_taint[tx, ty]; + if (ret && clearOnTest) + m_taint[tx, ty] = false; + return ret; + } + + // Old form that clears the taint flag when we check it. + public override bool IsTaintedAt(int xx, int yy) + { + return IsTaintedAt(xx, yy, true /* clearOnTest */); + } + + // TerrainData.GetDatabaseBlob + // The user wants something to store in the database. + public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob) + { + bool ret = false; + if (SizeX == Constants.RegionSize && SizeY == Constants.RegionSize) + { + DBRevisionCode = (int)DBTerrainRevision.Legacy256; + blob = ToLegacyTerrainSerialization(); + ret = true; + } + else + { + DBRevisionCode = (int)DBTerrainRevision.Compressed2D; + blob = ToCompressedTerrainSerialization(); + ret = true; + } + return ret; + } + + // TerrainData.CompressionFactor + private float m_compressionFactor = 100.0f; + public override float CompressionFactor { get { return m_compressionFactor; } } + + // TerrainData.GetCompressedMap + public override int[] GetCompressedMap() + { + int[] newMap = new int[SizeX * SizeY]; + + int ind = 0; + for (int xx = 0; xx < SizeX; xx++) + for (int yy = 0; yy < SizeY; yy++) + newMap[ind++] = m_heightmap[xx, yy]; + + return newMap; + + } + // TerrainData.Clone + public override TerrainData Clone() + { + HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ); + ret.m_heightmap = (int[,])this.m_heightmap.Clone(); + return ret; + } + + // TerrainData.GetFloatsSerialized + // This one dimensional version is ordered so height = map[y*sizeX+x]; + // DEPRECATED: don't use this function as it does not retain the dimensions of the terrain + // and the caller will probably do the wrong thing if the terrain is not the legacy 256x256. + public override float[] GetFloatsSerialized() + { + int points = SizeX * SizeY; + float[] heights = new float[points]; + + int idx = 0; + for (int jj = 0; jj < SizeY; jj++) + for (int ii = 0; ii < SizeX; ii++) + { + heights[idx++] = FromCompressedHeight(m_heightmap[ii, jj]); + } + + return heights; + } + + // TerrainData.GetDoubles + public override double[,] GetDoubles() + { + double[,] ret = new double[SizeX, SizeY]; + for (int xx = 0; xx < SizeX; xx++) + for (int yy = 0; yy < SizeY; yy++) + ret[xx, yy] = FromCompressedHeight(m_heightmap[xx, yy]); + + return ret; + } + + + // ============================================================= + + private int[,] m_heightmap; + // Remember subregions of the heightmap that has changed. + private bool[,] m_taint; + + // To save space (especially for large regions), keep the height as a short integer + // that is coded as the float height times the compression factor (usually '100' + // to make for two decimal points). + public int ToCompressedHeight(double pHeight) + { + return (int)(pHeight * CompressionFactor); + } + + public float FromCompressedHeight(int pHeight) + { + return ((float)pHeight) / CompressionFactor; + } + + // To keep with the legacy theme, create an instance of this class based on the + // way terrain used to be passed around. + public HeightmapTerrainData(double[,] pTerrain) + { + SizeX = pTerrain.GetLength(0); + SizeY = pTerrain.GetLength(1); + SizeZ = (int)Constants.RegionHeight; + m_compressionFactor = 100.0f; + + m_heightmap = new int[SizeX, SizeY]; + for (int ii = 0; ii < SizeX; ii++) + { + for (int jj = 0; jj < SizeY; jj++) + { + m_heightmap[ii, jj] = ToCompressedHeight(pTerrain[ii, jj]); + + } + } + // m_log.DebugFormat("{0} new by doubles. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ); + + m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize]; + ClearTaint(); + } + + // Create underlying structures but don't initialize the heightmap assuming the caller will immediately do that + public HeightmapTerrainData(int pX, int pY, int pZ) + { + SizeX = pX; + SizeY = pY; + SizeZ = pZ; + m_compressionFactor = 100.0f; + m_heightmap = new int[SizeX, SizeY]; + m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize]; + // m_log.DebugFormat("{0} new by dimensions. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ); + ClearTaint(); + ClearLand(0f); + } + + public HeightmapTerrainData(int[] cmap, float pCompressionFactor, int pX, int pY, int pZ) : this(pX, pY, pZ) + { + m_compressionFactor = pCompressionFactor; + int ind = 0; + for (int xx = 0; xx < SizeX; xx++) + for (int yy = 0; yy < SizeY; yy++) + m_heightmap[xx, yy] = cmap[ind++]; + // m_log.DebugFormat("{0} new by compressed map. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ); + } + + // Create a heighmap from a database blob + public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) : this(pSizeX, pSizeY, pSizeZ) + { + switch ((DBTerrainRevision)pFormatCode) + { + case DBTerrainRevision.Compressed2D: + FromCompressedTerrainSerialization(pBlob); + m_log.DebugFormat("{0} HeightmapTerrainData create from Compressed2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); + break; + default: + FromLegacyTerrainSerialization(pBlob); + m_log.DebugFormat("{0} HeightmapTerrainData create from legacy serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY); + break; + } + } + + // Just create an array of doubles. Presumes the caller implicitly knows the size. + public Array ToLegacyTerrainSerialization() + { + Array ret = null; + + using (MemoryStream str = new MemoryStream((int)Constants.RegionSize * (int)Constants.RegionSize * sizeof(double))) + { + using (BinaryWriter bw = new BinaryWriter(str)) + { + for (int xx = 0; xx < Constants.RegionSize; xx++) + { + for (int yy = 0; yy < Constants.RegionSize; yy++) + { + double height = this[xx, yy]; + if (height == 0.0) + height = double.Epsilon; + bw.Write(height); + } + } + } + ret = str.ToArray(); + } + return ret; + } + + // Just create an array of doubles. Presumes the caller implicitly knows the size. + public void FromLegacyTerrainSerialization(byte[] pBlob) + { + // In case database info doesn't match real terrain size, initialize the whole terrain. + ClearLand(); + + using (MemoryStream mstr = new MemoryStream(pBlob)) + { + using (BinaryReader br = new BinaryReader(mstr)) + { + for (int xx = 0; xx < (int)Constants.RegionSize; xx++) + { + for (int yy = 0; yy < (int)Constants.RegionSize; yy++) + { + float val = (float)br.ReadDouble(); + if (xx < SizeX && yy < SizeY) + m_heightmap[xx, yy] = ToCompressedHeight(val); + } + } + } + ClearTaint(); + } + } + + // See the reader below. + public Array ToCompressedTerrainSerialization() + { + Array ret = null; + using (MemoryStream str = new MemoryStream((3 * sizeof(Int32)) + (SizeX * SizeY * sizeof(Int16)))) + { + using (BinaryWriter bw = new BinaryWriter(str)) + { + bw.Write((Int32)DBTerrainRevision.Compressed2D); + bw.Write((Int32)SizeX); + bw.Write((Int32)SizeY); + bw.Write((Int32)CompressionFactor); + for (int yy = 0; yy < SizeY; yy++) + for (int xx = 0; xx < SizeX; xx++) + { + bw.Write((Int16)m_heightmap[xx, yy]); + } + } + ret = str.ToArray(); + } + return ret; + } + + // Initialize heightmap from blob consisting of: + // int32, int32, int32, int32, int16[] + // where the first int32 is format code, next two int32s are the X and y of heightmap data and + // the forth int is the compression factor for the following int16s + // This is just sets heightmap info. The actual size of the region was set on this instance's + // creation and any heights not initialized by theis blob are set to the default height. + public void FromCompressedTerrainSerialization(byte[] pBlob) + { + Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor; + + using (MemoryStream mstr = new MemoryStream(pBlob)) + { + using (BinaryReader br = new BinaryReader(mstr)) + { + hmFormatCode = br.ReadInt32(); + hmSizeX = br.ReadInt32(); + hmSizeY = br.ReadInt32(); + hmCompressionFactor = br.ReadInt32(); + + m_compressionFactor = hmCompressionFactor; + + // In case database info doesn't match real terrain size, initialize the whole terrain. + ClearLand(); + + for (int yy = 0; yy < hmSizeY; yy++) + { + for (int xx = 0; xx < hmSizeX; xx++) + { + Int16 val = br.ReadInt16(); + if (xx < SizeX && yy < SizeY) + m_heightmap[xx, yy] = val; + } + } + } + ClearTaint(); + + m_log.InfoFormat("{0} Read compressed 2d heightmap. Heightmap size=<{1},{2}>. Region size=<{3},{4}>. CompFact={5}", + LogHeader, hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor); + } + } + } +} diff --git a/OpenSim/Framework/Tests/AnimationTests.cs b/OpenSim/Framework/Tests/AnimationTests.cs index f3be81b..d8f17d0 100644 --- a/OpenSim/Framework/Tests/AnimationTests.cs +++ b/OpenSim/Framework/Tests/AnimationTests.cs @@ -32,7 +32,6 @@ using OpenMetaverse; using OpenMetaverse.StructuredData; using OpenSim.Framework; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; using Animation = OpenSim.Framework.Animation; namespace OpenSim.Framework.Tests diff --git a/OpenSim/Framework/Tests/AssetBaseTest.cs b/OpenSim/Framework/Tests/AssetBaseTest.cs index 25d2393..1975a4d 100644 --- a/OpenSim/Framework/Tests/AssetBaseTest.cs +++ b/OpenSim/Framework/Tests/AssetBaseTest.cs @@ -50,19 +50,15 @@ namespace OpenSim.Framework.Tests CheckContainsReferences(AssetType.ImageJPEG , false); CheckContainsReferences(AssetType.ImageTGA , false); CheckContainsReferences(AssetType.Landmark , false); - CheckContainsReferences(AssetType.LostAndFoundFolder, false); CheckContainsReferences(AssetType.LSLBytecode, false); CheckContainsReferences(AssetType.LSLText, false); CheckContainsReferences(AssetType.Notecard, false); CheckContainsReferences(AssetType.Object, false); - CheckContainsReferences(AssetType.RootFolder, false); CheckContainsReferences(AssetType.Simstate, false); - CheckContainsReferences(AssetType.SnapshotFolder, false); CheckContainsReferences(AssetType.Sound, false); CheckContainsReferences(AssetType.SoundWAV, false); CheckContainsReferences(AssetType.Texture, false); CheckContainsReferences(AssetType.TextureTGA, false); - CheckContainsReferences(AssetType.TrashFolder, false); CheckContainsReferences(AssetType.Unknown, false); } diff --git a/OpenSim/Framework/Tests/LocationTest.cs b/OpenSim/Framework/Tests/LocationTest.cs index a56ecb4..3d5d1d2 100644 --- a/OpenSim/Framework/Tests/LocationTest.cs +++ b/OpenSim/Framework/Tests/LocationTest.cs @@ -51,21 +51,28 @@ namespace OpenSim.Framework.Tests [Test] public void locationXYRegionHandle() { - Location TestLocation1 = new Location(256000,256000); - Location TestLocation2 = new Location(1099511628032000); + Location TestLocation1 = new Location(255000,256000); + Location TestLocation2 = new Location(1095216660736000); Assert.That(TestLocation1 == TestLocation2); - Assert.That(TestLocation2.X == 256000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided"); + Assert.That(TestLocation1.X == 255000 && TestLocation1.Y == 256000, "Test xy location doesn't match position in the constructor"); + Assert.That(TestLocation2.X == 255000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided"); - Assert.That(TestLocation2.RegionHandle == 1099511628032000, + Assert.That(TestLocation2.RegionHandle == 1095216660736000, "Location RegionHandle Property didn't match regionhandle provided in constructor"); + ulong RegionHandle = TestLocation1.RegionHandle; + Assert.That(RegionHandle.Equals(1095216660736000), "Equals(regionhandle) failed to match the position in the constructor"); - TestLocation1 = new Location(256001, 256001); - TestLocation2 = new Location(1099511628032000); + TestLocation2 = new Location(RegionHandle); + Assert.That(TestLocation2.Equals(255000, 256000), "Decoded regionhandle failed to match the original position in the constructor"); + + + TestLocation1 = new Location(255001, 256001); + TestLocation2 = new Location(1095216660736000); Assert.That(TestLocation1 != TestLocation2); - Assert.That(TestLocation1.Equals(256001, 256001), "Equals(x,y) failed to match the position in the constructor"); + Assert.That(TestLocation1.Equals(255001, 256001), "Equals(x,y) failed to match the position in the constructor"); Assert.That(TestLocation2.GetHashCode() == (TestLocation2.X.GetHashCode() ^ TestLocation2.Y.GetHashCode()), "GetHashCode failed to produce the expected hashcode"); diff --git a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs index 1dc8053..3f0a031 100644 --- a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs +++ b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs @@ -100,7 +100,7 @@ namespace OpenSim.Framework.Tests cadu.AVHeight = Size1.Z; AgentPosition position2 = new AgentPosition(); - position2.CopyFrom(cadu); + position2.CopyFrom(cadu, position1.SessionID); Assert.IsTrue( position2.AgentID == position1.AgentID diff --git a/OpenSim/Framework/Tests/UtilTest.cs b/OpenSim/Framework/Tests/UtilTest.cs index 11ca068..cfe3139 100644 --- a/OpenSim/Framework/Tests/UtilTest.cs +++ b/OpenSim/Framework/Tests/UtilTest.cs @@ -173,8 +173,8 @@ namespace OpenSim.Framework.Tests [Test] public void SLUtilTypeConvertTests() { - int[] assettypes = new int[]{-1,0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 - ,23,24,25,46,47,48}; + int[] assettypes = new int[]{-1,0,1,2,3,5,6,7,8,10,11,12,13,17,18,19,20,21,22 + ,24,25}; string[] contenttypes = new string[] { "application/octet-stream", @@ -186,26 +186,18 @@ namespace OpenSim.Framework.Tests "application/vnd.ll.primitive", "application/vnd.ll.notecard", "application/vnd.ll.folder", - "application/vnd.ll.rootfolder", "application/vnd.ll.lsltext", "application/vnd.ll.lslbyte", "image/tga", "application/vnd.ll.bodypart", - "application/vnd.ll.trashfolder", - "application/vnd.ll.snapshotfolder", - "application/vnd.ll.lostandfoundfolder", "audio/x-wav", "image/tga", "image/jpeg", "application/vnd.ll.animation", "application/vnd.ll.gesture", "application/x-metaverse-simstate", - "application/vnd.ll.favoritefolder", "application/vnd.ll.link", "application/vnd.ll.linkfolder", - "application/vnd.ll.currentoutfitfolder", - "application/vnd.ll.outfitfolder", - "application/vnd.ll.myoutfitsfolder" }; for (int i=0;i + /// A thread-safe Random since the .NET version is not. + /// See http://msdn.microsoft.com/en-us/library/system.random%28v=vs.100%29.aspx + /// + public class ThreadSafeRandom : Random + { + public ThreadSafeRandom() : base() {} + + public ThreadSafeRandom(int seed): base (seed) {} + + public override int Next() + { + lock (this) + return base.Next(); + } + + public override int Next(int maxValue) + { + lock (this) + return base.Next(maxValue); + } + + public override int Next(int minValue, int maxValue) + { + lock (this) + return base.Next(minValue, maxValue); + } + + public override void NextBytes(byte[] buffer) + { + lock (this) + base.NextBytes(buffer); + } + + public override double NextDouble() + { + lock (this) + return base.NextDouble(); + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/ThrottleOutPacketType.cs b/OpenSim/Framework/ThrottleOutPacketType.cs index d56231a..ca4b126 100644 --- a/OpenSim/Framework/ThrottleOutPacketType.cs +++ b/OpenSim/Framework/ThrottleOutPacketType.cs @@ -47,9 +47,6 @@ namespace OpenSim.Framework Texture = 5, /// Non-texture assets Asset = 6, - /// Avatar and primitive data - /// This is a sub-category of Task - State = 7, } [Flags] @@ -61,6 +58,5 @@ namespace OpenSim.Framework Task = 1 << 3, Texture = 1 << 4, Asset = 1 << 5, - State = 1 << 6, } } diff --git a/OpenSim/Framework/UntrustedWebRequest.cs b/OpenSim/Framework/UntrustedWebRequest.cs deleted file mode 100644 index e6411cc..0000000 --- a/OpenSim/Framework/UntrustedWebRequest.cs +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Net.Security; -using System.Text; -using log4net; - -namespace OpenSim.Framework -{ - /// - /// Used for requests to untrusted endpoints that may potentially be - /// malicious - /// - public static class UntrustedHttpWebRequest - { - /// Setting this to true will allow HTTP connections to localhost - private const bool DEBUG = true; - - private static readonly ILog m_log = - LogManager.GetLogger( - System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - private static readonly ICollection allowableSchemes = new List { "http", "https" }; - - /// - /// Creates an HttpWebRequest that is hardened against malicious - /// endpoints after ensuring the given Uri is safe to retrieve - /// - /// Web location to request - /// A hardened HttpWebRequest if the uri was determined to be safe - /// If uri is null - /// If uri is unsafe - public static HttpWebRequest Create(Uri uri) - { - return Create(uri, DEBUG, 1000 * 5, 1000 * 20, 10); - } - - /// - /// Creates an HttpWebRequest that is hardened against malicious - /// endpoints after ensuring the given Uri is safe to retrieve - /// - /// Web location to request - /// True to allow connections to localhost, otherwise false - /// Read write timeout, in milliseconds - /// Connection timeout, in milliseconds - /// Maximum number of allowed redirects - /// A hardened HttpWebRequest if the uri was determined to be safe - /// If uri is null - /// If uri is unsafe - public static HttpWebRequest Create(Uri uri, bool allowLoopback, int readWriteTimeoutMS, int timeoutMS, int maximumRedirects) - { - if (uri == null) - throw new ArgumentNullException("uri"); - - if (!IsUriAllowable(uri, allowLoopback)) - throw new ArgumentException("Uri " + uri + " was rejected"); - - HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(uri); - httpWebRequest.MaximumAutomaticRedirections = maximumRedirects; - httpWebRequest.ReadWriteTimeout = readWriteTimeoutMS; - httpWebRequest.Timeout = timeoutMS; - httpWebRequest.KeepAlive = false; - - return httpWebRequest; - } - - public static string PostToUntrustedUrl(Uri url, string data) - { - try - { - byte[] requestData = System.Text.Encoding.UTF8.GetBytes(data); - - HttpWebRequest request = Create(url); - request.Method = "POST"; - request.ContentLength = requestData.Length; - request.ContentType = "application/x-www-form-urlencoded"; - - using (Stream requestStream = request.GetRequestStream()) - requestStream.Write(requestData, 0, requestData.Length); - - using (WebResponse response = request.GetResponse()) - { - using (Stream responseStream = response.GetResponseStream()) - return responseStream.GetStreamString(); - } - } - catch (Exception ex) - { - m_log.Warn("POST to untrusted URL " + url + " failed: " + ex.Message); - return null; - } - } - - public static string GetUntrustedUrl(Uri url) - { - try - { - HttpWebRequest request = Create(url); - - using (WebResponse response = request.GetResponse()) - { - using (Stream responseStream = response.GetResponseStream()) - return responseStream.GetStreamString(); - } - } - catch (Exception ex) - { - m_log.Warn("GET from untrusted URL " + url + " failed: " + ex.Message); - return null; - } - } - - /// - /// Determines whether a URI is allowed based on scheme and host name. - /// No requireSSL check is done here - /// - /// True to allow loopback addresses to be used - /// The URI to test for whether it should be allowed. - /// - /// true if [is URI allowable] [the specified URI]; otherwise, false. - /// - private static bool IsUriAllowable(Uri uri, bool allowLoopback) - { - if (!allowableSchemes.Contains(uri.Scheme)) - { - m_log.WarnFormat("Rejecting URL {0} because it uses a disallowed scheme.", uri); - return false; - } - - // Try to interpret the hostname as an IP address so we can test for internal - // IP address ranges. Note that IP addresses can appear in many forms - // (e.g. http://127.0.0.1, http://2130706433, http://0x0100007f, http://::1 - // So we convert them to a canonical IPAddress instance, and test for all - // non-routable IP ranges: 10.*.*.*, 127.*.*.*, ::1 - // Note that Uri.IsLoopback is very unreliable, not catching many of these variants. - IPAddress hostIPAddress; - if (IPAddress.TryParse(uri.DnsSafeHost, out hostIPAddress)) - { - byte[] addressBytes = hostIPAddress.GetAddressBytes(); - - // The host is actually an IP address. - switch (hostIPAddress.AddressFamily) - { - case System.Net.Sockets.AddressFamily.InterNetwork: - if (!allowLoopback && (addressBytes[0] == 127 || addressBytes[0] == 10)) - { - m_log.WarnFormat("Rejecting URL {0} because it is a loopback address.", uri); - return false; - } - break; - case System.Net.Sockets.AddressFamily.InterNetworkV6: - if (!allowLoopback && IsIPv6Loopback(hostIPAddress)) - { - m_log.WarnFormat("Rejecting URL {0} because it is a loopback address.", uri); - return false; - } - break; - default: - m_log.WarnFormat("Rejecting URL {0} because it does not use an IPv4 or IPv6 address.", uri); - return false; - } - } - else - { - // The host is given by name. We require names to contain periods to - // help make sure it's not an internal address. - if (!allowLoopback && !uri.Host.Contains(".")) - { - m_log.WarnFormat("Rejecting URL {0} because it does not contain a period in the host name.", uri); - return false; - } - } - - return true; - } - - /// - /// Determines whether an IP address is the IPv6 equivalent of "localhost/127.0.0.1". - /// - /// The ip address to check. - /// - /// true if this is a loopback IP address; false otherwise. - /// - private static bool IsIPv6Loopback(IPAddress ip) - { - if (ip == null) - throw new ArgumentNullException("ip"); - - byte[] addressBytes = ip.GetAddressBytes(); - for (int i = 0; i < addressBytes.Length - 1; i++) - { - if (addressBytes[i] != 0) - return false; - } - - if (addressBytes[addressBytes.Length - 1] != 1) - return false; - - return true; - } - } -} diff --git a/OpenSim/Framework/UserProfileData.cs b/OpenSim/Framework/UserProfileData.cs index 9bac739..266ccf0 100644 --- a/OpenSim/Framework/UserProfileData.cs +++ b/OpenSim/Framework/UserProfileData.cs @@ -160,15 +160,19 @@ namespace OpenSim.Framework public virtual ulong HomeRegion { get - { - return Utils.UIntsToLong( - m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize); + { + return Util.RegionWorldLocToHandle(Util.RegionToWorldLoc(m_homeRegionX), Util.RegionToWorldLoc(m_homeRegionY)); + // return Utils.UIntsToLong( m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize); } set { - m_homeRegionX = (uint) (value >> 40); - m_homeRegionY = (((uint) (value)) >> 8); + uint regionWorldLocX, regionWorldLocY; + Util.RegionHandleToWorldLoc(value, out regionWorldLocX, out regionWorldLocY); + m_homeRegionX = Util.WorldToRegionLoc(regionWorldLocX); + m_homeRegionY = Util.WorldToRegionLoc(regionWorldLocY); + // m_homeRegionX = (uint) (value >> 40); + // m_homeRegionY = (((uint) (value)) >> 8); } } diff --git a/OpenSim/Framework/UserProfiles.cs b/OpenSim/Framework/UserProfiles.cs new file mode 100644 index 0000000..98ab651 --- /dev/null +++ b/OpenSim/Framework/UserProfiles.cs @@ -0,0 +1,126 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; + +namespace OpenSim.Framework +{ + public class UserClassifiedAdd + { + public UUID ClassifiedId = UUID.Zero; + public UUID CreatorId = UUID.Zero; + public int CreationDate = 0; + public int ExpirationDate = 0; + public int Category = 0; + public string Name = string.Empty; + public string Description = string.Empty; + public UUID ParcelId = UUID.Zero; + public int ParentEstate = 0; + public UUID SnapshotId = UUID.Zero; + public string SimName = string.Empty; + public string GlobalPos = "<0,0,0>"; + public string ParcelName = string.Empty; + public byte Flags = 0; + public int Price = 0; + } + + public class UserProfileProperties + { + public UUID UserId = UUID.Zero; + public UUID PartnerId = UUID.Zero; + public bool PublishProfile = false; + public bool PublishMature = false; + public string WebUrl = string.Empty; + public int WantToMask = 0; + public string WantToText = string.Empty; + public int SkillsMask = 0; + public string SkillsText = string.Empty; + public string Language = string.Empty; + public UUID ImageId = UUID.Zero; + public string AboutText = string.Empty; + public UUID FirstLifeImageId = UUID.Zero; + public string FirstLifeText = string.Empty; + } + + public class UserProfilePick + { + public UUID PickId = UUID.Zero; + public UUID CreatorId = UUID.Zero; + public bool TopPick = false; + public string Name = string.Empty; + public string OriginalName = string.Empty; + public string Desc = string.Empty; + public UUID ParcelId = UUID.Zero; + public UUID SnapshotId = UUID.Zero; + public string ParcelName = string.Empty; + public string SimName = string.Empty; + public string GlobalPos = "<0,0,0>"; + public string Gatekeeper = string.Empty; + public int SortOrder = 0; + public bool Enabled = false; + } + + public class UserProfileNotes + { + public UUID UserId; + public UUID TargetId; + public string Notes; + } + + public class UserPreferences + { + public UUID UserId; + public bool IMViaEmail = false; + public bool Visible = false; + public string EMail = string.Empty; + } + + public class UserAccountProperties + { + public string EmailAddress = string.Empty; + public string Firstname = string.Empty; + public string LastName = string.Empty; + public string Password = string.Empty; + public string UserId = string.Empty; + } + + public class UserAccountAuth + { + public string UserId = UUID.Zero.ToString(); + public string Password = string.Empty; + } + + public class UserAppData + { + public string TagId = string.Empty; + public string DataKey = string.Empty; + public string UserId = UUID.Zero.ToString(); + public string DataVal = string.Empty; + } +} + diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0bd2977..1f74168 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -45,14 +45,33 @@ using System.Text.RegularExpressions; using System.Xml; using System.Threading; using log4net; +using log4net.Appender; using Nini.Config; using Nwc.XmlRpc; using OpenMetaverse; using OpenMetaverse.StructuredData; using Amib.Threading; +using System.Collections.Concurrent; +using System.Collections.Specialized; +using System.Web; namespace OpenSim.Framework { + [Flags] + public enum PermissionMask : uint + { + None = 0, + Transfer = 1 << 13, + Modify = 1 << 14, + Copy = 1 << 15, + Export = 1 << 16, + Move = 1 << 19, + Damage = 1 << 20, + // All does not contain Export, which is special and must be + // explicitly given + All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19) + } + /// /// The method used by Util.FireAndForget for asynchronously firing events /// @@ -73,14 +92,53 @@ namespace OpenSim.Framework } /// + /// Class for delivering SmartThreadPool statistical information + /// + /// + /// We do it this way so that we do not directly expose STP. + /// + public class STPInfo + { + public string Name { get; set; } + public STPStartInfo STPStartInfo { get; set; } + public WIGStartInfo WIGStartInfo { get; set; } + public bool IsIdle { get; set; } + public bool IsShuttingDown { get; set; } + public int MaxThreads { get; set; } + public int MinThreads { get; set; } + public int InUseThreads { get; set; } + public int ActiveThreads { get; set; } + public int WaitingCallbacks { get; set; } + public int MaxConcurrentWorkItems { get; set; } + } + + /// /// Miscellaneous utility functions /// - public class Util + public static class Util { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Log-level for the thread pool: + /// 0 = no logging + /// 1 = only first line of stack trace; don't log common threads + /// 2 = full stack trace; don't log common threads + /// 3 = full stack trace, including common threads + /// + public static int LogThreadPool { get; set; } + public static bool LogOverloads { get; set; } + + public static readonly int MAX_THREADPOOL_LEVEL = 3; + + static Util() + { + LogThreadPool = 0; + LogOverloads = true; + } + private static uint nextXferID = 5000; - private static Random randomClass = new Random(); + private static Random randomClass = new ThreadSafeRandom(); // Get a list of invalid file characters (OS dependent) private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; @@ -92,8 +150,11 @@ namespace OpenSim.Framework /// private static SmartThreadPool m_ThreadPool; + // Watchdog timer that aborts threads that have timed-out + private static Timer m_threadPoolWatchdog; + // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. - private static readonly DateTime unixEpoch = + public static readonly DateTime UnixEpoch = DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); private static readonly string rawUUIDPattern @@ -104,6 +165,11 @@ namespace OpenSim.Framework public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; + public static bool IsPlatformMono + { + get { return Type.GetType("Mono.Runtime") != null; } + } + /// /// Gets the name of the directory where the current running executable /// is located @@ -291,6 +357,49 @@ namespace OpenSim.Framework return Utils.UIntsToLong(X, Y); } + // Regions are identified with a 'handle' made up of its region coordinates packed into a ulong. + // Several places rely on the ability to extract a region's location from its handle. + // Note the location is in 'world coordinates' (see below). + // Region handles are based on the lowest coordinate of the region so trim the passed x,y to be the regions 0,0. + public static ulong RegionWorldLocToHandle(uint X, uint Y) + { + return Utils.UIntsToLong(X, Y); + } + + public static ulong RegionLocToHandle(uint X, uint Y) + { + return Utils.UIntsToLong(Util.RegionToWorldLoc(X), Util.RegionToWorldLoc(Y)); + } + + public static void RegionHandleToWorldLoc(ulong handle, out uint X, out uint Y) + { + X = (uint)(handle >> 32); + Y = (uint)(handle & (ulong)uint.MaxValue); + } + + public static void RegionHandleToRegionLoc(ulong handle, out uint X, out uint Y) + { + uint worldX, worldY; + RegionHandleToWorldLoc(handle, out worldX, out worldY); + X = WorldToRegionLoc(worldX); + Y = WorldToRegionLoc(worldY); + } + + // A region location can be 'world coordinates' (meters from zero) or 'region coordinates' + // (number of regions from zero). This measurement of regions relies on the legacy 256 region size. + // These routines exist to make what is being converted explicit so the next person knows what was meant. + // Convert a region's 'world coordinate' to its 'region coordinate'. + public static uint WorldToRegionLoc(uint worldCoord) + { + return worldCoord / Constants.RegionSize; + } + + // Convert a region's 'region coordinate' to its 'world coordinate'. + public static uint RegionToWorldLoc(uint regionCoord) + { + return regionCoord * Constants.RegionSize; + } + public static T Clamp(T x, T min, T max) where T : IComparable { @@ -302,15 +411,31 @@ namespace OpenSim.Framework // Clamp the maximum magnitude of a vector public static Vector3 ClampV(Vector3 x, float max) { - Vector3 ret = x; float lenSq = x.LengthSquared(); if (lenSq > (max * max)) { x = x / x.Length() * max; } + return x; } + /// + /// Check if any of the values in a Vector3 are NaN or Infinity + /// + /// Vector3 to check + /// + public static bool IsNanOrInfinity(Vector3 v) + { + if (float.IsNaN(v.X) || float.IsNaN(v.Y) || float.IsNaN(v.Z)) + return true; + + if (float.IsInfinity(v.X) || float.IsInfinity(v.Y) || float.IsNaN(v.Z)) + return true; + + return false; + } + // Inclusive, within range test (true if equal to the endpoints) public static bool InRange(T x, T min, T max) where T : IComparable @@ -400,6 +525,19 @@ namespace OpenSim.Framework return sb.ToString(); } + public static byte[] DocToBytes(XmlDocument doc) + { + using (MemoryStream ms = new MemoryStream()) + using (XmlTextWriter xw = new XmlTextWriter(ms, null)) + { + xw.Formatting = Formatting.Indented; + doc.WriteTo(xw); + xw.Flush(); + + return ms.ToArray(); + } + } + /// /// Is the platform Windows? /// @@ -416,6 +554,11 @@ namespace OpenSim.Framework public static bool LoadArchSpecificWindowsDll(string libraryName) { + return LoadArchSpecificWindowsDll(libraryName, string.Empty); + } + + public static bool LoadArchSpecificWindowsDll(string libraryName, string path) + { // We do this so that OpenSimulator on Windows loads the correct native library depending on whether // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports // will find it already loaded later on. @@ -425,9 +568,9 @@ namespace OpenSim.Framework string nativeLibraryPath; if (Util.Is64BitProcess()) - nativeLibraryPath = "lib64/" + libraryName; + nativeLibraryPath = Path.Combine(Path.Combine(path, "lib64"), libraryName); else - nativeLibraryPath = "lib32/" + libraryName; + nativeLibraryPath = Path.Combine(Path.Combine(path, "lib32"), libraryName); m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath); @@ -479,20 +622,18 @@ namespace OpenSim.Framework public static int ToUnixTime(DateTime stamp) { - TimeSpan t = stamp.ToUniversalTime() - unixEpoch; - return (int) t.TotalSeconds; + TimeSpan t = stamp.ToUniversalTime() - UnixEpoch; + return (int)t.TotalSeconds; } public static DateTime ToDateTime(ulong seconds) { - DateTime epoch = unixEpoch; - return epoch.AddSeconds(seconds); + return UnixEpoch.AddSeconds(seconds); } public static DateTime ToDateTime(int seconds) { - DateTime epoch = unixEpoch; - return epoch.AddSeconds(seconds); + return UnixEpoch.AddSeconds(seconds); } /// @@ -664,16 +805,6 @@ namespace OpenSim.Framework } /// - /// Converts a URL to a IPAddress - /// - /// URL Standard Format - /// A resolved IP Address - public static IPAddress GetHostFromURL(string url) - { - return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]); - } - - /// /// Returns a IP address from a specified DNS, favouring IPv4 addresses. /// /// DNS Hostname @@ -763,6 +894,54 @@ namespace OpenSim.Framework } /// + /// Parses a foreign asset ID. + /// + /// A possibly-foreign asset ID: http://grid.example.com:8002/00000000-0000-0000-0000-000000000000 + /// The URL: http://grid.example.com:8002 + /// The asset ID: 00000000-0000-0000-0000-000000000000. Returned even if 'id' isn't foreign. + /// True: this is a foreign asset ID; False: it isn't + public static bool ParseForeignAssetID(string id, out string url, out string assetID) + { + url = String.Empty; + assetID = String.Empty; + + UUID uuid; + if (UUID.TryParse(id, out uuid)) + { + assetID = uuid.ToString(); + return false; + } + + if ((id.Length == 0) || (id[0] != 'h' && id[0] != 'H')) + return false; + + Uri assetUri; + if (!Uri.TryCreate(id, UriKind.Absolute, out assetUri) || assetUri.Scheme != Uri.UriSchemeHttp) + return false; + + // Simian + if (assetUri.Query != string.Empty) + { + NameValueCollection qscoll = HttpUtility.ParseQueryString(assetUri.Query); + assetID = qscoll["id"]; + if (assetID != null) + url = id.Replace(assetID, ""); // Malformed again, as simian expects + else + url = id; // !!! best effort + } + else // robust + { + url = "http://" + assetUri.Authority; + assetID = assetUri.LocalPath.Trim(new char[] { '/' }); + } + + if (!UUID.TryParse(assetID, out uuid)) + return false; + + return true; + } + + /// /// Removes all invalid path chars (OS dependent) /// /// path @@ -816,9 +995,22 @@ namespace OpenSim.Framework return "."; } + public static string logFile() + { + foreach (IAppender appender in LogManager.GetRepository().GetAppenders()) + { + if (appender is FileAppender) + { + return ((FileAppender)appender).File; + } + } + + return "./OpenSim.log"; + } + public static string logDir() { - return "."; + return Path.GetDirectoryName(logFile()); } // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html @@ -849,12 +1041,13 @@ namespace OpenSim.Framework return FileName; } - // Nini (config) related Methods + #region Nini (config) related Methods + public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) { if (!File.Exists(fileName)) { - //create new file + // create new file } XmlConfigSource config = new XmlConfigSource(fileName); AddDataRowToConfig(config, row); @@ -872,6 +1065,202 @@ namespace OpenSim.Framework } } + /// + /// Gets the value of a configuration variable by looking into + /// multiple sections in order. The latter sections overwrite + /// any values previously found. + /// + /// Type of the variable + /// The configuration object + /// The configuration variable + /// Ordered sequence of sections to look at + /// + public static T GetConfigVarFromSections(IConfigSource config, string varname, string[] sections) + { + return GetConfigVarFromSections(config, varname, sections, default(T)); + } + + /// + /// Gets the value of a configuration variable by looking into + /// multiple sections in order. The latter sections overwrite + /// any values previously found. + /// + /// + /// If no value is found then the given default value is returned + /// + /// Type of the variable + /// The configuration object + /// The configuration variable + /// Ordered sequence of sections to look at + /// Default value + /// + public static T GetConfigVarFromSections(IConfigSource config, string varname, string[] sections, object val) + { + foreach (string section in sections) + { + IConfig cnf = config.Configs[section]; + if (cnf == null) + continue; + + if (typeof(T) == typeof(String)) + val = cnf.GetString(varname, (string)val); + else if (typeof(T) == typeof(Boolean)) + val = cnf.GetBoolean(varname, (bool)val); + else if (typeof(T) == typeof(Int32)) + val = cnf.GetInt(varname, (int)val); + else if (typeof(T) == typeof(float)) + val = cnf.GetFloat(varname, (float)val); + else + m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T)); + } + + return (T)val; + } + + public static void MergeEnvironmentToConfig(IConfigSource ConfigSource) + { + IConfig enVars = ConfigSource.Configs["Environment"]; + // if section does not exist then user isn't expecting them, so don't bother. + if( enVars != null ) + { + // load the values from the environment + EnvConfigSource envConfigSource = new EnvConfigSource(); + // add the requested keys + string[] env_keys = enVars.GetKeys(); + foreach ( string key in env_keys ) + { + envConfigSource.AddEnv(key, string.Empty); + } + // load the values from environment + envConfigSource.LoadEnv(); + // add them in to the master + ConfigSource.Merge(envConfigSource); + ConfigSource.ExpandKeyValues(); + } + } + + public static T ReadSettingsFromIniFile(IConfig config, T settingsClass) + { + Type settingsType = settingsClass.GetType(); + + FieldInfo[] fieldInfos = settingsType.GetFields(); + foreach (FieldInfo fieldInfo in fieldInfos) + { + if (!fieldInfo.IsStatic) + { + if (fieldInfo.FieldType == typeof(System.String)) + { + fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Boolean)) + { + fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Int32)) + { + fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Single)) + { + fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.UInt32)) + { + fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); + } + } + } + + PropertyInfo[] propertyInfos = settingsType.GetProperties(); + foreach (PropertyInfo propInfo in propertyInfos) + { + if ((propInfo.CanRead) && (propInfo.CanWrite)) + { + if (propInfo.PropertyType == typeof(System.String)) + { + propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Boolean)) + { + propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Int32)) + { + propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Single)) + { + propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null); + } + if (propInfo.PropertyType == typeof(System.UInt32)) + { + propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null); + } + } + } + + return settingsClass; + } + + /// + /// Reads a configuration file, configFile, merging it with the main configuration, config. + /// If the file doesn't exist, it copies a given exampleConfigFile onto configFile, and then + /// merges it. + /// + /// The main configuration data + /// The name of a configuration file in ConfigDirectory variable, no path + /// Full path to an example configuration file + /// Full path ConfigDirectory/configFileName + /// True if the file was created in ConfigDirectory, false if it existed + /// True if success + public static bool MergeConfigurationFile(IConfigSource config, string configFileName, string exampleConfigFile, out string configFilePath, out bool created) + { + created = false; + configFilePath = string.Empty; + + IConfig cnf = config.Configs["Startup"]; + if (cnf == null) + { + m_log.WarnFormat("[UTILS]: Startup section doesn't exist"); + return false; + } + + string configDirectory = cnf.GetString("ConfigDirectory", "."); + string configFile = Path.Combine(configDirectory, configFileName); + + if (!File.Exists(configFile) && !string.IsNullOrEmpty(exampleConfigFile)) + { + // We need to copy the example onto it + + if (!Directory.Exists(configDirectory)) + Directory.CreateDirectory(configDirectory); + + try + { + File.Copy(exampleConfigFile, configFile); + created = true; + } + catch (Exception e) + { + m_log.WarnFormat("[UTILS]: Exception copying configuration file {0} to {1}: {2}", configFile, exampleConfigFile, e.Message); + return false; + } + } + + if (File.Exists(configFile)) + { + // Merge + config.Merge(new IniConfigSource(configFile)); + config.ExpandKeyValues(); + configFilePath = configFile; + return true; + } + else + return false; + } + + #endregion + public static float Clip(float x, float min, float max) { return Math.Min(Math.Max(x, min), max); @@ -999,46 +1388,6 @@ namespace OpenSim.Framework return ret; } - public static string Compress(string text) - { - byte[] buffer = Util.UTF8.GetBytes(text); - MemoryStream memory = new MemoryStream(); - using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true)) - { - compressor.Write(buffer, 0, buffer.Length); - } - - memory.Position = 0; - - byte[] compressed = new byte[memory.Length]; - memory.Read(compressed, 0, compressed.Length); - - byte[] compressedBuffer = new byte[compressed.Length + 4]; - Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length); - Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4); - return Convert.ToBase64String(compressedBuffer); - } - - public static string Decompress(string compressedText) - { - byte[] compressedBuffer = Convert.FromBase64String(compressedText); - using (MemoryStream memory = new MemoryStream()) - { - int msgLength = BitConverter.ToInt32(compressedBuffer, 0); - memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4); - - byte[] buffer = new byte[msgLength]; - - memory.Position = 0; - using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress)) - { - decompressor.Read(buffer, 0, buffer.Length); - } - - return Util.UTF8.GetString(buffer); - } - } - /// /// Copy data from one stream to another, leaving the read position of both streams at the beginning. /// @@ -1119,7 +1468,7 @@ namespace OpenSim.Framework byte[] bytes = { (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), - (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), + (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), (byte)x, (byte)(x >> 8), 0, 0, (byte)y, (byte)(y >> 8), 0, 0 }; return new UUID(bytes, 0); @@ -1130,7 +1479,7 @@ namespace OpenSim.Framework byte[] bytes = { (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), - (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), + (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), (byte)y, (byte)(y >> 8), 0, 0 }; return new UUID(bytes, 0); @@ -1203,7 +1552,7 @@ namespace OpenSim.Framework ru = "OSX/Mono"; else { - if (Type.GetType("Mono.Runtime") != null) + if (IsPlatformMono) ru = "Win/Mono"; else ru = "Win/.NET"; @@ -1242,79 +1591,56 @@ namespace OpenSim.Framework return displayConnectionString; } - public static T ReadSettingsFromIniFile(IConfig config, T settingsClass) + public static string Base64ToString(string str) { - Type settingsType = settingsClass.GetType(); + Decoder utf8Decode = Encoding.UTF8.GetDecoder(); - FieldInfo[] fieldInfos = settingsType.GetFields(); - foreach (FieldInfo fieldInfo in fieldInfos) + byte[] todecode_byte = Convert.FromBase64String(str); + int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length); + char[] decoded_char = new char[charCount]; + utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0); + string result = new String(decoded_char); + return result; + } + + public static void BinaryToASCII(char[] chars) + { + for (int i = 0; i < chars.Length; i++) { - if (!fieldInfo.IsStatic) - { - if (fieldInfo.FieldType == typeof(System.String)) - { - fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Boolean)) - { - fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Int32)) - { - fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Single)) - { - fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.UInt32)) - { - fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); - } - } - } - - PropertyInfo[] propertyInfos = settingsType.GetProperties(); - foreach (PropertyInfo propInfo in propertyInfos) - { - if ((propInfo.CanRead) && (propInfo.CanWrite)) - { - if (propInfo.PropertyType == typeof(System.String)) - { - propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null); - } - else if (propInfo.PropertyType == typeof(System.Boolean)) - { - propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null); - } - else if (propInfo.PropertyType == typeof(System.Int32)) - { - propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null); - } - else if (propInfo.PropertyType == typeof(System.Single)) - { - propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null); - } - if (propInfo.PropertyType == typeof(System.UInt32)) - { - propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null); - } - } + char ch = chars[i]; + if (ch < 32 || ch > 127) + chars[i] = '.'; } + } - return settingsClass; + public static string BinaryToASCII(string src) + { + char[] chars = src.ToCharArray(); + BinaryToASCII(chars); + return new String(chars); } - public static string Base64ToString(string str) + /// + /// Reads a known number of bytes from a stream. + /// Throws EndOfStreamException if the stream doesn't contain enough data. + /// + /// The stream to read data from + /// The array to write bytes into. The array + /// will be completely filled from the stream, so an appropriate + /// size must be given. + public static void ReadStream(Stream stream, byte[] data) { - Decoder utf8Decode = Encoding.UTF8.GetDecoder(); + int offset = 0; + int remaining = data.Length; - byte[] todecode_byte = Convert.FromBase64String(str); - int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length); - char[] decoded_char = new char[charCount]; - utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0); - string result = new String(decoded_char); - return result; + while (remaining > 0) + { + int read = stream.Read(data, offset, remaining); + if (read <= 0) + throw new EndOfStreamException(String.Format("End of stream reached with {0} bytes left to read", remaining)); + remaining -= read; + offset += read; + } } public static Guid GetHashGuid(string data, string salt) @@ -1466,32 +1792,6 @@ namespace OpenSim.Framework return found.ToArray(); } - public static string ServerURI(string uri) - { - if (uri == string.Empty) - return string.Empty; - - // Get rid of eventual slashes at the end - uri = uri.TrimEnd('/'); - - IPAddress ipaddr1 = null; - string port1 = ""; - try - { - ipaddr1 = Util.GetHostFromURL(uri); - } - catch { } - - try - { - port1 = uri.Split(new char[] { ':' })[2]; - } - catch { } - - // We tried our best to convert the domain names to IP addresses - return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri; - } - /// /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. /// @@ -1518,17 +1818,26 @@ namespace OpenSim.Framework /// public static byte[] StringToBytes256(string str) { - if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } - if (str.Length > 254) str = str.Remove(254); - if (!str.EndsWith("\0")) { str += "\0"; } + if (String.IsNullOrEmpty(str)) + return Utils.EmptyBytes; + + if (!str.EndsWith("\0")) + str += "\0"; // Because this is UTF-8 encoding and not ASCII, it's possible we // might have gotten an oversized array even after the string trim byte[] data = UTF8.GetBytes(str); + if (data.Length > 256) { - Array.Resize(ref data, 256); - data[255] = 0; + int cut = 255; + if((data[cut] & 0x80 ) != 0 ) + { + while(cut > 0 && (data[cut] & 0xc0) != 0xc0) + cut--; + } + Array.Resize(ref data, cut + 1); + data[cut] = 0; } return data; @@ -1560,23 +1869,56 @@ namespace OpenSim.Framework /// public static byte[] StringToBytes1024(string str) { - if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } - if (str.Length > 1023) str = str.Remove(1023); - if (!str.EndsWith("\0")) { str += "\0"; } + if (String.IsNullOrEmpty(str)) + return Utils.EmptyBytes; + + if (!str.EndsWith("\0")) + str += "\0"; // Because this is UTF-8 encoding and not ASCII, it's possible we // might have gotten an oversized array even after the string trim byte[] data = UTF8.GetBytes(str); + if (data.Length > 1024) { - Array.Resize(ref data, 1024); - data[1023] = 0; + int cut = 1023; + if((data[cut] & 0x80 ) != 0 ) + { + while(cut > 0 && (data[cut] & 0xc0) != 0xc0) + cut--; + } + Array.Resize(ref data, cut + 1); + data[cut] = 0; } return data; } /// + /// Pretty format the hashtable contents to a single line. + /// + /// + /// Used for debugging output. + /// + /// + public static string PrettyFormatToSingleLine(Hashtable ht) + { + StringBuilder sb = new StringBuilder(); + + int i = 0; + + foreach (string key in ht.Keys) + { + sb.AppendFormat("{0}:{1}", key, ht[key]); + + if (++i < ht.Count) + sb.AppendFormat(", "); + } + + return sb.ToString(); + } + + /// /// Used to trigger an early library load on Windows systems. /// /// @@ -1646,25 +1988,28 @@ namespace OpenSim.Framework } } - public static void FireAndForget(System.Threading.WaitCallback callback) - { - FireAndForget(callback, null); - } - - public static void InitThreadPool(int maxThreads) + public static void InitThreadPool(int minThreads, int maxThreads) { if (maxThreads < 2) throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); + + if (minThreads > maxThreads || minThreads < 2) + throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads"); + if (m_ThreadPool != null) - throw new InvalidOperationException("SmartThreadPool is already initialized"); + { + m_log.Warn("SmartThreadPool is already initialized. Ignoring request."); + return; + } STPStartInfo startInfo = new STPStartInfo(); startInfo.ThreadPoolName = "Util"; startInfo.IdleTimeout = 2000; startInfo.MaxWorkerThreads = maxThreads; - startInfo.MinWorkerThreads = 2; + startInfo.MinWorkerThreads = minThreads; m_ThreadPool = new SmartThreadPool(startInfo); + m_threadPoolWatchdog = new Timer(ThreadPoolWatchdog, null, 0, 1000); } public static int FireAndForgetCount() @@ -1687,15 +2032,179 @@ namespace OpenSim.Framework throw new NotImplementedException(); } } + + /// + /// Additional information about threads in the main thread pool. Used to time how long the + /// thread has been running, and abort it if it has timed-out. + /// + private class ThreadInfo + { + public long ThreadFuncNum { get; set; } + public string StackTrace { get; set; } + private string context; + public bool LogThread { get; set; } + + public IWorkItemResult WorkItem { get; set; } + public Thread Thread { get; set; } + public bool Running { get; set; } + public bool Aborted { get; set; } + private int started; + + public ThreadInfo(long threadFuncNum, string context) + { + ThreadFuncNum = threadFuncNum; + this.context = context; + LogThread = false; + Thread = null; + Running = false; + Aborted = false; + } + + public void Started() + { + Thread = Thread.CurrentThread; + started = EnvironmentTickCount(); + Running = true; + } + + public void Ended() + { + Running = false; + } + + public int Elapsed() + { + return EnvironmentTickCountSubtract(started); + } + + public void Abort() + { + Aborted = true; + WorkItem.Cancel(true); + } + + /// + /// Returns the thread's stack trace. + /// + /// + /// May return one of two stack traces. First, tries to get the thread's active stack + /// trace. But this can fail, so as a fallback this method will return the stack + /// trace that was active when the task was queued. + /// + public string GetStackTrace() + { + string ret = (context == null) ? "" : ("(" + context + ") "); + + StackTrace activeStackTrace = Util.GetStackTrace(Thread); + if (activeStackTrace != null) + ret += activeStackTrace.ToString(); + else if (StackTrace != null) + ret += "(Stack trace when queued) " + StackTrace; + // else, no stack trace available + + return ret; + } + } + + private static long nextThreadFuncNum = 0; + private static long numQueuedThreadFuncs = 0; + private static long numRunningThreadFuncs = 0; + private static long numTotalThreadFuncsCalled = 0; + private static Int32 threadFuncOverloadMode = 0; + + public static long TotalQueuedFireAndForgetCalls { get { return numQueuedThreadFuncs; } } + public static long TotalRunningFireAndForgetCalls { get { return numRunningThreadFuncs; } } + + // Maps (ThreadFunc number -> Thread) + private static ConcurrentDictionary activeThreads = new ConcurrentDictionary(); + + private static readonly int THREAD_TIMEOUT = 10 * 60 * 1000; // 10 minutes + + /// + /// Finds threads in the main thread pool that have timed-out, and aborts them. + /// + private static void ThreadPoolWatchdog(object state) + { + foreach (KeyValuePair entry in activeThreads) + { + ThreadInfo t = entry.Value; + if (t.Running && !t.Aborted && (t.Elapsed() >= THREAD_TIMEOUT)) + { + m_log.WarnFormat("Timeout in threadfunc {0} ({1}) {2}", t.ThreadFuncNum, t.Thread.Name, t.GetStackTrace()); + t.Abort(); + + ThreadInfo dummy; + activeThreads.TryRemove(entry.Key, out dummy); + + // It's possible that the thread won't abort. To make sure the thread pool isn't + // depleted, increase the pool size. + m_ThreadPool.MaxThreads++; + } + } + } + + public static long TotalFireAndForgetCallsMade { get { return numTotalThreadFuncsCalled; } } + + public static Dictionary GetFireAndForgetCallsMade() + { + return new Dictionary(m_fireAndForgetCallsMade); + } + + private static Dictionary m_fireAndForgetCallsMade = new Dictionary(); + + public static Dictionary GetFireAndForgetCallsInProgress() + { + return new Dictionary(m_fireAndForgetCallsInProgress); + } + + private static Dictionary m_fireAndForgetCallsInProgress = new Dictionary(); + + public static void FireAndForget(System.Threading.WaitCallback callback) + { + FireAndForget(callback, null, null); + } public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { + FireAndForget(callback, obj, null); + } + + public static void FireAndForget(System.Threading.WaitCallback callback, object obj, string context) + { + Interlocked.Increment(ref numTotalThreadFuncsCalled); + + if (context != null) + { + if (!m_fireAndForgetCallsMade.ContainsKey(context)) + m_fireAndForgetCallsMade[context] = 1; + else + m_fireAndForgetCallsMade[context]++; + + if (!m_fireAndForgetCallsInProgress.ContainsKey(context)) + m_fireAndForgetCallsInProgress[context] = 1; + else + m_fireAndForgetCallsInProgress[context]++; + } + WaitCallback realCallback; + bool loggingEnabled = LogThreadPool > 0; + + long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum); + ThreadInfo threadInfo = new ThreadInfo(threadFuncNum, context); + if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) { // If we're running regression tests, then we want any exceptions to rise up to the test code. - realCallback = o => { Culture.SetCurrentCulture(); callback(o); }; + realCallback = + o => + { + Culture.SetCurrentCulture(); + callback(o); + + if (context != null) + m_fireAndForgetCallsInProgress[context]--; + }; } else { @@ -1704,118 +2213,291 @@ namespace OpenSim.Framework // for decimals places but is read by a culture that treats commas as number seperators. realCallback = o => { - Culture.SetCurrentCulture(); + long numQueued1 = Interlocked.Decrement(ref numQueuedThreadFuncs); + long numRunning1 = Interlocked.Increment(ref numRunningThreadFuncs); + threadInfo.Started(); + activeThreads[threadFuncNum] = threadInfo; try { + if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread) + m_log.DebugFormat("Run threadfunc {0} (Queued {1}, Running {2})", threadFuncNum, numQueued1, numRunning1); + + Culture.SetCurrentCulture(); + callback(o); } + catch (ThreadAbortException e) + { + m_log.Error(string.Format("Aborted threadfunc {0} ", threadFuncNum), e); + } catch (Exception e) { - m_log.ErrorFormat( - "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", - e.Message, e.StackTrace); + m_log.Error(string.Format("[UTIL]: Util STP threadfunc {0} terminated with error ", threadFuncNum), e); + } + finally + { + Interlocked.Decrement(ref numRunningThreadFuncs); + threadInfo.Ended(); + ThreadInfo dummy; + activeThreads.TryRemove(threadFuncNum, out dummy); + if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread) + m_log.DebugFormat("Exit threadfunc {0} ({1})", threadFuncNum, FormatDuration(threadInfo.Elapsed())); + + if (context != null) + m_fireAndForgetCallsInProgress[context]--; } }; } - switch (FireAndForgetMethod) + long numQueued = Interlocked.Increment(ref numQueuedThreadFuncs); + try { - case FireAndForgetMethod.RegressionTest: - case FireAndForgetMethod.None: - realCallback.Invoke(obj); - break; - case FireAndForgetMethod.UnsafeQueueUserWorkItem: - ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); - break; - case FireAndForgetMethod.QueueUserWorkItem: - ThreadPool.QueueUserWorkItem(realCallback, obj); - break; - case FireAndForgetMethod.BeginInvoke: - FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; - wrapper.FireAndForget(realCallback, obj); - break; - case FireAndForgetMethod.SmartThreadPool: - if (m_ThreadPool == null) - InitThreadPool(15); - m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); - break; - case FireAndForgetMethod.Thread: - Thread thread = new Thread(delegate(object o) { realCallback(o); }); - thread.Start(obj); - break; - default: - throw new NotImplementedException(); + long numRunning = numRunningThreadFuncs; + + if (m_ThreadPool != null && LogOverloads) + { + if ((threadFuncOverloadMode == 0) && (numRunning >= m_ThreadPool.MaxThreads)) + { + if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 1, 0) == 0) + m_log.DebugFormat("Threadfunc: enable overload mode (Queued {0}, Running {1})", numQueued, numRunning); + } + else if ((threadFuncOverloadMode == 1) && (numRunning <= (m_ThreadPool.MaxThreads * 2) / 3)) + { + if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 0, 1) == 1) + m_log.DebugFormat("Threadfunc: disable overload mode (Queued {0}, Running {1})", numQueued, numRunning); + } + } + + if (loggingEnabled || (threadFuncOverloadMode == 1)) + { + string full, partial; + GetFireAndForgetStackTrace(out full, out partial); + threadInfo.StackTrace = full; + threadInfo.LogThread = ShouldLogThread(partial); + + if (threadInfo.LogThread) + { + m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}{4}", + threadFuncNum, numQueued, numRunningThreadFuncs, + (context == null) ? "" : ("(" + context + ") "), + (LogThreadPool >= 2) ? full : partial); + } + } + else + { + // Since we didn't log "Queue threadfunc", don't log "Run threadfunc" or "End threadfunc" either. + // Those log lines aren't useful when we don't know which function is running in the thread. + threadInfo.LogThread = false; + } + + switch (FireAndForgetMethod) + { + case FireAndForgetMethod.RegressionTest: + case FireAndForgetMethod.None: + realCallback.Invoke(obj); + break; + case FireAndForgetMethod.UnsafeQueueUserWorkItem: + ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); + break; + case FireAndForgetMethod.QueueUserWorkItem: + ThreadPool.QueueUserWorkItem(realCallback, obj); + break; + case FireAndForgetMethod.BeginInvoke: + FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; + wrapper.FireAndForget(realCallback, obj); + break; + case FireAndForgetMethod.SmartThreadPool: + if (m_ThreadPool == null) + InitThreadPool(2, 15); + threadInfo.WorkItem = m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); + break; + case FireAndForgetMethod.Thread: + Thread thread = new Thread(delegate(object o) { realCallback(o); }); + thread.Start(obj); + break; + default: + throw new NotImplementedException(); + } + } + catch (Exception) + { + Interlocked.Decrement(ref numQueuedThreadFuncs); + ThreadInfo dummy; + activeThreads.TryRemove(threadFuncNum, out dummy); + throw; } } /// - /// Get a thread pool report. + /// Returns whether the thread should be logged. Some very common threads aren't logged, + /// to avoid filling up the log. /// - /// - public static string GetThreadPoolReport() + /// A partial stack trace of where the thread was queued + /// Whether to log this thread + private static bool ShouldLogThread(string stackTrace) { - string threadPoolUsed = null; - int maxThreads = 0; - int minThreads = 0; - int allocatedThreads = 0; - int inUseThreads = 0; - int waitingCallbacks = 0; - int completionPortThreads = 0; + if (LogThreadPool < 3) + { + if (stackTrace.Contains("BeginFireQueueEmpty")) + return false; + } + + return true; + } - StringBuilder sb = new StringBuilder(); - if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) + /// + /// Returns a stack trace for a thread added using FireAndForget(). + /// + /// Will contain the full stack trace + /// Will contain only the first frame of the stack trace + private static void GetFireAndForgetStackTrace(out string full, out string partial) + { + string src = Environment.StackTrace; + string[] lines = src.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); + + StringBuilder dest = new StringBuilder(src.Length); + + bool started = false; + bool first = true; + partial = ""; + + for (int i = 0; i < lines.Length; i++) { - // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. - if (m_ThreadPool != null) + string line = lines[i]; + + if (!started) { - threadPoolUsed = "SmartThreadPool"; - maxThreads = m_ThreadPool.MaxThreads; - minThreads = m_ThreadPool.MinThreads; - inUseThreads = m_ThreadPool.InUseThreads; - allocatedThreads = m_ThreadPool.ActiveThreads; - waitingCallbacks = m_ThreadPool.WaitingCallbacks; + // Skip the initial stack frames, because they're of no interest for debugging + if (line.Contains("StackTrace") || line.Contains("FireAndForget")) + continue; + started = true; } + + if (first) + { + line = line.TrimStart(); + first = false; + partial = line; + } + + bool last = (i == lines.Length - 1); + if (last) + dest.Append(line); + else + dest.AppendLine(line); } - else if ( - FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem - || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) + + full = dest.ToString(); + } + +#pragma warning disable 0618 + /// + /// Return the stack trace of a different thread. + /// + /// + /// This is complicated because the thread needs to be paused in order to get its stack + /// trace. And pausing another thread can cause a deadlock. This method attempts to + /// avoid deadlock by using a short timeout (200ms), after which it gives up and + /// returns 'null' instead of the stack trace. + /// + /// Take from: http://stackoverflow.com/a/14935378 + /// + /// WARNING: this doesn't work in Mono. See https://bugzilla.novell.com/show_bug.cgi?id=571691 + /// + /// + /// The stack trace, or null if failed to get it + private static StackTrace GetStackTrace(Thread targetThread) + { + if (IsPlatformMono) { - threadPoolUsed = "BuiltInThreadPool"; - ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); - ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); - int availableThreads; - ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); - inUseThreads = maxThreads - availableThreads; - allocatedThreads = -1; - waitingCallbacks = -1; + // This doesn't work in Mono + return null; } - if (threadPoolUsed != null) + ManualResetEventSlim fallbackThreadReady = new ManualResetEventSlim(); + ManualResetEventSlim exitedSafely = new ManualResetEventSlim(); + + try { - sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); - sb.AppendFormat("Max threads : {0}\n", maxThreads); - sb.AppendFormat("Min threads : {0}\n", minThreads); - sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); - sb.AppendFormat("In use threads : {0}\n", inUseThreads); - sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); + new Thread(delegate() + { + fallbackThreadReady.Set(); + while (!exitedSafely.Wait(200)) + { + try + { + targetThread.Resume(); + } + catch (Exception) + { + // Whatever happens, do never stop to resume the main-thread regularly until the main-thread has exited safely. + } + } + }).Start(); + + fallbackThreadReady.Wait(); + // From here, you have about 200ms to get the stack-trace + + targetThread.Suspend(); + + StackTrace trace = null; + try + { + trace = new StackTrace(targetThread, true); + } + catch (ThreadStateException) + { + //failed to get stack trace, since the fallback-thread resumed the thread + //possible reasons: + //1.) This thread was just too slow + //2.) A deadlock ocurred + //Automatic retry seems too risky here, so just return null. + } + + try + { + targetThread.Resume(); + } + catch (ThreadStateException) + { + // Thread is running again already + } + + return trace; } - else + finally { - sb.AppendFormat("Thread pool not used\n"); + // Signal the fallack-thread to stop + exitedSafely.Set(); } - - return sb.ToString(); } +#pragma warning restore 0618 - private static object SmartThreadPoolCallback(object o) + /// + /// Get information about the current state of the smart thread pool. + /// + /// + /// null if this isn't the pool being used for non-scriptengine threads. + /// + public static STPInfo GetSmartThreadPoolInfo() { - object[] array = (object[])o; - WaitCallback callback = (WaitCallback)array[0]; - object obj = array[1]; + if (m_ThreadPool == null) + return null; - callback(obj); - return null; + STPInfo stpi = new STPInfo(); + stpi.Name = m_ThreadPool.Name; + stpi.STPStartInfo = m_ThreadPool.STPStartInfo; + stpi.IsIdle = m_ThreadPool.IsIdle; + stpi.IsShuttingDown = m_ThreadPool.IsShuttingdown; + stpi.MaxThreads = m_ThreadPool.MaxThreads; + stpi.MinThreads = m_ThreadPool.MinThreads; + stpi.InUseThreads = m_ThreadPool.InUseThreads; + stpi.ActiveThreads = m_ThreadPool.ActiveThreads; + stpi.WaitingCallbacks = m_ThreadPool.WaitingCallbacks; + stpi.MaxConcurrentWorkItems = m_ThreadPool.Concurrency; + + return stpi; } #endregion FireAndForget Threading Pattern @@ -1876,6 +2558,60 @@ namespace OpenSim.Framework } /// + /// Formats a duration (given in milliseconds). + /// + public static string FormatDuration(int ms) + { + TimeSpan span = new TimeSpan(ms * TimeSpan.TicksPerMillisecond); + + string str = ""; + string suffix = null; + + int hours = (int)span.TotalHours; + if (hours > 0) + { + str += hours.ToString(str.Length == 0 ? "0" : "00"); + suffix = "hours"; + } + + if ((hours > 0) || (span.Minutes > 0)) + { + if (str.Length > 0) + str += ":"; + str += span.Minutes.ToString(str.Length == 0 ? "0" : "00"); + if (suffix == null) + suffix = "min"; + } + + if ((hours > 0) || (span.Minutes > 0) || (span.Seconds > 0)) + { + if (str.Length > 0) + str += ":"; + str += span.Seconds.ToString(str.Length == 0 ? "0" : "00"); + if (suffix == null) + suffix = "sec"; + } + + if (suffix == null) + suffix = "ms"; + + if (span.TotalMinutes < 1) + { + int ms1 = span.Milliseconds; + if (str.Length > 0) + { + ms1 /= 100; + str += "."; + } + str += ms1.ToString("0"); + } + + str += " " + suffix; + + return str; + } + + /// /// Prints the call stack at any given point. Useful for debugging. /// public static void PrintCallStack() @@ -1942,16 +2678,18 @@ namespace OpenSim.Framework } #region Xml Serialization Utilities - public static bool ReadBoolean(XmlTextReader reader) + public static bool ReadBoolean(XmlReader reader) { + // AuroraSim uses "int" for some fields that are boolean in OpenSim, e.g. "PassCollisions". Don't fail because of this. reader.ReadStartElement(); - bool result = Boolean.Parse(reader.ReadContentAsString().ToLower()); + string val = reader.ReadContentAsString().ToLower(); + bool result = val.Equals("true") || val.Equals("1"); reader.ReadEndElement(); return result; } - public static UUID ReadUUID(XmlTextReader reader, string name) + public static UUID ReadUUID(XmlReader reader, string name) { UUID id; string idStr; @@ -1970,7 +2708,7 @@ namespace OpenSim.Framework return id; } - public static Vector3 ReadVector(XmlTextReader reader, string name) + public static Vector3 ReadVector(XmlReader reader, string name) { Vector3 vec; @@ -1983,7 +2721,7 @@ namespace OpenSim.Framework return vec; } - public static Quaternion ReadQuaternion(XmlTextReader reader, string name) + public static Quaternion ReadQuaternion(XmlReader reader, string name) { Quaternion quat = new Quaternion(); @@ -2012,7 +2750,7 @@ namespace OpenSim.Framework return quat; } - public static T ReadEnum(XmlTextReader reader, string name) + public static T ReadEnum(XmlReader reader, string name) { string value = reader.ReadElementContentAsString(name, String.Empty); // !!!!! to deal with flags without commas @@ -2024,7 +2762,9 @@ namespace OpenSim.Framework #endregion #region Universal User Identifiers - /// + + /// + /// Attempts to parse a UUI into its components: UUID, name and URL. /// /// uuid[;endpoint[;first last[;secret]]] /// the uuid part @@ -2034,7 +2774,7 @@ namespace OpenSim.Framework /// the secret part public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) { - uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; + uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "UserUPUUI"; secret = string.Empty; string[] parts = value.Split(';'); if (parts.Length >= 1) @@ -2060,6 +2800,27 @@ namespace OpenSim.Framework } /// + /// For foreign avatars, extracts their original name and Server URL from their First Name and Last Name. + /// + public static bool ParseForeignAvatarName(string firstname, string lastname, + out string realFirstName, out string realLastName, out string serverURI) + { + realFirstName = realLastName = serverURI = string.Empty; + + if (!lastname.Contains("@")) + return false; + + if (!firstname.Contains(".")) + return false; + + realFirstName = firstname.Split('.')[0]; + realLastName = firstname.Split('.')[1]; + serverURI = new Uri("http://" + lastname.Replace("@", "")).ToString(); + + return true; + } + + /// /// Produces a universal (HG) system-facing identifier given the information /// /// @@ -2092,10 +2853,15 @@ namespace OpenSim.Framework { string[] parts = firstName.Split(new char[] { '.' }); if (parts.Length == 2) - return id.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; + return CalcUniversalIdentifier(id, agentsURI, parts[0] + " " + parts[1]); } - return id.ToString() + ";" + agentsURI + ";" + firstName + " " + lastName; + + return CalcUniversalIdentifier(id, agentsURI, firstName + " " + lastName); + } + private static string CalcUniversalIdentifier(UUID id, string agentsURI, string name) + { + return id.ToString() + ";" + agentsURI + ";" + name; } /// @@ -2119,5 +2885,221 @@ namespace OpenSim.Framework return firstName + "." + lastName + " " + "@" + uri.Authority; } #endregion + + /// + /// Escapes the special characters used in "LIKE". + /// + /// + /// For example: EscapeForLike("foo_bar%baz") = "foo\_bar\%baz" + /// + public static string EscapeForLike(string str) + { + return str.Replace("_", "\\_").Replace("%", "\\%"); + } + + /// + /// Returns the name of the user's viewer. + /// + /// + /// This method handles two ways that viewers specify their name: + /// 1. Viewer = "Firestorm-Release 4.4.2.34167", Channel = "(don't care)" -> "Firestorm-Release 4.4.2.34167" + /// 2. Viewer = "4.5.1.38838", Channel = "Firestorm-Beta" -> "Firestorm-Beta 4.5.1.38838" + /// + public static string GetViewerName(AgentCircuitData agent) + { + string name = agent.Viewer; + if (name == null) + name = ""; + else + name = name.Trim(); + + // Check if 'Viewer' is just a version number. If it's *not*, then we + // assume that it contains the real viewer name, and we return it. + foreach (char c in name) + { + if (Char.IsLetter(c)) + return name; + } + + // The 'Viewer' string contains just a version number. If there's anything in + // 'Channel' then assume that it's the viewer name. + if ((agent.Channel != null) && (agent.Channel.Length > 0)) + name = agent.Channel.Trim() + " " + name; + + return name; + } + + public static void LogFailedXML(string message, string xml) + { + int length = xml.Length; + if (length > 2000) + xml = xml.Substring(0, 2000) + "..."; + + m_log.ErrorFormat("{0} Failed XML ({1} bytes) = {2}", message, length, xml); + } + + } + + public class DoubleQueue where T:class + { + private Queue m_lowQueue = new Queue(); + private Queue m_highQueue = new Queue(); + + private object m_syncRoot = new object(); + private Semaphore m_s = new Semaphore(0, 1); + + public DoubleQueue() + { + } + + public virtual int Count + { + get + { + lock (m_syncRoot) + return m_highQueue.Count + m_lowQueue.Count; + } + } + + public virtual void Enqueue(T data) + { + Enqueue(m_lowQueue, data); + } + + public virtual void EnqueueLow(T data) + { + Enqueue(m_lowQueue, data); + } + + public virtual void EnqueueHigh(T data) + { + Enqueue(m_highQueue, data); + } + + private void Enqueue(Queue q, T data) + { + lock (m_syncRoot) + { + q.Enqueue(data); + m_s.WaitOne(0); + m_s.Release(); + } + } + + public virtual T Dequeue() + { + return Dequeue(Timeout.Infinite); + } + + public virtual T Dequeue(int tmo) + { + return Dequeue(TimeSpan.FromMilliseconds(tmo)); + } + + public virtual T Dequeue(TimeSpan wait) + { + T res = null; + + if (!Dequeue(wait, ref res)) + return null; + + return res; + } + + public bool Dequeue(int timeout, ref T res) + { + return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); + } + + public bool Dequeue(TimeSpan wait, ref T res) + { + if (!m_s.WaitOne(wait)) + return false; + + lock (m_syncRoot) + { + if (m_highQueue.Count > 0) + res = m_highQueue.Dequeue(); + else if (m_lowQueue.Count > 0) + res = m_lowQueue.Dequeue(); + + if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) + return true; + + try + { + m_s.Release(); + } + catch + { + } + + return true; + } + } + + public virtual void Clear() + { + + lock (m_syncRoot) + { + // Make sure sem count is 0 + m_s.WaitOne(0); + + m_lowQueue.Clear(); + m_highQueue.Clear(); + } + } + } + + public class BetterRandom + { + private const int BufferSize = 1024; // must be a multiple of 4 + private byte[] RandomBuffer; + private int BufferOffset; + private RNGCryptoServiceProvider rng; + public BetterRandom() + { + RandomBuffer = new byte[BufferSize]; + rng = new RNGCryptoServiceProvider(); + BufferOffset = RandomBuffer.Length; + } + private void FillBuffer() + { + rng.GetBytes(RandomBuffer); + BufferOffset = 0; + } + public int Next() + { + if (BufferOffset >= RandomBuffer.Length) + { + FillBuffer(); + } + int val = BitConverter.ToInt32(RandomBuffer, BufferOffset) & 0x7fffffff; + BufferOffset += sizeof(int); + return val; + } + public int Next(int maxValue) + { + return Next() % maxValue; + } + public int Next(int minValue, int maxValue) + { + if (maxValue < minValue) + { + throw new ArgumentOutOfRangeException("maxValue must be greater than or equal to minValue"); + } + int range = maxValue - minValue; + return minValue + Next(range); + } + public double NextDouble() + { + int val = Next(); + return (double)val / int.MaxValue; + } + public void GetBytes(byte[] buff) + { + rng.GetBytes(buff); + } } } diff --git a/OpenSim/Framework/VersionInfo.cs b/OpenSim/Framework/VersionInfo.cs new file mode 100644 index 0000000..356e720 --- /dev/null +++ b/OpenSim/Framework/VersionInfo.cs @@ -0,0 +1,92 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +namespace OpenSim +{ + public class VersionInfo + { + public const string VersionNumber = "0.8.2.1"; + private const string IG_BUILD_NUMBER = "4"; + private const Flavour VERSION_FLAVOUR = Flavour.IG; + + public enum Flavour + { + Unknown, + Dev, + RC1, + RC2, + RC3, + Release, + Post_Fixes, + Extended, + IG + } + + public static string Version + { + get { return GetVersionString(VersionNumber, IG_BUILD_NUMBER, IG_BUILD_NUMBER, VERSION_FLAVOUR); } + } + + public static string GetVersionString(string versionNumber, string buildNumber, Flavour flavour) + { + string versionString = "OpenSim " + versionNumber + " " + flavour + " build " + buildNumber; + return versionString.PadRight(VERSIONINFO_VERSION_LENGTH); + } + + public const int VERSIONINFO_VERSION_LENGTH = 39; + + /// + /// This is the external interface version. It is separate from the OpenSimulator project version. + /// + /// + /// Commented because it's not used anymore, see below for new + /// versioning method. + //public readonly static int MajorInterfaceVersion = 8; + + /// + /// This rules versioning regarding teleports, and compatibility between simulators in that regard. + /// + /// + /// + /// The protocol version that we will use for outgoing transfers + /// Valid values are + /// "SIMULATION/0.3" + /// - This is the latest, and it supports teleports to variable-sized regions + /// - Older versions can teleport to this one, but only if the destination region + /// is 256x256 + /// "SIMULATION/0.2" + /// - A source simulator which only implements "SIMULATION/0.1" can still teleport here + /// - this protocol is more efficient than "SIMULATION/0.1" + /// "SIMULATION/0.1" + /// - this is an older teleport protocol used in OpenSimulator 0.7.5 and before. + /// + public readonly static float SimulationServiceVersionAcceptedMin = 0.3f; + public readonly static float SimulationServiceVersionAcceptedMax = 0.5f; + public readonly static float SimulationServiceVersionSupportedMin = 0.3f; + public readonly static float SimulationServiceVersionSupportedMax = 0.5f; + } +} diff --git a/OpenSim/Framework/WearableCacheItem.cs b/OpenSim/Framework/WearableCacheItem.cs new file mode 100644 index 0000000..1aecf79 --- /dev/null +++ b/OpenSim/Framework/WearableCacheItem.cs @@ -0,0 +1,157 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework +{ + [Serializable] + public class WearableCacheItem + { + public uint TextureIndex { get; set; } + public UUID CacheId { get; set; } + public UUID TextureID { get; set; } + public AssetBase TextureAsset { get; set; } + + + public static WearableCacheItem[] GetDefaultCacheItem() + { + int itemmax = 21; + WearableCacheItem[] retitems = new WearableCacheItem[itemmax]; + for (uint i=0;i ret = new List(); + if (pInput.Type == OSDType.Array) + { + OSDArray itemarray = (OSDArray) pInput; + foreach (OSDMap item in itemarray) + { + ret.Add(new WearableCacheItem() + { + TextureIndex = item["textureindex"].AsUInteger(), + CacheId = item["cacheid"].AsUUID(), + TextureID = item["textureid"].AsUUID() + }); + + if (dataCache != null && item.ContainsKey("assetdata")) + { + AssetBase asset = new AssetBase(item["textureid"].AsUUID(),"BakedTexture",(sbyte)AssetType.Texture,UUID.Zero.ToString()); + asset.Temporary = true; + asset.Data = item["assetdata"].AsBinary(); + dataCache.Cache(asset); + } + } + } + else if (pInput.Type == OSDType.Map) + { + OSDMap item = (OSDMap) pInput; + ret.Add(new WearableCacheItem(){ + TextureIndex = item["textureindex"].AsUInteger(), + CacheId = item["cacheid"].AsUUID(), + TextureID = item["textureid"].AsUUID() + }); + if (dataCache != null && item.ContainsKey("assetdata")) + { + string assetCreator = item["assetcreator"].AsString(); + string assetName = item["assetname"].AsString(); + AssetBase asset = new AssetBase(item["textureid"].AsUUID(), assetName, (sbyte)AssetType.Texture, assetCreator); + asset.Temporary = true; + asset.Data = item["assetdata"].AsBinary(); + dataCache.Cache(asset); + } + } + else + { + return new WearableCacheItem[0]; + } + return ret.ToArray(); + + } + public static OSD ToOSD(WearableCacheItem[] pcacheItems, IImprovedAssetCache dataCache) + { + OSDArray arr = new OSDArray(); + foreach (WearableCacheItem item in pcacheItems) + { + OSDMap itemmap = new OSDMap(); + itemmap.Add("textureindex", OSD.FromUInteger(item.TextureIndex)); + itemmap.Add("cacheid", OSD.FromUUID(item.CacheId)); + itemmap.Add("textureid", OSD.FromUUID(item.TextureID)); + if (dataCache != null) + { + if (dataCache.Check(item.TextureID.ToString())) + { + AssetBase assetItem = dataCache.Get(item.TextureID.ToString()); + if (assetItem != null) + { + itemmap.Add("assetdata", OSD.FromBinary(assetItem.Data)); + itemmap.Add("assetcreator", OSD.FromString(assetItem.CreatorID)); + itemmap.Add("assetname", OSD.FromString(assetItem.Name)); + } + } + } + arr.Add(itemmap); + } + return arr; + } + public static WearableCacheItem SearchTextureIndex(uint pTextureIndex,WearableCacheItem[] pcacheItems) + { + for (int i = 0; i < pcacheItems.Length; i++) + { + if (pcacheItems[i].TextureIndex == pTextureIndex) + return pcacheItems[i]; + } + return null; + } + public static WearableCacheItem SearchTextureCacheId(UUID pCacheId, WearableCacheItem[] pcacheItems) + { + for (int i = 0; i < pcacheItems.Length; i++) + { + if (pcacheItems[i].CacheId == pCacheId) + return pcacheItems[i]; + } + return null; + } + public static WearableCacheItem SearchTextureTextureId(UUID pTextureId, WearableCacheItem[] pcacheItems) + { + for (int i = 0; i < pcacheItems.Length; i++) + { + if (pcacheItems[i].TextureID == pTextureId) + return pcacheItems[i]; + } + return null; + } + } + + +} diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 5c34cf4..b180c8a 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -39,8 +39,13 @@ using System.Text; using System.Web; using System.Xml; using System.Xml.Serialization; +using System.Xml.Linq; using log4net; +using Nwc.XmlRpc; using OpenMetaverse.StructuredData; +using XMLResponseHelper = OpenSim.Framework.SynchronousRestObjectRequester.XMLResponseHelper; + +using OpenSim.Framework.ServiceAuth; namespace OpenSim.Framework { @@ -64,7 +69,12 @@ namespace OpenSim.Framework /// /// Request number for diagnostic purposes. /// - public static int RequestNumber { get; internal set; } + public static int RequestNumber { get; set; } + + /// + /// Control where OSD requests should be serialized per endpoint. + /// + public static bool SerializeOSDRequestsPerEndpoint { get; set; } /// /// this is the header field used to communicate the local request id @@ -84,8 +94,9 @@ namespace OpenSim.Framework /// /// This is to truncate any really large post data, such as an asset. In theory, the first section should /// give us useful information about the call (which agent it relates to if applicable, etc.). + /// This is also used to truncate messages when using DebugLevel 5. /// - public const int MaxRequestDiagLength = 100; + public const int MaxRequestDiagLength = 200; /// /// Dictionary of end points @@ -120,45 +131,104 @@ namespace OpenSim.Framework /// public static OSDMap PutToServiceCompressed(string url, OSDMap data, int timeout) { - return ServiceOSDRequest(url,data, "PUT", timeout, true); + return ServiceOSDRequest(url,data, "PUT", timeout, true, false); } public static OSDMap PutToService(string url, OSDMap data, int timeout) { - return ServiceOSDRequest(url,data, "PUT", timeout, false); + return ServiceOSDRequest(url,data, "PUT", timeout, false, false); } - public static OSDMap PostToService(string url, OSDMap data, int timeout) + public static OSDMap PostToService(string url, OSDMap data, int timeout, bool rpc) { - return ServiceOSDRequest(url, data, "POST", timeout, false); + return ServiceOSDRequest(url, data, "POST", timeout, false, rpc); } public static OSDMap PostToServiceCompressed(string url, OSDMap data, int timeout) { - return ServiceOSDRequest(url, data, "POST", timeout, true); + return ServiceOSDRequest(url, data, "POST", timeout, true, false); } public static OSDMap GetFromService(string url, int timeout) { - return ServiceOSDRequest(url, null, "GET", timeout, false); + return ServiceOSDRequest(url, null, "GET", timeout, false, false); } - - public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed) + + public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed, bool rpc) { - lock (EndPointLock(url)) + if (SerializeOSDRequestsPerEndpoint) + { + lock (EndPointLock(url)) + { + return ServiceOSDRequestWorker(url, data, method, timeout, compressed, rpc); + } + } + else { - return ServiceOSDRequestWorker(url,data,method,timeout,compressed); + return ServiceOSDRequestWorker(url, data, method, timeout, compressed, rpc); } } - private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed) + public static void LogOutgoingDetail(Stream outputStream) + { + LogOutgoingDetail("", outputStream); + } + + public static void LogOutgoingDetail(string context, Stream outputStream) + { + using (Stream stream = Util.Copy(outputStream)) + using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) + { + string output; + + if (DebugLevel == 5) + { + char[] chars = new char[WebUtil.MaxRequestDiagLength + 1]; // +1 so we know to add "..." only if needed + int len = reader.Read(chars, 0, WebUtil.MaxRequestDiagLength + 1); + output = new string(chars, 0, len); + } + else + { + output = reader.ReadToEnd(); + } + + LogOutgoingDetail(context, output); + } + } + + public static void LogOutgoingDetail(string type, int reqnum, string output) + { + LogOutgoingDetail(string.Format("{0} {1}: ", type, reqnum), output); + } + + public static void LogOutgoingDetail(string context, string output) + { + if (DebugLevel == 5) + { + if (output.Length > MaxRequestDiagLength) + output = output.Substring(0, MaxRequestDiagLength) + "..."; + } + + m_log.DebugFormat("[LOGHTTP]: {0}{1}", context, Util.BinaryToASCII(output)); + } + + public static void LogResponseDetail(int reqnum, Stream inputStream) + { + LogOutgoingDetail(string.Format("RESPONSE {0}: ", reqnum), inputStream); + } + + public static void LogResponseDetail(int reqnum, string input) + { + LogOutgoingDetail(string.Format("RESPONSE {0}: ", reqnum), input); + } + + private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed, bool rpc) { int reqnum = RequestNumber++; if (DebugLevel >= 3) - m_log.DebugFormat( - "[WEB UTIL]: HTTP OUT {0} ServiceOSD {1} {2} (timeout {3}, compressed {4})", - reqnum, method, url, timeout, compressed); + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} JSON-RPC {1} to {2}", + reqnum, method, url); string errorMessage = "unknown error"; int tickstart = Util.EnvironmentTickCount(); @@ -178,20 +248,27 @@ namespace OpenSim.Framework // If there is some input, write it into the request if (data != null) { - strBuffer = OSDParser.SerializeJsonString(data); + strBuffer = OSDParser.SerializeJsonString(data); + + if (DebugLevel >= 5) + LogOutgoingDetail("SEND", reqnum, strBuffer); + byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer); + request.ContentType = rpc ? "application/json-rpc" : "application/json"; + if (compressed) { - request.ContentType = "application/x-gzip"; + request.Headers["X-Content-Encoding"] = "gzip"; // can't set "Content-Encoding" because old OpenSims fail if they get an unrecognized Content-Encoding + using (MemoryStream ms = new MemoryStream()) { - using (GZipStream comp = new GZipStream(ms, CompressionMode.Compress)) + using (GZipStream comp = new GZipStream(ms, CompressionMode.Compress, true)) { comp.Write(buffer, 0, buffer.Length); // We need to close the gzip stream before we write it anywhere // because apparently something important related to gzip compression - // gets written on the strteam upon Dispose() + // gets written on the stream upon Dispose() } byte[] buf = ms.ToArray(); request.ContentLength = buf.Length; //Count bytes to send @@ -201,10 +278,9 @@ namespace OpenSim.Framework } else { - request.ContentType = "application/json"; request.ContentLength = buffer.Length; //Count bytes to send using (Stream requestStream = request.GetRequestStream()) - requestStream.Write(buffer, 0, buffer.Length); //Send it + requestStream.Write(buffer, 0, buffer.Length); //Send it } } @@ -216,10 +292,13 @@ namespace OpenSim.Framework { using (Stream responseStream = response.GetResponseStream()) { - string responseStr = null; - responseStr = responseStream.GetStreamString(); - // m_log.DebugFormat("[WEB UTIL]: <{0}> response is <{1}>",reqnum,responseStr); - return CanonicalizeResults(responseStr); + using (StreamReader reader = new StreamReader(responseStream)) + { + string responseStr = reader.ReadToEnd(); + if (WebUtil.DebugLevel >= 5) + WebUtil.LogResponseDetail(reqnum, responseStr); + return CanonicalizeResults(responseStr); + } } } } @@ -228,8 +307,8 @@ namespace OpenSim.Framework errorMessage = we.Message; if (we.Status == WebExceptionStatus.ProtocolError) { - HttpWebResponse webResponse = (HttpWebResponse)we.Response; - errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription); + using (HttpWebResponse webResponse = (HttpWebResponse)we.Response) + errorMessage = String.Format("[{0}] {1}", webResponse.StatusCode, webResponse.StatusDescription); } } catch (Exception ex) @@ -240,24 +319,23 @@ namespace OpenSim.Framework { int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); if (tickdiff > LongCallTime) + { m_log.InfoFormat( - "[WEB UTIL]: Slow ServiceOSD request {0} {1} {2} took {3}ms, {4}ms writing, {5}", - reqnum, - method, - url, - tickdiff, - tickdata, + "[LOGHTTP]: Slow JSON-RPC request {0} {1} to {2} took {3}ms, {4}ms writing, {5}", + reqnum, method, url, tickdiff, tickdata, strBuffer != null ? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer) : ""); + } else if (DebugLevel >= 4) - m_log.DebugFormat( - "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", + { + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing", reqnum, tickdiff, tickdata); + } } m_log.DebugFormat( - "[WEB UTIL]: ServiceOSD request {0} {1} {2} FAILED: {3}", reqnum, url, method, errorMessage); + "[LOGHTTP]: JSON-RPC request {0} {1} to {2} FAILED: {3}", reqnum, method, url, errorMessage); return ErrorResponseMap(errorMessage); } @@ -335,9 +413,8 @@ namespace OpenSim.Framework string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown"; if (DebugLevel >= 3) - m_log.DebugFormat( - "[WEB UTIL]: HTTP OUT {0} ServiceForm {1} {2} (timeout {3})", - reqnum, method, url, timeout); + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} ServiceForm '{1}' to {2}", + reqnum, method, url); string errorMessage = "unknown error"; int tickstart = Util.EnvironmentTickCount(); @@ -357,6 +434,10 @@ namespace OpenSim.Framework if (data != null) { queryString = BuildQueryString(data); + + if (DebugLevel >= 5) + LogOutgoingDetail("SEND", reqnum, queryString); + byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString); request.ContentLength = buffer.Length; @@ -373,12 +454,16 @@ namespace OpenSim.Framework { using (Stream responseStream = response.GetResponseStream()) { - string responseStr = null; + using (StreamReader reader = new StreamReader(responseStream)) + { + string responseStr = reader.ReadToEnd(); + if (WebUtil.DebugLevel >= 5) + WebUtil.LogResponseDetail(reqnum, responseStr); + OSD responseOSD = OSDParser.Deserialize(responseStr); - responseStr = responseStream.GetStreamString(); - OSD responseOSD = OSDParser.Deserialize(responseStr); - if (responseOSD.Type == OSDType.Map) - return (OSDMap)responseOSD; + if (responseOSD.Type == OSDType.Map) + return (OSDMap)responseOSD; + } } } } @@ -387,8 +472,8 @@ namespace OpenSim.Framework errorMessage = we.Message; if (we.Status == WebExceptionStatus.ProtocolError) { - HttpWebResponse webResponse = (HttpWebResponse)we.Response; - errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription); + using (HttpWebResponse webResponse = (HttpWebResponse)we.Response) + errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription); } } catch (Exception ex) @@ -399,23 +484,22 @@ namespace OpenSim.Framework { int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); if (tickdiff > LongCallTime) + { m_log.InfoFormat( - "[WEB UTIL]: Slow ServiceForm request {0} {1} {2} took {3}ms, {4}ms writing, {5}", - reqnum, - method, - url, - tickdiff, - tickdata, + "[LOGHTTP]: Slow ServiceForm request {0} '{1}' to {2} took {3}ms, {4}ms writing, {5}", + reqnum, method, url, tickdiff, tickdata, queryString != null ? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString : ""); + } else if (DebugLevel >= 4) - m_log.DebugFormat( - "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", + { + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing", reqnum, tickdiff, tickdata); + } } - m_log.WarnFormat("[WEB UTIL]: ServiceForm request {0} {1} {2} failed: {2}", reqnum, method, url, errorMessage); + m_log.WarnFormat("[LOGHTTP]: ServiceForm request {0} '{1}' to {2} failed: {3}", reqnum, method, url, errorMessage); return ErrorResponseMap(errorMessage); } @@ -592,38 +676,6 @@ namespace OpenSim.Framework return totalCopiedBytes; } - /// - /// Converts an entire stream to a string, regardless of current stream - /// position - /// - /// The stream to convert to a string - /// - /// When this method is done, the stream position will be - /// reset to its previous position before this method was called - public static string GetStreamString(this Stream stream) - { - string value = null; - - if (stream != null && stream.CanRead) - { - long rewindPos = -1; - - if (stream.CanSeek) - { - rewindPos = stream.Position; - stream.Seek(0, SeekOrigin.Begin); - } - - StreamReader reader = new StreamReader(stream); - value = reader.ReadToEnd(); - - if (rewindPos >= 0) - stream.Seek(rewindPos, SeekOrigin.Begin); - } - - return value; - } - #endregion Stream public class QBasedComparer : IComparer @@ -667,7 +719,7 @@ namespace OpenSim.Framework /// public static string[] GetPreferredImageTypes(string accept) { - if (accept == null || accept == string.Empty) + if (string.IsNullOrEmpty(accept)) return new string[0]; string[] types = accept.Split(new char[] { ',' }); @@ -724,11 +776,17 @@ namespace OpenSim.Framework string requestUrl, TRequest obj, Action action, int maxConnections) { + MakeRequest(verb, requestUrl, obj, action, maxConnections, null); + } + + public static void MakeRequest(string verb, + string requestUrl, TRequest obj, Action action, + int maxConnections, IServiceAuth auth) + { int reqnum = WebUtil.RequestNumber++; if (WebUtil.DebugLevel >= 3) - m_log.DebugFormat( - "[WEB UTIL]: HTTP OUT {0} AsynchronousRequestObject {1} {2}", + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} AsynchronousRequestObject {1} to {2}", reqnum, verb, requestUrl); int tickstart = Util.EnvironmentTickCount(); @@ -738,171 +796,174 @@ namespace OpenSim.Framework WebRequest request = WebRequest.Create(requestUrl); HttpWebRequest ht = (HttpWebRequest)request; + + if (auth != null) + auth.AddAuthorization(ht.Headers); + if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections) ht.ServicePoint.ConnectionLimit = maxConnections; - WebResponse response = null; TResponse deserial = default(TResponse); - XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); request.Method = verb; + MemoryStream buffer = null; - if (verb == "POST") + try { - request.ContentType = "text/xml"; + if (verb == "POST") + { + request.ContentType = "text/xml"; - buffer = new MemoryStream(); + buffer = new MemoryStream(); - XmlWriterSettings settings = new XmlWriterSettings(); - settings.Encoding = Encoding.UTF8; + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; - using (XmlWriter writer = XmlWriter.Create(buffer, settings)) - { - XmlSerializer serializer = new XmlSerializer(type); - serializer.Serialize(writer, obj); - writer.Flush(); - } + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, obj); + writer.Flush(); + } - int length = (int)buffer.Length; - request.ContentLength = length; + int length = (int)buffer.Length; + request.ContentLength = length; + byte[] data = buffer.ToArray(); - request.BeginGetRequestStream(delegate(IAsyncResult res) - { - Stream requestStream = request.EndGetRequestStream(res); + if (WebUtil.DebugLevel >= 5) + WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data)); - requestStream.Write(buffer.ToArray(), 0, length); - requestStream.Close(); + request.BeginGetRequestStream(delegate(IAsyncResult res) + { + using (Stream requestStream = request.EndGetRequestStream(res)) + requestStream.Write(data, 0, length); - // capture how much time was spent writing - tickdata = Util.EnvironmentTickCountSubtract(tickstart); + // capture how much time was spent writing + tickdata = Util.EnvironmentTickCountSubtract(tickstart); - request.BeginGetResponse(delegate(IAsyncResult ar) - { - response = request.EndGetResponse(ar); - Stream respStream = null; - try + request.BeginGetResponse(delegate(IAsyncResult ar) { - respStream = response.GetResponseStream(); - deserial = (TResponse)deserializer.Deserialize( - respStream); - } - catch (System.InvalidOperationException) - { - } - finally - { - // Let's not close this - //buffer.Close(); - respStream.Close(); - response.Close(); - } + using (WebResponse response = request.EndGetResponse(ar)) + { + try + { + using (Stream respStream = response.GetResponseStream()) + { + deserial = XMLResponseHelper.LogAndDeserialize( + reqnum, respStream, response.ContentLength); + } + } + catch (System.InvalidOperationException) + { + } + } - action(deserial); + action(deserial); + }, null); }, null); - }, null); - } - else - { - request.BeginGetResponse(delegate(IAsyncResult res2) + } + else { - try + request.BeginGetResponse(delegate(IAsyncResult res2) { - // If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't - // documented in MSDN - response = request.EndGetResponse(res2); - - Stream respStream = null; try { - respStream = response.GetResponseStream(); - deserial = (TResponse)deserializer.Deserialize(respStream); - } - catch (System.InvalidOperationException) - { - } - finally - { - respStream.Close(); - response.Close(); + // If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't + // documented in MSDN + using (WebResponse response = request.EndGetResponse(res2)) + { + try + { + using (Stream respStream = response.GetResponseStream()) + { + deserial = XMLResponseHelper.LogAndDeserialize( + reqnum, respStream, response.ContentLength); + } + } + catch (System.InvalidOperationException) + { + } + } } - } - catch (WebException e) - { - if (e.Status == WebExceptionStatus.ProtocolError) + catch (WebException e) { - if (e.Response is HttpWebResponse) + if (e.Status == WebExceptionStatus.ProtocolError) { - HttpWebResponse httpResponse = (HttpWebResponse)e.Response; - - if (httpResponse.StatusCode != HttpStatusCode.NotFound) + if (e.Response is HttpWebResponse) { - // We don't appear to be handling any other status codes, so log these feailures to that - // people don't spend unnecessary hours hunting phantom bugs. - m_log.DebugFormat( - "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}", - verb, requestUrl, httpResponse.StatusCode); + using (HttpWebResponse httpResponse = (HttpWebResponse)e.Response) + { + if (httpResponse.StatusCode != HttpStatusCode.NotFound) + { + // We don't appear to be handling any other status codes, so log these feailures to that + // people don't spend unnecessary hours hunting phantom bugs. + m_log.DebugFormat( + "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}", + verb, requestUrl, httpResponse.StatusCode); + } + } } } + else + { + m_log.ErrorFormat( + "[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}", + verb, requestUrl, e.Status, e.Message); + } } - else + catch (Exception e) { m_log.ErrorFormat( - "[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}", - verb, requestUrl, e.Status, e.Message); + "[ASYNC REQUEST]: Request {0} {1} failed with exception {2}{3}", + verb, requestUrl, e.Message, e.StackTrace); } - } - catch (Exception e) - { - m_log.ErrorFormat( - "[ASYNC REQUEST]: Request {0} {1} failed with exception {2}{3}", - verb, requestUrl, e.Message, e.StackTrace); - } - - // m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString()); + + // m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString()); - try - { - action(deserial); - } - catch (Exception e) + try + { + action(deserial); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}{3}", + verb, requestUrl, e.Message, e.StackTrace); + } + + }, null); + } + + int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); + if (tickdiff > WebUtil.LongCallTime) + { + string originalRequest = null; + + if (buffer != null) { - m_log.ErrorFormat( - "[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}{3}", - verb, requestUrl, e.Message, e.StackTrace); - } - - }, null); - } + originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); - int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); - if (tickdiff > WebUtil.LongCallTime) - { - string originalRequest = null; + if (originalRequest.Length > WebUtil.MaxRequestDiagLength) + originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength); + } - if (buffer != null) + m_log.InfoFormat( + "[LOGHTTP]: Slow AsynchronousRequestObject request {0} {1} to {2} took {3}ms, {4}ms writing, {5}", + reqnum, verb, requestUrl, tickdiff, tickdata, + originalRequest); + } + else if (WebUtil.DebugLevel >= 4) { - originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); - - if (originalRequest.Length > WebUtil.MaxRequestDiagLength) - originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength); + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing", + reqnum, tickdiff, tickdata); } - - m_log.InfoFormat( - "[ASYNC REQUEST]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", - reqnum, - verb, - requestUrl, - tickdiff, - tickdata, - originalRequest); } - else if (WebUtil.DebugLevel >= 4) - { - m_log.DebugFormat( - "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", - reqnum, tickdiff, tickdata); + finally + { + if (buffer != null) + buffer.Dispose(); } } } @@ -917,17 +978,17 @@ namespace OpenSim.Framework /// /// /// + /// /// /// /// Thrown if we encounter a network issue while posting /// the request. You'll want to make sure you deal with this as they're not uncommon - public static string MakeRequest(string verb, string requestUrl, string obj) + public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs, IServiceAuth auth) { int reqnum = WebUtil.RequestNumber++; if (WebUtil.DebugLevel >= 3) - m_log.DebugFormat( - "[WEB UTIL]: HTTP OUT {0} SynchronousRestForms {1} {2}", + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} SynchronousRestForms {1} to {2}", reqnum, verb, requestUrl); int tickstart = Util.EnvironmentTickCount(); @@ -935,6 +996,12 @@ namespace OpenSim.Framework WebRequest request = WebRequest.Create(requestUrl); request.Method = verb; + if (timeoutsecs > 0) + request.Timeout = timeoutsecs * 1000; + + if (auth != null) + auth.AddAuthorization(request.Headers); + string respstring = String.Empty; using (MemoryStream buffer = new MemoryStream()) @@ -952,22 +1019,27 @@ namespace OpenSim.Framework length = (int)obj.Length; request.ContentLength = length; + byte[] data = buffer.ToArray(); + + if (WebUtil.DebugLevel >= 5) + WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data)); Stream requestStream = null; try { requestStream = request.GetRequestStream(); - requestStream.Write(buffer.ToArray(), 0, length); + requestStream.Write(data, 0, length); } catch (Exception e) { - m_log.DebugFormat( - "[FORMS]: exception occured {0} {1}: {2}{3}", verb, requestUrl, e.Message, e.StackTrace); + m_log.InfoFormat("[FORMS]: Error sending request to {0}: {1}. Request: {2}", requestUrl, e.Message, + obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); + throw e; } finally { if (requestStream != null) - requestStream.Close(); + requestStream.Dispose(); // capture how much time was spent writing tickdata = Util.EnvironmentTickCountSubtract(tickstart); @@ -980,53 +1052,54 @@ namespace OpenSim.Framework { if (resp.ContentLength != 0) { - Stream respStream = null; - try - { - respStream = resp.GetResponseStream(); + using (Stream respStream = resp.GetResponseStream()) using (StreamReader reader = new StreamReader(respStream)) - { respstring = reader.ReadToEnd(); - } - } - catch (Exception e) - { - m_log.DebugFormat( - "[FORMS]: Exception occured on receiving {0} {1}: {2}{3}", - verb, requestUrl, e.Message, e.StackTrace); - } - finally - { - if (respStream != null) - respStream.Close(); - } } } } - catch (System.InvalidOperationException) + catch (Exception e) { - // This is what happens when there is invalid XML - m_log.DebugFormat("[FORMS]: InvalidOperationException on receiving {0} {1}", verb, requestUrl); + m_log.InfoFormat("[FORMS]: Error receiving response from {0}: {1}. Request: {2}", requestUrl, e.Message, + obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); + throw e; } } int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); if (tickdiff > WebUtil.LongCallTime) + { m_log.InfoFormat( - "[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", - reqnum, - verb, - requestUrl, - tickdiff, - tickdata, + "[LOGHTTP]: Slow SynchronousRestForms request {0} {1} to {2} took {3}ms, {4}ms writing, {5}", + reqnum, verb, requestUrl, tickdiff, tickdata, obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); + } else if (WebUtil.DebugLevel >= 4) - m_log.DebugFormat( - "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", + { + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing", reqnum, tickdiff, tickdata); + } + + if (WebUtil.DebugLevel >= 5) + WebUtil.LogResponseDetail(reqnum, respstring); return respstring; } + + public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs) + { + return MakeRequest(verb, requestUrl, obj, timeoutsecs, null); + } + + public static string MakeRequest(string verb, string requestUrl, string obj) + { + return MakeRequest(verb, requestUrl, obj, -1); + } + + public static string MakeRequest(string verb, string requestUrl, string obj, IServiceAuth auth) + { + return MakeRequest(verb, requestUrl, obj, -1, auth); + } } public class SynchronousRestObjectRequester @@ -1040,28 +1113,80 @@ namespace OpenSim.Framework /// /// /// - /// - /// - /// - /// Thrown if we encounter a network issue while posting - /// the request. You'll want to make sure you deal with this as they're not uncommon + /// + /// + /// The response. If there was an internal exception, then the default(TResponse) is returned. + /// public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj) { return MakeRequest(verb, requestUrl, obj, 0); } + public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj, IServiceAuth auth) + { + return MakeRequest(verb, requestUrl, obj, 0, auth); + } + /// + /// Perform a synchronous REST request. + /// + /// + /// + /// + /// + /// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds) + /// + /// + /// The response. If there was an internal exception or the request timed out, + /// then the default(TResponse) is returned. + /// public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj, int pTimeout) { return MakeRequest(verb, requestUrl, obj, pTimeout, 0); } + public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj, int pTimeout, IServiceAuth auth) + { + return MakeRequest(verb, requestUrl, obj, pTimeout, 0, auth); + } + + /// Perform a synchronous REST request. + /// + /// + /// + /// + /// + /// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds) + /// + /// + /// + /// The response. If there was an internal exception or the request timed out, + /// then the default(TResponse) is returned. + /// public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections) { + return MakeRequest(verb, requestUrl, obj, pTimeout, maxConnections, null); + } + + /// + /// Perform a synchronous REST request. + /// + /// + /// + /// + /// + /// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds) + /// + /// + /// + /// The response. If there was an internal exception or the request timed out, + /// then the default(TResponse) is returned. + /// + public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections, IServiceAuth auth) + { int reqnum = WebUtil.RequestNumber++; if (WebUtil.DebugLevel >= 3) - m_log.DebugFormat( - "[WEB UTIL]: HTTP OUT {0} SynchronousRestObject {1} {2}", + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} SynchronousRestObject {1} to {2}", reqnum, verb, requestUrl); int tickstart = Util.EnvironmentTickCount(); @@ -1072,129 +1197,252 @@ namespace OpenSim.Framework WebRequest request = WebRequest.Create(requestUrl); HttpWebRequest ht = (HttpWebRequest)request; + + if (auth != null) + auth.AddAuthorization(ht.Headers); + + if (pTimeout != 0) + ht.Timeout = pTimeout; + if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections) ht.ServicePoint.ConnectionLimit = maxConnections; request.Method = verb; MemoryStream buffer = null; - if ((verb == "POST") || (verb == "PUT")) + try { - request.ContentType = "text/xml"; + if ((verb == "POST") || (verb == "PUT")) + { + request.ContentType = "text/xml"; - buffer = new MemoryStream(); + buffer = new MemoryStream(); - XmlWriterSettings settings = new XmlWriterSettings(); - settings.Encoding = Encoding.UTF8; + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; - using (XmlWriter writer = XmlWriter.Create(buffer, settings)) - { - XmlSerializer serializer = new XmlSerializer(type); - serializer.Serialize(writer, obj); - writer.Flush(); - } + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, obj); + writer.Flush(); + } + + int length = (int)buffer.Length; + request.ContentLength = length; + byte[] data = buffer.ToArray(); + + if (WebUtil.DebugLevel >= 5) + WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data)); + + try + { + using (Stream requestStream = request.GetRequestStream()) + requestStream.Write(data, 0, length); + } + catch (Exception e) + { + m_log.DebugFormat( + "[SynchronousRestObjectRequester]: Exception in making request {0} {1}: {2}{3}", + verb, requestUrl, e.Message, e.StackTrace); - int length = (int)buffer.Length; - request.ContentLength = length; + return deserial; + } + finally + { + // capture how much time was spent writing + tickdata = Util.EnvironmentTickCountSubtract(tickstart); + } + } - Stream requestStream = null; try { - requestStream = request.GetRequestStream(); - requestStream.Write(buffer.ToArray(), 0, length); + using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse()) + { + if (resp.ContentLength != 0) + { + using (Stream respStream = resp.GetResponseStream()) + { + deserial = XMLResponseHelper.LogAndDeserialize( + reqnum, respStream, resp.ContentLength); + } + } + else + { + m_log.DebugFormat( + "[SynchronousRestObjectRequester]: Oops! no content found in response stream from {0} {1}", + verb, requestUrl); + } + } } - catch (Exception e) + catch (WebException e) { + using (HttpWebResponse hwr = (HttpWebResponse)e.Response) + { + if (hwr != null) + { + if (hwr.StatusCode == HttpStatusCode.NotFound) + return deserial; + if (hwr.StatusCode == HttpStatusCode.Unauthorized) + { + m_log.Error(string.Format( + "[SynchronousRestObjectRequester]: Web request {0} requires authentication ", + requestUrl)); + return deserial; + } + } + else + m_log.Error(string.Format( + "[SynchronousRestObjectRequester]: WebException for {0} {1} {2} ", + verb, requestUrl, typeof(TResponse).ToString()), e); + } + } + catch (System.InvalidOperationException) + { + // This is what happens when there is invalid XML m_log.DebugFormat( - "[SynchronousRestObjectRequester]: Exception in making request {0} {1}: {2}{3}", - verb, requestUrl, e.Message, e.StackTrace); - - return deserial; + "[SynchronousRestObjectRequester]: Invalid XML from {0} {1} {2}", + verb, requestUrl, typeof(TResponse).ToString()); } - finally + catch (Exception e) { - if (requestStream != null) - requestStream.Close(); - - // capture how much time was spent writing - tickdata = Util.EnvironmentTickCountSubtract(tickstart); + m_log.Debug(string.Format( + "[SynchronousRestObjectRequester]: Exception on response from {0} {1} ", + verb, requestUrl), e); } - } - try - { - using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse()) + int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); + if (tickdiff > WebUtil.LongCallTime) { - if (resp.ContentLength != 0) - { - Stream respStream = resp.GetResponseStream(); - XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); - deserial = (TResponse)deserializer.Deserialize(respStream); - respStream.Close(); - } - else + string originalRequest = null; + + if (buffer != null) { - m_log.DebugFormat( - "[SynchronousRestObjectRequester]: Oops! no content found in response stream from {0} {1}", - verb, requestUrl); + originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); + + if (originalRequest.Length > WebUtil.MaxRequestDiagLength) + originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength); } - } - } - catch (WebException e) - { - HttpWebResponse hwr = (HttpWebResponse)e.Response; - if (hwr != null && hwr.StatusCode == HttpStatusCode.NotFound) - return deserial; - else - m_log.ErrorFormat( - "[SynchronousRestObjectRequester]: WebException for {0} {1} {2}: {3} {4}", - verb, requestUrl, typeof(TResponse).ToString(), e.Message, e.StackTrace); + m_log.InfoFormat( + "[LOGHTTP]: Slow SynchronousRestObject request {0} {1} to {2} took {3}ms, {4}ms writing, {5}", + reqnum, verb, requestUrl, tickdiff, tickdata, + originalRequest); + } + else if (WebUtil.DebugLevel >= 4) + { + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing", + reqnum, tickdiff, tickdata); + } } - catch (System.InvalidOperationException) + finally { - // This is what happens when there is invalid XML - m_log.DebugFormat( - "[SynchronousRestObjectRequester]: Invalid XML from {0} {1} {2}", - verb, requestUrl, typeof(TResponse).ToString()); + if (buffer != null) + buffer.Dispose(); } - catch (Exception e) + + return deserial; + } + + + public static class XMLResponseHelper + { + public static TResponse LogAndDeserialize(int reqnum, Stream respStream, long contentLength) { - m_log.DebugFormat( - "[SynchronousRestObjectRequester]: Exception on response from {0} {1}: {2}{3}", - verb, requestUrl, e.Message, e.StackTrace); + XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); + + if (WebUtil.DebugLevel >= 5) + { + byte[] data = new byte[contentLength]; + Util.ReadStream(respStream, data); + + WebUtil.LogResponseDetail(reqnum, System.Text.Encoding.UTF8.GetString(data)); + + using (MemoryStream temp = new MemoryStream(data)) + return (TResponse)deserializer.Deserialize(temp); + } + else + { + return (TResponse)deserializer.Deserialize(respStream); + } } + } + } - int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); - if (tickdiff > WebUtil.LongCallTime) + + public static class XMLRPCRequester + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public static Hashtable SendRequest(Hashtable ReqParams, string method, string url) + { + int reqnum = WebUtil.RequestNumber++; + + if (WebUtil.DebugLevel >= 3) + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} XML-RPC '{1}' to {2}", + reqnum, method, url); + + int tickstart = Util.EnvironmentTickCount(); + string responseStr = null; + + try { - string originalRequest = null; + ArrayList SendParams = new ArrayList(); + SendParams.Add(ReqParams); - if (buffer != null) + XmlRpcRequest Req = new XmlRpcRequest(method, SendParams); + + if (WebUtil.DebugLevel >= 5) + { + string str = Req.ToString(); + str = XElement.Parse(str).ToString(SaveOptions.DisableFormatting); + WebUtil.LogOutgoingDetail("SEND", reqnum, str); + } + + XmlRpcResponse Resp = Req.Send(url, 30000); + + try { - originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); + responseStr = Resp.ToString(); + responseStr = XElement.Parse(responseStr).ToString(SaveOptions.DisableFormatting); - if (originalRequest.Length > WebUtil.MaxRequestDiagLength) - originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength); + if (WebUtil.DebugLevel >= 5) + WebUtil.LogResponseDetail(reqnum, responseStr); + } + catch (Exception e) + { + m_log.Error("Error parsing XML-RPC response", e); + } + + if (Resp.IsFault) + { + m_log.DebugFormat( + "[LOGHTTP]: XML-RPC request {0} '{1}' to {2} FAILED: FaultCode={3}, FaultMessage={4}", + reqnum, method, url, Resp.FaultCode, Resp.FaultString); + return null; } - m_log.InfoFormat( - "[SynchronousRestObjectRequester]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", - reqnum, - verb, - requestUrl, - tickdiff, - tickdata, - originalRequest); + Hashtable RespData = (Hashtable)Resp.Value; + return RespData; } - else if (WebUtil.DebugLevel >= 4) + finally { - m_log.DebugFormat( - "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", - reqnum, tickdiff, tickdata); + int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); + if (tickdiff > WebUtil.LongCallTime) + { + m_log.InfoFormat( + "[LOGHTTP]: Slow XML-RPC request {0} '{1}' to {2} took {3}ms, {4}", + reqnum, method, url, tickdiff, + responseStr != null + ? (responseStr.Length > WebUtil.MaxRequestDiagLength ? responseStr.Remove(WebUtil.MaxRequestDiagLength) : responseStr) + : ""); + } + else if (WebUtil.DebugLevel >= 4) + { + m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms", reqnum, tickdiff); + } } - - return deserial; } + } } diff --git a/OpenSim/Region/Application/Application.cs b/OpenSim/Region/Application/Application.cs index 0f90d37..bf34419 100644 --- a/OpenSim/Region/Application/Application.cs +++ b/OpenSim/Region/Application/Application.cs @@ -102,34 +102,81 @@ namespace OpenSim m_log.InfoFormat( "[OPENSIM MAIN]: Environment variable MONO_THREADS_PER_CPU is {0}", monoThreadsPerCpu ?? "unset"); - // Increase the number of IOCP threads available. Mono defaults to a tragically low number + // Verify the Threadpool allocates or uses enough worker and IO completion threads + // .NET 2.0, workerthreads default to 50 * numcores + // .NET 3.0, workerthreads defaults to 250 * numcores + // .NET 4.0, workerthreads are dynamic based on bitness and OS resources + // Max IO Completion threads are 1000 on all 3 CLRs + // + // Mono 2.10.9 to at least Mono 3.1, workerthreads default to 100 * numcores, iocp threads to 4 * numcores + int workerThreadsMin = 500; + int workerThreadsMax = 1000; // may need further adjustment to match other CLR + int iocpThreadsMin = 1000; + int iocpThreadsMax = 2000; // may need further adjustment to match other CLR + + { + int currentMinWorkerThreads, currentMinIocpThreads; + System.Threading.ThreadPool.GetMinThreads(out currentMinWorkerThreads, out currentMinIocpThreads); + m_log.InfoFormat( + "[OPENSIM MAIN]: Runtime gave us {0} min worker threads and {1} min IOCP threads", + currentMinWorkerThreads, currentMinIocpThreads); + } + int workerThreads, iocpThreads; System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); - m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} worker threads and {1} IOCP threads", workerThreads, iocpThreads); - if (workerThreads < 500 || iocpThreads < 1000) + m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} max worker threads and {1} max IOCP threads", workerThreads, iocpThreads); + + if (workerThreads < workerThreadsMin) + { + workerThreads = workerThreadsMin; + m_log.InfoFormat("[OPENSIM MAIN]: Bumping up max worker threads to {0}",workerThreads); + } + if (workerThreads > workerThreadsMax) { - workerThreads = 500; - iocpThreads = 1000; - m_log.Info("[OPENSIM MAIN]: Bumping up to 500 worker threads and 1000 IOCP threads"); - System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads); + workerThreads = workerThreadsMax; + m_log.InfoFormat("[OPENSIM MAIN]: Limiting max worker threads to {0}",workerThreads); } + // Increase the number of IOCP threads available. + // Mono defaults to a tragically low number (24 on 6-core / 8GB Fedora 17) + if (iocpThreads < iocpThreadsMin) + { + iocpThreads = iocpThreadsMin; + m_log.InfoFormat("[OPENSIM MAIN]: Bumping up max IOCP threads to {0}",iocpThreads); + } + // Make sure we don't overallocate IOCP threads and thrash system resources + if ( iocpThreads > iocpThreadsMax ) + { + iocpThreads = iocpThreadsMax; + m_log.InfoFormat("[OPENSIM MAIN]: Limiting max IOCP completion threads to {0}",iocpThreads); + } + // set the resulting worker and IO completion thread counts back to ThreadPool + if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) ) + { + m_log.InfoFormat( + "[OPENSIM MAIN]: Threadpool set to {0} max worker threads and {1} max IOCP threads", + workerThreads, iocpThreads); + } + else + { + m_log.Warn("[OPENSIM MAIN]: Threadpool reconfiguration failed, runtime defaults still in effect."); + } + // Check if the system is compatible with OpenSimulator. // Ensures that the minimum system requirements are met string supported = String.Empty; if (Util.IsEnvironmentSupported(ref supported)) { - m_log.Info("Environment is compatible.\n"); + m_log.Info("[OPENSIM MAIN]: Environment is supported by OpenSimulator."); } else { - m_log.Warn("Environment is unsupported (" + supported + ")\n"); + m_log.Warn("[OPENSIM MAIN]: Environment is not supported by OpenSimulator (" + supported + ")\n"); } // Configure nIni aliases and localles Culture.SetCurrentCulture(); - // Validate that the user has the most basic configuration done // If not, offer to do the most basic configuration for them warning them along the way of the importance of // reading these files. diff --git a/OpenSim/Region/Application/ConfigurationLoader.cs b/OpenSim/Region/Application/ConfigurationLoader.cs index fc3999f..b19e549 100644 --- a/OpenSim/Region/Application/ConfigurationLoader.cs +++ b/OpenSim/Region/Application/ConfigurationLoader.cs @@ -82,8 +82,7 @@ namespace OpenSim List sources = new List(); - string masterFileName = - startupConfig.GetString("inimaster", "OpenSimDefaults.ini"); + string masterFileName = startupConfig.GetString("inimaster", "OpenSimDefaults.ini"); if (masterFileName == "none") masterFileName = String.Empty; @@ -124,7 +123,7 @@ namespace OpenSim else { Application.iniFilePath = Path.GetFullPath( - Path.Combine(Util.configDir(), iniFileName)); + Path.Combine(Util.configDir(), iniFileName)); if (!File.Exists(Application.iniFilePath)) { @@ -139,12 +138,29 @@ namespace OpenSim } } + m_config = new OpenSimConfigSource(); + m_config.Source = new IniConfigSource(); + m_config.Source.Merge(DefaultConfig()); + + m_log.Info("[CONFIG]: Reading configuration settings"); + + for (int i = 0 ; i < sources.Count ; i++) + { + if (ReadConfig(m_config, sources[i])) + { + iniFileExists = true; + AddIncludes(m_config, sources); + } + } + + // Override distro settings with contents of inidirectory string iniDirName = startupConfig.GetString("inidirectory", "config"); string iniDirPath = Path.Combine(Util.configDir(), iniDirName); if (Directory.Exists(iniDirPath)) { - m_log.InfoFormat("Searching folder {0} for config ini files", iniDirPath); + m_log.InfoFormat("[CONFIG]: Searching folder {0} for config ini files", iniDirPath); + List overrideSources = new List(); string[] fileEntries = Directory.GetFiles(iniDirName); foreach (string filePath in fileEntries) @@ -152,58 +168,52 @@ namespace OpenSim if (Path.GetExtension(filePath).ToLower() == ".ini") { if (!sources.Contains(Path.GetFullPath(filePath))) + { + overrideSources.Add(Path.GetFullPath(filePath)); + // put it in sources too, to avoid circularity sources.Add(Path.GetFullPath(filePath)); + } } } - } - m_config = new OpenSimConfigSource(); - m_config.Source = new IniConfigSource(); - m_config.Source.Merge(DefaultConfig()); - m_log.Info("[CONFIG]: Reading configuration settings"); + if (overrideSources.Count > 0) + { + OpenSimConfigSource overrideConfig = new OpenSimConfigSource(); + overrideConfig.Source = new IniConfigSource(); + + for (int i = 0 ; i < overrideSources.Count ; i++) + { + if (ReadConfig(overrideConfig, overrideSources[i])) + { + iniFileExists = true; + AddIncludes(overrideConfig, overrideSources); + } + } + m_config.Source.Merge(overrideConfig.Source); + } + } if (sources.Count == 0) { m_log.FatalFormat("[CONFIG]: Could not load any configuration"); Environment.Exit(1); - } - - for (int i = 0 ; i < sources.Count ; i++) - { - if (ReadConfig(sources[i])) - { - iniFileExists = true; - AddIncludes(sources); - } - } - - if (!iniFileExists) + } + else if (!iniFileExists) { m_log.FatalFormat("[CONFIG]: Could not load any configuration"); m_log.FatalFormat("[CONFIG]: Configuration exists, but there was an error loading it!"); Environment.Exit(1); } + // Merge OpSys env vars + m_log.Info("[CONFIG]: Loading environment variables for Config"); + Util.MergeEnvironmentToConfig(m_config.Source); + // Make sure command line options take precedence m_config.Source.Merge(argvSource); - IConfig enVars = m_config.Source.Configs["Environment"]; - - if( enVars != null ) - { - string[] env_keys = enVars.GetKeys(); - - foreach ( string key in env_keys ) - { - envConfigSource.AddEnv(key, string.Empty); - } - - envConfigSource.LoadEnv(); - m_config.Source.Merge(envConfigSource); - m_config.Source.ExpandKeyValues(); - } - + m_config.Source.ReplaceKeyValues(); ReadConfigSettings(); @@ -214,10 +224,10 @@ namespace OpenSim /// Adds the included files as ini configuration files /// /// List of URL strings or filename strings - private void AddIncludes(List sources) + private void AddIncludes(OpenSimConfigSource configSource, List sources) { //loop over config sources - foreach (IConfig config in m_config.Source.Configs) + foreach (IConfig config in configSource.Source.Configs) { // Look for Include-* in the key name string[] keys = config.GetKeys(); @@ -284,7 +294,7 @@ namespace OpenSim /// /// Full path to the ini /// - private bool ReadConfig(string iniPath) + private bool ReadConfig(OpenSimConfigSource configSource, string iniPath) { bool success = false; @@ -292,7 +302,7 @@ namespace OpenSim { m_log.InfoFormat("[CONFIG]: Reading configuration file {0}", Path.GetFullPath(iniPath)); - m_config.Source.Merge(new IniConfigSource(iniPath)); + configSource.Source.Merge(new IniConfigSource(iniPath)); success = true; } else @@ -305,7 +315,7 @@ namespace OpenSim { XmlReader r = XmlReader.Create(iniPath); XmlConfigSource cs = new XmlConfigSource(r); - m_config.Source.Merge(cs); + configSource.Source.Merge(cs); success = true; } @@ -337,10 +347,7 @@ namespace OpenSim config.Set("physics", "OpenDynamicsEngine"); config.Set("meshing", "Meshmerizer"); config.Set("physical_prim", true); - config.Set("see_into_this_sim_from_neighbor", true); config.Set("serverside_object_permissions", true); - config.Set("storage_plugin", "OpenSim.Data.SQLite.dll"); - config.Set("storage_connection_string", "URI=file:OpenSim.db,version=3"); config.Set("storage_prim_inventories", true); config.Set("startup_console_commands_file", String.Empty); config.Set("shutdown_console_commands_file", String.Empty); @@ -372,7 +379,6 @@ namespace OpenSim { m_configSettings.PhysicsEngine = startupConfig.GetString("physics"); m_configSettings.MeshEngineName = startupConfig.GetString("meshing"); - m_configSettings.StorageDll = startupConfig.GetString("storage_plugin"); m_configSettings.ClientstackDll = startupConfig.GetString("clientstack_plugin", "OpenSim.Region.ClientStack.LindenUDP.dll"); diff --git a/OpenSim/Region/Application/IApplicationPlugin.cs b/OpenSim/Region/Application/IApplicationPlugin.cs index 6e6d48c..a3fa66c 100644 --- a/OpenSim/Region/Application/IApplicationPlugin.cs +++ b/OpenSim/Region/Application/IApplicationPlugin.cs @@ -26,12 +26,14 @@ */ using OpenSim.Framework; +using Mono.Addins; namespace OpenSim { /// /// OpenSimulator Application Plugin framework interface /// + [TypeExtensionPoint(NodeName="Plugin", NodeType = typeof(PluginExtensionNode), Path="/OpenSim/Startup")] public interface IApplicationPlugin : IPlugin { /// diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index c4731a3..5af8194 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -30,6 +30,7 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; @@ -44,6 +45,7 @@ using OpenSim.Framework.Servers; using OpenSim.Framework.Monitoring; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; namespace OpenSim { @@ -85,6 +87,7 @@ namespace OpenSim IConfig startupConfig = Config.Configs["Startup"]; IConfig networkConfig = Config.Configs["Network"]; + int stpMinThreads = 2; int stpMaxThreads = 15; if (startupConfig != null) @@ -111,12 +114,13 @@ namespace OpenSim if (!String.IsNullOrEmpty(asyncCallMethodStr) && Utils.EnumTryParse(asyncCallMethodStr, out asyncCallMethod)) Util.FireAndForgetMethod = asyncCallMethod; - stpMaxThreads = startupConfig.GetInt("MaxPoolThreads", 15); + stpMinThreads = startupConfig.GetInt("MinPoolThreads", 15); + stpMaxThreads = startupConfig.GetInt("MaxPoolThreads", 300); m_consolePrompt = startupConfig.GetString("ConsolePrompt", @"Region (\R) "); } if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) - Util.InitThreadPool(stpMaxThreads); + Util.InitThreadPool(stpMinThreads, stpMaxThreads); m_log.Info("[OPENSIM MAIN]: Using async_call_method " + Util.FireAndForgetMethod); } @@ -151,13 +155,14 @@ namespace OpenSim ((RemoteConsole)m_console).ReadConfig(Config); break; default: - m_console = new LocalConsole("Region"); + m_console = new LocalConsole("Region", Config.Configs["Startup"]); break; } } MainConsole.Instance = m_console; + LogEnvironmentInformation(); RegisterCommonAppenders(Config.Configs["Startup"]); RegisterConsoleCommands(); @@ -168,6 +173,13 @@ namespace OpenSim if (userStatsURI != String.Empty) MainServer.Instance.AddStreamHandler(new OpenSim.UXSimStatusHandler(this)); + if (managedStatsURI != String.Empty) + { + string urlBase = String.Format("/{0}/", managedStatsURI); + MainServer.Instance.AddHTTPHandler(urlBase, StatsManager.HandleStatsRequest); + m_log.InfoFormat("[OPENSIM] Enabling remote managed stats fetch. URL = {0}", urlBase); + } + if (m_console is RemoteConsole) { if (m_consolePort == 0) @@ -224,49 +236,56 @@ namespace OpenSim "Force the update of all objects on clients", HandleForceUpdate); - m_console.Commands.AddCommand("Debug", false, "debug packet", - "debug packet [ ]", - "Turn on packet debugging", - "If level > 255 then all incoming and outgoing packets are logged.\n" - + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n" - + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n" - + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n" - + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n" - + "If level <= 0 then no packets are logged.\n" - + "If an avatar name is given then only packets from that avatar are logged", - Debug); - m_console.Commands.AddCommand("General", false, "change region", "change region ", - "Change current console region", ChangeSelectedRegion); + "Change current console region", + ChangeSelectedRegion); m_console.Commands.AddCommand("Archiving", false, "save xml", "save xml", - "Save a region's data in XML format", SaveXml); + "Save a region's data in XML format", + SaveXml); m_console.Commands.AddCommand("Archiving", false, "save xml2", "save xml2", - "Save a region's data in XML2 format", SaveXml2); + "Save a region's data in XML2 format", + SaveXml2); m_console.Commands.AddCommand("Archiving", false, "load xml", "load xml [-newIDs [ ]]", - "Load a region's data from XML format", LoadXml); + "Load a region's data from XML format", + LoadXml); m_console.Commands.AddCommand("Archiving", false, "load xml2", "load xml2", - "Load a region's data from XML2 format", LoadXml2); + "Load a region's data from XML2 format", + LoadXml2); m_console.Commands.AddCommand("Archiving", false, "save prims xml2", "save prims xml2 [ ]", - "Save named prim to XML2", SavePrimsXml2); + "Save named prim to XML2", + SavePrimsXml2); m_console.Commands.AddCommand("Archiving", false, "load oar", - "load oar [--merge] [--skip-assets] []", + "load oar [--merge] [--skip-assets]" + + " [--default-user \"User Name\"]" + + " [--force-terrain] [--force-parcels]" + + " [--no-objects]" + + " [--rotation degrees] [--rotation-center \"\"]" + + " [--displacement \"\"]" + + " []", "Load a region's data from an OAR archive.", - "--merge will merge the OAR with the existing scene." + Environment.NewLine - + "--skip-assets will load the OAR but ignore the assets it contains." + Environment.NewLine - + "The path can be either a filesystem location or a URI." - + " If this is not given then the command looks for an OAR named region.oar in the current directory.", + "--merge will merge the OAR with the existing scene (suppresses terrain and parcel info loading).\n" + + "--default-user will use this user for any objects with an owner whose UUID is not found in the grid.\n" + + "--displacement will add this value to the position of every object loaded.\n" + + "--force-terrain forces the loading of terrain from the oar (undoes suppression done by --merge).\n" + + "--force-parcels forces the loading of parcels from the oar (undoes suppression done by --merge).\n" + + "--no-objects suppresses the addition of any objects (good for loading only the terrain).\n" + + "--rotation specified rotation to be applied to the oar. Specified in degrees.\n" + + "--rotation-center Location (relative to original OAR) to apply rotation. Default is <128,128,0>.\n" + + "--skip-assets will load the OAR but ignore the assets it contains.\n\n" + + "The path can be either a filesystem location or a URI.\n" + + " If this is not given then the command looks for an OAR named region.oar in the current directory.", LoadOar); m_console.Commands.AddCommand("Archiving", false, "save oar", @@ -288,7 +307,23 @@ namespace OpenSim m_console.Commands.AddCommand("Objects", false, "edit scale", "edit scale ", - "Change the scale of a named prim", HandleEditScale); + "Change the scale of a named prim", + HandleEditScale); + + m_console.Commands.AddCommand("Objects", false, "rotate scene", + "rotate scene [centerX, centerY]", + "Rotates all scene objects around centerX, centerY (defailt 128, 128) (please back up your region before using)", + HandleRotateScene); + + m_console.Commands.AddCommand("Objects", false, "scale scene", + "scale scene ", + "Scales the scene objects (please back up your region before using)", + HandleScaleScene); + + m_console.Commands.AddCommand("Objects", false, "translate scene", + "translate scene xOffset yOffset zOffset", + "translates the scene objects (please back up your region before using)", + HandleTranslateScene); m_console.Commands.AddCommand("Users", false, "kick user", "kick user [--force] [message]", @@ -306,31 +341,38 @@ namespace OpenSim m_console.Commands.AddCommand("Comms", false, "show connections", "show connections", - "Show connection data", HandleShow); + "Show connection data", + HandleShow); m_console.Commands.AddCommand("Comms", false, "show circuits", "show circuits", - "Show agent circuit data", HandleShow); + "Show agent circuit data", + HandleShow); m_console.Commands.AddCommand("Comms", false, "show pending-objects", "show pending-objects", - "Show # of objects on the pending queues of all scene viewers", HandleShow); + "Show # of objects on the pending queues of all scene viewers", + HandleShow); m_console.Commands.AddCommand("General", false, "show modules", "show modules", - "Show module data", HandleShow); + "Show module data", + HandleShow); m_console.Commands.AddCommand("Regions", false, "show regions", "show regions", - "Show region data", HandleShow); + "Show region data", + HandleShow); m_console.Commands.AddCommand("Regions", false, "show ratings", "show ratings", - "Show rating data", HandleShow); + "Show rating data", + HandleShow); m_console.Commands.AddCommand("Objects", false, "backup", "backup", - "Persist currently unsaved object changes immediately instead of waiting for the normal persistence call.", RunCommand); + "Persist currently unsaved object changes immediately instead of waiting for the normal persistence call.", + RunCommand); m_console.Commands.AddCommand("Regions", false, "create region", "create region [\"region name\"] ", @@ -343,34 +385,47 @@ namespace OpenSim m_console.Commands.AddCommand("Regions", false, "restart", "restart", - "Restart all sims in this instance", RunCommand); + "Restart the currently selected region(s) in this instance", + RunCommand); m_console.Commands.AddCommand("General", false, "command-script", "command-script \n"); + o.Append("\n"); + } + + public static void InsertPeriodicUpdaters(ref StringBuilder o, string[] divID, int[] seconds, string[] reportfrag) + { + o.Append(""); + } + + public static void HtmlHeaders_O(ref StringBuilder o) + { + o.Append("\n"); + o.Append(""); + o.Append(""); + } + + public static void HtmlHeaders_C(ref StringBuilder o) + { + o.Append(""); + o.Append(""); + } + + public static void AddReportLinks(ref StringBuilder o, Dictionary reports, string pClass) + { + int repcount = 0; + foreach (string str in reports.Keys) + { + if (reports[str].ReportName.Length > 0) + { + if (repcount > 0) + { + o.Append("|  "); + } + A(ref o, reports[str].ReportName, str, pClass); + o.Append("  "); + repcount++; + } + } + } + + public static void A(ref StringBuilder o, string linktext, string linkhref, string pClass) + { + o.Append(" 0) + { + GenericClass(ref o, pClass); + } + o.Append(" href=\""); + o.Append(linkhref); + o.Append("\">"); + o.Append(linktext); + o.Append(""); + } + } +} diff --git a/OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs b/OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs new file mode 100644 index 0000000..80c4487 --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs @@ -0,0 +1,39 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Collections; + +namespace OpenSim.Region.UserStatistics +{ + public interface IStatsController + { + string ReportName { get; } + Hashtable ProcessModel(Hashtable pParams); + string RenderView(Hashtable pModelResult); + string RenderJson(Hashtable pModelResult); + } +} diff --git a/OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs b/OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs new file mode 100644 index 0000000..4d45b80 --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs @@ -0,0 +1,159 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using Mono.Data.SqliteClient; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Framework.Monitoring; + +namespace OpenSim.Region.UserStatistics +{ + public class LogLinesAJAX : IStatsController + { + private Regex normalizeEndLines = new Regex(@"\r\n", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline); + + private Regex webFormat = new Regex(@"[^\s]*\s([^,]*),[^\s]*\s([A-Z]*)[^\s-][^\[]*\[([^\]]*)\]([^\n]*)", + RegexOptions.Singleline | RegexOptions.Compiled); + private Regex TitleColor = new Regex(@"[^\s]*\s(?:[^,]*),[^\s]*\s(?:[A-Z]*)[^\s-][^\[]*\[([^\]]*)\](?:[^\n]*)", + RegexOptions.Singleline | RegexOptions.Compiled); + + + #region IStatsController Members + + public string ReportName + { + get { return ""; } + } + + public Hashtable ProcessModel(Hashtable pParams) + { + Hashtable nh = new Hashtable(); + nh.Add("loglines", pParams["LogLines"]); + return nh; + } + + public string RenderView(Hashtable pModelResult) + { + StringBuilder output = new StringBuilder(); + + HTMLUtil.HR(ref output, ""); + output.Append("

ActiveLog

\n"); + + string tmp = normalizeEndLines.Replace(pModelResult["loglines"].ToString(), "\n"); + + string[] result = Regex.Split(tmp, "\n"); + + string formatopen = ""; + string formatclose = ""; + + for (int i = 0; i < result.Length; i++) + { + if (result[i].Length >= 30) + { + string logtype = result[i].Substring(24, 6); + switch (logtype) + { + case "WARN ": + formatopen = ""; + formatclose = ""; + break; + + case "ERROR ": + formatopen = ""; + formatclose = ""; + break; + + default: + formatopen = ""; + formatclose = ""; + break; + + } + } + StringBuilder replaceStr = new StringBuilder(); + //string titlecolorresults = + + string formatresult = Regex.Replace(TitleColor.Replace(result[i], "$1"), "[^ABCDEFabcdef0-9]", ""); + if (formatresult.Length > 6) + { + formatresult = formatresult.Substring(0, 6); + + } + for (int j = formatresult.Length; j <= 5; j++) + formatresult += "0"; + replaceStr.Append("$1 - [$3] $4
"); + string repstr = replaceStr.ToString(); + + output.Append(formatopen); + output.Append(webFormat.Replace(result[i], repstr)); + output.Append(formatclose); + } + + + return output.ToString(); + } + + /// + /// Return the last log lines. Output in the format: + ///
+        /// {"logLines": [
+        /// "line1",
+        /// "line2",
+        /// ...
+        /// ]
+        /// }
+        /// 
+ ///
+ /// + /// + public string RenderJson(Hashtable pModelResult) + { + OSDMap logInfo = new OpenMetaverse.StructuredData.OSDMap(); + + OSDArray logLines = new OpenMetaverse.StructuredData.OSDArray(); + string tmp = normalizeEndLines.Replace(pModelResult["loglines"].ToString(), "\n"); + string[] result = Regex.Split(tmp, "\n"); + for (int i = 0; i < result.Length; i++) + { + logLines.Add(new OSDString(result[i])); + } + logInfo.Add("logLines", logLines); + return logInfo.ToString(); + } + + #endregion + } +} diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs b/OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs new file mode 100644 index 0000000..6f8b2aa --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs @@ -0,0 +1,80 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using OpenSim.Framework; + +namespace OpenSim.Region.UserStatistics +{ + public class Prototype_distributor : IStatsController + { + private string jsFileName = "prototype.js"; + private string prototypejs = string.Empty; + + public Prototype_distributor() + { + jsFileName = "prototype.js"; + } + + public Prototype_distributor(string jsName) + { + jsFileName = jsName; + } + + public string ReportName + { + get { return ""; } + } + public Hashtable ProcessModel(Hashtable pParams) + { + Hashtable pResult = new Hashtable(); + pResult["js"] = jsFileName; + return pResult; + } + + public string RenderView(Hashtable pModelResult) + { + string fileName = (string)pModelResult["js"]; + using (StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/" + fileName, FileMode.Open))) + { + prototypejs = fs.ReadToEnd(); + fs.Close(); + } + return prototypejs; + } + + public string RenderJson(Hashtable pModelResult) + { + return "{}"; + } + + } +} diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs b/OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs new file mode 100644 index 0000000..0e94912 --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs @@ -0,0 +1,288 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using Mono.Data.SqliteClient; +using OpenMetaverse; +using OpenSim.Framework; + +namespace OpenSim.Region.UserStatistics +{ + public class Sessions_Report : IStatsController + { + #region IStatsController Members + + public string ReportName + { + get { return "Sessions"; } + } + + public Hashtable ProcessModel(Hashtable pParams) + { + Hashtable modeldata = new Hashtable(); + modeldata.Add("Scenes", pParams["Scenes"]); + modeldata.Add("Reports", pParams["Reports"]); + SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"]; + List lstSessions = new List(); + Hashtable requestvars = (Hashtable) pParams["RequestVars"]; + + + string puserUUID = string.Empty; + string clientVersionString = string.Empty; + int queryparams = 0; + + if (requestvars != null) + { + if (requestvars.ContainsKey("UserID")) + { + UUID testUUID = UUID.Zero; + if (UUID.TryParse(requestvars["UserID"].ToString(), out testUUID)) + { + puserUUID = requestvars["UserID"].ToString(); + + } + } + + if (requestvars.ContainsKey("VersionString")) + { + clientVersionString = requestvars["VersionString"].ToString(); + } + } + + lock (dbConn) + { + string sql = + "SELECT distinct a.name_f, a.name_l, a.Agent_ID, b.Session_ID, b.client_version, b.last_updated, b.start_time FROM stats_session_data a LEFT OUTER JOIN stats_session_data b ON a.Agent_ID = b.Agent_ID"; + + if (puserUUID.Length > 0) + { + if (queryparams == 0) + sql += " WHERE"; + else + sql += " AND"; + + sql += " b.agent_id=:agent_id"; + queryparams++; + } + + if (clientVersionString.Length > 0) + { + if (queryparams == 0) + sql += " WHERE"; + else + sql += " AND"; + + sql += " b.client_version=:client_version"; + queryparams++; + } + + sql += " ORDER BY a.name_f, a.name_l, b.last_updated;"; + + SqliteCommand cmd = new SqliteCommand(sql, dbConn); + + if (puserUUID.Length > 0) + cmd.Parameters.Add(new SqliteParameter(":agent_id", puserUUID)); + if (clientVersionString.Length > 0) + cmd.Parameters.Add(new SqliteParameter(":client_version", clientVersionString)); + + SqliteDataReader sdr = cmd.ExecuteReader(); + + if (sdr.HasRows) + { + UUID userUUID = UUID.Zero; + + SessionList activeSessionList = new SessionList(); + activeSessionList.user_id=UUID.Random(); + while (sdr.Read()) + { + UUID readUUID = UUID.Parse(sdr["agent_id"].ToString()); + if (readUUID != userUUID) + { + activeSessionList = new SessionList(); + activeSessionList.user_id = readUUID; + activeSessionList.firstname = sdr["name_f"].ToString(); + activeSessionList.lastname = sdr["name_l"].ToString(); + activeSessionList.sessions = new List(); + lstSessions.Add(activeSessionList); + } + + ShortSessionData ssd = new ShortSessionData(); + + ssd.last_update = Utils.UnixTimeToDateTime((uint)Convert.ToInt32(sdr["last_updated"])); + ssd.start_time = Utils.UnixTimeToDateTime((uint)Convert.ToInt32(sdr["start_time"])); + ssd.session_id = UUID.Parse(sdr["session_id"].ToString()); + ssd.client_version = sdr["client_version"].ToString(); + activeSessionList.sessions.Add(ssd); + + userUUID = activeSessionList.user_id; + } + } + sdr.Close(); + sdr.Dispose(); + + } + modeldata["SessionData"] = lstSessions; + return modeldata; + } + + public string RenderView(Hashtable pModelResult) + { + List lstSession = (List) pModelResult["SessionData"]; + Dictionary reports = (Dictionary)pModelResult["Reports"]; + + const string STYLESHEET = + @" + +"; + + StringBuilder output = new StringBuilder(); + HTMLUtil.HtmlHeaders_O(ref output); + output.Append(STYLESHEET); + HTMLUtil.HtmlHeaders_C(ref output); + + HTMLUtil.AddReportLinks(ref output, reports, ""); + + HTMLUtil.TABLE_O(ref output, "defaultr"); + HTMLUtil.TR_O(ref output, "defaultr"); + HTMLUtil.TD_O(ref output, "header"); + output.Append("FirstName"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, "header"); + output.Append("LastName"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, "header"); + output.Append("SessionEnd"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, "header"); + output.Append("SessionLength"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, "header"); + output.Append("Client"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TR_C(ref output); + if (lstSession.Count == 0) + { + HTMLUtil.TR_O(ref output, ""); + HTMLUtil.TD_O(ref output, "align_top", 1, 5); + output.Append("No results for that query"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TR_C(ref output); + } + foreach (SessionList ssnlst in lstSession) + { + int cnt = 0; + foreach (ShortSessionData sesdata in ssnlst.sessions) + { + HTMLUtil.TR_O(ref output, ""); + if (cnt++ == 0) + { + HTMLUtil.TD_O(ref output, "align_top", ssnlst.sessions.Count, 1); + output.Append(ssnlst.firstname); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, "align_top", ssnlst.sessions.Count, 1); + output.Append(ssnlst.lastname); + HTMLUtil.TD_C(ref output); + } + HTMLUtil.TD_O(ref output, "content"); + output.Append(sesdata.last_update.ToShortDateString()); + output.Append(" - "); + output.Append(sesdata.last_update.ToShortTimeString()); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, "content"); + TimeSpan dtlength = sesdata.last_update.Subtract(sesdata.start_time); + if (dtlength.Days > 0) + { + output.Append(dtlength.Days); + output.Append(" Days "); + } + if (dtlength.Hours > 0) + { + output.Append(dtlength.Hours); + output.Append(" Hours "); + } + if (dtlength.Minutes > 0) + { + output.Append(dtlength.Minutes); + output.Append(" Minutes"); + } + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, "content"); + output.Append(sesdata.client_version); + HTMLUtil.TD_C(ref output); + HTMLUtil.TR_C(ref output); + + } + HTMLUtil.TR_O(ref output, ""); + HTMLUtil.TD_O(ref output, "align_top", 1, 5); + HTMLUtil.HR(ref output, ""); + HTMLUtil.TD_C(ref output); + HTMLUtil.TR_C(ref output); + } + HTMLUtil.TABLE_C(ref output); + output.Append("\n"); + return output.ToString(); + } + + public class SessionList + { + public string firstname; + public string lastname; + public UUID user_id; + public List sessions; + } + + public struct ShortSessionData + { + public UUID session_id; + public string client_version; + public DateTime last_update; + public DateTime start_time; + } + + public string RenderJson(Hashtable pModelResult) + { + return "{}"; + } + #endregion + } + +} diff --git a/OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs b/OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs new file mode 100644 index 0000000..06d9e91 --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs @@ -0,0 +1,276 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using Mono.Data.SqliteClient; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Framework.Monitoring; + +namespace OpenSim.Region.UserStatistics +{ + public class SimStatsAJAX : IStatsController + { + #region IStatsController Members + + public string ReportName + { + get { return ""; } + } + + public Hashtable ProcessModel(Hashtable pParams) + { + List m_scene = (List)pParams["Scenes"]; + + Hashtable nh = new Hashtable(); + nh.Add("hdata", m_scene); + nh.Add("simstats", pParams["SimStats"]); + return nh; + } + + public string RenderView(Hashtable pModelResult) + { + StringBuilder output = new StringBuilder(); + List all_scenes = (List) pModelResult["hdata"]; + Dictionary sdatadic = (Dictionary)pModelResult["simstats"]; + + const string TableClass = "defaultr"; + const string TRClass = "defaultr"; + const string TDHeaderClass = "header"; + const string TDDataClass = "content"; + //const string TDDataClassRight = "contentright"; + const string TDDataClassCenter = "contentcenter"; + + foreach (USimStatsData sdata in sdatadic.Values) + { + + + foreach (Scene sn in all_scenes) + { + if (sn.RegionInfo.RegionID == sdata.RegionId) + { + output.Append("

"); + output.Append(sn.RegionInfo.RegionName); + output.Append("

"); + } + } + HTMLUtil.TABLE_O(ref output, TableClass); + HTMLUtil.TR_O(ref output, TRClass); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("Dilatn"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("SimFPS"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("PhysFPS"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("AgntUp"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("RootAg"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("ChldAg"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("Prims"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("ATvPrm"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("AtvScr"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("ScrLPS"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TR_C(ref output); + HTMLUtil.TR_O(ref output, TRClass); + HTMLUtil.TD_O(ref output, TDDataClass); + output.Append(sdata.TimeDilation); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClass); + output.Append(sdata.SimFps); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.PhysicsFps); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.AgentUpdates); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.RootAgents); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.ChildAgents); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.TotalPrims); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.ActivePrims); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.ActiveScripts); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.ScriptLinesPerSecond); + HTMLUtil.TD_C(ref output); + HTMLUtil.TR_C(ref output); + HTMLUtil.TR_O(ref output, TRClass); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("FrmMS"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("AgtMS"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("PhysMS"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("OthrMS"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("OutPPS"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("InPPS"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("NoAckKB"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("PndDWN"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDHeaderClass); + output.Append("PndUP"); + HTMLUtil.TD_C(ref output); + HTMLUtil.TR_C(ref output); + HTMLUtil.TR_O(ref output, TRClass); + HTMLUtil.TD_O(ref output, TDDataClass); + output.Append(sdata.TotalFrameTime); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClass); + output.Append(sdata.AgentFrameTime); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.PhysicsFrameTime); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.OtherFrameTime); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.OutPacketsPerSecond); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.InPacketsPerSecond); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.UnackedBytes); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.PendingDownloads); + HTMLUtil.TD_C(ref output); + HTMLUtil.TD_O(ref output, TDDataClassCenter); + output.Append(sdata.PendingUploads); + HTMLUtil.TD_C(ref output); + HTMLUtil.TR_C(ref output); + HTMLUtil.TABLE_C(ref output); + + } + + return output.ToString(); + } + + /// + /// Return stat information for all regions in the sim. Returns data of the form: + ///
+        /// {"REGIONNAME": {
+        ///     "region": "REGIONNAME",
+        ///     "timeDilation": "101", 
+        ///     ...     // the rest of the stat info
+        ///     },
+        ///  ...    // entries for each region
+        ///  }
+        /// 
+ ///
+ /// + /// + public string RenderJson(Hashtable pModelResult) + { + List all_scenes = (List) pModelResult["hdata"]; + Dictionary sdatadic = (Dictionary)pModelResult["simstats"]; + + OSDMap allStatsInfo = new OpenMetaverse.StructuredData.OSDMap(); + foreach (USimStatsData sdata in sdatadic.Values) + { + OSDMap statsInfo = new OpenMetaverse.StructuredData.OSDMap(); + string regionName = "unknown"; + foreach (Scene sn in all_scenes) + { + if (sn.RegionInfo.RegionID == sdata.RegionId) + { + regionName = sn.RegionInfo.RegionName; + break; + } + } + statsInfo.Add("region", new OSDString(regionName)); + statsInfo.Add("timeDilation", new OSDString(sdata.TimeDilation.ToString())); + statsInfo.Add("simFPS", new OSDString(sdata.SimFps.ToString())); + statsInfo.Add("physicsFPS", new OSDString(sdata.PhysicsFps.ToString())); + statsInfo.Add("agentUpdates", new OSDString(sdata.AgentUpdates.ToString())); + statsInfo.Add("rootAgents", new OSDString(sdata.RootAgents.ToString())); + statsInfo.Add("childAgents", new OSDString(sdata.ChildAgents.ToString())); + statsInfo.Add("totalPrims", new OSDString(sdata.TotalPrims.ToString())); + statsInfo.Add("activePrims", new OSDString(sdata.ActivePrims.ToString())); + statsInfo.Add("activeScripts", new OSDString(sdata.ActiveScripts.ToString())); + statsInfo.Add("scriptLinesPerSec", new OSDString(sdata.ScriptLinesPerSecond.ToString())); + statsInfo.Add("totalFrameTime", new OSDString(sdata.TotalFrameTime.ToString())); + statsInfo.Add("agentFrameTime", new OSDString(sdata.AgentFrameTime.ToString())); + statsInfo.Add("physicsFrameTime", new OSDString(sdata.PhysicsFrameTime.ToString())); + statsInfo.Add("otherFrameTime", new OSDString(sdata.OtherFrameTime.ToString())); + statsInfo.Add("outPacketsPerSec", new OSDString(sdata.OutPacketsPerSecond.ToString())); + statsInfo.Add("inPacketsPerSec", new OSDString(sdata.InPacketsPerSecond.ToString())); + statsInfo.Add("unackedByptes", new OSDString(sdata.UnackedBytes.ToString())); + statsInfo.Add("pendingDownloads", new OSDString(sdata.PendingDownloads.ToString())); + statsInfo.Add("pendingUploads", new OSDString(sdata.PendingUploads.ToString())); + + allStatsInfo.Add(regionName, statsInfo); + } + return allStatsInfo.ToString(); + } + + #endregion + } +} diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs b/OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs new file mode 100644 index 0000000..601e06b --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs @@ -0,0 +1,70 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using OpenSim.Framework; + +namespace OpenSim.Region.UserStatistics +{ + public class Updater_distributor : IStatsController + { + private string updaterjs = string.Empty; + + public string ReportName + { + get { return ""; } + } + + public Hashtable ProcessModel(Hashtable pParams) + { + Hashtable pResult = new Hashtable(); + if (updaterjs.Length == 0) + { + StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/updater.js", FileMode.Open)); + updaterjs = fs.ReadToEnd(); + fs.Close(); + fs.Dispose(); + } + pResult["js"] = updaterjs; + return pResult; + } + + public string RenderView(Hashtable pModelResult) + { + return pModelResult["js"].ToString(); + } + + public string RenderJson(Hashtable pModelResult) { + return "{}"; + } + + } +} \ No newline at end of file diff --git a/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs b/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs new file mode 100644 index 0000000..bcb6361 --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs @@ -0,0 +1,1203 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; // to be used for REST-->Grid shortly +using System.Reflection; +using System.Text; +using System.Threading; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using Mono.Data.SqliteClient; +using Mono.Addins; + +using Caps = OpenSim.Framework.Capabilities.Caps; + +using OSD = OpenMetaverse.StructuredData.OSD; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; + +namespace OpenSim.Region.UserStatistics +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebStatsModule")] + public class WebStatsModule : ISharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private static SqliteConnection dbConn; + + /// + /// User statistics sessions keyed by agent ID + /// + private Dictionary m_sessions = new Dictionary(); + + private List m_scenes = new List(); + private Dictionary reports = new Dictionary(); + private Dictionary m_simstatsCounters = new Dictionary(); + private const int updateStatsMod = 6; + private int updateLogMod = 1; + private volatile int updateLogCounter = 0; + private volatile int concurrencyCounter = 0; + private bool enabled = false; + private string m_loglines = String.Empty; + private volatile int lastHit = 12000; + + #region ISharedRegionModule + + public virtual void Initialise(IConfigSource config) + { + IConfig cnfg = config.Configs["WebStats"]; + + if (cnfg != null) + enabled = cnfg.GetBoolean("enabled", false); + } + + public virtual void PostInitialise() + { + if (!enabled) + return; + + if (Util.IsWindows()) + Util.LoadArchSpecificWindowsDll("sqlite3.dll"); + + //IConfig startupConfig = config.Configs["Startup"]; + + dbConn = new SqliteConnection("URI=file:LocalUserStatistics.db,version=3"); + dbConn.Open(); + CreateTables(dbConn); + + Prototype_distributor protodep = new Prototype_distributor(); + Updater_distributor updatedep = new Updater_distributor(); + ActiveConnectionsAJAX ajConnections = new ActiveConnectionsAJAX(); + SimStatsAJAX ajSimStats = new SimStatsAJAX(); + LogLinesAJAX ajLogLines = new LogLinesAJAX(); + Default_Report defaultReport = new Default_Report(); + Clients_report clientReport = new Clients_report(); + Sessions_Report sessionsReport = new Sessions_Report(); + + reports.Add("prototype.js", protodep); + reports.Add("updater.js", updatedep); + reports.Add("activeconnectionsajax.html", ajConnections); + reports.Add("simstatsajax.html", ajSimStats); + reports.Add("activelogajax.html", ajLogLines); + reports.Add("default.report", defaultReport); + reports.Add("clients.report", clientReport); + reports.Add("sessions.report", sessionsReport); + + reports.Add("sim.css", new Prototype_distributor("sim.css")); + reports.Add("sim.html", new Prototype_distributor("sim.html")); + reports.Add("jquery.js", new Prototype_distributor("jquery.js")); + + //// + // Add Your own Reports here (Do Not Modify Lines here Devs!) + //// + + //// + // End Own reports section + //// + + MainServer.Instance.AddHTTPHandler("/SStats/", HandleStatsRequest); + MainServer.Instance.AddHTTPHandler("/CAPS/VS/", HandleUnknownCAPSRequest); + } + + public virtual void AddRegion(Scene scene) + { + if (!enabled) + return; + + lock (m_scenes) + { + m_scenes.Add(scene); + updateLogMod = m_scenes.Count * 2; + + m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID)); + + scene.EventManager.OnRegisterCaps += OnRegisterCaps; + scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps; + scene.EventManager.OnClientClosed += OnClientClosed; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; + scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket; + } + } + + public void RegionLoaded(Scene scene) + { + } + + public void RemoveRegion(Scene scene) + { + if (!enabled) + return; + + lock (m_scenes) + { + m_scenes.Remove(scene); + updateLogMod = m_scenes.Count * 2; + m_simstatsCounters.Remove(scene.RegionInfo.RegionID); + } + } + + public virtual void Close() + { + if (!enabled) + return; + + dbConn.Close(); + dbConn.Dispose(); + m_sessions.Clear(); + m_scenes.Clear(); + reports.Clear(); + m_simstatsCounters.Clear(); + } + + public virtual string Name + { + get { return "ViewerStatsModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + #endregion + + private void ReceiveClassicSimStatsPacket(SimStats stats) + { + if (!enabled) + return; + + try + { + // Ignore the update if there's a report running right now + // ignore the update if there hasn't been a hit in 30 seconds. + if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000) + return; + + // We will conduct this under lock so that fields such as updateLogCounter do not potentially get + // confused if a scene is removed. + // XXX: Possibly the scope of this lock could be reduced though it's not critical. + lock (m_scenes) + { + if (updateLogMod != 0 && updateLogCounter++ % updateLogMod == 0) + { + m_loglines = readLogLines(10); + + if (updateLogCounter > 10000) + updateLogCounter = 1; + } + + USimStatsData ss = m_simstatsCounters[stats.RegionUUID]; + + if ((++ss.StatsCounter % updateStatsMod) == 0) + { + ss.ConsumeSimStats(stats); + } + } + } + catch (KeyNotFoundException) + { + } + } + + private Hashtable HandleUnknownCAPSRequest(Hashtable request) + { + //string regpath = request["uri"].ToString(); + int response_code = 200; + string contenttype = "text/html"; + UpdateUserStats(ParseViewerStats(request["body"].ToString(), UUID.Zero), dbConn); + Hashtable responsedata = new Hashtable(); + + responsedata["int_response_code"] = response_code; + responsedata["content_type"] = contenttype; + responsedata["keepalive"] = false; + responsedata["str_response_string"] = string.Empty; + return responsedata; + } + + private Hashtable HandleStatsRequest(Hashtable request) + { + lastHit = System.Environment.TickCount; + Hashtable responsedata = new Hashtable(); + string regpath = request["uri"].ToString(); + int response_code = 404; + string contenttype = "text/html"; + bool jsonFormatOutput = false; + + string strOut = string.Empty; + + // The request patch should be "/SStats/reportName" where 'reportName' + // is one of the names added to the 'reports' hashmap. + regpath = regpath.Remove(0, 8); + if (regpath.Length == 0) regpath = "default.report"; + if (reports.ContainsKey(regpath)) + { + IStatsController rep = reports[regpath]; + Hashtable repParams = new Hashtable(); + + if (request.ContainsKey("json")) + jsonFormatOutput = true; + + if (request.ContainsKey("requestvars")) + repParams["RequestVars"] = request["requestvars"]; + else + repParams["RequestVars"] = new Hashtable(); + + if (request.ContainsKey("querystringkeys")) + repParams["QueryStringKeys"] = request["querystringkeys"]; + else + repParams["QueryStringKeys"] = new string[0]; + + + repParams["DatabaseConnection"] = dbConn; + repParams["Scenes"] = m_scenes; + repParams["SimStats"] = m_simstatsCounters; + repParams["LogLines"] = m_loglines; + repParams["Reports"] = reports; + + concurrencyCounter++; + + if (jsonFormatOutput) + { + strOut = rep.RenderJson(rep.ProcessModel(repParams)); + contenttype = "text/json"; + } + else + { + strOut = rep.RenderView(rep.ProcessModel(repParams)); + } + + if (regpath.EndsWith("js")) + { + contenttype = "text/javascript"; + } + + if (regpath.EndsWith("css")) + { + contenttype = "text/css"; + } + + concurrencyCounter--; + + response_code = 200; + } + else + { + strOut = MainServer.Instance.GetHTTP404(""); + } + + responsedata["int_response_code"] = response_code; + responsedata["content_type"] = contenttype; + responsedata["keepalive"] = false; + responsedata["str_response_string"] = strOut; + + return responsedata; + } + + private void CreateTables(SqliteConnection db) + { + using (SqliteCommand createcmd = new SqliteCommand(SQL_STATS_TABLE_CREATE, db)) + { + createcmd.ExecuteNonQuery(); + } + } + + private void OnRegisterCaps(UUID agentID, Caps caps) + { +// m_log.DebugFormat("[WEB STATS MODULE]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps); + + string capsPath = "/CAPS/VS/" + UUID.Random(); + caps.RegisterHandler( + "ViewerStats", + new RestStreamHandler( + "POST", + capsPath, + (request, path, param, httpRequest, httpResponse) + => ViewerStatsReport(request, path, param, agentID, caps), + "ViewerStats", + agentID.ToString())); + } + + private void OnDeRegisterCaps(UUID agentID, Caps caps) + { + } + + protected virtual void AddEventHandlers() + { + lock (m_scenes) + { + updateLogMod = m_scenes.Count * 2; + foreach (Scene scene in m_scenes) + { + scene.EventManager.OnRegisterCaps += OnRegisterCaps; + scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps; + scene.EventManager.OnClientClosed += OnClientClosed; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; + } + } + } + + private void OnMakeRootAgent(ScenePresence agent) + { +// m_log.DebugFormat( +// "[WEB STATS MODULE]: Looking for session {0} for {1} in {2}", +// agent.ControllingClient.SessionId, agent.Name, agent.Scene.Name); + + lock (m_sessions) + { + UserSession uid; + + if (!m_sessions.ContainsKey(agent.UUID)) + { + UserSessionData usd = UserSessionUtil.newUserSessionData(); + uid = new UserSession(); + uid.name_f = agent.Firstname; + uid.name_l = agent.Lastname; + uid.session_data = usd; + + m_sessions.Add(agent.UUID, uid); + } + else + { + uid = m_sessions[agent.UUID]; + } + + uid.region_id = agent.Scene.RegionInfo.RegionID; + uid.session_id = agent.ControllingClient.SessionId; + } + } + + private void OnClientClosed(UUID agentID, Scene scene) + { + lock (m_sessions) + { + if (m_sessions.ContainsKey(agentID) && m_sessions[agentID].region_id == scene.RegionInfo.RegionID) + { + m_sessions.Remove(agentID); + } + } + } + + private string readLogLines(int amount) + { + Encoding encoding = Encoding.ASCII; + int sizeOfChar = encoding.GetByteCount("\n"); + byte[] buffer = encoding.GetBytes("\n"); + string logfile = Util.logFile(); + FileStream fs = new FileStream(logfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + Int64 tokenCount = 0; + Int64 endPosition = fs.Length / sizeOfChar; + + for (Int64 position = sizeOfChar; position < endPosition; position += sizeOfChar) + { + fs.Seek(-position, SeekOrigin.End); + fs.Read(buffer, 0, buffer.Length); + + if (encoding.GetString(buffer) == "\n") + { + tokenCount++; + if (tokenCount == amount) + { + byte[] returnBuffer = new byte[fs.Length - fs.Position]; + fs.Read(returnBuffer, 0, returnBuffer.Length); + fs.Close(); + fs.Dispose(); + return encoding.GetString(returnBuffer); + } + } + } + + // handle case where number of tokens in file is less than numberOfTokens + fs.Seek(0, SeekOrigin.Begin); + buffer = new byte[fs.Length]; + fs.Read(buffer, 0, buffer.Length); + fs.Close(); + fs.Dispose(); + return encoding.GetString(buffer); + } + + /// + /// Callback for a viewerstats cap + /// + /// + /// + /// + /// + /// + /// + private string ViewerStatsReport(string request, string path, string param, + UUID agentID, Caps caps) + { +// m_log.DebugFormat("[WEB STATS MODULE]: Received viewer starts report from {0}", agentID); + + UpdateUserStats(ParseViewerStats(request, agentID), dbConn); + + return String.Empty; + } + + private UserSession ParseViewerStats(string request, UUID agentID) + { + UserSession uid = new UserSession(); + UserSessionData usd; + OSD message = OSDParser.DeserializeLLSDXml(request); + OSDMap mmap; + + lock (m_sessions) + { + if (agentID != UUID.Zero) + { + if (!m_sessions.ContainsKey(agentID)) + { + m_log.WarnFormat("[WEB STATS MODULE]: no session for stat disclosure for agent {0}", agentID); + return new UserSession(); + } + + uid = m_sessions[agentID]; + +// m_log.DebugFormat("[WEB STATS MODULE]: Got session {0} for {1}", uid.session_id, agentID); + } + else + { + // parse through the beginning to locate the session + if (message.Type != OSDType.Map) + return new UserSession(); + + mmap = (OSDMap)message; + { + UUID sessionID = mmap["session_id"].AsUUID(); + + if (sessionID == UUID.Zero) + return new UserSession(); + + + // search through each session looking for the owner + foreach (UUID usersessionid in m_sessions.Keys) + { + // got it! + if (m_sessions[usersessionid].session_id == sessionID) + { + agentID = usersessionid; + uid = m_sessions[usersessionid]; + break; + } + + } + + // can't find a session + if (agentID == UUID.Zero) + { + return new UserSession(); + } + } + } + } + + usd = uid.session_data; + + if (message.Type != OSDType.Map) + return new UserSession(); + + mmap = (OSDMap)message; + { + if (mmap["agent"].Type != OSDType.Map) + return new UserSession(); + OSDMap agent_map = (OSDMap)mmap["agent"]; + usd.agent_id = agentID; + usd.name_f = uid.name_f; + usd.name_l = uid.name_l; + usd.region_id = uid.region_id; + usd.a_language = agent_map["language"].AsString(); + usd.mem_use = (float)agent_map["mem_use"].AsReal(); + usd.meters_traveled = (float)agent_map["meters_traveled"].AsReal(); + usd.regions_visited = agent_map["regions_visited"].AsInteger(); + usd.run_time = (float)agent_map["run_time"].AsReal(); + usd.start_time = (float)agent_map["start_time"].AsReal(); + usd.client_version = agent_map["version"].AsString(); + + UserSessionUtil.UpdateMultiItems(ref usd, agent_map["agents_in_view"].AsInteger(), + (float)agent_map["ping"].AsReal(), + (float)agent_map["sim_fps"].AsReal(), + (float)agent_map["fps"].AsReal()); + + if (mmap["downloads"].Type != OSDType.Map) + return new UserSession(); + OSDMap downloads_map = (OSDMap)mmap["downloads"]; + usd.d_object_kb = (float)downloads_map["object_kbytes"].AsReal(); + usd.d_texture_kb = (float)downloads_map["texture_kbytes"].AsReal(); + usd.d_world_kb = (float)downloads_map["workd_kbytes"].AsReal(); + +// m_log.DebugFormat("[WEB STATS MODULE]: mmap[\"session_id\"] = [{0}]", mmap["session_id"].AsUUID()); + + usd.session_id = mmap["session_id"].AsUUID(); + + if (mmap["system"].Type != OSDType.Map) + return new UserSession(); + OSDMap system_map = (OSDMap)mmap["system"]; + + usd.s_cpu = system_map["cpu"].AsString(); + usd.s_gpu = system_map["gpu"].AsString(); + usd.s_os = system_map["os"].AsString(); + usd.s_ram = system_map["ram"].AsInteger(); + + if (mmap["stats"].Type != OSDType.Map) + return new UserSession(); + + OSDMap stats_map = (OSDMap)mmap["stats"]; + { + + if (stats_map["failures"].Type != OSDType.Map) + return new UserSession(); + OSDMap stats_failures = (OSDMap)stats_map["failures"]; + usd.f_dropped = stats_failures["dropped"].AsInteger(); + usd.f_failed_resends = stats_failures["failed_resends"].AsInteger(); + usd.f_invalid = stats_failures["invalid"].AsInteger(); + usd.f_resent = stats_failures["resent"].AsInteger(); + usd.f_send_packet = stats_failures["send_packet"].AsInteger(); + + if (stats_map["net"].Type != OSDType.Map) + return new UserSession(); + OSDMap stats_net = (OSDMap)stats_map["net"]; + { + if (stats_net["in"].Type != OSDType.Map) + return new UserSession(); + + OSDMap net_in = (OSDMap)stats_net["in"]; + usd.n_in_kb = (float)net_in["kbytes"].AsReal(); + usd.n_in_pk = net_in["packets"].AsInteger(); + + if (stats_net["out"].Type != OSDType.Map) + return new UserSession(); + OSDMap net_out = (OSDMap)stats_net["out"]; + + usd.n_out_kb = (float)net_out["kbytes"].AsReal(); + usd.n_out_pk = net_out["packets"].AsInteger(); + } + } + } + + uid.session_data = usd; + m_sessions[agentID] = uid; + +// m_log.DebugFormat( +// "[WEB STATS MODULE]: Parse data for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id); + + return uid; + } + + private void UpdateUserStats(UserSession uid, SqliteConnection db) + { +// m_log.DebugFormat( +// "[WEB STATS MODULE]: Updating user stats for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id); + + if (uid.session_id == UUID.Zero) + return; + + lock (db) + { + using (SqliteCommand updatecmd = new SqliteCommand(SQL_STATS_TABLE_INSERT, db)) + { + updatecmd.Parameters.Add(new SqliteParameter(":session_id", uid.session_data.session_id.ToString())); + updatecmd.Parameters.Add(new SqliteParameter(":agent_id", uid.session_data.agent_id.ToString())); + updatecmd.Parameters.Add(new SqliteParameter(":region_id", uid.session_data.region_id.ToString())); + updatecmd.Parameters.Add(new SqliteParameter(":last_updated", (int) uid.session_data.last_updated)); + updatecmd.Parameters.Add(new SqliteParameter(":remote_ip", uid.session_data.remote_ip)); + updatecmd.Parameters.Add(new SqliteParameter(":name_f", uid.session_data.name_f)); + updatecmd.Parameters.Add(new SqliteParameter(":name_l", uid.session_data.name_l)); + updatecmd.Parameters.Add(new SqliteParameter(":avg_agents_in_view", uid.session_data.avg_agents_in_view)); + updatecmd.Parameters.Add(new SqliteParameter(":min_agents_in_view", + (int) uid.session_data.min_agents_in_view)); + updatecmd.Parameters.Add(new SqliteParameter(":max_agents_in_view", + (int) uid.session_data.max_agents_in_view)); + updatecmd.Parameters.Add(new SqliteParameter(":mode_agents_in_view", + (int) uid.session_data.mode_agents_in_view)); + updatecmd.Parameters.Add(new SqliteParameter(":avg_fps", uid.session_data.avg_fps)); + updatecmd.Parameters.Add(new SqliteParameter(":min_fps", uid.session_data.min_fps)); + updatecmd.Parameters.Add(new SqliteParameter(":max_fps", uid.session_data.max_fps)); + updatecmd.Parameters.Add(new SqliteParameter(":mode_fps", uid.session_data.mode_fps)); + updatecmd.Parameters.Add(new SqliteParameter(":a_language", uid.session_data.a_language)); + updatecmd.Parameters.Add(new SqliteParameter(":mem_use", uid.session_data.mem_use)); + updatecmd.Parameters.Add(new SqliteParameter(":meters_traveled", uid.session_data.meters_traveled)); + updatecmd.Parameters.Add(new SqliteParameter(":avg_ping", uid.session_data.avg_ping)); + updatecmd.Parameters.Add(new SqliteParameter(":min_ping", uid.session_data.min_ping)); + updatecmd.Parameters.Add(new SqliteParameter(":max_ping", uid.session_data.max_ping)); + updatecmd.Parameters.Add(new SqliteParameter(":mode_ping", uid.session_data.mode_ping)); + updatecmd.Parameters.Add(new SqliteParameter(":regions_visited", uid.session_data.regions_visited)); + updatecmd.Parameters.Add(new SqliteParameter(":run_time", uid.session_data.run_time)); + updatecmd.Parameters.Add(new SqliteParameter(":avg_sim_fps", uid.session_data.avg_sim_fps)); + updatecmd.Parameters.Add(new SqliteParameter(":min_sim_fps", uid.session_data.min_sim_fps)); + updatecmd.Parameters.Add(new SqliteParameter(":max_sim_fps", uid.session_data.max_sim_fps)); + updatecmd.Parameters.Add(new SqliteParameter(":mode_sim_fps", uid.session_data.mode_sim_fps)); + updatecmd.Parameters.Add(new SqliteParameter(":start_time", uid.session_data.start_time)); + updatecmd.Parameters.Add(new SqliteParameter(":client_version", uid.session_data.client_version)); + updatecmd.Parameters.Add(new SqliteParameter(":s_cpu", uid.session_data.s_cpu)); + updatecmd.Parameters.Add(new SqliteParameter(":s_gpu", uid.session_data.s_gpu)); + updatecmd.Parameters.Add(new SqliteParameter(":s_os", uid.session_data.s_os)); + updatecmd.Parameters.Add(new SqliteParameter(":s_ram", uid.session_data.s_ram)); + updatecmd.Parameters.Add(new SqliteParameter(":d_object_kb", uid.session_data.d_object_kb)); + updatecmd.Parameters.Add(new SqliteParameter(":d_texture_kb", uid.session_data.d_texture_kb)); + updatecmd.Parameters.Add(new SqliteParameter(":d_world_kb", uid.session_data.d_world_kb)); + updatecmd.Parameters.Add(new SqliteParameter(":n_in_kb", uid.session_data.n_in_kb)); + updatecmd.Parameters.Add(new SqliteParameter(":n_in_pk", uid.session_data.n_in_pk)); + updatecmd.Parameters.Add(new SqliteParameter(":n_out_kb", uid.session_data.n_out_kb)); + updatecmd.Parameters.Add(new SqliteParameter(":n_out_pk", uid.session_data.n_out_pk)); + updatecmd.Parameters.Add(new SqliteParameter(":f_dropped", uid.session_data.f_dropped)); + updatecmd.Parameters.Add(new SqliteParameter(":f_failed_resends", uid.session_data.f_failed_resends)); + updatecmd.Parameters.Add(new SqliteParameter(":f_invalid", uid.session_data.f_invalid)); + updatecmd.Parameters.Add(new SqliteParameter(":f_off_circuit", uid.session_data.f_off_circuit)); + updatecmd.Parameters.Add(new SqliteParameter(":f_resent", uid.session_data.f_resent)); + updatecmd.Parameters.Add(new SqliteParameter(":f_send_packet", uid.session_data.f_send_packet)); + +// StringBuilder parameters = new StringBuilder(); +// SqliteParameterCollection spc = updatecmd.Parameters; +// foreach (SqliteParameter sp in spc) +// parameters.AppendFormat("{0}={1},", sp.ParameterName, sp.Value); +// +// m_log.DebugFormat("[WEB STATS MODULE]: Parameters {0}", parameters); + +// m_log.DebugFormat("[WEB STATS MODULE]: Database stats update for {0}", uid.session_data.agent_id); + + updatecmd.ExecuteNonQuery(); + } + } + } + + #region SQL + private const string SQL_STATS_TABLE_CREATE = @"CREATE TABLE IF NOT EXISTS stats_session_data ( + session_id VARCHAR(36) NOT NULL PRIMARY KEY, + agent_id VARCHAR(36) NOT NULL DEFAULT '', + region_id VARCHAR(36) NOT NULL DEFAULT '', + last_updated INT NOT NULL DEFAULT '0', + remote_ip VARCHAR(16) NOT NULL DEFAULT '', + name_f VARCHAR(50) NOT NULL DEFAULT '', + name_l VARCHAR(50) NOT NULL DEFAULT '', + avg_agents_in_view FLOAT NOT NULL DEFAULT '0', + min_agents_in_view INT NOT NULL DEFAULT '0', + max_agents_in_view INT NOT NULL DEFAULT '0', + mode_agents_in_view INT NOT NULL DEFAULT '0', + avg_fps FLOAT NOT NULL DEFAULT '0', + min_fps FLOAT NOT NULL DEFAULT '0', + max_fps FLOAT NOT NULL DEFAULT '0', + mode_fps FLOAT NOT NULL DEFAULT '0', + a_language VARCHAR(25) NOT NULL DEFAULT '', + mem_use FLOAT NOT NULL DEFAULT '0', + meters_traveled FLOAT NOT NULL DEFAULT '0', + avg_ping FLOAT NOT NULL DEFAULT '0', + min_ping FLOAT NOT NULL DEFAULT '0', + max_ping FLOAT NOT NULL DEFAULT '0', + mode_ping FLOAT NOT NULL DEFAULT '0', + regions_visited INT NOT NULL DEFAULT '0', + run_time FLOAT NOT NULL DEFAULT '0', + avg_sim_fps FLOAT NOT NULL DEFAULT '0', + min_sim_fps FLOAT NOT NULL DEFAULT '0', + max_sim_fps FLOAT NOT NULL DEFAULT '0', + mode_sim_fps FLOAT NOT NULL DEFAULT '0', + start_time FLOAT NOT NULL DEFAULT '0', + client_version VARCHAR(255) NOT NULL DEFAULT '', + s_cpu VARCHAR(255) NOT NULL DEFAULT '', + s_gpu VARCHAR(255) NOT NULL DEFAULT '', + s_os VARCHAR(2255) NOT NULL DEFAULT '', + s_ram INT NOT NULL DEFAULT '0', + d_object_kb FLOAT NOT NULL DEFAULT '0', + d_texture_kb FLOAT NOT NULL DEFAULT '0', + d_world_kb FLOAT NOT NULL DEFAULT '0', + n_in_kb FLOAT NOT NULL DEFAULT '0', + n_in_pk INT NOT NULL DEFAULT '0', + n_out_kb FLOAT NOT NULL DEFAULT '0', + n_out_pk INT NOT NULL DEFAULT '0', + f_dropped INT NOT NULL DEFAULT '0', + f_failed_resends INT NOT NULL DEFAULT '0', + f_invalid INT NOT NULL DEFAULT '0', + f_off_circuit INT NOT NULL DEFAULT '0', + f_resent INT NOT NULL DEFAULT '0', + f_send_packet INT NOT NULL DEFAULT '0' + );"; + + private const string SQL_STATS_TABLE_INSERT = @"INSERT OR REPLACE INTO stats_session_data ( +session_id, agent_id, region_id, last_updated, remote_ip, name_f, name_l, avg_agents_in_view, min_agents_in_view, max_agents_in_view, +mode_agents_in_view, avg_fps, min_fps, max_fps, mode_fps, a_language, mem_use, meters_traveled, avg_ping, min_ping, max_ping, mode_ping, +regions_visited, run_time, avg_sim_fps, min_sim_fps, max_sim_fps, mode_sim_fps, start_time, client_version, s_cpu, s_gpu, s_os, s_ram, +d_object_kb, d_texture_kb, d_world_kb, n_in_kb, n_in_pk, n_out_kb, n_out_pk, f_dropped, f_failed_resends, f_invalid, f_off_circuit, +f_resent, f_send_packet +) +VALUES +( +:session_id, :agent_id, :region_id, :last_updated, :remote_ip, :name_f, :name_l, :avg_agents_in_view, :min_agents_in_view, :max_agents_in_view, +:mode_agents_in_view, :avg_fps, :min_fps, :max_fps, :mode_fps, :a_language, :mem_use, :meters_traveled, :avg_ping, :min_ping, :max_ping, :mode_ping, +:regions_visited, :run_time, :avg_sim_fps, :min_sim_fps, :max_sim_fps, :mode_sim_fps, :start_time, :client_version, :s_cpu, :s_gpu, :s_os, :s_ram, +:d_object_kb, :d_texture_kb, :d_world_kb, :n_in_kb, :n_in_pk, :n_out_kb, :n_out_pk, :f_dropped, :f_failed_resends, :f_invalid, :f_off_circuit, +:f_resent, :f_send_packet +) +"; + + #endregion + + } + + public static class UserSessionUtil + { + public static UserSessionData newUserSessionData() + { + UserSessionData obj = ZeroSession(new UserSessionData()); + return obj; + } + + public static void UpdateMultiItems(ref UserSessionData s, int agents_in_view, float ping, float sim_fps, float fps) + { + // don't insert zero values here or it'll skew the statistics. + if (agents_in_view == 0 && fps == 0 && sim_fps == 0 && ping == 0) + return; + s._agents_in_view.Add(agents_in_view); + s._fps.Add(fps); + s._sim_fps.Add(sim_fps); + s._ping.Add(ping); + + int[] __agents_in_view = s._agents_in_view.ToArray(); + + s.avg_agents_in_view = ArrayAvg_i(__agents_in_view); + s.min_agents_in_view = ArrayMin_i(__agents_in_view); + s.max_agents_in_view = ArrayMax_i(__agents_in_view); + s.mode_agents_in_view = ArrayMode_i(__agents_in_view); + + float[] __fps = s._fps.ToArray(); + s.avg_fps = ArrayAvg_f(__fps); + s.min_fps = ArrayMin_f(__fps); + s.max_fps = ArrayMax_f(__fps); + s.mode_fps = ArrayMode_f(__fps); + + float[] __sim_fps = s._sim_fps.ToArray(); + s.avg_sim_fps = ArrayAvg_f(__sim_fps); + s.min_sim_fps = ArrayMin_f(__sim_fps); + s.max_sim_fps = ArrayMax_f(__sim_fps); + s.mode_sim_fps = ArrayMode_f(__sim_fps); + + float[] __ping = s._ping.ToArray(); + s.avg_ping = ArrayAvg_f(__ping); + s.min_ping = ArrayMin_f(__ping); + s.max_ping = ArrayMax_f(__ping); + s.mode_ping = ArrayMode_f(__ping); + } + + #region Statistics + + public static int ArrayMin_i(int[] arr) + { + int cnt = arr.Length; + if (cnt == 0) + return 0; + + Array.Sort(arr); + return arr[0]; + } + + public static int ArrayMax_i(int[] arr) + { + int cnt = arr.Length; + if (cnt == 0) + return 0; + + Array.Sort(arr); + return arr[cnt-1]; + } + + public static float ArrayMin_f(float[] arr) + { + int cnt = arr.Length; + if (cnt == 0) + return 0; + + Array.Sort(arr); + return arr[0]; + } + + public static float ArrayMax_f(float[] arr) + { + int cnt = arr.Length; + if (cnt == 0) + return 0; + + Array.Sort(arr); + return arr[cnt - 1]; + } + + public static float ArrayAvg_i(int[] arr) + { + int cnt = arr.Length; + + if (cnt == 0) + return 0; + + float result = arr[0]; + + for (int i = 1; i < cnt; i++) + result += arr[i]; + + return result / cnt; + } + + public static float ArrayAvg_f(float[] arr) + { + int cnt = arr.Length; + + if (cnt == 0) + return 0; + + float result = arr[0]; + + for (int i = 1; i < cnt; i++) + result += arr[i]; + + return result / cnt; + } + + public static float ArrayMode_f(float[] arr) + { + List mode = new List(); + + float[] srtArr = new float[arr.Length]; + float[,] freq = new float[arr.Length, 2]; + Array.Copy(arr, srtArr, arr.Length); + Array.Sort(srtArr); + + float tmp = srtArr[0]; + int index = 0; + int i = 0; + while (i < srtArr.Length) + { + freq[index, 0] = tmp; + + while (tmp == srtArr[i]) + { + freq[index, 1]++; + i++; + + if (i > srtArr.Length - 1) + break; + } + + if (i < srtArr.Length) + { + tmp = srtArr[i]; + index++; + } + + } + + Array.Clear(srtArr, 0, srtArr.Length); + + for (i = 0; i < srtArr.Length; i++) + srtArr[i] = freq[i, 1]; + + Array.Sort(srtArr); + + if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1) + return 0; + + float freqtest = (float)freq.Length / freq.Rank; + + for (i = 0; i < freqtest; i++) + { + if (freq[i, 1] == srtArr[index]) + mode.Add(freq[i, 0]); + + } + + return mode.ToArray()[0]; + } + + public static int ArrayMode_i(int[] arr) + { + List mode = new List(); + + int[] srtArr = new int[arr.Length]; + int[,] freq = new int[arr.Length, 2]; + Array.Copy(arr, srtArr, arr.Length); + Array.Sort(srtArr); + + int tmp = srtArr[0]; + int index = 0; + int i = 0; + while (i < srtArr.Length) + { + freq[index, 0] = tmp; + + while (tmp == srtArr[i]) + { + freq[index, 1]++; + i++; + + if (i > srtArr.Length - 1) + break; + } + + if (i < srtArr.Length) + { + tmp = srtArr[i]; + index++; + } + + } + + Array.Clear(srtArr, 0, srtArr.Length); + + for (i = 0; i < srtArr.Length; i++) + srtArr[i] = freq[i, 1]; + + Array.Sort(srtArr); + + if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1) + return 0; + + float freqtest = (float)freq.Length / freq.Rank; + + for (i = 0; i < freqtest; i++) + { + if (freq[i, 1] == srtArr[index]) + mode.Add(freq[i, 0]); + + } + + return mode.ToArray()[0]; + } + + #endregion + + private static UserSessionData ZeroSession(UserSessionData s) + { + s.session_id = UUID.Zero; + s.agent_id = UUID.Zero; + s.region_id = UUID.Zero; + s.last_updated = Util.UnixTimeSinceEpoch(); + s.remote_ip = ""; + s.name_f = ""; + s.name_l = ""; + s.avg_agents_in_view = 0; + s.min_agents_in_view = 0; + s.max_agents_in_view = 0; + s.mode_agents_in_view = 0; + s.avg_fps = 0; + s.min_fps = 0; + s.max_fps = 0; + s.mode_fps = 0; + s.a_language = ""; + s.mem_use = 0; + s.meters_traveled = 0; + s.avg_ping = 0; + s.min_ping = 0; + s.max_ping = 0; + s.mode_ping = 0; + s.regions_visited = 0; + s.run_time = 0; + s.avg_sim_fps = 0; + s.min_sim_fps = 0; + s.max_sim_fps = 0; + s.mode_sim_fps = 0; + s.start_time = 0; + s.client_version = ""; + s.s_cpu = ""; + s.s_gpu = ""; + s.s_os = ""; + s.s_ram = 0; + s.d_object_kb = 0; + s.d_texture_kb = 0; + s.d_world_kb = 0; + s.n_in_kb = 0; + s.n_in_pk = 0; + s.n_out_kb = 0; + s.n_out_pk = 0; + s.f_dropped = 0; + s.f_failed_resends = 0; + s.f_invalid = 0; + s.f_off_circuit = 0; + s.f_resent = 0; + s.f_send_packet = 0; + s._ping = new List(); + s._fps = new List(); + s._sim_fps = new List(); + s._agents_in_view = new List(); + return s; + } + } + #region structs + + public class UserSession + { + public UUID session_id; + public UUID region_id; + public string name_f; + public string name_l; + public UserSessionData session_data; + } + + public struct UserSessionData + { + public UUID session_id; + public UUID agent_id; + public UUID region_id; + public float last_updated; + public string remote_ip; + public string name_f; + public string name_l; + public float avg_agents_in_view; + public float min_agents_in_view; + public float max_agents_in_view; + public float mode_agents_in_view; + public float avg_fps; + public float min_fps; + public float max_fps; + public float mode_fps; + public string a_language; + public float mem_use; + public float meters_traveled; + public float avg_ping; + public float min_ping; + public float max_ping; + public float mode_ping; + public int regions_visited; + public float run_time; + public float avg_sim_fps; + public float min_sim_fps; + public float max_sim_fps; + public float mode_sim_fps; + public float start_time; + public string client_version; + public string s_cpu; + public string s_gpu; + public string s_os; + public int s_ram; + public float d_object_kb; + public float d_texture_kb; + public float d_world_kb; + public float n_in_kb; + public int n_in_pk; + public float n_out_kb; + public int n_out_pk; + public int f_dropped; + public int f_failed_resends; + public int f_invalid; + public int f_off_circuit; + public int f_resent; + public int f_send_packet; + public List _ping; + public List _fps; + public List _sim_fps; + public List _agents_in_view; + } + + #endregion + + public class USimStatsData + { + private UUID m_regionID = UUID.Zero; + private volatile int m_statcounter = 0; + private volatile float m_timeDilation; + private volatile float m_simFps; + private volatile float m_physicsFps; + private volatile float m_agentUpdates; + private volatile float m_rootAgents; + private volatile float m_childAgents; + private volatile float m_totalPrims; + private volatile float m_activePrims; + private volatile float m_totalFrameTime; + private volatile float m_netFrameTime; + private volatile float m_physicsFrameTime; + private volatile float m_otherFrameTime; + private volatile float m_imageFrameTime; + private volatile float m_inPacketsPerSecond; + private volatile float m_outPacketsPerSecond; + private volatile float m_unackedBytes; + private volatile float m_agentFrameTime; + private volatile float m_pendingDownloads; + private volatile float m_pendingUploads; + private volatile float m_activeScripts; + private volatile float m_scriptLinesPerSecond; + + public UUID RegionId { get { return m_regionID; } } + public int StatsCounter { get { return m_statcounter; } set { m_statcounter = value;}} + public float TimeDilation { get { return m_timeDilation; } } + public float SimFps { get { return m_simFps; } } + public float PhysicsFps { get { return m_physicsFps; } } + public float AgentUpdates { get { return m_agentUpdates; } } + public float RootAgents { get { return m_rootAgents; } } + public float ChildAgents { get { return m_childAgents; } } + public float TotalPrims { get { return m_totalPrims; } } + public float ActivePrims { get { return m_activePrims; } } + public float TotalFrameTime { get { return m_totalFrameTime; } } + public float NetFrameTime { get { return m_netFrameTime; } } + public float PhysicsFrameTime { get { return m_physicsFrameTime; } } + public float OtherFrameTime { get { return m_otherFrameTime; } } + public float ImageFrameTime { get { return m_imageFrameTime; } } + public float InPacketsPerSecond { get { return m_inPacketsPerSecond; } } + public float OutPacketsPerSecond { get { return m_outPacketsPerSecond; } } + public float UnackedBytes { get { return m_unackedBytes; } } + public float AgentFrameTime { get { return m_agentFrameTime; } } + public float PendingDownloads { get { return m_pendingDownloads; } } + public float PendingUploads { get { return m_pendingUploads; } } + public float ActiveScripts { get { return m_activeScripts; } } + public float ScriptLinesPerSecond { get { return m_scriptLinesPerSecond; } } + + public USimStatsData(UUID pRegionID) + { + m_regionID = pRegionID; + } + + public void ConsumeSimStats(SimStats stats) + { + m_regionID = stats.RegionUUID; + m_timeDilation = stats.StatsBlock[0].StatValue; + m_simFps = stats.StatsBlock[1].StatValue; + m_physicsFps = stats.StatsBlock[2].StatValue; + m_agentUpdates = stats.StatsBlock[3].StatValue; + m_rootAgents = stats.StatsBlock[4].StatValue; + m_childAgents = stats.StatsBlock[5].StatValue; + m_totalPrims = stats.StatsBlock[6].StatValue; + m_activePrims = stats.StatsBlock[7].StatValue; + m_totalFrameTime = stats.StatsBlock[8].StatValue; + m_netFrameTime = stats.StatsBlock[9].StatValue; + m_physicsFrameTime = stats.StatsBlock[10].StatValue; + m_otherFrameTime = stats.StatsBlock[11].StatValue; + m_imageFrameTime = stats.StatsBlock[12].StatValue; + m_inPacketsPerSecond = stats.StatsBlock[13].StatValue; + m_outPacketsPerSecond = stats.StatsBlock[14].StatValue; + m_unackedBytes = stats.StatsBlock[15].StatValue; + m_agentFrameTime = stats.StatsBlock[16].StatValue; + m_pendingDownloads = stats.StatsBlock[17].StatValue; + m_pendingUploads = stats.StatsBlock[18].StatValue; + m_activeScripts = stats.StatsBlock[19].StatValue; + m_scriptLinesPerSecond = stats.StatsBlock[20].StatValue; + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/CameraOnlyModeModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/CameraOnlyModeModule.cs new file mode 100644 index 0000000..7ae4223 --- /dev/null +++ b/OpenSim/Region/OptionalModules/ViewerSupport/CameraOnlyModeModule.cs @@ -0,0 +1,176 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Reflection; +using System.Text; +using System.Collections.Generic; +using System.Threading; + +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim; +using OpenSim.Region; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Framework; +//using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using Nini.Config; +using log4net; +using Mono.Addins; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; +using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags; + +namespace OpenSim.Region.OptionalModules.ViewerSupport +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CameraOnlyMode")] + public class CameraOnlyModeModule : INonSharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Scene m_scene; + private SimulatorFeaturesHelper m_Helper; + private bool m_Enabled; + private int m_UserLevel; + + public string Name + { + get { return "CameraOnlyModeModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Initialise(IConfigSource config) + { + IConfig moduleConfig = config.Configs["CameraOnlyModeModule"]; + if (moduleConfig != null) + { + m_Enabled = moduleConfig.GetBoolean("enabled", false); + if (m_Enabled) + { + m_UserLevel = moduleConfig.GetInt("UserLevel", 0); + m_log.Info("[CAMERA-ONLY MODE]: CameraOnlyModeModule enabled"); + } + + } + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + if (m_Enabled) + { + m_scene = scene; + //m_scene.EventManager.OnMakeRootAgent += (OnMakeRootAgent); + } + } + + //private void OnMakeRootAgent(ScenePresence obj) + //{ + // throw new NotImplementedException(); + //} + + public void RegionLoaded(Scene scene) + { + if (m_Enabled) + { + IEntityTransferModule et = m_scene.RequestModuleInterface(); + m_Helper = new SimulatorFeaturesHelper(scene, et); + + ISimulatorFeaturesModule featuresModule = m_scene.RequestModuleInterface(); + if (featuresModule != null) + featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest; + } + } + + public void RemoveRegion(Scene scene) + { + } + + private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features) + { + m_log.DebugFormat("[CAMERA-ONLY MODE]: OnSimulatorFeaturesRequest in {0}", m_scene.RegionInfo.RegionName); + if (m_Helper.ShouldSend(agentID) && m_Helper.UserLevel(agentID) <= m_UserLevel) + { + OSDMap extrasMap; + if (features.ContainsKey("OpenSimExtras")) + { + extrasMap = (OSDMap)features["OpenSimExtras"]; + } + else + { + extrasMap = new OSDMap(); + features["OpenSimExtras"] = extrasMap; + } + extrasMap["camera-only-mode"] = OSDMap.FromString("true"); + m_log.DebugFormat("[CAMERA-ONLY MODE]: Sent in {0}", m_scene.RegionInfo.RegionName); + + // Detaching attachments doesn't work for HG visitors, + // so I'm giving that up. + //Util.FireAndForget(delegate { DetachAttachments(agentID); }); + } + else + m_log.DebugFormat("[CAMERA-ONLY MODE]: NOT Sending camera-only-mode in {0}", m_scene.RegionInfo.RegionName); + } + + private void DetachAttachments(UUID agentID) + { + ScenePresence sp = m_scene.GetScenePresence(agentID); + if ((sp.TeleportFlags & TeleportFlags.ViaLogin) != 0) + // Wait a little, cos there's weird stuff going on at login related to + // the Current Outfit Folder + Thread.Sleep(8000); + + if (sp != null && m_scene.AttachmentsModule != null) + { + List attachs = sp.GetAttachments(); + if (attachs != null && attachs.Count > 0) + { + foreach (SceneObjectGroup sog in attachs) + { + m_log.DebugFormat("[CAMERA-ONLY MODE]: Forcibly detaching attach {0} from {1} in {2}", + sog.Name, sp.Name, m_scene.RegionInfo.RegionName); + + m_scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, sog); + } + } + } + } + + } + +} diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/DynamicFloaterModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicFloaterModule.cs new file mode 100644 index 0000000..e76e8f2 --- /dev/null +++ b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicFloaterModule.cs @@ -0,0 +1,238 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Reflection; +using System.Text; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim; +using OpenSim.Region; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using Nini.Config; +using log4net; +using Mono.Addins; +using Caps = OpenSim.Framework.Capabilities.Caps; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; + +namespace OpenSim.Region.OptionalModules.ViewerSupport +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DynamicFloater")] + public class DynamicFloaterModule : INonSharedRegionModule, IDynamicFloaterModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Scene m_scene; + + private Dictionary> m_floaters = new Dictionary>(); + + public string Name + { + get { return "DynamicFloaterModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Initialise(IConfigSource config) + { + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + m_scene = scene; + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnClientClosed += OnClientClosed; + m_scene.RegisterModuleInterface(this); + } + + public void RegionLoaded(Scene scene) + { + } + + public void RemoveRegion(Scene scene) + { + } + + private void OnNewClient(IClientAPI client) + { + client.OnChatFromClient += OnChatFromClient; + } + + private void OnClientClosed(UUID agentID, Scene scene) + { + m_floaters.Remove(agentID); + } + + private void SendToClient(ScenePresence sp, string msg) + { + sp.ControllingClient.SendChatMessage(msg, + (byte)ChatTypeEnum.Owner, + sp.AbsolutePosition, + "Server", + UUID.Zero, + UUID.Zero, + (byte)ChatSourceType.Object, + (byte)ChatAudibleLevel.Fully); + } + + public void DoUserFloater(UUID agentID, FloaterData dialogData, string configuration) + { + ScenePresence sp = m_scene.GetScenePresence(agentID); + if (sp == null || sp.IsChildAgent) + return; + + if (!m_floaters.ContainsKey(agentID)) + m_floaters[agentID] = new Dictionary(); + + if (m_floaters[agentID].ContainsKey(dialogData.Channel)) + return; + + m_floaters[agentID].Add(dialogData.Channel, dialogData); + + string xml; + if (dialogData.XmlText != null && dialogData.XmlText != String.Empty) + { + xml = dialogData.XmlText; + } + else + { + using (FileStream fs = File.Open(dialogData.XmlName + ".xml", FileMode.Open)) + { + using (StreamReader sr = new StreamReader(fs)) + xml = sr.ReadToEnd().Replace("\n", ""); + } + } + + List xparts = new List(); + + while (xml.Length > 0) + { + string x = xml; + if (x.Length > 600) + { + x = x.Substring(0, 600); + xml = xml.Substring(600); + } + else + { + xml = String.Empty; + } + + xparts.Add(x); + } + + for (int i = 0 ; i < xparts.Count ; i++) + SendToClient(sp, String.Format("># floater {2} create {0}/{1} " + xparts[i], i + 1, xparts.Count, dialogData.FloaterName)); + + 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)); + } + + private void OnChatFromClient(object sender, OSChatMessage msg) + { + if (msg.Sender == null) + return; + + //m_log.DebugFormat("chan {0} msg {1}", msg.Channel, msg.Message); + + IClientAPI client = msg.Sender; + + if (!m_floaters.ContainsKey(client.AgentId)) + return; + + string[] parts = msg.Message.Split(new char[] {':'}); + if (parts.Length == 0) + return; + + ScenePresence sp = m_scene.GetScenePresence(client.AgentId); + if (sp == null || sp.IsChildAgent) + return; + + Dictionary d = m_floaters[client.AgentId]; + + // Work around a viewer bug - VALUE from any + // dialog can appear on this channel and needs to + // be dispatched to ALL open dialogs for the user + if (msg.Channel == 427169570) + { + if (parts[0] == "VALUE") + { + foreach (FloaterData dd in d.Values) + { + if(dd.Handler(client, dd, parts)) + { + m_floaters[client.AgentId].Remove(dd.Channel); + SendToClient(sp, String.Format("># floater {0} destroy", dd.FloaterName)); + break; + } + } + } + return; + } + + if (!d.ContainsKey(msg.Channel)) + return; + + FloaterData data = d[msg.Channel]; + + if (parts[0] == "NOTIFY") + { + if (parts[1] == "cancel" || parts[1] == data.FloaterName) + { + m_floaters[client.AgentId].Remove(data.Channel); + SendToClient(sp, String.Format("># floater {0} destroy", data.FloaterName)); + } + } + + if (data.Handler != null && data.Handler(client, data, parts)) + { + m_floaters[client.AgentId].Remove(data.Channel); + SendToClient(sp, String.Format("># floater {0} destroy", data.FloaterName)); + } + } + + public void FloaterControl(ScenePresence sp, FloaterData d, string msg) + { + string sendData = String.Format("># floater {0} {1}", d.FloaterName, msg); + SendToClient(sp, sendData); + + } + } +} diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs new file mode 100644 index 0000000..d37369c --- /dev/null +++ b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs @@ -0,0 +1,304 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Reflection; +using System.Text; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim; +using OpenSim.Region; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Framework; +//using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using Nini.Config; +using log4net; +using Mono.Addins; +using Caps = OpenSim.Framework.Capabilities.Caps; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; + +namespace OpenSim.Region.OptionalModules.ViewerSupport +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DynamicMenu")] + public class DynamicMenuModule : INonSharedRegionModule, IDynamicMenuModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private class MenuItemData + { + public string Title; + public UUID AgentID; + public InsertLocation Location; + public UserMode Mode; + public CustomMenuHandler Handler; + } + + private Dictionary> m_menuItems = + new Dictionary>(); + + private Scene m_scene; + + public string Name + { + get { return "DynamicMenuModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Initialise(IConfigSource config) + { + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + m_scene = scene; + scene.EventManager.OnRegisterCaps += OnRegisterCaps; + m_scene.RegisterModuleInterface(this); + } + + public void RegionLoaded(Scene scene) + { + ISimulatorFeaturesModule featuresModule = m_scene.RequestModuleInterface(); + + if (featuresModule != null) + featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest; + } + + public void RemoveRegion(Scene scene) + { + } + + private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features) + { + OSD menus = new OSDMap(); + if (features.ContainsKey("menus")) + menus = features["menus"]; + + OSDMap agent = new OSDMap(); + OSDMap world = new OSDMap(); + OSDMap tools = new OSDMap(); + OSDMap advanced = new OSDMap(); + OSDMap admin = new OSDMap(); + if (((OSDMap)menus).ContainsKey("agent")) + agent = (OSDMap)((OSDMap)menus)["agent"]; + if (((OSDMap)menus).ContainsKey("world")) + world = (OSDMap)((OSDMap)menus)["world"]; + if (((OSDMap)menus).ContainsKey("tools")) + tools = (OSDMap)((OSDMap)menus)["tools"]; + if (((OSDMap)menus).ContainsKey("advanced")) + advanced = (OSDMap)((OSDMap)menus)["advanced"]; + if (((OSDMap)menus).ContainsKey("admin")) + admin = (OSDMap)((OSDMap)menus)["admin"]; + + if (m_menuItems.ContainsKey(UUID.Zero)) + { + foreach (MenuItemData d in m_menuItems[UUID.Zero]) + { + if (d.Mode == UserMode.God && (!m_scene.Permissions.IsGod(agentID))) + continue; + + OSDMap loc = null; + switch (d.Location) + { + case InsertLocation.Agent: + loc = agent; + break; + case InsertLocation.World: + loc = world; + break; + case InsertLocation.Tools: + loc = tools; + break; + case InsertLocation.Advanced: + loc = advanced; + break; + case InsertLocation.Admin: + loc = admin; + break; + } + + if (loc == null) + continue; + + loc[d.Title] = OSD.FromString(d.Title); + } + } + + if (m_menuItems.ContainsKey(agentID)) + { + foreach (MenuItemData d in m_menuItems[agentID]) + { + if (d.Mode == UserMode.God && (!m_scene.Permissions.IsGod(agentID))) + continue; + + OSDMap loc = null; + switch (d.Location) + { + case InsertLocation.Agent: + loc = agent; + break; + case InsertLocation.World: + loc = world; + break; + case InsertLocation.Tools: + loc = tools; + break; + case InsertLocation.Advanced: + loc = advanced; + break; + case InsertLocation.Admin: + loc = admin; + break; + } + + if (loc == null) + continue; + + loc[d.Title] = OSD.FromString(d.Title); + } + } + + + ((OSDMap)menus)["agent"] = agent; + ((OSDMap)menus)["world"] = world; + ((OSDMap)menus)["tools"] = tools; + ((OSDMap)menus)["advanced"] = advanced; + ((OSDMap)menus)["admin"] = admin; + + features["menus"] = menus; + } + + private void OnRegisterCaps(UUID agentID, Caps caps) + { + string capUrl = "/CAPS/" + UUID.Random() + "/"; + + capUrl = "/CAPS/" + UUID.Random() + "/"; + caps.RegisterHandler("CustomMenuAction", new MenuActionHandler(capUrl, "CustomMenuAction", agentID, this, m_scene)); + } + + internal void HandleMenuSelection(string action, UUID agentID, List selection) + { + if (m_menuItems.ContainsKey(agentID)) + { + foreach (MenuItemData d in m_menuItems[agentID]) + { + if (d.Title == action) + d.Handler(action, agentID, selection); + } + } + + if (m_menuItems.ContainsKey(UUID.Zero)) + { + foreach (MenuItemData d in m_menuItems[UUID.Zero]) + { + if (d.Title == action) + d.Handler(action, agentID, selection); + } + } + } + + public void AddMenuItem(string title, InsertLocation location, UserMode mode, CustomMenuHandler handler) + { + AddMenuItem(UUID.Zero, title, location, mode, handler); + } + + public void AddMenuItem(UUID agentID, string title, InsertLocation location, UserMode mode, CustomMenuHandler handler) + { + if (!m_menuItems.ContainsKey(agentID)) + m_menuItems[agentID] = new List(); + + m_menuItems[agentID].Add(new MenuItemData() { Title = title, AgentID = agentID, Location = location, Mode = mode, Handler = handler }); + } + + public void RemoveMenuItem(string action) + { + foreach (KeyValuePair> kvp in m_menuItems) + { + List pendingDeletes = new List(); + foreach (MenuItemData d in kvp.Value) + { + if (d.Title == action) + pendingDeletes.Add(d); + } + + foreach (MenuItemData d in pendingDeletes) + kvp.Value.Remove(d); + } + } + } + + public class MenuActionHandler : BaseStreamHandler + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private UUID m_agentID; + private Scene m_scene; + private DynamicMenuModule m_module; + + public MenuActionHandler(string path, string name, UUID agentID, DynamicMenuModule module, Scene scene) + :base("POST", path, name, agentID.ToString()) + { + m_agentID = agentID; + m_scene = scene; + m_module = module; + } + + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + StreamReader reader = new StreamReader(request); + string requestBody = reader.ReadToEnd(); + + OSD osd = OSDParser.DeserializeLLSDXml(requestBody); + + string action = ((OSDMap)osd)["action"].AsString(); + OSDArray selection = (OSDArray)((OSDMap)osd)["selection"]; + List sel = new List(); + for (int i = 0 ; i < selection.Count ; i++) + sel.Add(selection[i].AsUInteger()); + + Util.FireAndForget( + x => { m_module.HandleMenuSelection(action, m_agentID, sel); }, null, "DynamicMenuModule.HandleMenuSelection"); + + Encoding encoding = Encoding.UTF8; + return encoding.GetBytes(OSDParser.SerializeLLSDXmlString(new OSD())); + } + } +} diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/GodNamesModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/GodNamesModule.cs new file mode 100644 index 0000000..e0537a4 --- /dev/null +++ b/OpenSim/Region/OptionalModules/ViewerSupport/GodNamesModule.cs @@ -0,0 +1,144 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.OptionalModules.ViewerSupport +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GodNamesModule")] + public class GodNamesModule : ISharedRegionModule + { + // Infrastructure + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // Configuration + private static bool m_enabled = false; + private static List m_lastNames = new List(); + private static List m_fullNames = new List(); + + public void Initialise(IConfigSource config) + { + IConfig moduleConfig = config.Configs["GodNames"]; + + if (moduleConfig == null) { + return; + } + + if (!moduleConfig.GetBoolean("Enabled", false)) { + m_log.Info("[GODNAMES]: Addon is disabled"); + return; + } + + m_log.Info("[GODNAMES]: Enabled"); + m_enabled = true; + string conf_str = moduleConfig.GetString("FullNames", String.Empty); + foreach (string strl in conf_str.Split(',')) { + string strlan = strl.Trim(" \t".ToCharArray()); + m_log.DebugFormat("[GODNAMES]: Adding {0} as a God name", strlan); + m_fullNames.Add(strlan); + } + + conf_str = moduleConfig.GetString("Surnames", String.Empty); + foreach (string strl in conf_str.Split(',')) { + string strlan = strl.Trim(" \t".ToCharArray()); + m_log.DebugFormat("[GODNAMES]: Adding {0} as a God last name", strlan); + m_lastNames.Add(strlan); + } + } + + public void AddRegion(Scene scene) { + /*no op*/ + } + + public void RemoveRegion(Scene scene) { + /*no op*/ + } + + public void PostInitialise() { + /*no op*/ + } + + public void Close() { + /*no op*/ + } + + public Type ReplaceableInterface { + get { return null; } + } + + public string Name { + get { return "Godnames"; } + } + + public bool IsSharedModule { + get { return true; } + } + + public virtual void RegionLoaded(Scene scene) + { + if (!m_enabled) + return; + + ISimulatorFeaturesModule featuresModule = scene.RequestModuleInterface(); + + if (featuresModule != null) + featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest; + + } + + private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features) + { + OSD namesmap = new OSDMap(); + if (features.ContainsKey("god_names")) + namesmap = features["god_names"]; + else + features["god_names"] = namesmap; + + OSDArray fnames = new OSDArray(); + foreach (string name in m_fullNames) { + fnames.Add(name); + } + ((OSDMap)namesmap)["full_names"] = fnames; + + OSDArray lnames = new OSDArray(); + foreach (string name in m_lastNames) { + lnames.Add(name); + } + ((OSDMap)namesmap)["last_names"] = lnames; + } + } +} diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/SimulatorFeaturesHelper.cs b/OpenSim/Region/OptionalModules/ViewerSupport/SimulatorFeaturesHelper.cs new file mode 100644 index 0000000..2661522 --- /dev/null +++ b/OpenSim/Region/OptionalModules/ViewerSupport/SimulatorFeaturesHelper.cs @@ -0,0 +1,171 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Reflection; +using System.Text; +using System.Collections.Generic; +using System.Threading; + +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim; +using OpenSim.Region; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +//using OpenSim.Framework.Capabilities; +using Nini.Config; +using log4net; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; +using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags; + +namespace OpenSim.Region.OptionalModules.ViewerSupport +{ + public class SimulatorFeaturesHelper + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IEntityTransferModule m_TransferModule; + private Scene m_scene; + + private struct RegionSend { + public UUID region; + public bool send; + }; + // Using a static cache so that we don't have to perform the time-consuming tests + // in ShouldSend on Extra SimFeatures that go on the same response but come from + // different modules. + // This cached is indexed on the agentID and maps to a list of regions + private static ExpiringCache> m_Cache = new ExpiringCache>(); + private const double TIMEOUT = 1.0; // time in cache + + public SimulatorFeaturesHelper(Scene scene, IEntityTransferModule et) + { + m_scene = scene; + m_TransferModule = et; + } + + public bool ShouldSend(UUID agentID) + { + List rsendlist; + RegionSend rsend; + if (m_Cache.TryGetValue(agentID, out rsendlist)) + { + rsend = rsendlist.Find(r => r.region == m_scene.RegionInfo.RegionID); + if (rsend.region != UUID.Zero) // Found it + { + return rsend.send; + } + } + + // Relatively complex logic for deciding whether to send the extra SimFeature or not. + // This is because the viewer calls this cap to all sims that it knows about, + // including the departing sims and non-neighbors (those that are cached). + rsend.region = m_scene.RegionInfo.RegionID; + rsend.send = false; + IClientAPI client = null; + int counter = 200; + + // Let's wait a little to see if we get a client here + while (!m_scene.TryGetClient(agentID, out client) && counter-- > 0) + Thread.Sleep(50); + + if (client != null) + { + ScenePresence sp = WaitGetScenePresence(agentID); + + if (sp != null) + { + // On the receiving region, the call to this cap may arrive before + // the agent is root. Make sure we only proceed from here when the agent + // has been made root + counter = 200; + while ((sp.IsInTransit || sp.IsChildAgent) && counter-- > 0) + { + Thread.Sleep(50); + } + + // The viewer calls this cap on the departing sims too. Make sure + // that we only proceed after the agent is not in transit anymore. + // The agent must be root and not going anywhere + if (!sp.IsChildAgent && !m_TransferModule.IsInTransit(agentID)) + rsend.send = true; + + } + } + //else + // m_log.DebugFormat("[XXX]: client is null"); + + + if (rsendlist == null) + { + rsendlist = new List(); + m_Cache.AddOrUpdate(agentID, rsendlist, TIMEOUT); + } + rsendlist.Add(rsend); + + return rsend.send; + } + + public int UserLevel(UUID agentID) + { + int level = 0; + UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, agentID); + if (account != null) + level = account.UserLevel; + + return level; + } + + protected virtual ScenePresence WaitGetScenePresence(UUID agentID) + { + int ntimes = 20; + ScenePresence sp = null; + while ((sp = m_scene.GetScenePresence(agentID)) == null && (ntimes-- > 0)) + Thread.Sleep(1000); + + if (sp == null) + m_log.WarnFormat( + "[XXX]: Did not find presence with id {0} in {1} before timeout", + agentID, m_scene.RegionInfo.RegionName); + else + { + ntimes = 10; + while (sp.IsInTransit && (ntimes-- > 0)) + Thread.Sleep(1000); + } + + return sp; + } + + } + +} diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/SpecialUIModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/SpecialUIModule.cs new file mode 100644 index 0000000..3fe922d --- /dev/null +++ b/OpenSim/Region/OptionalModules/ViewerSupport/SpecialUIModule.cs @@ -0,0 +1,165 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Reflection; +using System.Text; +using System.Collections.Generic; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim; +using OpenSim.Region; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Framework; +//using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using Nini.Config; +using log4net; +using Mono.Addins; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; +using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags; + +namespace OpenSim.Region.OptionalModules.ViewerSupport +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SpecialUI")] + public class SpecialUIModule : INonSharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private const string VIEWER_SUPPORT_DIR = "ViewerSupport"; + + private Scene m_scene; + private SimulatorFeaturesHelper m_Helper; + private bool m_Enabled; + private int m_UserLevel; + + public string Name + { + get { return "SpecialUIModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Initialise(IConfigSource config) + { + IConfig moduleConfig = config.Configs["SpecialUIModule"]; + if (moduleConfig != null) + { + m_Enabled = moduleConfig.GetBoolean("enabled", false); + if (m_Enabled) + { + m_UserLevel = moduleConfig.GetInt("UserLevel", 0); + m_log.Info("[SPECIAL UI]: SpecialUIModule enabled"); + } + + } + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + if (m_Enabled) + { + m_scene = scene; + } + } + + public void RegionLoaded(Scene scene) + { + if (m_Enabled) + { + IEntityTransferModule et = m_scene.RequestModuleInterface(); + m_Helper = new SimulatorFeaturesHelper(scene, et); + + ISimulatorFeaturesModule featuresModule = m_scene.RequestModuleInterface(); + if (featuresModule != null) + featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest; + } + } + + public void RemoveRegion(Scene scene) + { + } + + private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features) + { + m_log.DebugFormat("[SPECIAL UI]: OnSimulatorFeaturesRequest in {0}", m_scene.RegionInfo.RegionName); + if (m_Helper.ShouldSend(agentID) && m_Helper.UserLevel(agentID) <= m_UserLevel) + { + OSDMap extrasMap; + OSDMap specialUI = new OSDMap(); + using (StreamReader s = new StreamReader(Path.Combine(VIEWER_SUPPORT_DIR, "panel_toolbar.xml"))) + { + if (features.ContainsKey("OpenSimExtras")) + extrasMap = (OSDMap)features["OpenSimExtras"]; + else + { + extrasMap = new OSDMap(); + features["OpenSimExtras"] = extrasMap; + } + + specialUI["toolbar"] = OSDMap.FromString(s.ReadToEnd()); + extrasMap["special-ui"] = specialUI; + } + m_log.DebugFormat("[SPECIAL UI]: Sending panel_toolbar.xml in {0}", m_scene.RegionInfo.RegionName); + + if (Directory.Exists(Path.Combine(VIEWER_SUPPORT_DIR, "Floaters"))) + { + OSDMap floaters = new OSDMap(); + uint n = 0; + foreach (String name in Directory.GetFiles(Path.Combine(VIEWER_SUPPORT_DIR, "Floaters"), "*.xml")) + { + using (StreamReader s = new StreamReader(name)) + { + string simple_name = Path.GetFileNameWithoutExtension(name); + OSDMap floater = new OSDMap(); + floaters[simple_name] = OSDMap.FromString(s.ReadToEnd()); + n++; + } + } + specialUI["floaters"] = floaters; + m_log.DebugFormat("[SPECIAL UI]: Sending {0} floaters", n); + } + } + else + m_log.DebugFormat("[SPECIAL UI]: NOT Sending panel_toolbar.xml in {0}", m_scene.RegionInfo.RegionName); + + } + + } + +} diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs index 1d35c54..ceb3332 100644 --- a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs +++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs @@ -76,6 +76,10 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup /// AutoBackupBusyCheck: True/False. Default: True. /// If True, we will only take an auto-backup if a set of conditions are met. /// These conditions are heuristics to try and avoid taking a backup when the sim is busy. + /// AutoBackupSkipAssets + /// If true, assets are not saved to the oar file. Considerably reduces impact on simulator when backing up. Intended for when assets db is backed up separately + /// AutoBackupKeepFilesForDays + /// Backup files older than this value (in days) are deleted during the current backup process, 0 will disable this and keep all backup files indefinitely /// AutoBackupScript: String. Default: not specified (disabled). /// File path to an executable script or binary to run when an automatic backup is taken. /// The file should really be (Windows) an .exe or .bat, or (Linux/Mac) a shell script or binary. @@ -111,6 +115,9 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup private delegate T DefaultGetter(string settingName, T defaultValue); private bool m_enabled; + private ICommandConsole m_console; + private List m_Scenes = new List (); + /// /// Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState! @@ -202,8 +209,20 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup /// Currently a no-op for AutoBackup because we have to wait for region to be fully loaded. /// /// - void IRegionModuleBase.AddRegion(Scene scene) + void IRegionModuleBase.AddRegion (Scene scene) { + if (!this.m_enabled) { + return; + } + lock (m_Scenes) { + m_Scenes.Add (scene); + } + m_console = MainConsole.Instance; + + m_console.Commands.AddCommand ( + "AutoBackup", false, "dobackup", + "dobackup", + "do backup.", DoBackup); } /// @@ -216,7 +235,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup { return; } - + m_Scenes.Remove (scene); if (this.m_states.ContainsKey(scene)) { AutoBackupModuleState abms = this.m_states[scene]; @@ -258,6 +277,8 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup AutoBackupModuleState abms = this.ParseConfig(scene, false); m_log.Debug("[AUTO BACKUP]: Config for " + scene.RegionInfo.RegionName); m_log.Debug((abms == null ? "DEFAULT" : abms.ToString())); + + m_states.Add(scene, abms); } /// @@ -269,6 +290,28 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup #endregion + private void DoBackup (string module, string[] args) + { + if (args.Length != 2) { + MainConsole.Instance.OutputFormat ("Usage: dobackup "); + return; + } + bool found = false; + string name = args [1]; + lock (m_Scenes) { + foreach (Scene s in m_Scenes) { + string test = s.Name.ToString (); + if (test == name) { + found = true; + DoRegionBackup (s); + } + } + if (!found) { + MainConsole.Instance.OutputFormat ("No such region {0}. Nothing to backup", name); + } + } + } + /// /// Set up internal state for a given scene. Fairly complex code. /// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene. @@ -334,7 +377,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup double interval = this.ResolveDouble("AutoBackupInterval", this.m_defaultState.IntervalMinutes, config, regionConfig) * 60000.0; - if (state == null && interval != this.m_defaultState.IntervalMinutes*60000.0) + if (state == null && interval != this.m_defaultState.IntervalMinutes * 60000.0) { state = new AutoBackupModuleState(); } @@ -412,6 +455,32 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup state.BusyCheck = tmpBusyCheck; } + // Included Option To Skip Assets + bool tmpSkipAssets = ResolveBoolean("AutoBackupSkipAssets", + this.m_defaultState.SkipAssets, config, regionConfig); + if (state == null && tmpSkipAssets != this.m_defaultState.SkipAssets) + { + state = new AutoBackupModuleState(); + } + + if (state != null) + { + state.SkipAssets = tmpSkipAssets; + } + + // How long to keep backup files in days, 0 Disables this feature + int tmpKeepFilesForDays = ResolveInt("AutoBackupKeepFilesForDays", + this.m_defaultState.KeepFilesForDays, config, regionConfig); + if (state == null && tmpKeepFilesForDays != this.m_defaultState.KeepFilesForDays) + { + state = new AutoBackupModuleState(); + } + + if (state != null) + { + state.KeepFilesForDays = tmpKeepFilesForDays; + } + // Set file naming algorithm string stmpNamingType = ResolveString("AutoBackupNaming", this.m_defaultState.NamingType.ToString(), config, regionConfig); @@ -480,7 +549,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup catch (Exception e) { m_log.Warn( - "BAD NEWS. You won't be able to save backups to directory " + + "[AUTO BACKUP]: BAD NEWS. You won't be able to save backups to directory " + state.BackupDir + " because it doesn't exist or there's a permissions issue with it. Here's the exception.", e); @@ -488,6 +557,9 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup } } + if(state == null) + return m_defaultState; + return state; } @@ -594,7 +666,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup bool heuristicsPassed = false; if (!this.m_timerMap.ContainsKey((Timer) sender)) { - m_log.Debug("Code-up error: timerMap doesn't contain timer " + sender); + m_log.Debug("[AUTO BACKUP]: Code-up error: timerMap doesn't contain timer " + sender); } List tmap = this.m_timerMap[(Timer) sender]; @@ -630,6 +702,9 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup } this.DoRegionBackup(scene); } + + // Remove Old Backups + this.RemoveOldFiles(state); } } } @@ -640,7 +715,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup /// private void DoRegionBackup(IScene scene) { - if (scene.RegionStatus != RegionStatus.Up) + if (!scene.Ready) { // We won't backup a region that isn't operating normally. m_log.Warn("[AUTO BACKUP]: Not backing up region " + scene.RegionInfo.RegionName + @@ -662,7 +737,41 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup m_pendingSaves.Add(guid, scene); state.LiveRequests.Add(guid, savePath); ((Scene) scene).EventManager.OnOarFileSaved += new EventManager.OarFileSaved(EventManager_OnOarFileSaved); - iram.ArchiveRegion(savePath, guid, null); + + m_log.Info("[AUTO BACKUP]: Backing up region " + scene.RegionInfo.RegionName); + + // Must pass options, even if dictionary is empty! + Dictionary options = new Dictionary(); + + if (state.SkipAssets) + options["noassets"] = true; + + iram.ArchiveRegion(savePath, guid, options); + } + + // For the given state, remove backup files older than the states KeepFilesForDays property + private void RemoveOldFiles(AutoBackupModuleState state) + { + // 0 Means Disabled, Keep Files Indefinitely + if (state.KeepFilesForDays > 0) + { + string[] files = Directory.GetFiles(state.BackupDir, "*.oar"); + DateTime CuttOffDate = DateTime.Now.AddDays(0 - state.KeepFilesForDays); + + foreach (string file in files) + { + try + { + FileInfo fi = new FileInfo(file); + if (fi.CreationTime < CuttOffDate) + fi.Delete(); + } + catch (Exception Ex) + { + m_log.Error("[AUTO BACKUP]: Error deleting old backup file '" + file + "': " + Ex.Message); + } + } + } } /// diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs index f9e118b..ce7c368 100644 --- a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs +++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModuleState.cs @@ -45,9 +45,11 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup this.Enabled = false; this.BackupDir = "."; this.BusyCheck = true; + this.SkipAssets = false; this.Timer = null; this.NamingType = NamingType.Time; this.Script = null; + this.KeepFilesForDays = 0; } public Dictionary LiveRequests @@ -91,6 +93,12 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup set; } + public bool SkipAssets + { + get; + set; + } + public string Script { get; @@ -109,6 +117,12 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup set; } + public int KeepFilesForDays + { + get; + set; + } + public new string ToString() { string retval = ""; diff --git a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs index a999b7f..4cd5676 100644 --- a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs +++ b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs @@ -103,7 +103,9 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule #region IMoneyModule Members +#pragma warning disable 0067 public event ObjectPaid OnObjectPaid; +#pragma warning restore 0067 public int UploadCharge { @@ -191,9 +193,14 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule // Please do not refactor these to be just one method // Existing implementations need the distinction // - public void ApplyCharge(UUID agentID, int amount, string text) + public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string extraData) { } + + public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type) + { + } + public void ApplyUploadCharge(UUID agentID, int amount, string text) { } @@ -322,7 +329,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule client.SendAlertMessage(e.Message + " "); } - client.SendMoneyBalance(TransactionID, true, new byte[0], returnfunds); + client.SendMoneyBalance(TransactionID, true, new byte[0], returnfunds, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); } else { @@ -385,12 +392,12 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule { if (sender != null) { - sender.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(senderID)); + sender.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(senderID), 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); } if (receiver != null) { - receiver.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(receiverID)); + receiver.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(receiverID), 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); } } } @@ -555,7 +562,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// private int GetFundsForAgentID(UUID AgentID) { - int returnfunds = 75004; // Set it to the OpenSim version, plus the IG build number. Muahahaha; + int returnfunds = 0; return returnfunds; } @@ -688,19 +695,14 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// Event called Economy Data Request handler. /// /// - public void EconomyDataRequestHandler(UUID agentId) + public void EconomyDataRequestHandler(IClientAPI user) { - IClientAPI user = LocateClientObject(agentId); + Scene s = (Scene)user.Scene; - if (user != null) - { - Scene s = LocateSceneClientIn(user.AgentId); - - user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, - PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, - PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, - TeleportMinPrice, TeleportPriceExponent); - } + user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, + PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, + PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, + TeleportMinPrice, TeleportPriceExponent); } 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 5ea2bcd..fb644b7 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -44,10 +44,24 @@ namespace OpenSim.Region.OptionalModules.World.NPC { public bool SenseAsAgent { get; set; } + public delegate void ChatToNPC( + string message, byte type, Vector3 fromPos, string fromName, + UUID fromAgentID, UUID ownerID, byte source, byte audible); + + /// + /// Fired when the NPC receives a chat message. + /// + public event ChatToNPC OnChatToNPC; + + /// + /// Fired when the NPC receives an instant message. + /// + public event Action OnInstantMessageToNPC; + private readonly string m_firstname; private readonly string m_lastname; private readonly Vector3 m_startPos; - private readonly UUID m_uuid = UUID.Random(); + private readonly UUID m_uuid; private readonly Scene m_scene; private readonly UUID m_ownerID; @@ -57,6 +71,19 @@ namespace OpenSim.Region.OptionalModules.World.NPC m_firstname = firstname; m_lastname = lastname; m_startPos = position; + m_uuid = UUID.Random(); + m_scene = scene; + m_ownerID = ownerID; + SenseAsAgent = senseAsAgent; + } + + public NPCAvatar( + string firstname, string lastname, UUID agentID, Vector3 position, UUID ownerID, bool senseAsAgent, Scene scene) + { + m_firstname = firstname; + m_lastname = lastname; + m_startPos = position; + m_uuid = agentID; m_scene = scene; m_ownerID = ownerID; SenseAsAgent = senseAsAgent; @@ -258,6 +285,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event Action OnCompleteMovementToRegion; public event UpdateAgent OnPreAgentUpdate; public event UpdateAgent OnAgentUpdate; + public event UpdateAgent OnAgentCameraUpdate; public event AgentRequestSit OnAgentRequestSit; public event AgentSit OnAgentSit; public event AvatarPickerRequest OnAvatarPickerRequest; @@ -391,6 +419,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; public event EstateChangeInfo OnEstateChangeInfo; public event EstateManageTelehub OnEstateManageTelehub; + public event CachedTextureRequest OnCachedTextureRequest; public event ScriptReset OnScriptReset; public event GetScriptRunning OnGetScriptRunning; public event SetScriptRunning OnSetScriptRunning; @@ -569,6 +598,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } + public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures) + { + + } + public virtual void Kick(string message) { } @@ -586,7 +620,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC } - public virtual void SendKillObject(ulong regionHandle, List localID) + public virtual void SendKillObject(List localID) { } @@ -607,25 +641,26 @@ namespace OpenSim.Region.OptionalModules.World.NPC string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, UUID ownerID, byte source, byte audible) { - } + ChatToNPC ctn = OnChatToNPC; - public virtual void SendChatMessage( - byte[] message, byte type, Vector3 fromPos, string fromName, - UUID fromAgentID, UUID ownerID, byte source, byte audible) - { + if (ctn != null) + ctn(message, type, fromPos, fromName, fromAgentID, ownerID, source, audible); } public void SendInstantMessage(GridInstantMessage im) { - + Action oimtn = OnInstantMessageToNPC; + + if (oimtn != null) + oimtn(im); } - public void SendGenericMessage(string method, List message) + public void SendGenericMessage(string method, UUID invoice, List message) { } - public void SendGenericMessage(string method, List message) + public void SendGenericMessage(string method, UUID invoice, List message) { } @@ -688,7 +723,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public virtual void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance) + public virtual void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item) { } @@ -860,11 +895,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public bool AddMoney(int debit) - { - return false; - } - public void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong time, uint dlen, uint ylen, float phase) { } @@ -1227,12 +1257,17 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public void StopFlying(ISceneEntity presence) + public void SendAgentTerseUpdate(ISceneEntity presence) { } public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data) { } + + public void SendPartPhysicsProprieties(ISceneEntity entity) + { + } + } } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index d6cf1ab..9232db9 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -116,7 +116,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC return false; // Delete existing npc attachments - scene.AttachmentsModule.DeleteAttachmentsFromScene(npc, false); + if(scene.AttachmentsModule != null) + scene.AttachmentsModule.DeleteAttachmentsFromScene(npc, false); // XXX: We can't just use IAvatarFactoryModule.SetAppearance() yet // since it doesn't transfer attachments @@ -125,7 +126,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC npc.Appearance = npcAppearance; // Rez needed npc attachments - scene.AttachmentsModule.RezAttachments(npc); + if (scene.AttachmentsModule != null) + scene.AttachmentsModule.RezAttachments(npc); IAvatarFactoryModule module = scene.RequestModuleInterface(); @@ -138,15 +140,37 @@ namespace OpenSim.Region.OptionalModules.World.NPC Vector3 position, UUID owner, bool senseAsAgent, Scene scene, AvatarAppearance appearance) { - NPCAvatar npcAvatar = new NPCAvatar(firstname, lastname, position, - owner, senseAsAgent, scene); + return CreateNPC(firstname, lastname, position, UUID.Zero, owner, senseAsAgent, scene, appearance); + } + + public UUID CreateNPC(string firstname, string lastname, + Vector3 position, UUID agentID, UUID owner, bool senseAsAgent, Scene scene, + AvatarAppearance appearance) + { + NPCAvatar npcAvatar = null; + + try + { + if (agentID == UUID.Zero) + npcAvatar = new NPCAvatar(firstname, lastname, position, + owner, senseAsAgent, scene); + else + npcAvatar = new NPCAvatar(firstname, lastname, agentID, position, + owner, senseAsAgent, scene); + } + catch (Exception e) + { + m_log.Info("[NPC MODULE]: exception creating NPC avatar: " + e.ToString()); + return UUID.Zero; + } + npcAvatar.CircuitCode = (uint)Util.RandomClass.Next(0, int.MaxValue); m_log.DebugFormat( - "[NPC MODULE]: Creating NPC {0} {1} {2}, owner={3}, senseAsAgent={4} at {5} in {6}", - firstname, lastname, npcAvatar.AgentId, owner, - senseAsAgent, position, scene.RegionInfo.RegionName); + "[NPC MODULE]: Creating NPC {0} {1} {2}, owner={3}, senseAsAgent={4} at {5} in {6}", + firstname, lastname, npcAvatar.AgentId, owner, + senseAsAgent, position, scene.RegionInfo.RegionName); AgentCircuitData acd = new AgentCircuitData(); acd.AgentID = npcAvatar.AgentId; @@ -154,8 +178,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC acd.lastname = lastname; acd.ServiceURLs = new Dictionary(); - AvatarAppearance npcAppearance = new AvatarAppearance(appearance, - true); + AvatarAppearance npcAppearance = new AvatarAppearance(appearance, true); acd.Appearance = npcAppearance; /* @@ -173,7 +196,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC { scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode, acd); - scene.AddNewClient(npcAvatar, PresenceType.Npc); + scene.AddNewAgent(npcAvatar, PresenceType.Npc); ScenePresence sp; if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp)) @@ -186,16 +209,16 @@ namespace OpenSim.Region.OptionalModules.World.NPC sp.CompleteMovement(npcAvatar, false); m_avatars.Add(npcAvatar.AgentId, npcAvatar); - m_log.DebugFormat("[NPC MODULE]: Created NPC {0} {1}", - npcAvatar.AgentId, sp.Name); + m_log.DebugFormat("[NPC MODULE]: Created NPC {0} {1}", npcAvatar.AgentId, sp.Name); return npcAvatar.AgentId; } else { m_log.WarnFormat( - "[NPC MODULE]: Could not find scene presence for NPC {0} {1}", - sp.Name, sp.UUID); + "[NPC MODULE]: Could not find scene presence for NPC {0} {1}", + sp.Name, sp.UUID); + return UUID.Zero; } } @@ -211,12 +234,13 @@ namespace OpenSim.Region.OptionalModules.World.NPC ScenePresence sp; if (scene.TryGetScenePresence(agentID, out sp)) { - /* - m_log.DebugFormat( - "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}", - sp.Name, pos, scene.RegionInfo.RegionName, - noFly, landAtTarget); - */ + if (sp.IsSatOnObject || sp.SitGround) + return false; + +// m_log.DebugFormat( +// "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}", +// sp.Name, pos, scene.RegionInfo.RegionName, +// noFly, landAtTarget); sp.MoveToTarget(pos, noFly, landAtTarget); sp.SetAlwaysRun = running; @@ -293,9 +317,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC ScenePresence sp; if (scene.TryGetScenePresence(agentID, out sp)) { - sp.HandleAgentRequestSit(m_avatars[agentID], agentID, - partID, Vector3.Zero); - //sp.HandleAgentSit(m_avatars[agentID], agentID); + sp.HandleAgentRequestSit(m_avatars[agentID], agentID, partID, Vector3.Zero); return true; } @@ -376,23 +398,30 @@ namespace OpenSim.Region.OptionalModules.World.NPC public bool DeleteNPC(UUID agentID, Scene scene) { + bool doRemove = false; + NPCAvatar av; lock (m_avatars) { - NPCAvatar av; if (m_avatars.TryGetValue(agentID, out av)) { /* m_log.DebugFormat("[NPC MODULE]: Found {0} {1} to remove", agentID, av.Name); */ - scene.RemoveClient(agentID, false); + doRemove = true; + } + } + + if (doRemove) + { + scene.CloseAgent(agentID, false); + lock (m_avatars) + { m_avatars.Remove(agentID); - /* - m_log.DebugFormat("[NPC MODULE]: Removed NPC {0} {1}", - agentID, av.Name); - */ - return true; } + m_log.DebugFormat("[NPC MODULE]: Removed NPC {0} {1}", + agentID, av.Name); + return true; } /* m_log.DebugFormat("[NPC MODULE]: Could not find {0} to remove", @@ -416,13 +445,20 @@ namespace OpenSim.Region.OptionalModules.World.NPC /// /// Check if the caller has permission to manipulate the given NPC. /// + /// + /// A caller has permission if + /// * The caller UUID given is UUID.Zero. + /// * The avatar is unowned (owner is UUID.Zero). + /// * The avatar is owned and the owner and callerID match. + /// * The avatar is owned and the callerID matches its agentID. + /// /// /// /// true if they do, false if they don't. private bool CheckPermissions(NPCAvatar av, UUID callerID) { return callerID == UUID.Zero || av.OwnerID == UUID.Zero || - av.OwnerID == callerID; + av.OwnerID == callerID || av.AgentId == callerID; } } } diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index bf23040..77dfd40 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs @@ -33,7 +33,6 @@ using Nini.Config; using NUnit.Framework; using OpenMetaverse; using OpenSim.Framework; -using OpenSim.Framework.Communications; using OpenSim.Region.CoreModules.Avatar.Attachments; using OpenSim.Region.CoreModules.Avatar.AvatarFactory; using OpenSim.Region.CoreModules.Framework.InventoryAccess; @@ -43,7 +42,6 @@ using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.AvatarService; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Region.OptionalModules.World.NPC.Tests { @@ -71,11 +69,13 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; } - [SetUp] - public void Init() + public void SetUpScene() { - base.SetUp(); + SetUpScene(256, 256); + } + public void SetUpScene(uint sizeX, uint sizeY) + { IConfigSource config = new IniConfigSource(); config.AddConfig("NPC"); config.Configs["NPC"].Set("Enabled", "true"); @@ -87,7 +87,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests m_attMod = new AttachmentsModule(); m_npcMod = new NPCModule(); - m_scene = new SceneHelpers().SetupScene(); + m_scene = new SceneHelpers().SetupScene("test scene", UUID.Random(), 1000, 1000, sizeX, sizeY, config); SceneHelpers.SetupSceneModules(m_scene, config, m_afMod, m_umMod, m_attMod, m_npcMod, new BasicInventoryAccessModule()); } @@ -97,6 +97,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); + SetUpScene(); + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); // ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); @@ -110,7 +112,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests // ScenePresence.SendInitialData() to reset our entire appearance. m_scene.AssetService.Store(AssetHelpers.CreateNotecardAsset(originalFace8TextureId)); - m_afMod.SetAppearance(sp, originalTe, null); + m_afMod.SetAppearance(sp, originalTe, null, null); UUID npcId = m_npcMod.CreateNPC("John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, sp.Appearance); @@ -133,6 +135,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); + SetUpScene(); + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); // ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); @@ -155,7 +159,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests public void TestCreateWithAttachments() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); +// TestHelpers.EnableLogging(); + + SetUpScene(); UUID userId = TestHelpers.ParseTail(0x1); UserAccountHelpers.CreateUserWithInventory(m_scene, userId); @@ -191,11 +197,66 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests } [Test] + public void TestCreateWithMultiAttachments() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + SetUpScene(); +// m_attMod.DebugLevel = 1; + + UUID userId = TestHelpers.ParseTail(0x1); + UserAccountHelpers.CreateUserWithInventory(m_scene, userId); + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + + InventoryItemBase att1Item + = UserInventoryHelpers.CreateInventoryItem( + m_scene, "att1", TestHelpers.ParseTail(0x2), TestHelpers.ParseTail(0x3), sp.UUID, InventoryType.Object); + InventoryItemBase att2Item + = UserInventoryHelpers.CreateInventoryItem( + m_scene, "att2", TestHelpers.ParseTail(0x12), TestHelpers.ParseTail(0x13), sp.UUID, InventoryType.Object); + + m_attMod.RezSingleAttachmentFromInventory(sp, att1Item.ID, (uint)AttachmentPoint.Chest); + m_attMod.RezSingleAttachmentFromInventory(sp, att2Item.ID, (uint)AttachmentPoint.Chest | 0x80); + + UUID npcId = m_npcMod.CreateNPC("John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, sp.Appearance); + + ScenePresence npc = m_scene.GetScenePresence(npcId); + + // Check scene presence status + Assert.That(npc.HasAttachments(), Is.True); + List attachments = npc.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(2)); + + // Just for now, we won't test the name since this is (wrongly) the asset part name rather than the item + // name. TODO: Do need to fix ultimately since the item may be renamed before being passed on to an NPC. +// Assert.That(attSo.Name, Is.EqualTo(attName)); + + TestAttachedObject(attachments[0], AttachmentPoint.Chest, npc.UUID); + TestAttachedObject(attachments[1], AttachmentPoint.Chest, npc.UUID); + + // Attached objects on the same point must have different FromItemIDs to be shown to other avatars, at least + // on Singularity 1.8.5. Otherwise, only one (the first ObjectUpdate sent) appears. + Assert.AreNotEqual(attachments[0].FromItemID, attachments[1].FromItemID); + } + + private void TestAttachedObject(SceneObjectGroup attSo, AttachmentPoint attPoint, UUID ownerId) + { + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)attPoint)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + Assert.That(attSo.OwnerID, Is.EqualTo(ownerId)); + } + + [Test] public void TestLoadAppearance() { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); + SetUpScene(); + UUID userId = TestHelpers.ParseTail(0x1); UserAccountHelpers.CreateUserWithInventory(m_scene, userId); ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); @@ -237,7 +298,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests public void TestMove() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); +// TestHelpers.EnableLogging(); + + SetUpScene(); ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); // ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); @@ -303,11 +366,64 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests } [Test] + public void TestMoveInVarRegion() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + SetUpScene(512, 512); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); +// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); + + Vector3 startPos = new Vector3(128, 246, 30); + UUID npcId = m_npcMod.CreateNPC("John", "Smith", startPos, UUID.Zero, true, m_scene, sp.Appearance); + + ScenePresence npc = m_scene.GetScenePresence(npcId); + Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); + + // For now, we'll make the scene presence fly to simplify this test, but this needs to change. + npc.Flying = true; + + m_scene.Update(1); + Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); + + Vector3 targetPos = startPos + new Vector3(0, 20, 0); + m_npcMod.MoveToTarget(npc.UUID, m_scene, targetPos, false, false, false); + + Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); + //Assert.That(npc.Rotation, Is.EqualTo(new Quaternion(0, 0, 0.7071068f, 0.7071068f))); + Assert.That( + npc.Rotation, new QuaternionToleranceConstraint(new Quaternion(0, 0, 0.7071068f, 0.7071068f), 0.000001)); + + m_scene.Update(1); + + // We should really check the exact figure. + Assert.That(npc.AbsolutePosition.X, Is.EqualTo(startPos.X)); + Assert.That(npc.AbsolutePosition.Y, Is.GreaterThan(startPos.Y)); + Assert.That(npc.AbsolutePosition.Z, Is.EqualTo(startPos.Z)); + Assert.That(npc.AbsolutePosition.Z, Is.LessThan(targetPos.X)); + + for (int i = 0; i < 20; i++) + { + m_scene.Update(1); +// Console.WriteLine("pos: {0}", npc.AbsolutePosition); + } + + double distanceToTarget = Util.GetDistanceTo(npc.AbsolutePosition, targetPos); + Assert.That(distanceToTarget, Is.LessThan(1), "NPC not within 1 unit of target position on first move"); + Assert.That(npc.AbsolutePosition, Is.EqualTo(targetPos)); + Assert.That(npc.AgentControlFlags, Is.EqualTo((uint)AgentManager.ControlFlags.NONE)); + } + + [Test] public void TestSitAndStandWithSitTarget() { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); + SetUpScene(); + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); Vector3 startPos = new Vector3(128, 128, 30); @@ -321,9 +437,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests Assert.That(part.SitTargetAvatar, Is.EqualTo(npcId)); Assert.That(npc.ParentID, Is.EqualTo(part.LocalId)); - Assert.That( - npc.AbsolutePosition, - Is.EqualTo(part.AbsolutePosition + part.SitTargetPosition + ScenePresence.SIT_TARGET_ADJUSTMENT)); +// Assert.That( +// npc.AbsolutePosition, +// Is.EqualTo(part.AbsolutePosition + part.SitTargetPosition + ScenePresence.SIT_TARGET_ADJUSTMENT)); m_npcMod.Stand(npc.UUID, m_scene); @@ -335,7 +451,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests public void TestSitAndStandWithNoSitTarget() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); +// TestHelpers.EnableLogging(); + + SetUpScene(); ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); @@ -353,13 +471,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); Assert.That(npc.ParentID, Is.EqualTo(part.LocalId)); - // FIXME: This is different for live avatars - z position is adjusted. This is half the height of the - // default avatar. - // Curiously, Vector3.ToString() will not display the last two places of the float. For example, - // printing out npc.AbsolutePosition will give <0, 0, 0.8454993> not <0, 0, 0.845499337> + // We should really be using the NPC size but this would mean preserving the physics actor since it is + // removed on sit. Assert.That( npc.AbsolutePosition, - Is.EqualTo(part.AbsolutePosition + new Vector3(0, 0, 0.845499337f))); + Is.EqualTo(part.AbsolutePosition + new Vector3(0, 0, sp.PhysicsActor.Size.Z / 2))); m_npcMod.Stand(npc.UUID, m_scene); @@ -367,4 +483,4 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests Assert.That(npc.ParentID, Is.EqualTo(0)); } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs index 12169ab..0927c4f 100644 --- a/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs +++ b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs @@ -30,6 +30,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; +using System.Threading; using log4net; using Mono.Addins; using Nini.Config; @@ -48,7 +49,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SceneCommandsModule")] public class SceneCommandsModule : ISceneCommandsModule, INonSharedRegionModule { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Scene m_scene; @@ -93,28 +94,44 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments "Debug", this, "debug scene get", "debug scene get", "List current scene options.", - "If active is false then main scene update and maintenance loops are suspended.\n" - + "If animations is true then extra animations debug information is logged.\n" - + "If collisions is false then collisions with other objects are turned off.\n" - + "If pbackup is false then periodic scene backup is turned off.\n" - + "If physics is false then all physics objects are non-physical.\n" - + "If scripting is false then no scripting operations happen.\n" - + "If teleport is true then some extra teleport debug information is logged.\n" - + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.", + "active - if false then main scene update and maintenance loops are suspended.\n" + + "animations - if true then extra animations debug information is logged.\n" + + "appear-refresh - if true then appearance is resent to other avatars every 60 seconds.\n" + + "child-repri - how far an avatar must move in meters before we update the position of its child agents in neighbouring regions.\n" + + "client-pos-upd - the tolerance before clients are updated with new rotation information for an avatar.\n" + + "client-rot-upd - the tolerance before clients are updated with new rotation information for an avatar.\n" + + "client-vel-upd - the tolerance before clients are updated with new velocity information for an avatar.\n" + + "root-upd-per - if greater than 1, terse updates are only sent to root agents other than the originator on every n updates.\n" + + "child-upd-per - if greater than 1, terse updates are only sent to child agents on every n updates.\n" + + "collisions - if false then collisions with other objects are turned off.\n" + + "pbackup - if false then periodic scene backup is turned off.\n" + + "physics - if false then all physics objects are non-physical.\n" + + "scripting - if false then no scripting operations happen.\n" + + "teleport - if true then some extra teleport debug information is logged.\n" + + "update-on-timer - If true then the scene is updated via a timer. If false then a thread with sleep is used.\n" + + "updates - if true then any frame which exceeds double the maximum desired frame time is logged.", HandleDebugSceneGetCommand); scene.AddCommand( "Debug", this, "debug scene set", - "debug scene set active|collisions|pbackup|physics|scripting|teleport|updates true|false", + "debug scene set ", "Turn on scene debugging options.", - "If active is false then main scene update and maintenance loops are suspended.\n" - + "If animations is true then extra animations debug information is logged.\n" - + "If collisions is false then collisions with other objects are turned off.\n" - + "If pbackup is false then periodic scene backup is turned off.\n" - + "If physics is false then all physics objects are non-physical.\n" - + "If scripting is false then no scripting operations happen.\n" - + "If teleport is true then some extra teleport debug information is logged.\n" - + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.", + "active - if false then main scene update and maintenance loops are suspended.\n" + + "animations - if true then extra animations debug information is logged.\n" + + "appear-refresh - if true then appearance is resent to other avatars every 60 seconds.\n" + + "child-repri - how far an avatar must move in meters before we update the position of its child agents in neighbouring regions.\n" + + "client-pos-upd - the tolerance before clients are updated with new rotation information for an avatar.\n" + + "client-rot-upd - the tolerance before clients are updated with new rotation information for an avatar.\n" + + "client-vel-upd - the tolerance before clients are updated with new velocity information for an avatar.\n" + + "root-upd-per - if greater than 1, terse updates are only sent to root agents other than the originator on every n updates.\n" + + "child-upd-per - if greater than 1, terse updates are only sent to child agents on every n updates.\n" + + "collisions - if false then collisions with other objects are turned off.\n" + + "pbackup - if false then periodic scene backup is turned off.\n" + + "physics - if false then all physics objects are non-physical.\n" + + "scripting - if false then no scripting operations happen.\n" + + "teleport - if true then some extra teleport debug information is logged.\n" + + "update-on-timer - If true then the scene is updated via a timer. If false then a thread with sleep is used.\n" + + "updates - if true then any frame which exceeds double the maximum desired frame time is logged.", HandleDebugSceneSetCommand); } @@ -138,10 +155,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments ConsoleDisplayList cdl = new ConsoleDisplayList(); cdl.AddRow("active", m_scene.Active); cdl.AddRow("animations", m_scene.DebugAnimations); + cdl.AddRow("appear-refresh", m_scene.SendPeriodicAppearanceUpdates); + cdl.AddRow("child-repri", m_scene.ChildReprioritizationDistance); + cdl.AddRow("client-pos-upd", m_scene.RootPositionUpdateTolerance); + cdl.AddRow("client-rot-upd", m_scene.RootRotationUpdateTolerance); + cdl.AddRow("client-vel-upd", m_scene.RootVelocityUpdateTolerance); + cdl.AddRow("root-upd-per", m_scene.RootTerseUpdatePeriod); + cdl.AddRow("child-upd-per", m_scene.ChildTerseUpdatePeriod); cdl.AddRow("pbackup", m_scene.PeriodicBackup); cdl.AddRow("physics", m_scene.PhysicsEnabled); cdl.AddRow("scripting", m_scene.ScriptsEnabled); cdl.AddRow("teleport", m_scene.DebugTeleporting); + cdl.AddRow("update-on-timer", m_scene.UpdateOnTimer); cdl.AddRow("updates", m_scene.DebugUpdates); MainConsole.Instance.OutputFormat("Scene {0} options:", m_scene.Name); @@ -163,8 +188,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments } else { - MainConsole.Instance.Output( - "Usage: debug scene set active|collisions|pbackup|physics|scripting|teleport|updates true|false"); + MainConsole.Instance.Output("Usage: debug scene set "); } } @@ -186,6 +210,69 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments m_scene.DebugAnimations = active; } + if (options.ContainsKey("appear-refresh")) + { + bool newValue; + + // FIXME: This can only come from the console at the moment but might not always be true. + if (ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, options["appear-refresh"], out newValue)) + m_scene.SendPeriodicAppearanceUpdates = newValue; + } + + if (options.ContainsKey("child-repri")) + { + double newValue; + + // FIXME: This can only come from the console at the moment but might not always be true. + if (ConsoleUtil.TryParseConsoleDouble(MainConsole.Instance, options["child-repri"], out newValue)) + m_scene.ChildReprioritizationDistance = newValue; + } + + if (options.ContainsKey("client-pos-upd")) + { + float newValue; + + // FIXME: This can only come from the console at the moment but might not always be true. + if (ConsoleUtil.TryParseConsoleFloat(MainConsole.Instance, options["client-pos-upd"], out newValue)) + m_scene.RootPositionUpdateTolerance = newValue; + } + + if (options.ContainsKey("client-rot-upd")) + { + float newValue; + + // FIXME: This can only come from the console at the moment but might not always be true. + if (ConsoleUtil.TryParseConsoleFloat(MainConsole.Instance, options["client-rot-upd"], out newValue)) + m_scene.RootRotationUpdateTolerance = newValue; + } + + if (options.ContainsKey("client-vel-upd")) + { + float newValue; + + // FIXME: This can only come from the console at the moment but might not always be true. + if (ConsoleUtil.TryParseConsoleFloat(MainConsole.Instance, options["client-vel-upd"], out newValue)) + m_scene.RootVelocityUpdateTolerance = newValue; + } + + if (options.ContainsKey("root-upd-per")) + { + int newValue; + + // FIXME: This can only come from the console at the moment but might not always be true. + if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, options["root-upd-per"], out newValue)) + m_scene.RootTerseUpdatePeriod = newValue; + } + + if (options.ContainsKey("child-upd-per")) + { + int newValue; + + // FIXME: This can only come from the console at the moment but might not always be true. + if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, options["child-upd-per"], out newValue)) + m_scene.ChildTerseUpdatePeriod = newValue; + } + if (options.ContainsKey("pbackup")) { bool active; @@ -221,6 +308,21 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments m_scene.DebugTeleporting = enableTeleportDebugging; } + if (options.ContainsKey("update-on-timer")) + { + bool enableUpdateOnTimer; + if (bool.TryParse(options["update-on-timer"], out enableUpdateOnTimer)) + { + m_scene.UpdateOnTimer = enableUpdateOnTimer; + m_scene.Active = false; + + while (m_scene.IsRunning) + Thread.Sleep(20); + + m_scene.Active = true; + } + } + if (options.ContainsKey("updates")) { bool enableUpdateDebugging; diff --git a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs index 8144870..e4a3382 100644 --- a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs +++ b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs @@ -748,8 +748,8 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator position.X = s_tree.AbsolutePosition.X + (float)randX; position.Y = s_tree.AbsolutePosition.Y + (float)randY; - if (position.X <= ((int)Constants.RegionSize - 1) && position.X >= 0 && - position.Y <= ((int)Constants.RegionSize - 1) && position.Y >= 0 && + if (position.X <= (m_scene.RegionInfo.RegionSizeX - 1) && position.X >= 0 && + position.Y <= (m_scene.RegionInfo.RegionSizeY - 1) && position.Y >= 0 && Util.GetDistanceTo(position, copse.m_seed_point) <= copse.m_range) { UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; diff --git a/OpenSim/Region/OptionalModules/World/WorldView/WorldViewRequestHandler.cs b/OpenSim/Region/OptionalModules/World/WorldView/WorldViewRequestHandler.cs index 550b5d4..8720cc7 100644 --- a/OpenSim/Region/OptionalModules/World/WorldView/WorldViewRequestHandler.cs +++ b/OpenSim/Region/OptionalModules/World/WorldView/WorldViewRequestHandler.cs @@ -55,7 +55,7 @@ namespace OpenSim.Region.OptionalModules.World.WorldView m_WorldViewModule = fmodule; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { httpResponse.ContentType = "image/jpeg"; diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs deleted file mode 100644 index fb9cb66..0000000 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Reflection; -using System.Runtime.InteropServices; - -// Information about this assembly is defined by the following -// attributes. -// -// change them to the information which is associated with the assembly -// you compile. - -[assembly : AssemblyTitle("BasicPhysicsPlugin")] -[assembly : AssemblyDescription("")] -[assembly : AssemblyConfiguration("")] -[assembly : AssemblyCompany("http://opensimulator.org")] -[assembly : AssemblyProduct("BasicPhysicsPlugin")] -[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] -[assembly : AssemblyTrademark("")] -[assembly : AssemblyCulture("")] - -// This sets the default COM visibility of types in the assembly to invisible. -// If you need to expose a type to COM, use [ComVisible(true)] on that type. - -[assembly : ComVisible(false)] - -// The assembly version has following format : -// -// Major.Minor.Build.Revision -// -// You can specify all values by your own or you can build default build and revision -// numbers with the '*' character (the default): - -[assembly : AssemblyVersion("0.7.5.*")] diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs deleted file mode 100644 index e43136a..0000000 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.BasicPhysicsPlugin -{ - public class BasicActor : PhysicsActor - { - private Vector3 _size; - - public BasicActor(Vector3 size) - { - Size = size; - } - - public override int PhysicsActorType - { - get { return (int) ActorTypes.Agent; } - set { return; } - } - - public override Vector3 RotationalVelocity { get; set; } - - public override bool SetAlwaysRun - { - get { return false; } - set { return; } - } - - public override uint LocalID - { - set { return; } - } - - public override bool Grabbed - { - set { return; } - } - - public override bool Selected - { - set { return; } - } - - public override float Buoyancy - { - get { return 0f; } - set { return; } - } - - public override bool FloatOnWater - { - set { return; } - } - - public override bool IsPhysical - { - get { return false; } - set { return; } - } - - public override bool ThrottleUpdates - { - get { return false; } - set { return; } - } - - public override bool Flying { get; set; } - - public override bool IsColliding { get; set; } - - public override bool CollidingGround - { - get { return false; } - set { return; } - } - - public override bool CollidingObj - { - get { return false; } - set { return; } - } - - public override bool Stopped - { - get { return false; } - } - - public override Vector3 Position { get; set; } - - public override Vector3 Size - { - get { return _size; } - set { - _size = value; - _size.Z = _size.Z / 2.0f; - } - } - - public override PrimitiveBaseShape Shape - { - set { return; } - } - - public override float Mass - { - get { return 0f; } - } - - public override Vector3 Force - { - get { return Vector3.Zero; } - set { return; } - } - - public override int VehicleType - { - get { return 0; } - set { return; } - } - - public override void VehicleFloatParam(int param, float value) - { - - } - - public override void VehicleVectorParam(int param, Vector3 value) - { - - } - - public override void VehicleRotationParam(int param, Quaternion rotation) - { - - } - - public override void VehicleFlags(int param, bool remove) - { - - } - - public override void SetVolumeDetect(int param) - { - - } - - public override Vector3 CenterOfMass - { - get { return Vector3.Zero; } - } - - public override Vector3 GeometricCenter - { - get { return Vector3.Zero; } - } - - public override Vector3 Velocity { get; set; } - - public override Vector3 Torque - { - get { return Vector3.Zero; } - set { return; } - } - - public override float CollisionScore - { - get { return 0f; } - set { } - } - - public override Quaternion Orientation - { - get { return Quaternion.Identity; } - set { } - } - - public override Vector3 Acceleration { get; set; } - - public override bool Kinematic - { - get { return true; } - set { } - } - - public override void link(PhysicsActor obj) - { - } - - public override void delink() - { - } - - public override void LockAngularMotion(Vector3 axis) - { - } - - public override void AddForce(Vector3 force, bool pushforce) - { - } - - public override void AddAngularForce(Vector3 force, bool pushforce) - { - } - - public override void SetMomentum(Vector3 momentum) - { - } - - public override void CrossingFailure() - { - } - - public override Vector3 PIDTarget - { - set { return; } - } - - public override bool PIDActive - { - set { return; } - } - - public override float PIDTau - { - set { return; } - } - - public override float PIDHoverHeight - { - set { return; } - } - - public override bool PIDHoverActive - { - set { return; } - } - - public override PIDHoverType PIDHoverType - { - set { return; } - } - - public override float PIDHoverTau - { - set { return; } - } - - public override Quaternion APIDTarget - { - set { return; } - } - - public override bool APIDActive - { - set { return; } - } - - public override float APIDStrength - { - set { return; } - } - - public override float APIDDamping - { - set { return; } - } - - public override void SubscribeEvents(int ms) - { - } - - public override void UnSubscribeEvents() - { - } - - public override bool SubscribedEvents() - { - return false; - } - } -} diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs deleted file mode 100644 index 7ab2a03..0000000 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.BasicPhysicsPlugin -{ - /// - /// Effectively a physics plugin that simulates no physics at all. - /// - public class BasicPhysicsPlugin : IPhysicsPlugin - { - public BasicPhysicsPlugin() - { - } - - public bool Init() - { - return true; - } - - public PhysicsScene GetScene(string sceneIdentifier) - { - return new BasicScene(sceneIdentifier); - } - - public string GetName() - { - return ("basicphysics"); - } - - public void Dispose() - { - } - } -} diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPrim.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPrim.cs deleted file mode 100644 index 47d7df3..0000000 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPrim.cs +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.BasicPhysicsPlugin -{ - public class BasicPhysicsPrim : PhysicsActor - { - private Vector3 _size; -// private PrimitiveBaseShape _shape; - - public BasicPhysicsPrim( - string name, uint localId, Vector3 position, Vector3 size, Quaternion orientation, PrimitiveBaseShape shape) - { - Name = name; - LocalID = localId; - Position = position; - Size = size; - Orientation = orientation; - Shape = shape; - } - - public override int PhysicsActorType - { - get { return (int) ActorTypes.Agent; } - set { return; } - } - - public override Vector3 RotationalVelocity { get; set; } - - public override bool SetAlwaysRun - { - get { return false; } - set { return; } - } - - public override uint LocalID - { - set { return; } - } - - public override bool Grabbed - { - set { return; } - } - - public override bool Selected - { - set { return; } - } - - public override float Buoyancy - { - get { return 0f; } - set { return; } - } - - public override bool FloatOnWater - { - set { return; } - } - - public override bool IsPhysical - { - get { return false; } - set { return; } - } - - public override bool ThrottleUpdates - { - get { return false; } - set { return; } - } - - public override bool Flying { get; set; } - - public override bool IsColliding { get; set; } - - public override bool CollidingGround - { - get { return false; } - set { return; } - } - - public override bool CollidingObj - { - get { return false; } - set { return; } - } - - public override bool Stopped - { - get { return false; } - } - - public override Vector3 Position { get; set; } - - public override Vector3 Size - { - get { return _size; } - set { - _size = value; - _size.Z = _size.Z / 2.0f; - } - } - - public override PrimitiveBaseShape Shape - { -// set { _shape = value; } - set {} - } - - public override float Mass - { - get { return 0f; } - } - - public override Vector3 Force - { - get { return Vector3.Zero; } - set { return; } - } - - public override int VehicleType - { - get { return 0; } - set { return; } - } - - public override void VehicleFloatParam(int param, float value) - { - - } - - public override void VehicleVectorParam(int param, Vector3 value) - { - - } - - public override void VehicleRotationParam(int param, Quaternion rotation) - { - - } - - public override void VehicleFlags(int param, bool remove) - { - - } - - public override void SetVolumeDetect(int param) - { - - } - - public override Vector3 CenterOfMass - { - get { return Vector3.Zero; } - } - - public override Vector3 GeometricCenter - { - get { return Vector3.Zero; } - } - - public override Vector3 Velocity { get; set; } - - public override Vector3 Torque - { - get { return Vector3.Zero; } - set { return; } - } - - public override float CollisionScore - { - get { return 0f; } - set { } - } - - public override Quaternion Orientation { get; set; } - - public override Vector3 Acceleration { get; set; } - - public override bool Kinematic - { - get { return true; } - set { } - } - - public override void link(PhysicsActor obj) - { - } - - public override void delink() - { - } - - public override void LockAngularMotion(Vector3 axis) - { - } - - public override void AddForce(Vector3 force, bool pushforce) - { - } - - public override void AddAngularForce(Vector3 force, bool pushforce) - { - } - - public override void SetMomentum(Vector3 momentum) - { - } - - public override void CrossingFailure() - { - } - - public override Vector3 PIDTarget - { - set { return; } - } - - public override bool PIDActive - { - set { return; } - } - - public override float PIDTau - { - set { return; } - } - - public override float PIDHoverHeight - { - set { return; } - } - - public override bool PIDHoverActive - { - set { return; } - } - - public override PIDHoverType PIDHoverType - { - set { return; } - } - - public override float PIDHoverTau - { - set { return; } - } - - public override Quaternion APIDTarget - { - set { return; } - } - - public override bool APIDActive - { - set { return; } - } - - public override float APIDStrength - { - set { return; } - } - - public override float APIDDamping - { - set { return; } - } - - public override void SubscribeEvents(int ms) - { - } - - public override void UnSubscribeEvents() - { - } - - public override bool SubscribedEvents() - { - return false; - } - } -} diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs deleted file mode 100644 index f5826ed..0000000 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.BasicPhysicsPlugin -{ - /// - /// This is an incomplete extremely basic physics implementation - /// - /// - /// Not useful for anything at the moment apart from some regression testing in other components where some form - /// of physics plugin is needed. - /// - public class BasicScene : PhysicsScene - { - private List _actors = new List(); - private List _prims = new List(); - private float[] _heightMap; - - //protected internal string sceneIdentifier; - - public BasicScene(string _sceneIdentifier) - { - //sceneIdentifier = _sceneIdentifier; - } - - public override void Initialise(IMesher meshmerizer, IConfigSource config) - { - } - - public override void Dispose() {} - - public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, - Vector3 size, Quaternion rotation, bool isPhysical, uint localid) - { - BasicPhysicsPrim prim = new BasicPhysicsPrim(primName, localid, position, size, rotation, pbs); - prim.IsPhysical = isPhysical; - - _prims.Add(prim); - - return prim; - } - - public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) - { - BasicActor act = new BasicActor(size); - act.Position = position; - act.Flying = isFlying; - _actors.Add(act); - return act; - } - - public override void RemovePrim(PhysicsActor actor) - { - BasicPhysicsPrim prim = (BasicPhysicsPrim)actor; - if (_prims.Contains(prim)) - _prims.Remove(prim); - } - - public override void RemoveAvatar(PhysicsActor actor) - { - BasicActor act = (BasicActor)actor; - if (_actors.Contains(act)) - _actors.Remove(act); - } - - public override void AddPhysicsActorTaint(PhysicsActor prim) - { - } - - public override float Simulate(float timeStep) - { - float fps = 0; - for (int i = 0; i < _actors.Count; ++i) - { - BasicActor actor = _actors[i]; - Vector3 actorPosition = actor.Position; - Vector3 actorVelocity = actor.Velocity; - - actorPosition.X += actor.Velocity.X*timeStep; - actorPosition.Y += actor.Velocity.Y*timeStep; - - if (actor.Position.Y < 0) - { - actorPosition.Y = 0.1F; - } - else if (actor.Position.Y >= Constants.RegionSize) - { - actorPosition.Y = ((int)Constants.RegionSize - 0.1f); - } - - if (actor.Position.X < 0) - { - actorPosition.X = 0.1F; - } - else if (actor.Position.X >= Constants.RegionSize) - { - actorPosition.X = ((int)Constants.RegionSize - 0.1f); - } - - float terrainHeight = 0; - if (_heightMap != null) - terrainHeight = _heightMap[(int)actor.Position.Y * Constants.RegionSize + (int)actor.Position.X]; - - float height = terrainHeight + actor.Size.Z; - - if (actor.Flying) - { - if (actor.Position.Z + (actor.Velocity.Z * timeStep) < terrainHeight + 2) - { - actorPosition.Z = height; - actorVelocity.Z = 0; - actor.IsColliding = true; - } - else - { - actorPosition.Z += actor.Velocity.Z * timeStep; - actor.IsColliding = false; - } - } - else - { - actorPosition.Z = height; - actorVelocity.Z = 0; - actor.IsColliding = true; - } - - actor.Position = actorPosition; - actor.Velocity = actorVelocity; - } - - return fps; - } - - public override void GetResults() - { - } - - public override bool IsThreaded - { - get { return (false); // for now we won't be multithreaded - } - } - - public override void SetTerrain(float[] heightMap) - { - _heightMap = heightMap; - } - - public override void DeleteTerrain() - { - } - - public override void SetWaterLevel(float baseheight) - { - } - - public override Dictionary GetTopColliders() - { - Dictionary returncolliders = new Dictionary(); - return returncolliders; - } - } -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs deleted file mode 100644 index d91c47f..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs +++ /dev/null @@ -1,814 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Reflection; -using log4net; -using OMV = OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ -public sealed class BSCharacter : BSPhysObject -{ - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static readonly string LogHeader = "[BULLETS CHAR]"; - - // private bool _stopped; - private OMV.Vector3 _size; - private bool _grabbed; - private bool _selected; - private OMV.Vector3 _position; - private float _mass; - private float _avatarDensity; - private float _avatarVolume; - private OMV.Vector3 _force; - private OMV.Vector3 _velocity; - private OMV.Vector3 _torque; - private float _collisionScore; - private OMV.Vector3 _acceleration; - private OMV.Quaternion _orientation; - private int _physicsActorType; - private bool _isPhysical; - private bool _flying; - private bool _setAlwaysRun; - private bool _throttleUpdates; - private bool _isColliding; - private bool _collidingObj; - private bool _floatOnWater; - private OMV.Vector3 _rotationalVelocity; - private bool _kinematic; - private float _buoyancy; - - // The friction and velocity of the avatar is modified depending on whether walking or not. - private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar - private float _currentFriction; // the friction currently being used (changed by setVelocity). - - private BSVMotor _velocityMotor; - - private OMV.Vector3 _PIDTarget; - private bool _usePID; - private float _PIDTau; - private bool _useHoverPID; - private float _PIDHoverHeight; - private PIDHoverType _PIDHoverType; - private float _PIDHoverTao; - - public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) - : base(parent_scene, localID, avName, "BSCharacter") - { - _physicsActorType = (int)ActorTypes.Agent; - _position = pos; - - // Old versions of ScenePresence passed only the height. If width and/or depth are zero, - // replace with the default values. - _size = size; - if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; - if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; - - // A motor to control the acceleration and deceleration of the avatar movement. - // _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); - // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); - // Infinite decay and timescale values so motor only changes current to target values. - _velocityMotor = new BSVMotor("BSCharacter.Velocity", - 0.2f, // time scale - BSMotor.Infinite, // decay time scale - BSMotor.InfiniteVector, // friction timescale - 1f // efficiency - ); - _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. - - _flying = isFlying; - _orientation = OMV.Quaternion.Identity; - _velocity = OMV.Vector3.Zero; - _appliedVelocity = OMV.Vector3.Zero; - _buoyancy = ComputeBuoyancyFromFlying(isFlying); - _currentFriction = BSParam.AvatarStandingFriction; - _avatarDensity = BSParam.AvatarDensity; - - // The dimensions of the avatar capsule are kept in the scale. - // Physics creates a unit capsule which is scaled by the physics engine. - ComputeAvatarScale(_size); - // set _avatarVolume and _mass based on capsule size, _density and Scale - ComputeAvatarVolumeAndMass(); - DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", - LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); - - // do actual creation in taint time - PhysicsScene.TaintedObject("BSCharacter.create", delegate() - { - DetailLog("{0},BSCharacter.create,taint", LocalID); - // New body and shape into PhysBody and PhysShape - PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); - - SetPhysicalProperties(); - }); - return; - } - - // called when this character is being destroyed and the resources should be released - public override void Destroy() - { - base.Destroy(); - - DetailLog("{0},BSCharacter.Destroy", LocalID); - PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() - { - PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); - PhysBody.Clear(); - PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); - PhysShape.Clear(); - }); - } - - private void SetPhysicalProperties() - { - BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); - - ZeroMotion(true); - ForcePosition = _position; - // Set the velocity and compute the proper friction - ForceVelocity = _velocity; - // Setting the current and target in the motor will cause it to start computing any deceleration. - _velocityMotor.Reset(); - _velocityMotor.SetCurrent(_velocity); - _velocityMotor.SetTarget(_velocity); - _velocityMotor.Enabled = false; - - // This will enable or disable the flying buoyancy of the avatar. - // Needs to be reset especially when an avatar is recreated after crossing a region boundry. - Flying = _flying; - - BulletSimAPI.SetRestitution2(PhysBody.ptr, BSParam.AvatarRestitution); - BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); - BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); - BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold); - if (BSParam.CcdMotionThreshold > 0f) - { - BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold); - BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius); - } - - UpdatePhysicalMassProperties(RawMass, false); - - // Make so capsule does not fall over - BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero); - - BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); - - BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr, _position, _orientation); - - // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); - BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION); - BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); - - // Do this after the object has been added to the world - PhysBody.collisionType = CollisionType.Avatar; - PhysBody.ApplyCollisionMask(); - } - - public override void RequestPhysicsterseUpdate() - { - base.RequestPhysicsterseUpdate(); - } - // No one calls this method so I don't know what it could possibly mean - public override bool Stopped { get { return false; } } - - public override OMV.Vector3 Size { - get - { - // Avatar capsule size is kept in the scale parameter. - return _size; - } - - set { - // When an avatar's size is set, only the height is changed. - _size = value; - // Old versions of ScenePresence passed only the height. If width and/or depth are zero, - // replace with the default values. - if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; - if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; - - ComputeAvatarScale(_size); - ComputeAvatarVolumeAndMass(); - DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", - LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); - - PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() - { - if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) - { - BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); - UpdatePhysicalMassProperties(RawMass, true); - // Make sure this change appears as a property update event - BulletSimAPI.PushUpdate2(PhysBody.ptr); - } - }); - - } - } - - public override PrimitiveBaseShape Shape - { - set { BaseShape = value; } - } - // I want the physics engine to make an avatar capsule - public override BSPhysicsShapeType PreferredPhysicalShape - { - get {return BSPhysicsShapeType.SHAPE_CAPSULE; } - } - - public override bool Grabbed { - set { _grabbed = value; } - } - public override bool Selected { - set { _selected = value; } - } - public override void CrossingFailure() { return; } - public override void link(PhysicsActor obj) { return; } - public override void delink() { return; } - - // Set motion values to zero. - // Do it to the properties so the values get set in the physics engine. - // Push the setting of the values to the viewer. - // Called at taint time! - public override void ZeroMotion(bool inTaintTime) - { - _velocity = OMV.Vector3.Zero; - _acceleration = OMV.Vector3.Zero; - _rotationalVelocity = OMV.Vector3.Zero; - - // Zero some other properties directly into the physics engine - PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() - { - if (PhysBody.HasPhysicalBody) - BulletSimAPI.ClearAllForces2(PhysBody.ptr); - }); - } - public override void ZeroAngularMotion(bool inTaintTime) - { - _rotationalVelocity = OMV.Vector3.Zero; - - PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() - { - if (PhysBody.HasPhysicalBody) - { - BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); - BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); - // The next also get rid of applied linear force but the linear velocity is untouched. - BulletSimAPI.ClearForces2(PhysBody.ptr); - } - }); - } - - - public override void LockAngularMotion(OMV.Vector3 axis) { return; } - - public override OMV.Vector3 RawPosition - { - get { return _position; } - set { _position = value; } - } - public override OMV.Vector3 Position { - get { - // Don't refetch the position because this function is called a zillion times - // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); - return _position; - } - set { - _position = value; - PositionSanityCheck(); - - PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() - { - DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); - if (PhysBody.HasPhysicalBody) - BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); - }); - } - } - public override OMV.Vector3 ForcePosition { - get { - _position = BulletSimAPI.GetPosition2(PhysBody.ptr); - return _position; - } - set { - _position = value; - PositionSanityCheck(); - BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); - } - } - - - // Check that the current position is sane and, if not, modify the position to make it so. - // Check for being below terrain or on water. - // Returns 'true' of the position was made sane by some action. - private bool PositionSanityCheck() - { - bool ret = false; - - // TODO: check for out of bounds - if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) - { - // The character is out of the known/simulated area. - // Upper levels of code will handle the transition to other areas so, for - // the time, we just ignore the position. - return ret; - } - - // If below the ground, move the avatar up - float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); - if (Position.Z < terrainHeight) - { - DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); - _position.Z = terrainHeight + 2.0f; - ret = true; - } - if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) - { - float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); - if (Position.Z < waterHeight) - { - _position.Z = waterHeight; - ret = true; - } - } - - return ret; - } - - // A version of the sanity check that also makes sure a new position value is - // pushed back to the physics engine. This routine would be used by anyone - // who is not already pushing the value. - private bool PositionSanityCheck(bool inTaintTime) - { - bool ret = false; - if (PositionSanityCheck()) - { - // The new position value must be pushed into the physics engine but we can't - // just assign to "Position" because of potential call loops. - PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() - { - DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); - if (PhysBody.HasPhysicalBody) - BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); - }); - ret = true; - } - return ret; - } - - public override float Mass { get { return _mass; } } - - // used when we only want this prim's mass and not the linkset thing - public override float RawMass { - get {return _mass; } - } - public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) - { - OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); - BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); - } - - public override OMV.Vector3 Force { - get { return _force; } - set { - _force = value; - // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); - PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() - { - DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); - if (PhysBody.HasPhysicalBody) - BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); - }); - } - } - - public bool TouchingGround() - { - bool ret = BulletSimAPI.RayCastGround(PhysicsScene.World.ptr,_position,_size.Z * 0.55f, PhysBody.ptr); - return ret; - } - // Avatars don't do vehicles - public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } } - public override void VehicleFloatParam(int param, float value) { } - public override void VehicleVectorParam(int param, OMV.Vector3 value) {} - public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } - public override void VehicleFlags(int param, bool remove) { } - - // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more - public override void SetVolumeDetect(int param) { return; } - - public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } - public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } - - // Sets the target in the motor. This starts the changing of the avatar's velocity. - public override OMV.Vector3 TargetVelocity - { - get - { - return _velocityMotor.TargetValue; - } - set - { - DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); - - if (!_flying) - if ((value.Z >= 0.0001f) || (value.Z <= -0.0001f) || _velocity.Z < -0.0001f) - if (!TouchingGround()) - value.Z = _velocity.Z; - if (_setAlwaysRun) - value *= 1.3f; - - OMV.Vector3 targetVel = value; - - PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() - { - - _velocityMotor.Reset(); - _velocityMotor.SetTarget(targetVel); - _velocityMotor.SetCurrent(_velocity); - _velocityMotor.Enabled = true; - - // Make sure a property update happens next step so the motor gets incorporated. - BulletSimAPI.PushUpdate2(PhysBody.ptr); - }); - } - } - // Directly setting velocity means this is what the user really wants now. - public override OMV.Vector3 Velocity { - get { return _velocity; } - set { - _velocity = value; - // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); - PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() - { - _velocityMotor.Reset(); - _velocityMotor.SetCurrent(_velocity); - _velocityMotor.SetTarget(_velocity); - // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar. - _velocityMotor.Enabled = false; - - DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); - ForceVelocity = _velocity; - }); - } - } - public override OMV.Vector3 ForceVelocity { - get { return _velocity; } - set { - PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); - - _velocity = value; - // Depending on whether the avatar is moving or not, change the friction - // to keep the avatar from slipping around - if (_velocity.Length() == 0) - { - if (_currentFriction != BSParam.AvatarStandingFriction) - { - _currentFriction = BSParam.AvatarStandingFriction; - if (PhysBody.HasPhysicalBody) - BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); - } - } - else - { - if (_currentFriction != BSParam.AvatarFriction) - { - _currentFriction = BSParam.AvatarFriction; - if (PhysBody.HasPhysicalBody) - BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); - } - } - // Remember the set velocity so we can suppress the reduction by friction, ... - _appliedVelocity = value; - - BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); - BulletSimAPI.Activate2(PhysBody.ptr, true); - } - } - public override OMV.Vector3 Torque { - get { return _torque; } - set { _torque = value; - } - } - public override float CollisionScore { - get { return _collisionScore; } - set { _collisionScore = value; - } - } - public override OMV.Vector3 Acceleration { - get { return _acceleration; } - set { _acceleration = value; } - } - public override OMV.Quaternion RawOrientation - { - get { return _orientation; } - set { _orientation = value; } - } - public override OMV.Quaternion Orientation { - get { return _orientation; } - set { - _orientation = value; - // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); - PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() - { - if (PhysBody.HasPhysicalBody) - { - // _position = BulletSimAPI.GetPosition2(BSBody.ptr); - BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); - } - }); - } - } - // Go directly to Bullet to get/set the value. - public override OMV.Quaternion ForceOrientation - { - get - { - _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); - return _orientation; - } - set - { - _orientation = value; - BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); - } - } - public override int PhysicsActorType { - get { return _physicsActorType; } - set { _physicsActorType = value; - } - } - public override bool IsPhysical { - get { return _isPhysical; } - set { _isPhysical = value; - } - } - public override bool IsSolid { - get { return true; } - } - public override bool IsStatic { - get { return false; } - } - public override bool Flying { - get { return _flying; } - set { - _flying = value; - - // simulate flying by changing the effect of gravity - Buoyancy = ComputeBuoyancyFromFlying(_flying); - } - } - // Flying is implimented by changing the avatar's buoyancy. - // Would this be done better with a vehicle type? - private float ComputeBuoyancyFromFlying(bool ifFlying) { - return ifFlying ? 1f : 0f; - } - public override bool - SetAlwaysRun { - get { return _setAlwaysRun; } - set { _setAlwaysRun = value; } - } - public override bool ThrottleUpdates { - get { return _throttleUpdates; } - set { _throttleUpdates = value; } - } - public override bool IsColliding { - get { return (CollidingStep == PhysicsScene.SimulationStep); } - set { _isColliding = value; } - } - public override bool CollidingGround { - get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } - set { CollidingGround = value; } - } - public override bool CollidingObj { - get { return _collidingObj; } - set { _collidingObj = value; } - } - public override bool FloatOnWater { - set { - _floatOnWater = value; - PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() - { - if (PhysBody.HasPhysicalBody) - { - if (_floatOnWater) - CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); - else - CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); - } - }); - } - } - public override OMV.Vector3 RotationalVelocity { - get { return _rotationalVelocity; } - set { _rotationalVelocity = value; } - } - public override OMV.Vector3 ForceRotationalVelocity { - get { return _rotationalVelocity; } - set { _rotationalVelocity = value; } - } - public override bool Kinematic { - get { return _kinematic; } - set { _kinematic = value; } - } - // neg=fall quickly, 0=1g, 1=0g, pos=float up - public override float Buoyancy { - get { return _buoyancy; } - set { _buoyancy = value; - PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() - { - DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); - ForceBuoyancy = _buoyancy; - }); - } - } - public override float ForceBuoyancy { - get { return _buoyancy; } - set { - PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); - - _buoyancy = value; - DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); - // Buoyancy is faked by changing the gravity applied to the object - float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); - if (PhysBody.HasPhysicalBody) - BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); - } - } - - // Used for MoveTo - public override OMV.Vector3 PIDTarget { - set { _PIDTarget = value; } - } - public override bool PIDActive { - set { _usePID = value; } - } - public override float PIDTau { - set { _PIDTau = value; } - } - - // Used for llSetHoverHeight and maybe vehicle height - // Hover Height will override MoveTo target's Z - public override bool PIDHoverActive { - set { _useHoverPID = value; } - } - public override float PIDHoverHeight { - set { _PIDHoverHeight = value; } - } - public override PIDHoverType PIDHoverType { - set { _PIDHoverType = value; } - } - public override float PIDHoverTau { - set { _PIDHoverTao = value; } - } - - // For RotLookAt - public override OMV.Quaternion APIDTarget { set { return; } } - public override bool APIDActive { set { return; } } - public override float APIDStrength { set { return; } } - public override float APIDDamping { set { return; } } - - public override void AddForce(OMV.Vector3 force, bool pushforce) { - if (force.IsFinite()) - { - _force.X += force.X; - _force.Y += force.Y; - _force.Z += force.Z; - // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); - PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() - { - DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); - if (PhysBody.HasPhysicalBody) - BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); - }); - } - else - { - m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader); - } - //m_lastUpdateSent = false; - } - - public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { - } - public override void SetMomentum(OMV.Vector3 momentum) { - } - - private void ComputeAvatarScale(OMV.Vector3 size) - { - OMV.Vector3 newScale = size; - // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; - // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; - - // From the total height, remove the capsule half spheres that are at each end - // The 1.15f came from ODE. Not sure what this factors in. - // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); - - // The total scale height is the central cylindar plus the caps on the two ends. - newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f); - - // Convert diameters to radii and height to half height -- the way Bullet expects it. - Scale = newScale / 2f; - } - - // set _avatarVolume and _mass based on capsule size, _density and Scale - private void ComputeAvatarVolumeAndMass() - { - _avatarVolume = (float)( - Math.PI - * Scale.X - * Scale.Y // the area of capsule cylinder - * Scale.Z // times height of capsule cylinder - + 1.33333333f - * Math.PI - * Scale.X - * Math.Min(Scale.X, Scale.Y) - * Scale.Y // plus the volume of the capsule end caps - ); - _mass = _avatarDensity * _avatarVolume; - } - - // The physics engine says that properties have updated. Update same and inform - // the world that things have changed. - public override void UpdateProperties(EntityProperties entprop) - { - _position = entprop.Position; - _orientation = entprop.Rotation; - _velocity = entprop.Velocity; - _acceleration = entprop.Acceleration; - _rotationalVelocity = entprop.RotationalVelocity; - - // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. - PositionSanityCheck(true); - - if (_velocityMotor.Enabled) - { - // TODO: Decide if the step parameters should be changed depending on the avatar's - // state (flying, colliding, ...). - - OMV.Vector3 stepVelocity = _velocityMotor.Step(PhysicsScene.LastTimeStep); - - // If falling, we keep the world's downward vector no matter what the other axis specify. - if (!Flying && !IsColliding) - { - stepVelocity.Z = entprop.Velocity.Z; - DetailLog("{0},BSCharacter.UpdateProperties,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); - } - - // If the user has said stop and we've stopped applying velocity correction, - // the motor can be turned off. Set the velocity to zero so the zero motion is sent to the viewer. - if (_velocityMotor.TargetValue.ApproxEquals(OMV.Vector3.Zero, 0.01f) && _velocityMotor.ErrorIsZero) - { - ZeroMotion(true); - stepVelocity = OMV.Vector3.Zero; - _velocityMotor.Enabled = false; - DetailLog("{0},BSCharacter.UpdateProperties,taint,disableVelocityMotor,m={1}", LocalID, _velocityMotor); - } - - _velocity = stepVelocity; - entprop.Velocity = _velocity; - BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); - } - - // remember the current and last set values - LastEntityProperties = CurrentEntityProperties; - CurrentEntityProperties = entprop; - - // Tell the linkset about value changes - Linkset.UpdateProperties(this, true); - - // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. - // base.RequestPhysicsterseUpdate(); - - DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", - LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs deleted file mode 100644 index f1bed39..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ - -public abstract class BSConstraint : IDisposable -{ - private static string LogHeader = "[BULLETSIM CONSTRAINT]"; - - protected BulletWorld m_world; - protected BulletBody m_body1; - protected BulletBody m_body2; - protected BulletConstraint m_constraint; - protected bool m_enabled = false; - - public BulletBody Body1 { get { return m_body1; } } - public BulletBody Body2 { get { return m_body2; } } - public BulletConstraint Constraint { get { return m_constraint; } } - public abstract ConstraintType Type { get; } - public bool IsEnabled { get { return m_enabled; } } - - public BSConstraint() - { - } - - public virtual void Dispose() - { - if (m_enabled) - { - m_enabled = false; - if (m_constraint.HasPhysicalConstraint) - { - bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); - m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", - BSScene.DetailLogZero, - m_body1.ID, m_body1.ptr.ToString(), - m_body2.ID, m_body2.ptr.ToString(), - success); - m_constraint.Clear(); - } - } - } - - public virtual bool SetLinearLimits(Vector3 low, Vector3 high) - { - bool ret = false; - if (m_enabled) - ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high); - return ret; - } - - public virtual bool SetAngularLimits(Vector3 low, Vector3 high) - { - bool ret = false; - if (m_enabled) - ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high); - return ret; - } - - public virtual bool SetSolverIterations(float cnt) - { - bool ret = false; - if (m_enabled) - { - BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt); - ret = true; - } - return ret; - } - - public virtual bool CalculateTransforms() - { - bool ret = false; - if (m_enabled) - { - // Recompute the internal transforms - BulletSimAPI.CalculateTransforms2(m_constraint.ptr); - ret = true; - } - return ret; - } - - // Reset this constraint making sure it has all its internal structures - // recomputed and is enabled and ready to go. - public virtual bool RecomputeConstraintVariables(float mass) - { - bool ret = false; - if (m_enabled) - { - ret = CalculateTransforms(); - if (ret) - { - // Setting an object's mass to zero (making it static like when it's selected) - // automatically disables the constraints. - // If the link is enabled, be sure to set the constraint itself to enabled. - BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, BSParam.NumericBool(true)); - } - else - { - m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID); - } - } - return ret; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs deleted file mode 100644 index d1e3f55..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ - -public sealed class BSConstraint6Dof : BSConstraint -{ - private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; - - public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } - - // Create a btGeneric6DofConstraint - public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frame1, Quaternion frame1rot, - Vector3 frame2, Quaternion frame2rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) - { - m_world = world; - m_body1 = obj1; - m_body2 = obj2; - m_constraint = new BulletConstraint( - BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, - frame1, frame1rot, - frame2, frame2rot, - useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); - m_enabled = true; - world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", - BSScene.DetailLogZero, world.worldID, - obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString()); - } - - public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 joinPoint, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) - { - m_world = world; - m_body1 = obj1; - m_body2 = obj2; - if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody) - { - world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", - BSScene.DetailLogZero, world.worldID, - obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString()); - world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", - LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString()); - m_enabled = false; - } - else - { - m_constraint = new BulletConstraint( - BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr, - joinPoint, - useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); - world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", - BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString(), - obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString()); - if (!m_constraint.HasPhysicalConstraint) - { - world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", - LogHeader, obj1.ID, obj2.ID); - m_enabled = false; - } - else - { - m_enabled = true; - } - } - } - - public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) - { - bool ret = false; - if (m_enabled) - { - BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); - ret = true; - } - return ret; - } - - public bool SetCFMAndERP(float cfm, float erp) - { - bool ret = false; - if (m_enabled) - { - BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); - BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); - BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); - ret = true; - } - return ret; - } - - public bool UseFrameOffset(bool useOffset) - { - bool ret = false; - float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; - if (m_enabled) - ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff); - return ret; - } - - public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce) - { - bool ret = false; - float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; - if (m_enabled) - { - ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce); - m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", - BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); - } - return ret; - } - - public bool SetBreakingImpulseThreshold(float threshold) - { - bool ret = false; - if (m_enabled) - ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold); - return ret; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs deleted file mode 100644 index 87d1e44..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using log4net; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ - -public sealed class BSConstraintCollection : IDisposable -{ - // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]"; - - delegate bool ConstraintAction(BSConstraint constrain); - - private List m_constraints; - private BulletWorld m_world; - - public BSConstraintCollection(BulletWorld world) - { - m_world = world; - m_constraints = new List(); - } - - public void Dispose() - { - this.Clear(); - } - - public void Clear() - { - lock (m_constraints) - { - foreach (BSConstraint cons in m_constraints) - { - cons.Dispose(); - } - m_constraints.Clear(); - } - } - - public bool AddConstraint(BSConstraint cons) - { - lock (m_constraints) - { - // There is only one constraint between any bodies. Remove any old just to make sure. - RemoveAndDestroyConstraint(cons.Body1, cons.Body2); - - m_constraints.Add(cons); - } - - return true; - } - - // Get the constraint between two bodies. There can be only one. - // Return 'true' if a constraint was found. - public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint) - { - bool found = false; - BSConstraint foundConstraint = null; - - uint lookingID1 = body1.ID; - uint lookingID2 = body2.ID; - lock (m_constraints) - { - foreach (BSConstraint constrain in m_constraints) - { - if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2) - || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1)) - { - foundConstraint = constrain; - found = true; - break; - } - } - } - returnConstraint = foundConstraint; - return found; - } - - // Remove any constraint between the passed bodies. - // Presumed there is only one such constraint possible. - // Return 'true' if a constraint was found and destroyed. - public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2) - { - bool ret = false; - lock (m_constraints) - { - BSConstraint constrain; - if (this.TryGetConstraint(body1, body2, out constrain)) - { - // remove the constraint from our collection - RemoveAndDestroyConstraint(constrain); - ret = true; - } - } - - return ret; - } - - // The constraint MUST exist in the collection - public bool RemoveAndDestroyConstraint(BSConstraint constrain) - { - lock (m_constraints) - { - // remove the constraint from our collection - m_constraints.Remove(constrain); - } - // tell the engine that all its structures need to be freed - constrain.Dispose(); - // we destroyed something - return true; - } - - // Remove all constraints that reference the passed body. - // Return 'true' if any constraints were destroyed. - public bool RemoveAndDestroyConstraint(BulletBody body1) - { - List toRemove = new List(); - uint lookingID = body1.ID; - lock (m_constraints) - { - foreach (BSConstraint constrain in m_constraints) - { - if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID) - { - toRemove.Add(constrain); - } - } - foreach (BSConstraint constrain in toRemove) - { - m_constraints.Remove(constrain); - constrain.Dispose(); - } - } - return (toRemove.Count > 0); - } - - public bool RecalculateAllConstraints() - { - bool ret = false; - lock (m_constraints) - { - foreach (BSConstraint constrain in m_constraints) - { - constrain.CalculateTransforms(); - ret = true; - } - } - return ret; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs deleted file mode 100644 index fbd1bc0..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ - -public sealed class BSConstraintHinge : BSConstraint -{ - public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } - - public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 pivotInA, Vector3 pivotInB, - Vector3 axisInA, Vector3 axisInB, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) - { - m_world = world; - m_body1 = obj1; - m_body2 = obj2; - m_constraint = new BulletConstraint( - BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, - pivotInA, pivotInB, - axisInA, axisInB, - useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); - m_enabled = true; - } - -} - -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs deleted file mode 100644 index 415ad4f..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs +++ /dev/null @@ -1,1377 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial - * are Copyright (c) 2009 Linden Research, Inc and are used under their license - * of Creative Commons Attribution-Share Alike 3.0 - * (http://creativecommons.org/licenses/by-sa/3.0/). - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using OpenMetaverse; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ - public sealed class BSDynamics - { - private static string LogHeader = "[BULLETSIM VEHICLE]"; - - private BSScene PhysicsScene { get; set; } - // the prim this dynamic controller belongs to - private BSPrim Prim { get; set; } - - // mass of the vehicle fetched each time we're calles - private float m_vehicleMass; - - // Vehicle properties - public Vehicle Type { get; set; } - - // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier - private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: - // HOVER_TERRAIN_ONLY - // HOVER_GLOBAL_HEIGHT - // NO_DEFLECTION_UP - // HOVER_WATER_ONLY - // HOVER_UP_ONLY - // LIMIT_MOTOR_UP - // LIMIT_ROLL_ONLY - private Vector3 m_BlockingEndPoint = Vector3.Zero; - private Quaternion m_RollreferenceFrame = Quaternion.Identity; - private Quaternion m_referenceFrame = Quaternion.Identity; - - // Linear properties - private BSVMotor m_linearMotor = new BSVMotor("LinearMotor"); - private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time - private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center - private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL - private Vector3 m_linearFrictionTimescale = Vector3.Zero; - private float m_linearMotorDecayTimescale = 0; - private float m_linearMotorTimescale = 0; - private Vector3 m_lastLinearVelocityVector = Vector3.Zero; - private Vector3 m_lastPositionVector = Vector3.Zero; - // private bool m_LinearMotorSetLastFrame = false; - // private Vector3 m_linearMotorOffset = Vector3.Zero; - - //Angular properties - private BSVMotor m_angularMotor = new BSVMotor("AngularMotor"); - private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor - // private int m_angularMotorApply = 0; // application frame counter - private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity - private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate - private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate - private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate - private Vector3 m_lastAngularVelocity = Vector3.Zero; - private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body - - //Deflection properties - private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection"); - private float m_angularDeflectionEfficiency = 0; - private float m_angularDeflectionTimescale = 0; - private float m_linearDeflectionEfficiency = 0; - private float m_linearDeflectionTimescale = 0; - - //Banking properties - private float m_bankingEfficiency = 0; - private float m_bankingMix = 0; - private float m_bankingTimescale = 0; - - //Hover and Buoyancy properties - private BSVMotor m_hoverMotor = new BSVMotor("Hover"); - private float m_VhoverHeight = 0f; - private float m_VhoverEfficiency = 0f; - private float m_VhoverTimescale = 0f; - private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height - private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. - // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) - // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. - // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. - - //Attractor properties - private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); - private float m_verticalAttractionEfficiency = 1.0f; // damped - private float m_verticalAttractionCutoff = 500f; // per the documentation - // Timescale > cutoff means no vert attractor. - private float m_verticalAttractionTimescale = 510f; - - // Just some recomputed constants: - static readonly float PIOverFour = ((float)Math.PI) / 4f; - static readonly float PIOverTwo = ((float)Math.PI) / 2f; - - public BSDynamics(BSScene myScene, BSPrim myPrim) - { - PhysicsScene = myScene; - Prim = myPrim; - Type = Vehicle.TYPE_NONE; - } - - // Return 'true' if this vehicle is doing vehicle things - public bool IsActive - { - get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; } - } - - internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) - { - VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); - switch (pParam) - { - case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: - m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); - break; - case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: - m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); - break; - case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: - m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); - m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; - break; - case Vehicle.ANGULAR_MOTOR_TIMESCALE: - m_angularMotorTimescale = Math.Max(pValue, 0.01f); - m_angularMotor.TimeScale = m_angularMotorTimescale; - break; - case Vehicle.BANKING_EFFICIENCY: - m_bankingEfficiency = ClampInRange(-1f, pValue, 1f); - break; - case Vehicle.BANKING_MIX: - m_bankingMix = Math.Max(pValue, 0.01f); - break; - case Vehicle.BANKING_TIMESCALE: - m_bankingTimescale = Math.Max(pValue, 0.01f); - break; - case Vehicle.BUOYANCY: - m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); - break; - case Vehicle.HOVER_EFFICIENCY: - m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); - break; - case Vehicle.HOVER_HEIGHT: - m_VhoverHeight = pValue; - break; - case Vehicle.HOVER_TIMESCALE: - m_VhoverTimescale = Math.Max(pValue, 0.01f); - break; - case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: - m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); - break; - case Vehicle.LINEAR_DEFLECTION_TIMESCALE: - m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); - break; - case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: - m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); - m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; - break; - case Vehicle.LINEAR_MOTOR_TIMESCALE: - m_linearMotorTimescale = Math.Max(pValue, 0.01f); - m_linearMotor.TimeScale = m_linearMotorTimescale; - break; - case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: - m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f); - m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; - break; - case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: - m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); - m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale; - break; - - // These are vector properties but the engine lets you use a single float value to - // set all of the components to the same value - case Vehicle.ANGULAR_FRICTION_TIMESCALE: - m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); - m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; - break; - case Vehicle.ANGULAR_MOTOR_DIRECTION: - m_angularMotorDirection = new Vector3(pValue, pValue, pValue); - m_angularMotor.SetTarget(m_angularMotorDirection); - break; - case Vehicle.LINEAR_FRICTION_TIMESCALE: - m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); - m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; - break; - case Vehicle.LINEAR_MOTOR_DIRECTION: - m_linearMotorDirection = new Vector3(pValue, pValue, pValue); - m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); - m_linearMotor.SetTarget(m_linearMotorDirection); - break; - case Vehicle.LINEAR_MOTOR_OFFSET: - m_linearMotorOffset = new Vector3(pValue, pValue, pValue); - break; - - } - }//end ProcessFloatVehicleParam - - internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) - { - VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); - switch (pParam) - { - case Vehicle.ANGULAR_FRICTION_TIMESCALE: - m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; - break; - case Vehicle.ANGULAR_MOTOR_DIRECTION: - // Limit requested angular speed to 2 rps= 4 pi rads/sec - pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f); - pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); - pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); - m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_angularMotor.SetTarget(m_angularMotorDirection); - break; - case Vehicle.LINEAR_FRICTION_TIMESCALE: - m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; - break; - case Vehicle.LINEAR_MOTOR_DIRECTION: - m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_linearMotor.SetTarget(m_linearMotorDirection); - break; - case Vehicle.LINEAR_MOTOR_OFFSET: - m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - case Vehicle.BLOCK_EXIT: - m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - } - }//end ProcessVectorVehicleParam - - internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) - { - VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); - switch (pParam) - { - case Vehicle.REFERENCE_FRAME: - m_referenceFrame = pValue; - break; - case Vehicle.ROLL_FRAME: - m_RollreferenceFrame = pValue; - break; - } - }//end ProcessRotationVehicleParam - - internal void ProcessVehicleFlags(int pParam, bool remove) - { - VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); - VehicleFlag parm = (VehicleFlag)pParam; - if (pParam == -1) - m_flags = (VehicleFlag)0; - else - { - if (remove) - m_flags &= ~parm; - else - m_flags |= parm; - } - } - - internal void ProcessTypeChange(Vehicle pType) - { - VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); - // Set Defaults For Type - Type = pType; - switch (pType) - { - case Vehicle.TYPE_NONE: - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 0; - m_linearMotorDecayTimescale = 0; - m_linearFrictionTimescale = new Vector3(0, 0, 0); - - m_angularMotorDirection = Vector3.Zero; - m_angularMotorDecayTimescale = 0; - m_angularMotorTimescale = 0; - m_angularFrictionTimescale = new Vector3(0, 0, 0); - - m_VhoverHeight = 0; - m_VhoverEfficiency = 0; - m_VhoverTimescale = 0; - m_VehicleBuoyancy = 0; - - m_linearDeflectionEfficiency = 1; - m_linearDeflectionTimescale = 1; - - m_angularDeflectionEfficiency = 0; - m_angularDeflectionTimescale = 1000; - - m_verticalAttractionEfficiency = 0; - m_verticalAttractionTimescale = 0; - - m_bankingEfficiency = 0; - m_bankingTimescale = 1000; - m_bankingMix = 1; - - m_referenceFrame = Quaternion.Identity; - m_flags = (VehicleFlag)0; - - break; - - case Vehicle.TYPE_SLED: - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 1000; - m_linearMotorDecayTimescale = 120; - m_linearFrictionTimescale = new Vector3(30, 1, 1000); - - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 1000; - m_angularMotorDecayTimescale = 120; - m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); - - m_VhoverHeight = 0; - m_VhoverEfficiency = 10; // TODO: this looks wrong!! - m_VhoverTimescale = 10; - m_VehicleBuoyancy = 0; - - m_linearDeflectionEfficiency = 1; - m_linearDeflectionTimescale = 1; - - m_angularDeflectionEfficiency = 1; - m_angularDeflectionTimescale = 1000; - - m_verticalAttractionEfficiency = 0; - m_verticalAttractionTimescale = 0; - - m_bankingEfficiency = 0; - m_bankingTimescale = 10; - m_bankingMix = 1; - - m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY - | VehicleFlag.HOVER_TERRAIN_ONLY - | VehicleFlag.HOVER_GLOBAL_HEIGHT - | VehicleFlag.HOVER_UP_ONLY); - m_flags |= (VehicleFlag.NO_DEFLECTION_UP - | VehicleFlag.LIMIT_ROLL_ONLY - | VehicleFlag.LIMIT_MOTOR_UP); - - break; - case Vehicle.TYPE_CAR: - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 1; - m_linearMotorDecayTimescale = 60; - m_linearFrictionTimescale = new Vector3(100, 2, 1000); - - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 1; - m_angularMotorDecayTimescale = 0.8f; - m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); - - m_VhoverHeight = 0; - m_VhoverEfficiency = 0; - m_VhoverTimescale = 1000; - m_VehicleBuoyancy = 0; - - m_linearDeflectionEfficiency = 1; - m_linearDeflectionTimescale = 2; - - m_angularDeflectionEfficiency = 0; - m_angularDeflectionTimescale = 10; - - m_verticalAttractionEfficiency = 1f; - m_verticalAttractionTimescale = 10f; - - m_bankingEfficiency = -0.2f; - m_bankingMix = 1; - m_bankingTimescale = 1; - - m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY - | VehicleFlag.HOVER_TERRAIN_ONLY - | VehicleFlag.HOVER_GLOBAL_HEIGHT); - m_flags |= (VehicleFlag.NO_DEFLECTION_UP - | VehicleFlag.LIMIT_ROLL_ONLY - | VehicleFlag.LIMIT_MOTOR_UP - | VehicleFlag.HOVER_UP_ONLY); - break; - case Vehicle.TYPE_BOAT: - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 5; - m_linearMotorDecayTimescale = 60; - m_linearFrictionTimescale = new Vector3(10, 3, 2); - - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 4; - m_angularMotorDecayTimescale = 4; - m_angularFrictionTimescale = new Vector3(10,10,10); - - m_VhoverHeight = 0; - m_VhoverEfficiency = 0.5f; - m_VhoverTimescale = 2; - m_VehicleBuoyancy = 1; - - m_linearDeflectionEfficiency = 0.5f; - m_linearDeflectionTimescale = 3; - - m_angularDeflectionEfficiency = 0.5f; - m_angularDeflectionTimescale = 5; - - m_verticalAttractionEfficiency = 0.5f; - m_verticalAttractionTimescale = 5f; - - m_bankingEfficiency = -0.3f; - m_bankingMix = 0.8f; - m_bankingTimescale = 1; - - m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY - | VehicleFlag.HOVER_GLOBAL_HEIGHT - | VehicleFlag.LIMIT_ROLL_ONLY - | VehicleFlag.HOVER_UP_ONLY); - m_flags |= (VehicleFlag.NO_DEFLECTION_UP - | VehicleFlag.LIMIT_MOTOR_UP - | VehicleFlag.HOVER_WATER_ONLY); - break; - case Vehicle.TYPE_AIRPLANE: - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 2; - m_linearMotorDecayTimescale = 60; - m_linearFrictionTimescale = new Vector3(200, 10, 5); - - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 4; - m_angularMotorDecayTimescale = 4; - m_angularFrictionTimescale = new Vector3(20, 20, 20); - - m_VhoverHeight = 0; - m_VhoverEfficiency = 0.5f; - m_VhoverTimescale = 1000; - m_VehicleBuoyancy = 0; - - m_linearDeflectionEfficiency = 0.5f; - m_linearDeflectionTimescale = 3; - - m_angularDeflectionEfficiency = 1; - m_angularDeflectionTimescale = 2; - - m_verticalAttractionEfficiency = 0.9f; - m_verticalAttractionTimescale = 2f; - - m_bankingEfficiency = 1; - m_bankingMix = 0.7f; - m_bankingTimescale = 2; - - m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY - | VehicleFlag.HOVER_TERRAIN_ONLY - | VehicleFlag.HOVER_GLOBAL_HEIGHT - | VehicleFlag.HOVER_UP_ONLY - | VehicleFlag.NO_DEFLECTION_UP - | VehicleFlag.LIMIT_MOTOR_UP); - m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); - break; - case Vehicle.TYPE_BALLOON: - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 5; - m_linearFrictionTimescale = new Vector3(5, 5, 5); - m_linearMotorDecayTimescale = 60; - - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 6; - m_angularFrictionTimescale = new Vector3(10, 10, 10); - m_angularMotorDecayTimescale = 10; - - m_VhoverHeight = 5; - m_VhoverEfficiency = 0.8f; - m_VhoverTimescale = 10; - m_VehicleBuoyancy = 1; - - m_linearDeflectionEfficiency = 0; - m_linearDeflectionTimescale = 5; - - m_angularDeflectionEfficiency = 0; - m_angularDeflectionTimescale = 5; - - m_verticalAttractionEfficiency = 1f; - m_verticalAttractionTimescale = 100f; - - m_bankingEfficiency = 0; - m_bankingMix = 0.7f; - m_bankingTimescale = 5; - - m_referenceFrame = Quaternion.Identity; - - m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY - | VehicleFlag.HOVER_TERRAIN_ONLY - | VehicleFlag.HOVER_UP_ONLY - | VehicleFlag.NO_DEFLECTION_UP - | VehicleFlag.LIMIT_MOTOR_UP); - m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY - | VehicleFlag.HOVER_GLOBAL_HEIGHT); - break; - } - - // Update any physical parameters based on this type. - Refresh(); - - m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, - m_linearMotorDecayTimescale, m_linearFrictionTimescale, - 1f); - m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) - - m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, - m_angularMotorDecayTimescale, m_angularFrictionTimescale, - 1f); - m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) - - m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, - BSMotor.Infinite, BSMotor.InfiniteVector, - m_verticalAttractionEfficiency); - // Z goes away and we keep X and Y - m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f); - m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) - } - - // Some of the properties of this prim may have changed. - // Do any updating needed for a vehicle - public void Refresh() - { - if (IsActive) - { - // Remember the mass so we don't have to fetch it every step - m_vehicleMass = Prim.Linkset.LinksetMass; - - // Friction affects are handled by this vehicle code - float friction = 0f; - BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction); - - // Moderate angular movement introduced by Bullet. - // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. - // Maybe compute linear and angular factor and damping from params. - float angularDamping = BSParam.VehicleAngularDamping; - BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); - - // Vehicles report collision events so we know when it's on the ground - BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); - - Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass); - BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); - BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr); - - Vector3 grav = PhysicsScene.DefaultGravity * (1f - Prim.Buoyancy); - BulletSimAPI.SetGravity2(Prim.PhysBody.ptr, grav); - - VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}", - Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping); - } - else - { - BulletSimAPI.RemoveFromCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); - } - } - - public bool RemoveBodyDependencies(BSPhysObject prim) - { - // If active, we need to add our properties back when the body is rebuilt. - return IsActive; - } - - public void RestoreBodyDependencies(BSPhysObject prim) - { - if (Prim.LocalID != prim.LocalID) - { - // The call should be on us by our prim. Error if not. - PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}", - LogHeader, prim.LocalID, Prim.LocalID); - return; - } - Refresh(); - } - - #region Known vehicle value functions - // Vehicle physical parameters that we buffer from constant getting and setting. - // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set. - // Changing is remembered and the parameter is stored back into the physics engine only if updated. - // This does two things: 1) saves continuious calls into unmanaged code, and - // 2) signals when a physics property update must happen back to the simulator - // to update values modified for the vehicle. - private int m_knownChanged; - private int m_knownHas; - private float m_knownTerrainHeight; - private float m_knownWaterLevel; - private Vector3 m_knownPosition; - private Vector3 m_knownVelocity; - private Vector3 m_knownForce; - private Quaternion m_knownOrientation; - private Vector3 m_knownRotationalVelocity; - private Vector3 m_knownRotationalForce; - private Vector3 m_knownForwardVelocity; // vehicle relative forward speed - - private const int m_knownChangedPosition = 1 << 0; - private const int m_knownChangedVelocity = 1 << 1; - private const int m_knownChangedForce = 1 << 2; - private const int m_knownChangedOrientation = 1 << 3; - private const int m_knownChangedRotationalVelocity = 1 << 4; - private const int m_knownChangedRotationalForce = 1 << 5; - private const int m_knownChangedTerrainHeight = 1 << 6; - private const int m_knownChangedWaterLevel = 1 << 7; - private const int m_knownChangedForwardVelocity = 1 << 8; - - private void ForgetKnownVehicleProperties() - { - m_knownHas = 0; - m_knownChanged = 0; - } - // Push all the changed values back into the physics engine - private void PushKnownChanged() - { - if (m_knownChanged != 0) - { - if ((m_knownChanged & m_knownChangedPosition) != 0) - Prim.ForcePosition = m_knownPosition; - - if ((m_knownChanged & m_knownChangedOrientation) != 0) - Prim.ForceOrientation = m_knownOrientation; - - if ((m_knownChanged & m_knownChangedVelocity) != 0) - { - Prim.ForceVelocity = m_knownVelocity; - BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity); - } - - if ((m_knownChanged & m_knownChangedForce) != 0) - Prim.AddForce((Vector3)m_knownForce, false, true); - - if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) - { - Prim.ForceRotationalVelocity = m_knownRotationalVelocity; - // Fake out Bullet by making it think the velocity is the same as last time. - BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, m_knownRotationalVelocity); - } - - if ((m_knownChanged & m_knownChangedRotationalForce) != 0) - Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true); - - // If we set one of the values (ie, the physics engine didn't do it) we must force - // an UpdateProperties event to send the changes up to the simulator. - BulletSimAPI.PushUpdate2(Prim.PhysBody.ptr); - } - m_knownChanged = 0; - } - - // Since the computation of terrain height can be a little involved, this routine - // is used to fetch the height only once for each vehicle simulation step. - private float GetTerrainHeight(Vector3 pos) - { - if ((m_knownHas & m_knownChangedTerrainHeight) == 0) - { - m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); - m_knownHas |= m_knownChangedTerrainHeight; - } - return m_knownTerrainHeight; - } - - // Since the computation of water level can be a little involved, this routine - // is used ot fetch the level only once for each vehicle simulation step. - private float GetWaterLevel(Vector3 pos) - { - if ((m_knownHas & m_knownChangedWaterLevel) == 0) - { - m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); - m_knownHas |= m_knownChangedWaterLevel; - } - return (float)m_knownWaterLevel; - } - - private Vector3 VehiclePosition - { - get - { - if ((m_knownHas & m_knownChangedPosition) == 0) - { - m_knownPosition = Prim.ForcePosition; - m_knownHas |= m_knownChangedPosition; - } - return m_knownPosition; - } - set - { - m_knownPosition = value; - m_knownChanged |= m_knownChangedPosition; - m_knownHas |= m_knownChangedPosition; - } - } - - private Quaternion VehicleOrientation - { - get - { - if ((m_knownHas & m_knownChangedOrientation) == 0) - { - m_knownOrientation = Prim.ForceOrientation; - m_knownHas |= m_knownChangedOrientation; - } - return m_knownOrientation; - } - set - { - m_knownOrientation = value; - m_knownChanged |= m_knownChangedOrientation; - m_knownHas |= m_knownChangedOrientation; - } - } - - private Vector3 VehicleVelocity - { - get - { - if ((m_knownHas & m_knownChangedVelocity) == 0) - { - m_knownVelocity = Prim.ForceVelocity; - m_knownHas |= m_knownChangedVelocity; - } - return (Vector3)m_knownVelocity; - } - set - { - m_knownVelocity = value; - m_knownChanged |= m_knownChangedVelocity; - m_knownHas |= m_knownChangedVelocity; - } - } - - private void VehicleAddForce(Vector3 aForce) - { - if ((m_knownHas & m_knownChangedForce) == 0) - { - m_knownForce = Vector3.Zero; - } - m_knownForce += aForce; - m_knownChanged |= m_knownChangedForce; - m_knownHas |= m_knownChangedForce; - } - - private Vector3 VehicleRotationalVelocity - { - get - { - if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) - { - m_knownRotationalVelocity = Prim.ForceRotationalVelocity; - m_knownHas |= m_knownChangedRotationalVelocity; - } - return (Vector3)m_knownRotationalVelocity; - } - set - { - m_knownRotationalVelocity = value; - m_knownChanged |= m_knownChangedRotationalVelocity; - m_knownHas |= m_knownChangedRotationalVelocity; - } - } - private void VehicleAddAngularForce(Vector3 aForce) - { - if ((m_knownHas & m_knownChangedRotationalForce) == 0) - { - m_knownRotationalForce = Vector3.Zero; - } - m_knownRotationalForce += aForce; - m_knownChanged |= m_knownChangedRotationalForce; - m_knownHas |= m_knownChangedRotationalForce; - } - // Vehicle relative forward velocity - private Vector3 VehicleForwardVelocity - { - get - { - if ((m_knownHas & m_knownChangedForwardVelocity) == 0) - { - m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); - m_knownHas |= m_knownChangedForwardVelocity; - } - return m_knownForwardVelocity; - } - } - private float VehicleForwardSpeed - { - get - { - return VehicleForwardVelocity.X; - } - } - - #endregion // Known vehicle value functions - - // One step of the vehicle properties for the next 'pTimestep' seconds. - internal void Step(float pTimestep) - { - if (!IsActive) return; - - ForgetKnownVehicleProperties(); - - MoveLinear(pTimestep); - MoveAngular(pTimestep); - - LimitRotation(pTimestep); - - // remember the position so next step we can limit absolute movement effects - m_lastPositionVector = VehiclePosition; - - // If we forced the changing of some vehicle parameters, update the values and - // for the physics engine to note the changes so an UpdateProperties event will happen. - PushKnownChanged(); - - VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", - Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity); - } - - // Apply the effect of the linear motor and other linear motions (like hover and float). - private void MoveLinear(float pTimestep) - { - Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); - - // The movement computed in the linear motor is relative to the vehicle - // coordinates. Rotate the movement to world coordinates. - linearMotorContribution *= VehicleOrientation; - - // ================================================================== - // Buoyancy: force to overcome gravity. - // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; - // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity. - Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy; - - Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep); - - Vector3 hoverContribution = ComputeLinearHover(pTimestep); - - ComputeLinearBlockingEndPoint(pTimestep); - - Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep); - - // ================================================================== - Vector3 newVelocity = linearMotorContribution - + terrainHeightContribution - + hoverContribution - + limitMotorUpContribution; - - Vector3 newForce = buoyancyContribution; - - // If not changing some axis, reduce out velocity - if ((m_flags & (VehicleFlag.NO_X)) != 0) - newVelocity.X = 0; - if ((m_flags & (VehicleFlag.NO_Y)) != 0) - newVelocity.Y = 0; - if ((m_flags & (VehicleFlag.NO_Z)) != 0) - newVelocity.Z = 0; - - // ================================================================== - // Clamp high or low velocities - float newVelocityLengthSq = newVelocity.LengthSquared(); - if (newVelocityLengthSq > 1000f) - { - newVelocity /= newVelocity.Length(); - newVelocity *= 1000f; - } - else if (newVelocityLengthSq < 0.001f) - newVelocity = Vector3.Zero; - - // ================================================================== - // Stuff new linear velocity into the vehicle. - // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us. - VehicleVelocity = newVelocity; - - // Other linear forces are applied as forces. - Vector3 totalDownForce = newForce * m_vehicleMass; - if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f)) - { - VehicleAddForce(totalDownForce); - } - - VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}", - Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding); - VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}", - Prim.LocalID, - linearMotorContribution, terrainHeightContribution, hoverContribution, - limitMotorUpContribution, buoyancyContribution - ); - - } // end MoveLinear() - - public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep) - { - Vector3 ret = Vector3.Zero; - // If below the terrain, move us above the ground a little. - // TODO: Consider taking the rotated size of the object or possibly casting a ray. - if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) - { - // TODO: correct position by applying force rather than forcing position. - Vector3 newPosition = VehiclePosition; - newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; - VehiclePosition = newPosition; - VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", - Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); - } - return ret; - } - - public Vector3 ComputeLinearHover(float pTimestep) - { - Vector3 ret = Vector3.Zero; - - // m_VhoverEfficiency: 0=bouncy, 1=totally damped - // m_VhoverTimescale: time to achieve height - if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) - { - // We should hover, get the target height - if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) - { - m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight; - } - if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) - { - m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight; - } - if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) - { - m_VhoverTargetHeight = m_VhoverHeight; - } - - if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) - { - // If body is already heigher, use its height as target height - if (VehiclePosition.Z > m_VhoverTargetHeight) - m_VhoverTargetHeight = VehiclePosition.Z; - } - - if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) - { - if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) - { - Vector3 pos = VehiclePosition; - pos.Z = m_VhoverTargetHeight; - VehiclePosition = pos; - } - } - else - { - // Error is positive if below the target and negative if above. - float verticalError = m_VhoverTargetHeight - VehiclePosition.Z; - float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; - - // TODO: implement m_VhoverEfficiency correctly - if (Math.Abs(verticalError) > m_VhoverEfficiency) - { - ret = new Vector3(0f, 0f, verticalCorrectionVelocity); - } - } - - VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}", - Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight); - } - - return ret; - } - - public bool ComputeLinearBlockingEndPoint(float pTimestep) - { - bool changed = false; - - Vector3 pos = VehiclePosition; - Vector3 posChange = pos - m_lastPositionVector; - if (m_BlockingEndPoint != Vector3.Zero) - { - if (pos.X >= (m_BlockingEndPoint.X - (float)1)) - { - pos.X -= posChange.X + 1; - changed = true; - } - if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) - { - pos.Y -= posChange.Y + 1; - changed = true; - } - if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) - { - pos.Z -= posChange.Z + 1; - changed = true; - } - if (pos.X <= 0) - { - pos.X += posChange.X + 1; - changed = true; - } - if (pos.Y <= 0) - { - pos.Y += posChange.Y + 1; - changed = true; - } - if (changed) - { - VehiclePosition = pos; - VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", - Prim.LocalID, m_BlockingEndPoint, posChange, pos); - } - } - return changed; - } - - // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : - // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when - // used with conjunction with banking: the strength of the banking will decay when the - // vehicle no longer experiences collisions. The decay timescale is the same as - // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering - // when they are in mid jump. - // TODO: this code is wrong. Also, what should it do for boats (height from water)? - // This is just using the ground and a general collision check. Should really be using - // a downward raycast to find what is below. - public Vector3 ComputeLinearMotorUp(float pTimestep) - { - Vector3 ret = Vector3.Zero; - float distanceAboveGround = 0f; - - if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) - { - float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); - distanceAboveGround = VehiclePosition.Z - targetHeight; - // Not colliding if the vehicle is off the ground - if (!Prim.IsColliding) - { - // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); - ret = new Vector3(0, 0, -distanceAboveGround); - } - // TODO: this calculation is wrong. From the description at - // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce - // has a decay factor. This says this force should - // be computed with a motor. - // TODO: add interaction with banking. - } - VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", - Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); - return ret; - } - - // ======================================================================= - // ======================================================================= - // Apply the effect of the angular motor. - // The 'contribution' is how much angular correction velocity each function wants. - // All the contributions are added together and the resulting velocity is - // set directly on the vehicle. - private void MoveAngular(float pTimestep) - { - // The user wants this many radians per second angular change? - Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); - - // ================================================================== - // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : - // This flag prevents linear deflection parallel to world z-axis. This is useful - // for preventing ground vehicles with large linear deflection, like bumper cars, - // from climbing their linear deflection into the sky. - // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement - if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) - { - angularMotorContribution.X = 0f; - angularMotorContribution.Y = 0f; - VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution); - } - - Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(); - - Vector3 deflectionContribution = ComputeAngularDeflection(); - - Vector3 bankingContribution = ComputeAngularBanking(); - - // ================================================================== - m_lastVertAttractor = verticalAttractionContribution; - - m_lastAngularVelocity = angularMotorContribution - + verticalAttractionContribution - + deflectionContribution - + bankingContribution; - - // ================================================================== - // Apply the correction velocity. - // TODO: Should this be applied as an angular force (torque)? - if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) - { - VehicleRotationalVelocity = m_lastAngularVelocity; - - VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}", - Prim.LocalID, - angularMotorContribution, verticalAttractionContribution, - bankingContribution, deflectionContribution, - m_lastAngularVelocity - ); - } - else - { - // The vehicle is not adding anything angular wise. - VehicleRotationalVelocity = Vector3.Zero; - VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); - } - - // ================================================================== - //Offset section - if (m_linearMotorOffset != Vector3.Zero) - { - //Offset of linear velocity doesn't change the linear velocity, - // but causes a torque to be applied, for example... - // - // IIIII >>> IIIII - // IIIII >>> IIIII - // IIIII >>> IIIII - // ^ - // | Applying a force at the arrow will cause the object to move forward, but also rotate - // - // - // The torque created is the linear velocity crossed with the offset - - // TODO: this computation should be in the linear section - // because that is where we know the impulse being applied. - Vector3 torqueFromOffset = Vector3.Zero; - // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); - if (float.IsNaN(torqueFromOffset.X)) - torqueFromOffset.X = 0; - if (float.IsNaN(torqueFromOffset.Y)) - torqueFromOffset.Y = 0; - if (float.IsNaN(torqueFromOffset.Z)) - torqueFromOffset.Z = 0; - - VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); - VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); - } - - } - // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: - // Some vehicles, like boats, should always keep their up-side up. This can be done by - // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to - // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the - // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency, - // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An - // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an - // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. - public Vector3 ComputeAngularVerticalAttraction() - { - Vector3 ret = Vector3.Zero; - - // If vertical attaction timescale is reasonable - if (m_verticalAttractionTimescale < m_verticalAttractionCutoff) - { - // Take a vector pointing up and convert it from world to vehicle relative coords. - Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; - - // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) - // is now: - // leaning to one side: rotated around the X axis with the Y value going - // from zero (nearly straight up) to one (completely to the side)) or - // leaning front-to-back: rotated around the Y axis with the value of X being between - // zero and one. - // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. - - // Y error means needed rotation around X axis and visa versa. - // Since the error goes from zero to one, the asin is the corresponding angle. - ret.X = (float)Math.Asin(verticalError.Y); - // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) - ret.Y = -(float)Math.Asin(verticalError.X); - - // If verticalError.Z is negative, the vehicle is upside down. Add additional push. - if (verticalError.Z < 0f) - { - ret.X += PIOverFour; - ret.Y += PIOverFour; - } - - // 'ret' is now the necessary velocity to correct tilt in one second. - // Correction happens over a number of seconds. - Vector3 unscaledContrib = ret; - ret /= m_verticalAttractionTimescale; - - VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}", - Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret); - } - return ret; - } - - // Return the angular correction to correct the direction the vehicle is pointing to be - // the direction is should want to be pointing. - // The vehicle is moving in some direction and correct its orientation to it is pointing - // in that direction. - // TODO: implement reference frame. - public Vector3 ComputeAngularDeflection() - { - Vector3 ret = Vector3.Zero; - return ret; // DEBUG DEBUG DEBUG - // Disable angular deflection for the moment. - // Since angularMotorUp and angularDeflection are computed independently, they will calculate - // approximately the same X or Y correction. When added together (when contributions are combined) - // this creates an over-correction and then wabbling as the target is overshot. - // TODO: rethink how the different correction computations inter-relate. - - if (m_angularDeflectionEfficiency != 0) - { - // The direction the vehicle is moving - Vector3 movingDirection = VehicleVelocity; - movingDirection.Normalize(); - - // The direction the vehicle is pointing - Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; - pointingDirection.Normalize(); - - // The difference between what is and what should be. - Vector3 deflectionError = movingDirection - pointingDirection; - - // Don't try to correct very large errors (not our job) - if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f; - if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f; - if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f; - - // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); - - // Scale the correction by recovery timescale and efficiency - ret = (-deflectionError) * m_angularDeflectionEfficiency; - ret /= m_angularDeflectionTimescale; - - VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", - Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); - VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", - Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); - } - return ret; - } - - // Return an angular change to rotate the vehicle around the Z axis when the vehicle - // is tipped around the X axis. - // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: - // The vertical attractor feature must be enabled in order for the banking behavior to - // function. The way banking works is this: a rotation around the vehicle's roll-axis will - // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude - // of the yaw effect will be proportional to the - // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's - // velocity along its preferred axis of motion. - // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any - // positive rotation (by the right-hand rule) about the roll-axis will effect a - // (negative) torque around the yaw-axis, making it turn to the right--that is the - // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. - // Negating the banking coefficient will make it so that the vehicle leans to the - // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). - // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making - // banking vehicles do what you want rather than what the laws of physics allow. - // For example, consider a real motorcycle...it must be moving forward in order for - // it to turn while banking, however video-game motorcycles are often configured - // to turn in place when at a dead stop--because they are often easier to control - // that way using the limited interface of the keyboard or game controller. The - // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic - // banking by functioning as a slider between a banking that is correspondingly - // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the - // banking effect depends only on the vehicle's rotation about its roll-axis compared - // to "dynamic" where the banking is also proportional to its velocity along its - // roll-axis. Finding the best value of the "mixture" will probably require trial and error. - // The time it takes for the banking behavior to defeat a preexisting angular velocity about the - // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to - // bank quickly then give it a banking timescale of about a second or less, otherwise you can - // make a sluggish vehicle by giving it a timescale of several seconds. - public Vector3 ComputeAngularBanking() - { - Vector3 ret = Vector3.Zero; - - if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) - { - // This works by rotating a unit vector to the orientation of the vehicle. The - // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt - // up to one for full over). - Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation; - - // Figure out the yaw value for this much roll. - float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency; - // Keep the sign - if (rollComponents.Y < 0f) - turnComponent = -turnComponent; - - // TODO: there must be a better computation of the banking force. - float bankingTurnForce = turnComponent; - - // actual error = static turn error + dynamic turn error - float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed; - // TODO: the banking effect should not go to infinity but what to limit it to? - mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f); - - // Build the force vector to change rotation from what it is to what it should be - ret.Z = -mixedBankingError; - - // Don't do it all at once. - ret /= m_bankingTimescale; - - VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}", - Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret); - } - return ret; - } - - // This is from previous instantiations of XXXDynamics.cs. - // Applies roll reference frame. - // TODO: is this the right way to separate the code to do this operation? - // Should this be in MoveAngular()? - internal void LimitRotation(float timestep) - { - Quaternion rotq = VehicleOrientation; - Quaternion m_rot = rotq; - if (m_RollreferenceFrame != Quaternion.Identity) - { - if (rotq.X >= m_RollreferenceFrame.X) - { - m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); - } - if (rotq.Y >= m_RollreferenceFrame.Y) - { - m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); - } - if (rotq.X <= -m_RollreferenceFrame.X) - { - m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); - } - if (rotq.Y <= -m_RollreferenceFrame.Y) - { - m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); - } - } - if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) - { - m_rot.X = 0; - m_rot.Y = 0; - } - if (rotq != m_rot) - { - VehicleOrientation = m_rot; - VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); - } - - } - - private float ClampInRange(float low, float val, float high) - { - return Math.Max(low, Math.Min(val, high)); - // return Utils.Clamp(val, low, high); - } - - // Invoke the detailed logger and output something if it's enabled. - private void VDetailLog(string msg, params Object[] args) - { - if (Prim.PhysicsScene.VehicleLoggingEnabled) - Prim.PhysicsScene.DetailLog(msg, args); - } - } -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs deleted file mode 100644 index 845a113..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OMV = OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ - -// A BSPrim can get individual information about its linkedness attached -// to it through an instance of a subclass of LinksetInfo. -// Each type of linkset will define the information needed for its type. -public abstract class BSLinksetInfo -{ - public virtual void Clear() { } -} - -public abstract class BSLinkset -{ - // private static string LogHeader = "[BULLETSIM LINKSET]"; - - public enum LinksetImplementation - { - Constraint = 0, // linkset tied together with constraints - Compound = 1, // linkset tied together as a compound object - Manual = 2 // linkset tied together manually (code moves all the pieces) - } - // Create the correct type of linkset for this child - public static BSLinkset Factory(BSScene physScene, BSPhysObject parent) - { - BSLinkset ret = null; - - switch ((int)BSParam.LinksetImplementation) - { - case (int)LinksetImplementation.Constraint: - ret = new BSLinksetConstraints(physScene, parent); - break; - case (int)LinksetImplementation.Compound: - ret = new BSLinksetCompound(physScene, parent); - break; - case (int)LinksetImplementation.Manual: - // ret = new BSLinksetManual(physScene, parent); - break; - default: - ret = new BSLinksetCompound(physScene, parent); - break; - } - return ret; - } - - public BSPhysObject LinksetRoot { get; protected set; } - - public BSScene PhysicsScene { get; private set; } - - static int m_nextLinksetID = 1; - public int LinksetID { get; private set; } - - // The children under the root in this linkset. - protected HashSet m_children; - - // We lock the diddling of linkset classes to prevent any badness. - // This locks the modification of the instances of this class. Changes - // to the physical representation is done via the tainting mechenism. - protected object m_linksetActivityLock = new Object(); - - // Some linksets have a preferred physical shape. - // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. - public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) - { - return BSPhysicsShapeType.SHAPE_UNKNOWN; - } - - // We keep the prim's mass in the linkset structure since it could be dependent on other prims - public float LinksetMass { get; protected set; } - - public virtual bool LinksetIsColliding { get { return false; } } - - public OMV.Vector3 CenterOfMass - { - get { return ComputeLinksetCenterOfMass(); } - } - - public OMV.Vector3 GeometricCenter - { - get { return ComputeLinksetGeometricCenter(); } - } - - protected BSLinkset(BSScene scene, BSPhysObject parent) - { - // A simple linkset of one (no children) - LinksetID = m_nextLinksetID++; - // We create LOTS of linksets. - if (m_nextLinksetID <= 0) - m_nextLinksetID = 1; - PhysicsScene = scene; - LinksetRoot = parent; - m_children = new HashSet(); - LinksetMass = parent.RawMass; - Rebuilding = false; - } - - // Link to a linkset where the child knows the parent. - // Parent changing should not happen so do some sanity checking. - // We return the parent's linkset so the child can track its membership. - // Called at runtime. - public BSLinkset AddMeToLinkset(BSPhysObject child) - { - lock (m_linksetActivityLock) - { - // Don't add the root to its own linkset - if (!IsRoot(child)) - AddChildToLinkset(child); - LinksetMass = ComputeLinksetMass(); - } - return this; - } - - // Remove a child from a linkset. - // Returns a new linkset for the child which is a linkset of one (just the - // orphened child). - // Called at runtime. - public BSLinkset RemoveMeFromLinkset(BSPhysObject child) - { - lock (m_linksetActivityLock) - { - if (IsRoot(child)) - { - // Cannot remove the root from a linkset. - return this; - } - RemoveChildFromLinkset(child); - LinksetMass = ComputeLinksetMass(); - } - - // The child is down to a linkset of just itself - return BSLinkset.Factory(PhysicsScene, child); - } - - // Return 'true' if the passed object is the root object of this linkset - public bool IsRoot(BSPhysObject requestor) - { - return (requestor.LocalID == LinksetRoot.LocalID); - } - - public int NumberOfChildren { get { return m_children.Count; } } - - // Return 'true' if this linkset has any children (more than the root member) - public bool HasAnyChildren { get { return (m_children.Count > 0); } } - - // Return 'true' if this child is in this linkset - public bool HasChild(BSPhysObject child) - { - bool ret = false; - lock (m_linksetActivityLock) - { - ret = m_children.Contains(child); - /* Safer version but the above should work - foreach (BSPhysObject bp in m_children) - { - if (child.LocalID == bp.LocalID) - { - ret = true; - break; - } - } - */ - } - return ret; - } - - // Perform an action on each member of the linkset including root prim. - // Depends on the action on whether this should be done at taint time. - public delegate bool ForEachMemberAction(BSPhysObject obj); - public virtual bool ForEachMember(ForEachMemberAction action) - { - bool ret = false; - lock (m_linksetActivityLock) - { - action(LinksetRoot); - foreach (BSPhysObject po in m_children) - { - if (action(po)) - break; - } - } - return ret; - } - - // I am the root of a linkset and a new child is being added - // Called while LinkActivity is locked. - protected abstract void AddChildToLinkset(BSPhysObject child); - - // I am the root of a linkset and one of my children is being removed. - // Safe to call even if the child is not really in my linkset. - protected abstract void RemoveChildFromLinkset(BSPhysObject child); - - // When physical properties are changed the linkset needs to recalculate - // its internal properties. - // May be called at runtime or taint-time. - public virtual void Refresh(BSPhysObject requestor) - { - LinksetMass = ComputeLinksetMass(); - } - - // Flag denoting the linkset is in the process of being rebuilt. - // Used to know not the schedule a rebuild in the middle of a rebuild. - protected bool Rebuilding { get; set; } - - // The object is going dynamic (physical). Do any setup necessary - // for a dynamic linkset. - // Only the state of the passed object can be modified. The rest of the linkset - // has not yet been fully constructed. - // Return 'true' if any properties updated on the passed object. - // Called at taint-time! - public abstract bool MakeDynamic(BSPhysObject child); - - // The object is going static (non-physical). Do any setup necessary - // for a static linkset. - // Return 'true' if any properties updated on the passed object. - // Called at taint-time! - public abstract bool MakeStatic(BSPhysObject child); - - // Called when a parameter update comes from the physics engine for any object - // of the linkset is received. - // Passed flag is update came from physics engine (true) or the user (false). - // Called at taint-time!! - public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate); - - // Routine used when rebuilding the body of the root of the linkset - // Destroy all the constraints have have been made to root. - // This is called when the root body is changing. - // Returns 'true' of something was actually removed and would need restoring - // Called at taint-time!! - public abstract bool RemoveBodyDependencies(BSPrim child); - - // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', - // this routine will restore the removed constraints. - // Called at taint-time!! - public abstract void RestoreBodyDependencies(BSPrim child); - - // ================================================================ - protected virtual float ComputeLinksetMass() - { - float mass = LinksetRoot.RawMass; - if (HasAnyChildren) - { - lock (m_linksetActivityLock) - { - foreach (BSPhysObject bp in m_children) - { - mass += bp.RawMass; - } - } - } - return mass; - } - - protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() - { - OMV.Vector3 com; - lock (m_linksetActivityLock) - { - com = LinksetRoot.Position * LinksetRoot.RawMass; - float totalMass = LinksetRoot.RawMass; - - foreach (BSPhysObject bp in m_children) - { - com += bp.Position * bp.RawMass; - totalMass += bp.RawMass; - } - if (totalMass != 0f) - com /= totalMass; - } - - return com; - } - - protected virtual OMV.Vector3 ComputeLinksetGeometricCenter() - { - OMV.Vector3 com; - lock (m_linksetActivityLock) - { - com = LinksetRoot.Position; - - foreach (BSPhysObject bp in m_children) - { - com += bp.Position * bp.RawMass; - } - com /= (m_children.Count + 1); - } - - return com; - } - - // Invoke the detailed logger and output something if it's enabled. - protected void DetailLog(string msg, params Object[] args) - { - if (PhysicsScene.PhysicsLogging.Enabled) - PhysicsScene.DetailLog(msg, args); - } - -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs deleted file mode 100644 index 9a977e6..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OpenSim.Framework; - -using OMV = OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ - -// When a child is linked, the relationship position of the child to the parent -// is remembered so the child's world position can be recomputed when it is -// removed from the linkset. -sealed class BSLinksetCompoundInfo : BSLinksetInfo -{ - public OMV.Vector3 OffsetPos; - public OMV.Quaternion OffsetRot; - public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r) - { - OffsetPos = p; - OffsetRot = r; - } - public override void Clear() - { - OffsetPos = OMV.Vector3.Zero; - OffsetRot = OMV.Quaternion.Identity; - } - public override string ToString() - { - StringBuilder buff = new StringBuilder(); - buff.Append(""); - return buff.ToString(); - } -}; - -public sealed class BSLinksetCompound : BSLinkset -{ - private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; - - public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent) - { - } - - // For compound implimented linksets, if there are children, use compound shape for the root. - public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) - { - // Returning 'unknown' means we don't have a preference. - BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - if (IsRoot(requestor) && HasAnyChildren) - { - ret = BSPhysicsShapeType.SHAPE_COMPOUND; - } - // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); - return ret; - } - - // When physical properties are changed the linkset needs to recalculate - // its internal properties. - public override void Refresh(BSPhysObject requestor) - { - base.Refresh(requestor); - - // Something changed so do the rebuilding thing - // ScheduleRebuild(); - } - - // Schedule a refresh to happen after all the other taint processing. - private void ScheduleRebuild(BSPhysObject requestor) - { - DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1}", - requestor.LocalID, Rebuilding); - // When rebuilding, it is possible to set properties that would normally require a rebuild. - // If already rebuilding, don't request another rebuild. - if (!Rebuilding) - { - PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() - { - if (HasAnyChildren) - RecomputeLinksetCompound(); - }); - } - } - - // The object is going dynamic (physical). Do any setup necessary - // for a dynamic linkset. - // Only the state of the passed object can be modified. The rest of the linkset - // has not yet been fully constructed. - // Return 'true' if any properties updated on the passed object. - // Called at taint-time! - public override bool MakeDynamic(BSPhysObject child) - { - bool ret = false; - DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); - if (IsRoot(child)) - { - // The root is going dynamic. Make sure mass is properly set. - ScheduleRebuild(LinksetRoot); - } - else - { - // The origional prims are removed from the world as the shape of the root compound - // shape takes over. - BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); - BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); - // We don't want collisions from the old linkset children. - BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - - child.PhysBody.collisionType = CollisionType.LinksetChild; - - ret = true; - } - return ret; - } - - // The object is going static (non-physical). Do any setup necessary for a static linkset. - // Return 'true' if any properties updated on the passed object. - // This doesn't normally happen -- OpenSim removes the objects from the physical - // world if it is a static linkset. - // Called at taint-time! - public override bool MakeStatic(BSPhysObject child) - { - bool ret = false; - DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); - if (IsRoot(child)) - { - ScheduleRebuild(LinksetRoot); - } - else - { - // The non-physical children can come back to life. - BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); - - child.PhysBody.collisionType = CollisionType.LinksetChild; - - // Don't force activation so setting of DISABLE_SIMULATION can stay if used. - BulletSimAPI.Activate2(child.PhysBody.ptr, false); - ret = true; - } - return ret; - } - - public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate) - { - // The user moving a child around requires the rebuilding of the linkset compound shape - // One problem is this happens when a border is crossed -- the simulator implementation - // is to store the position into the group which causes the move of the object - // but it also means all the child positions get updated. - // What would cause an unnecessary rebuild so we make sure the linkset is in a - // region before bothering to do a rebuild. - if (!IsRoot(updated) - && !physicalUpdate - && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) - { - updated.LinksetInfo = null; - ScheduleRebuild(updated); - } - } - - // Routine called when rebuilding the body of some member of the linkset. - // Since we don't keep in world relationships, do nothing unless it's a child changing. - // Returns 'true' of something was actually removed and would need restoring - // Called at taint-time!! - public override bool RemoveBodyDependencies(BSPrim child) - { - bool ret = false; - - DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", - child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(), IsRoot(child)); - - if (!IsRoot(child)) - { - // Because it is a convenient time, recompute child world position and rotation based on - // its position in the linkset. - RecomputeChildWorldPosition(child, true); - } - - // Cannot schedule a refresh/rebuild here because this routine is called when - // the linkset is being rebuilt. - // InternalRefresh(LinksetRoot); - - return ret; - } - - // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', - // this routine will restore the removed constraints. - // Called at taint-time!! - public override void RestoreBodyDependencies(BSPrim child) - { - } - - // When the linkset is built, the child shape is added to the compound shape relative to the - // root shape. The linkset then moves around but this does not move the actual child - // prim. The child prim's location must be recomputed based on the location of the root shape. - private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime) - { - BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; - if (lci != null) - { - if (inTaintTime) - { - OMV.Vector3 oldPos = child.RawPosition; - child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos; - child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; - DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", - child.LocalID, oldPos, lci, child.RawPosition); - } - else - { - // TaintedObject is not used here so the raw position is set now and not at taint-time. - child.Position = LinksetRoot.RawPosition + lci.OffsetPos; - child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; - } - } - else - { - // This happens when children have been added to the linkset but the linkset - // has not been constructed yet. So like, at taint time, adding children to a linkset - // and then changing properties of the children (makePhysical, for instance) - // but the post-print action of actually rebuilding the linkset has not yet happened. - // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", - // LogHeader, child.LocalID); - DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); - } - } - - // ================================================================ - - // Add a new child to the linkset. - // Called while LinkActivity is locked. - protected override void AddChildToLinkset(BSPhysObject child) - { - if (!HasChild(child)) - { - m_children.Add(child); - - DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); - - // Rebuild the compound shape with the new child shape included - ScheduleRebuild(child); - } - return; - } - - // Remove the specified child from the linkset. - // Safe to call even if the child is not really in the linkset. - protected override void RemoveChildFromLinkset(BSPhysObject child) - { - if (m_children.Remove(child)) - { - DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", - child.LocalID, - LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(), - child.LocalID, child.PhysBody.ptr.ToString()); - - // Cause the child's body to be rebuilt and thus restored to normal operation - RecomputeChildWorldPosition(child, false); - child.ForceBodyShapeRebuild(false); - - if (!HasAnyChildren) - { - // The linkset is now empty. The root needs rebuilding. - LinksetRoot.ForceBodyShapeRebuild(false); - } - else - { - // Rebuild the compound shape with the child removed - ScheduleRebuild(child); - } - } - return; - } - - // Called before the simulation step to make sure the compound based linkset - // is all initialized. - // Constraint linksets are rebuilt every time. - // Note that this works for rebuilding just the root after a linkset is taken apart. - // Called at taint time!! - private void RecomputeLinksetCompound() - { - try - { - // Suppress rebuilding while rebuilding - Rebuilding = true; - - // Cause the root shape to be rebuilt as a compound object with just the root in it - LinksetRoot.ForceBodyShapeRebuild(true); - - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", - LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); - - // Add a shape for each of the other children in the linkset - ForEachMember(delegate(BSPhysObject cPrim) - { - if (!IsRoot(cPrim)) - { - // Compute the displacement of the child from the root of the linkset. - // This info is saved in the child prim so the relationship does not - // change over time and the new child position can be computed - // when the linkset is being disassembled (the linkset may have moved). - BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; - if (lci == null) - { - // Each child position and rotation is given relative to the root. - OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); - OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; - OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; - - // Save relative position for recomputing child's world position after moving linkset. - lci = new BSLinksetCompoundInfo(displacementPos, displacementRot); - cPrim.LinksetInfo = lci; - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci); - } - - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", - LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); - - if (cPrim.PhysShape.isNativeShape) - { - // A native shape is turning into a hull collision shape because native - // shapes are not shared so we have to hullify it so it will be tracked - // and freed at the correct time. This also solves the scaling problem - // (native shapes scaled but hull/meshes are assumed to not be). - // TODO: decide of the native shape can just be used in the compound shape. - // Use call to CreateGeomNonSpecial(). - BulletShape saveShape = cPrim.PhysShape; - cPrim.PhysShape.Clear(); // Don't let the create free the child's shape - // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null); - PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); - BulletShape newShape = cPrim.PhysShape; - cPrim.PhysShape = saveShape; - BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos, lci.OffsetRot); - } - else - { - // For the shared shapes (meshes and hulls), just use the shape in the child. - // The reference count added here will be decremented when the compound shape - // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). - if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) - { - PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", - LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); - } - BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos, lci.OffsetRot); - } - } - return false; // 'false' says to move onto the next child in the list - }); - - // With all of the linkset packed into the root prim, it has the mass of everyone. - LinksetMass = LinksetMass; - LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); - } - finally - { - Rebuilding = false; - } - - BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); - - // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. - // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, - // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); - - } -} -} \ No newline at end of file diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs deleted file mode 100644 index 46ff99f..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OMV = OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ -public sealed class BSLinksetConstraints : BSLinkset -{ - // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; - - public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent) - { - } - - // When physical properties are changed the linkset needs to recalculate - // its internal properties. - // This is queued in the 'post taint' queue so the - // refresh will happen once after all the other taints are applied. - public override void Refresh(BSPhysObject requestor) - { - base.Refresh(requestor); - - // Queue to happen after all the other taint processing - PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() - { - if (HasAnyChildren && IsRoot(requestor)) - RecomputeLinksetConstraints(); - }); - } - - // The object is going dynamic (physical). Do any setup necessary - // for a dynamic linkset. - // Only the state of the passed object can be modified. The rest of the linkset - // has not yet been fully constructed. - // Return 'true' if any properties updated on the passed object. - // Called at taint-time! - public override bool MakeDynamic(BSPhysObject child) - { - // What is done for each object in BSPrim is what we want. - return false; - } - - // The object is going static (non-physical). Do any setup necessary for a static linkset. - // Return 'true' if any properties updated on the passed object. - // This doesn't normally happen -- OpenSim removes the objects from the physical - // world if it is a static linkset. - // Called at taint-time! - public override bool MakeStatic(BSPhysObject child) - { - // What is done for each object in BSPrim is what we want. - return false; - } - - // Called at taint-time!! - public override void UpdateProperties(BSPhysObject updated, bool inTaintTime) - { - // Nothing to do for constraints on property updates - } - - // Routine called when rebuilding the body of some member of the linkset. - // Destroy all the constraints have have been made to root and set - // up to rebuild the constraints before the next simulation step. - // Returns 'true' of something was actually removed and would need restoring - // Called at taint-time!! - public override bool RemoveBodyDependencies(BSPrim child) - { - bool ret = false; - - DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", - child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString()); - - lock (m_linksetActivityLock) - { - // Just undo all the constraints for this linkset. Rebuild at the end of the step. - ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); - // Cause the constraints, et al to be rebuilt before the next simulation step. - Refresh(LinksetRoot); - } - return ret; - } - - // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', - // this routine will restore the removed constraints. - // Called at taint-time!! - public override void RestoreBodyDependencies(BSPrim child) - { - // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. - } - - // ================================================================ - - // Add a new child to the linkset. - // Called while LinkActivity is locked. - protected override void AddChildToLinkset(BSPhysObject child) - { - if (!HasChild(child)) - { - m_children.Add(child); - - DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); - - // Cause constraints and assorted properties to be recomputed before the next simulation step. - Refresh(LinksetRoot); - } - return; - } - - // Remove the specified child from the linkset. - // Safe to call even if the child is not really in my linkset. - protected override void RemoveChildFromLinkset(BSPhysObject child) - { - if (m_children.Remove(child)) - { - BSPhysObject rootx = LinksetRoot; // capture the root and body as of now - BSPhysObject childx = child; - - DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", - childx.LocalID, - rootx.LocalID, rootx.PhysBody.ptr.ToString(), - childx.LocalID, childx.PhysBody.ptr.ToString()); - - PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() - { - PhysicallyUnlinkAChildFromRoot(rootx, childx); - }); - // See that the linkset parameters are recomputed at the end of the taint time. - Refresh(LinksetRoot); - } - else - { - // Non-fatal occurance. - // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); - } - return; - } - - // Create a constraint between me (root of linkset) and the passed prim (the child). - // Called at taint time! - private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) - { - // Don't build the constraint when asked. Put it off until just before the simulation step. - Refresh(rootPrim); - } - - private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim) - { - // Zero motion for children so they don't interpolate - childPrim.ZeroMotion(true); - - // Relative position normalized to the root prim - // Essentually a vector pointing from center of rootPrim to center of childPrim - OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position; - - // real world coordinate of midpoint between the two objects - OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); - - DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", - rootPrim.LocalID, - rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString(), - childPrim.LocalID, childPrim.PhysBody.ptr.ToString(), - rootPrim.Position, childPrim.Position, midPoint); - - // create a constraint that allows no freedom of movement between the two objects - // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 - - BSConstraint6Dof constrain = new BSConstraint6Dof( - PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); - // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); - - /* NOTE: below is an attempt to build constraint with full frame computation, etc. - * Using the midpoint is easier since it lets the Bullet code manipulate the transforms - * of the objects. - * Code left for future programmers. - // ================================================================================== - // relative position normalized to the root prim - OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); - OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation; - - // relative rotation of the child to the parent - OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; - OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); - - DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); - BS6DofConstraint constrain = new BS6DofConstraint( - PhysicsScene.World, rootPrim.Body, childPrim.Body, - OMV.Vector3.Zero, - OMV.Quaternion.Inverse(rootPrim.Orientation), - OMV.Vector3.Zero, - OMV.Quaternion.Inverse(childPrim.Orientation), - true, - true - ); - // ================================================================================== - */ - - PhysicsScene.Constraints.AddConstraint(constrain); - - // zero linear and angular limits makes the objects unable to move in relation to each other - constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); - constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); - - // tweek the constraint to increase stability - constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset)); - constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor), - BSParam.LinkConstraintTransMotorMaxVel, - BSParam.LinkConstraintTransMotorMaxForce); - constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP); - if (BSParam.LinkConstraintSolverIterations != 0f) - { - constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations); - } - return constrain; - } - - // Remove linkage between the linkset root and a particular child - // The root and child bodies are passed in because we need to remove the constraint between - // the bodies that were present at unlink time. - // Called at taint time! - private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) - { - bool ret = false; - DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", - rootPrim.LocalID, - rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString(), - childPrim.LocalID, childPrim.PhysBody.ptr.ToString()); - - // Find the constraint for this link and get rid of it from the overall collection and from my list - if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) - { - // Make the child refresh its location - BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr); - ret = true; - } - - return ret; - } - - // Remove linkage between myself and any possible children I might have. - // Returns 'true' of any constraints were destroyed. - // Called at taint time! - private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) - { - DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); - - return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); - } - - // Call each of the constraints that make up this linkset and recompute the - // various transforms and variables. Create constraints of not created yet. - // Called before the simulation step to make sure the constraint based linkset - // is all initialized. - // Called at taint time!! - private void RecomputeLinksetConstraints() - { - float linksetMass = LinksetMass; - LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true); - - // DEBUG: see of inter-linkset collisions are causing problems - // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, - // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); - DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", - LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(), linksetMass); - - foreach (BSPhysObject child in m_children) - { - // A child in the linkset physically shows the mass of the whole linkset. - // This allows Bullet to apply enough force on the child to move the whole linkset. - // (Also do the mass stuff before recomputing the constraint so mass is not zero.) - child.UpdatePhysicalMassProperties(linksetMass, true); - - BSConstraint constrain; - if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) - { - // If constraint doesn't exist yet, create it. - constrain = BuildConstraint(LinksetRoot, child); - } - constrain.RecomputeConstraintVariables(linksetMass); - - // DEBUG: see of inter-linkset collisions are causing problems - // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr, - // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); - - // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG - } - - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs deleted file mode 100644 index d7941b6..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using System.Reflection; -using Nini.Config; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ - -public struct MaterialAttributes -{ - // Material type values that correspond with definitions for LSL - public enum Material : int - { - Stone = 0, - Metal, - Glass, - Wood, - Flesh, - Plastic, - Rubber, - Light, - // Hereafter are BulletSim additions - Avatar, - NumberOfTypes // the count of types in the enum. - } - - // Names must be in the order of the above enum. - // These names must coorespond to the lower case field names in the MaterialAttributes - // structure as reflection is used to select the field to put the value in. - public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"}; - - public MaterialAttributes(string t, float d, float f, float r) - { - type = t; - density = d; - friction = f; - restitution = r; - } - public string type; - public float density; - public float friction; - public float restitution; -} - -public static class BSMaterials -{ - // Attributes for each material type - private static readonly MaterialAttributes[] Attributes; - - // Map of material name to material type code - public static readonly Dictionary MaterialMap; - - static BSMaterials() - { - // Attribute sets for both the non-physical and physical instances of materials. - Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; - - // Map of name to type code. - MaterialMap = new Dictionary(); - MaterialMap.Add("Stone", MaterialAttributes.Material.Stone); - MaterialMap.Add("Metal", MaterialAttributes.Material.Metal); - MaterialMap.Add("Glass", MaterialAttributes.Material.Glass); - MaterialMap.Add("Wood", MaterialAttributes.Material.Wood); - MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh); - MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic); - MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber); - MaterialMap.Add("Light", MaterialAttributes.Material.Light); - MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar); - } - - // This is where all the default material attributes are defined. - public static void InitializeFromDefaults(ConfigurationParameters parms) - { - // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL - float dDensity = parms.defaultDensity; - float dFriction = parms.defaultFriction; - float dRestitution = parms.defaultRestitution; - Attributes[(int)MaterialAttributes.Material.Stone] = - new MaterialAttributes("stone",dDensity, 0.8f, 0.4f); - Attributes[(int)MaterialAttributes.Material.Metal] = - new MaterialAttributes("metal",dDensity, 0.3f, 0.4f); - Attributes[(int)MaterialAttributes.Material.Glass] = - new MaterialAttributes("glass",dDensity, 0.2f, 0.7f); - Attributes[(int)MaterialAttributes.Material.Wood] = - new MaterialAttributes("wood",dDensity, 0.6f, 0.5f); - Attributes[(int)MaterialAttributes.Material.Flesh] = - new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f); - Attributes[(int)MaterialAttributes.Material.Plastic] = - new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f); - Attributes[(int)MaterialAttributes.Material.Rubber] = - new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f); - Attributes[(int)MaterialAttributes.Material.Light] = - new MaterialAttributes("light",dDensity, dFriction, dRestitution); - Attributes[(int)MaterialAttributes.Material.Avatar] = - new MaterialAttributes("avatar",3.5f, 0.2f, 0f); - - Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f); - Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("metalPhysical",dDensity, 0.3f, 0.4f); - Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f); - Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f); - Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f); - Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f); - Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 0.9f); - Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution); - Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("avatarPhysical",3.5f, 0.2f, 0f); - } - - // Under the [BulletSim] section, one can change the individual material - // attribute values. The format of the configuration parameter is: - // ["Physical"] = floatValue - // For instance: - // [BulletSim] - // StoneFriction = 0.2 - // FleshRestitutionPhysical = 0.8 - // Materials can have different parameters for their static and - // physical instantiations. When setting the non-physical value, - // both values are changed. Setting the physical value only changes - // the physical value. - public static void InitializefromParameters(IConfig pConfig) - { - foreach (KeyValuePair kvp in MaterialMap) - { - string matName = kvp.Key; - foreach (string attribName in MaterialAttributes.MaterialAttribs) - { - string paramName = matName + attribName; - if (pConfig.Contains(paramName)) - { - float paramValue = pConfig.GetFloat(paramName); - SetAttributeValue((int)kvp.Value, attribName, paramValue); - // set the physical value also - SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); - } - paramName += "Physical"; - if (pConfig.Contains(paramName)) - { - float paramValue = pConfig.GetFloat(paramName); - SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); - } - } - } - } - - // Use reflection to set the value in the attribute structure. - private static void SetAttributeValue(int matType, string attribName, float val) - { - MaterialAttributes thisAttrib = Attributes[matType]; - FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); - if (fieldInfo != null) - { - fieldInfo.SetValue(thisAttrib, val); - Attributes[matType] = thisAttrib; - } - } - - // Given a material type, return a structure of attributes. - public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) - { - int ind = (int)type; - if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; - return Attributes[ind]; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs deleted file mode 100644 index 7abc9b2..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -using System; -using System.Collections.Generic; -using System.Text; -using OpenMetaverse; -using OpenSim.Framework; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ -public abstract class BSMotor -{ - // Timescales and other things can be turned off by setting them to 'infinite'. - public const float Infinite = 12345.6f; - public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); - - public BSMotor(string useName) - { - UseName = useName; - PhysicsScene = null; - Enabled = true; - } - public virtual bool Enabled { get; set; } - public virtual void Reset() { } - public virtual void Zero() { } - public virtual void GenerateTestOutput(float timeStep) { } - - // A name passed at motor creation for easily identifyable debugging messages. - public string UseName { get; private set; } - - // Used only for outputting debug information. Might not be set so check for null. - public BSScene PhysicsScene { get; set; } - protected void MDetailLog(string msg, params Object[] parms) - { - if (PhysicsScene != null) - { - if (PhysicsScene.VehicleLoggingEnabled) - { - PhysicsScene.DetailLog(msg, parms); - } - } - } -} - -// Motor which moves CurrentValue to TargetValue over TimeScale seconds. -// The TargetValue decays in TargetValueDecayTimeScale and -// the CurrentValue will be held back by FrictionTimeScale. -// This motor will "zero itself" over time in that the targetValue will -// decay to zero and the currentValue will follow it to that zero. -// The overall effect is for the returned correction value to go from large -// values (the total difference between current and target minus friction) -// to small and eventually zero values. -// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. - -// For instance, if something is moving at speed X and the desired speed is Y, -// CurrentValue is X and TargetValue is Y. As the motor is stepped, new -// values of CurrentValue are returned that approach the TargetValue. -// The feature of decaying TargetValue is so vehicles will eventually -// come to a stop rather than run forever. This can be disabled by -// setting TargetValueDecayTimescale to 'infinite'. -// The change from CurrentValue to TargetValue is linear over TimeScale seconds. -public class BSVMotor : BSMotor -{ - // public Vector3 FrameOfReference { get; set; } - // public Vector3 Offset { get; set; } - - public virtual float TimeScale { get; set; } - public virtual float TargetValueDecayTimeScale { get; set; } - public virtual Vector3 FrictionTimescale { get; set; } - public virtual float Efficiency { get; set; } - - public virtual float ErrorZeroThreshold { get; set; } - - public virtual Vector3 TargetValue { get; protected set; } - public virtual Vector3 CurrentValue { get; protected set; } - public virtual Vector3 LastError { get; protected set; } - - public virtual bool ErrorIsZero - { get { - return (LastError == Vector3.Zero || LastError.LengthSquared() <= ErrorZeroThreshold); - } - } - - public BSVMotor(string useName) - : base(useName) - { - TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; - Efficiency = 1f; - FrictionTimescale = BSMotor.InfiniteVector; - CurrentValue = TargetValue = Vector3.Zero; - ErrorZeroThreshold = 0.001f; - } - public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) - : this(useName) - { - TimeScale = timeScale; - TargetValueDecayTimeScale = decayTimeScale; - FrictionTimescale = frictionTimeScale; - Efficiency = efficiency; - CurrentValue = TargetValue = Vector3.Zero; - } - public void SetCurrent(Vector3 current) - { - CurrentValue = current; - } - public void SetTarget(Vector3 target) - { - TargetValue = target; - } - public override void Zero() - { - base.Zero(); - CurrentValue = TargetValue = Vector3.Zero; - } - - // Compute the next step and return the new current value - public virtual Vector3 Step(float timeStep) - { - if (!Enabled) return TargetValue; - - Vector3 origTarget = TargetValue; // DEBUG - Vector3 origCurrVal = CurrentValue; // DEBUG - - Vector3 correction = Vector3.Zero; - Vector3 error = TargetValue - CurrentValue; - if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) - { - correction = Step(timeStep, error); - - CurrentValue += correction; - - // The desired value reduces to zero which also reduces the difference with current. - // If the decay time is infinite, don't decay at all. - float decayFactor = 0f; - if (TargetValueDecayTimeScale != BSMotor.Infinite) - { - decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; - TargetValue *= (1f - decayFactor); - } - - // The amount we can correct the error is reduced by the friction - Vector3 frictionFactor = Vector3.Zero; - if (FrictionTimescale != BSMotor.InfiniteVector) - { - // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; - // Individual friction components can be 'infinite' so compute each separately. - frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X); - frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y); - frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z); - frictionFactor *= timeStep; - CurrentValue *= (Vector3.One - frictionFactor); - } - - MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", - BSScene.DetailLogZero, UseName, origCurrVal, origTarget, - timeStep, error, correction); - MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", - BSScene.DetailLogZero, UseName, - TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, - TargetValue, CurrentValue); - } - else - { - // Difference between what we have and target is small. Motor is done. - CurrentValue = TargetValue; - MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", - BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); - } - - return CurrentValue; - } - public virtual Vector3 Step(float timeStep, Vector3 error) - { - if (!Enabled) return Vector3.Zero; - - LastError = error; - Vector3 returnCorrection = Vector3.Zero; - if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) - { - // correction = error / secondsItShouldTakeToCorrect - Vector3 correctionAmount; - if (TimeScale == 0f || TimeScale == BSMotor.Infinite) - correctionAmount = error * timeStep; - else - correctionAmount = error / TimeScale * timeStep; - - returnCorrection = correctionAmount; - MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", - BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); - } - return returnCorrection; - } - - // The user sets all the parameters and calls this which outputs values until error is zero. - public override void GenerateTestOutput(float timeStep) - { - // maximum number of outputs to generate. - int maxOutput = 50; - MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); - MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}", - BSScene.DetailLogZero, UseName, - TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, - CurrentValue, TargetValue); - - LastError = BSMotor.InfiniteVector; - while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) - { - Vector3 lastStep = Step(timeStep); - MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}", - BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); - } - MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); - - - } - - public override string ToString() - { - return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>", - UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale); - } -} - -public class BSFMotor : BSMotor -{ - public float TimeScale { get; set; } - public float DecayTimeScale { get; set; } - public float Friction { get; set; } - public float Efficiency { get; set; } - - public float Target { get; private set; } - public float CurrentValue { get; private set; } - - public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) - : base(useName) - { - } - public void SetCurrent(float target) - { - } - public void SetTarget(float target) - { - } - public virtual float Step(float timeStep) - { - return 0f; - } -} - -// Proportional, Integral, Derivitive Motor -// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. -public class BSPIDVMotor : BSVMotor -{ - // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10. - public Vector3 proportionFactor { get; set; } - public Vector3 integralFactor { get; set; } - public Vector3 derivFactor { get; set; } - - // Arbritrary factor range. - // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. - public float EfficiencyHigh = 0.4f; - public float EfficiencyLow = 4.0f; - - // Running integration of the error - Vector3 RunningIntegration { get; set; } - - public BSPIDVMotor(string useName) - : base(useName) - { - proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); - integralFactor = new Vector3(1.00f, 1.00f, 1.00f); - derivFactor = new Vector3(1.00f, 1.00f, 1.00f); - RunningIntegration = Vector3.Zero; - LastError = Vector3.Zero; - } - - public override void Zero() - { - base.Zero(); - } - - public override float Efficiency - { - get { return base.Efficiency; } - set - { - base.Efficiency = Util.Clamp(value, 0f, 1f); - // Compute factors based on efficiency. - // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. - // If efficiency is low (0f), use a factor value that overcorrects. - // TODO: might want to vary contribution of different factor depending on efficiency. - float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; - // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; - proportionFactor = new Vector3(factor, factor, factor); - integralFactor = new Vector3(factor, factor, factor); - derivFactor = new Vector3(factor, factor, factor); - } - } - - // Ignore Current and Target Values and just advance the PID computation on this error. - public override Vector3 Step(float timeStep, Vector3 error) - { - if (!Enabled) return Vector3.Zero; - - // Add up the error so we can integrate over the accumulated errors - RunningIntegration += error * timeStep; - - // A simple derivitive is the rate of change from the last error. - Vector3 derivFactor = (error - LastError) * timeStep; - LastError = error; - - // Correction = -(proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) - Vector3 ret = -( - error * proportionFactor - + RunningIntegration * integralFactor - + derivFactor * derivFactor - ); - - return ret; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs deleted file mode 100644 index 5e93a03..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OpenSim.Region.Physics.Manager; - -using OpenMetaverse; -using Nini.Config; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ -public static class BSParam -{ - // Level of Detail values kept as float because that's what the Meshmerizer wants - public static float MeshLOD { get; private set; } - public static float MeshMegaPrimLOD { get; private set; } - public static float MeshMegaPrimThreshold { get; private set; } - public static float SculptLOD { get; private set; } - - public static float MinimumObjectMass { get; private set; } - public static float MaximumObjectMass { get; private set; } - - public static float LinearDamping { get; private set; } - public static float AngularDamping { get; private set; } - public static float DeactivationTime { get; private set; } - public static float LinearSleepingThreshold { get; private set; } - public static float AngularSleepingThreshold { get; private set; } - public static float CcdMotionThreshold { get; private set; } - public static float CcdSweptSphereRadius { get; private set; } - public static float ContactProcessingThreshold { get; private set; } - - public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed - public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes - public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects - - public static float TerrainImplementation { get; private set; } - public static float TerrainFriction { get; private set; } - public static float TerrainHitFraction { get; private set; } - public static float TerrainRestitution { get; private set; } - public static float TerrainCollisionMargin { get; private set; } - - // Avatar parameters - public static float AvatarFriction { get; private set; } - public static float AvatarStandingFriction { get; private set; } - public static float AvatarDensity { get; private set; } - public static float AvatarRestitution { get; private set; } - public static float AvatarCapsuleWidth { get; private set; } - public static float AvatarCapsuleDepth { get; private set; } - public static float AvatarCapsuleHeight { get; private set; } - public static float AvatarContactProcessingThreshold { get; private set; } - - public static float VehicleAngularDamping { get; private set; } - - public static float LinksetImplementation { get; private set; } - public static float LinkConstraintUseFrameOffset { get; private set; } - public static float LinkConstraintEnableTransMotor { get; private set; } - public static float LinkConstraintTransMotorMaxVel { get; private set; } - public static float LinkConstraintTransMotorMaxForce { get; private set; } - public static float LinkConstraintERP { get; private set; } - public static float LinkConstraintCFM { get; private set; } - public static float LinkConstraintSolverIterations { get; private set; } - - public static float PID_D { get; private set; } // derivative - public static float PID_P { get; private set; } // proportional - - public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); - public delegate float ParamGet(BSScene scene); - public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); - public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); - - public struct ParameterDefn - { - public string name; // string name of the parameter - public string desc; // a short description of what the parameter means - public float defaultValue; // default value if not specified anywhere else - public ParamUser userParam; // get the value from the configuration file - public ParamGet getter; // return the current value stored for this parameter - public ParamSet setter; // set the current value for this parameter - public SetOnObject onObject; // set the value on an object in the physical domain - public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) - { - name = n; - desc = d; - defaultValue = v; - userParam = u; - getter = g; - setter = s; - onObject = null; - } - public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) - { - name = n; - desc = d; - defaultValue = v; - userParam = u; - getter = g; - setter = s; - onObject = o; - } - } - - // List of all of the externally visible parameters. - // For each parameter, this table maps a text name to getter and setters. - // To add a new externally referencable/settable parameter, add the paramter storage - // location somewhere in the program and make an entry in this table with the - // getters and setters. - // It is easiest to find an existing definition and copy it. - // Parameter values are floats. Booleans are converted to a floating value. - // - // A ParameterDefn() takes the following parameters: - // -- the text name of the parameter. This is used for console input and ini file. - // -- a short text description of the parameter. This shows up in the console listing. - // -- a default value (float) - // -- a delegate for fetching the parameter from the ini file. - // Should handle fetching the right type from the ini file and converting it. - // -- a delegate for getting the value as a float - // -- a delegate for setting the value from a float - // -- an optional delegate to update the value in the world. Most often used to - // push the new value to an in-world object. - // - // The single letter parameters for the delegates are: - // s = BSScene - // o = BSPhysObject - // p = string parameter name - // l = localID of referenced object - // v = value (float) - // cf = parameter configuration class (for fetching values from ini file) - private static ParameterDefn[] ParameterDefinitions = - { - new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", - ConfigurationParameters.numericTrue, - (s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, - (s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); }, - (s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ), - new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", - ConfigurationParameters.numericFalse, - (s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, - (s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); }, - (s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ), - new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", - ConfigurationParameters.numericTrue, - (s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, - (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); }, - (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ), - - new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", - 8f, - (s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); }, - (s) => { return MeshLOD; }, - (s,p,l,v) => { MeshLOD = v; } ), - new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", - 16f, - (s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); }, - (s) => { return MeshMegaPrimLOD; }, - (s,p,l,v) => { MeshMegaPrimLOD = v; } ), - new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", - 10f, - (s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); }, - (s) => { return MeshMegaPrimThreshold; }, - (s,p,l,v) => { MeshMegaPrimThreshold = v; } ), - new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", - 32f, - (s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); }, - (s) => { return SculptLOD; }, - (s,p,l,v) => { SculptLOD = v; } ), - - new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", - 10f, - (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); }, - (s) => { return (float)s.m_maxSubSteps; }, - (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ), - new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", - 1f / 60f, - (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); }, - (s) => { return (float)s.m_fixedTimeStep; }, - (s,p,l,v) => { s.m_fixedTimeStep = v; } ), - new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", - 2048f, - (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); }, - (s) => { return (float)s.m_maxCollisionsPerFrame; }, - (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), - new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame", - 8000f, - (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, - (s) => { return (float)s.m_maxUpdatesPerFrame; }, - (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), - new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", - 500f, - (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, - (s) => { return (float)s.m_taintsToProcessPerStep; }, - (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), - new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)", - 0.0001f, - (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); }, - (s) => { return (float)MinimumObjectMass; }, - (s,p,l,v) => { MinimumObjectMass = v; } ), - new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", - 10000.01f, - (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); }, - (s) => { return (float)MaximumObjectMass; }, - (s,p,l,v) => { MaximumObjectMass = v; } ), - - new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", - 2200f, - (s,cf,p,v) => { PID_D = cf.GetFloat(p, v); }, - (s) => { return (float)PID_D; }, - (s,p,l,v) => { PID_D = v; } ), - new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", - 900f, - (s,cf,p,v) => { PID_P = cf.GetFloat(p, v); }, - (s) => { return (float)PID_P; }, - (s,p,l,v) => { PID_P = v; } ), - - new ParameterDefn("DefaultFriction", "Friction factor used on new objects", - 0.2f, - (s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].defaultFriction; }, - (s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ), - new ParameterDefn("DefaultDensity", "Density for new objects" , - 10.000006836f, // Aluminum g/cm3 - (s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].defaultDensity; }, - (s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ), - new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , - 0f, - (s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].defaultRestitution; }, - (s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ), - new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", - 0.04f, - (s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].collisionMargin; }, - (s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ), - new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)", - -9.80665f, - (s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].gravity; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); }, - (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ), - - - new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", - 0f, - (s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); }, - (s) => { return LinearDamping; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); }, - (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, AngularDamping); } ), - new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", - 0f, - (s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); }, - (s) => { return AngularDamping; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); }, - (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, LinearDamping, v); } ), - new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", - 0.2f, - (s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); }, - (s) => { return DeactivationTime; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); }, - (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ), - new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", - 0.8f, - (s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); }, - (s) => { return LinearSleepingThreshold; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); }, - (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), - new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", - 1.0f, - (s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); }, - (s) => { return AngularSleepingThreshold; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); }, - (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), - new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , - 0f, // set to zero to disable - (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); }, - (s) => { return CcdMotionThreshold; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); }, - (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ), - new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , - 0f, - (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); }, - (s) => { return CcdSweptSphereRadius; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); }, - (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ), - new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , - 0.1f, - (s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); }, - (s) => { return ContactProcessingThreshold; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); }, - (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ), - - new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", - (float)BSTerrainPhys.TerrainImplementation.Heightmap, - (s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); }, - (s) => { return TerrainImplementation; }, - (s,p,l,v) => { TerrainImplementation = v; } ), - new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , - 0.3f, - (s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); }, - (s) => { return TerrainFriction; }, - (s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ), - new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , - 0.8f, - (s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); }, - (s) => { return TerrainHitFraction; }, - (s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ), - new ParameterDefn("TerrainRestitution", "Bouncyness" , - 0f, - (s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); }, - (s) => { return TerrainRestitution; }, - (s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ), - new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , - 0.04f, - (s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); }, - (s) => { return TerrainCollisionMargin; }, - (s,p,l,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ), - - new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", - 0.2f, - (s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); }, - (s) => { return AvatarFriction; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ), - new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", - 10.0f, - (s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); }, - (s) => { return AvatarStandingFriction; }, - (s,p,l,v) => { AvatarStandingFriction = v; } ), - new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", - 3.5f, - (s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); }, - (s) => { return AvatarDensity; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ), - new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", - 0f, - (s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); }, - (s) => { return AvatarRestitution; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ), - new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", - 0.6f, - (s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); }, - (s) => { return AvatarCapsuleWidth; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ), - new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", - 0.45f, - (s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); }, - (s) => { return AvatarCapsuleDepth; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ), - new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", - 1.5f, - (s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); }, - (s) => { return AvatarCapsuleHeight; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ), - new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", - 0.1f, - (s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); }, - (s) => { return AvatarContactProcessingThreshold; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ), - - new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", - 0.95f, - (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); }, - (s) => { return VehicleAngularDamping; }, - (s,p,l,v) => { VehicleAngularDamping = v; } ), - - new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", - 0f, - (s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; }, - (s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ), - new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", - 0f, - (s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; }, - (s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ), - new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", - ConfigurationParameters.numericFalse, - (s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; }, - (s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ), - new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", - ConfigurationParameters.numericFalse, - (s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; }, - (s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ), - new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", - ConfigurationParameters.numericTrue, - (s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; }, - (s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ), - new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", - ConfigurationParameters.numericTrue, - (s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; }, - (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ), - new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", - ConfigurationParameters.numericFalse, - (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; }, - (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ), - new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)", - 0f, // zero says use Bullet default - (s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].numberOfSolverIterations; }, - (s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ), - - new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", - (float)BSLinkset.LinksetImplementation.Compound, - (s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); }, - (s) => { return LinksetImplementation; }, - (s,p,l,v) => { LinksetImplementation = v; } ), - new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", - ConfigurationParameters.numericFalse, - (s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return LinkConstraintUseFrameOffset; }, - (s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ), - new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", - ConfigurationParameters.numericTrue, - (s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return LinkConstraintEnableTransMotor; }, - (s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ), - new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", - 5.0f, - (s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); }, - (s) => { return LinkConstraintTransMotorMaxVel; }, - (s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ), - new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", - 0.1f, - (s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, - (s) => { return LinkConstraintTransMotorMaxForce; }, - (s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ), - new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", - 0.1f, - (s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); }, - (s) => { return LinkConstraintCFM; }, - (s,p,l,v) => { LinkConstraintCFM = v; } ), - new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", - 0.1f, - (s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); }, - (s) => { return LinkConstraintERP; }, - (s,p,l,v) => { LinkConstraintERP = v; } ), - new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", - 40, - (s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); }, - (s) => { return LinkConstraintSolverIterations; }, - (s,p,l,v) => { LinkConstraintSolverIterations = v; } ), - - new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)", - 0f, - (s,cf,p,v) => { s.UnmanagedParams[0].physicsLoggingFrames = cf.GetInt(p, (int)v); }, - (s) => { return (float)s.UnmanagedParams[0].physicsLoggingFrames; }, - (s,p,l,v) => { s.UnmanagedParams[0].physicsLoggingFrames = (int)v; } ), - }; - - // Convert a boolean to our numeric true and false values - public static float NumericBool(bool b) - { - return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); - } - - // Convert numeric true and false values to a boolean - public static bool BoolNumeric(float b) - { - return (b == ConfigurationParameters.numericTrue ? true : false); - } - - // Search through the parameter definitions and return the matching - // ParameterDefn structure. - // Case does not matter as names are compared after converting to lower case. - // Returns 'false' if the parameter is not found. - internal static bool TryGetParameter(string paramName, out ParameterDefn defn) - { - bool ret = false; - ParameterDefn foundDefn = new ParameterDefn(); - string pName = paramName.ToLower(); - - foreach (ParameterDefn parm in ParameterDefinitions) - { - if (pName == parm.name.ToLower()) - { - foundDefn = parm; - ret = true; - break; - } - } - defn = foundDefn; - return ret; - } - - // Pass through the settable parameters and set the default values - internal static void SetParameterDefaultValues(BSScene physicsScene) - { - foreach (ParameterDefn parm in ParameterDefinitions) - { - parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue); - } - } - - // Get user set values out of the ini file. - internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg) - { - foreach (ParameterDefn parm in ParameterDefinitions) - { - parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue); - } - } - - internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; - - // This creates an array in the correct format for returning the list of - // parameters. This is used by the 'list' option of the 'physics' command. - internal static void BuildParameterTable() - { - if (SettableParameters.Length < ParameterDefinitions.Length) - { - List entries = new List(); - for (int ii = 0; ii < ParameterDefinitions.Length; ii++) - { - ParameterDefn pd = ParameterDefinitions[ii]; - entries.Add(new PhysParameterEntry(pd.name, pd.desc)); - } - - // make the list in alphabetical order for estetic reasons - entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2) - { - return ppe1.name.CompareTo(ppe2.name); - }); - - SettableParameters = entries.ToArray(); - } - } - - -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs deleted file mode 100644 index 689da7f..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OMV = OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ -/* - * Class to wrap all objects. - * The rest of BulletSim doesn't need to keep checking for avatars or prims - * unless the difference is significant. - * - * Variables in the physicsl objects are in three forms: - * VariableName: used by the simulator and performs taint operations, etc - * RawVariableName: direct reference to the BulletSim storage for the variable value - * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. - * The last two (and certainly the last one) should be referenced only in taint-time. - */ - -/* - * As of 20121221, the following are the call sequences (going down) for different script physical functions: - * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce - * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce - * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse - * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v - * BS.ApplyCentralForce BS.ApplyTorque - */ - -public abstract class BSPhysObject : PhysicsActor -{ - protected BSPhysObject() - { - } - protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) - { - PhysicsScene = parentScene; - LocalID = localID; - PhysObjectName = name; - TypeName = typeName; - - Linkset = BSLinkset.Factory(PhysicsScene, this); - LastAssetBuildFailed = false; - - // Default material type - Material = MaterialAttributes.Material.Wood; - - CollisionCollection = new CollisionEventUpdate(); - SubscribedEventsMs = 0; - CollidingStep = 0; - CollidingGroundStep = 0; - } - - // Tell the object to clean up. - public virtual void Destroy() - { - UnRegisterAllPreStepActions(); - } - - public BSScene PhysicsScene { get; protected set; } - // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor - public string PhysObjectName { get; protected set; } - public string TypeName { get; protected set; } - - public BSLinkset Linkset { get; set; } - public BSLinksetInfo LinksetInfo { get; set; } - - // Return the object mass without calculating it or having side effects - public abstract float RawMass { get; } - // Set the raw mass but also update physical mass properties (inertia, ...) - // 'inWorld' true if the object has already been added to the dynamic world. - public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld); - - // The last value calculated for the prim's inertia - public OMV.Vector3 Inertia { get; set; } - - // Reference to the physical body (btCollisionObject) of this object - public BulletBody PhysBody; - // Reference to the physical shape (btCollisionShape) of this object - public BulletShape PhysShape; - - // 'true' if the mesh's underlying asset failed to build. - // This will keep us from looping after the first time the build failed. - public bool LastAssetBuildFailed { get; set; } - - // The objects base shape information. Null if not a prim type shape. - public PrimitiveBaseShape BaseShape { get; protected set; } - // Some types of objects have preferred physical representations. - // Returns SHAPE_UNKNOWN if there is no preference. - public virtual BSPhysicsShapeType PreferredPhysicalShape - { - get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } - } - - // When the physical properties are updated, an EntityProperty holds the update values. - // Keep the current and last EntityProperties to enable computation of differences - // between the current update and the previous values. - public EntityProperties CurrentEntityProperties { get; set; } - public EntityProperties LastEntityProperties { get; set; } - - public virtual OMV.Vector3 Scale { get; set; } - public abstract bool IsSolid { get; } - public abstract bool IsStatic { get; } - - // Materialness - public MaterialAttributes.Material Material { get; private set; } - public override void SetMaterial(int material) - { - Material = (MaterialAttributes.Material)material; - } - - // Stop all physical motion. - public abstract void ZeroMotion(bool inTaintTime); - public abstract void ZeroAngularMotion(bool inTaintTime); - - // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured. - public virtual void StepVehicle(float timeStep) { } - - // Update the physical location and motion of the object. Called with data from Bullet. - public abstract void UpdateProperties(EntityProperties entprop); - - public abstract OMV.Vector3 RawPosition { get; set; } - public abstract OMV.Vector3 ForcePosition { get; set; } - - public abstract OMV.Quaternion RawOrientation { get; set; } - public abstract OMV.Quaternion ForceOrientation { get; set; } - - // The system is telling us the velocity it wants to move at. - // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor - public override OMV.Vector3 TargetVelocity - { - get { return m_targetVelocity; } - set - { - m_targetVelocity = value; - Velocity = value; - } - } - public abstract OMV.Vector3 ForceVelocity { get; set; } - - public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } - - public abstract float ForceBuoyancy { get; set; } - - public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } - - #region Collisions - - // Requested number of milliseconds between collision events. Zero means disabled. - protected int SubscribedEventsMs { get; set; } - // Given subscription, the time that a collision may be passed up - protected int NextCollisionOkTime { get; set; } - // The simulation step that last had a collision - protected long CollidingStep { get; set; } - // The simulation step that last had a collision with the ground - protected long CollidingGroundStep { get; set; } - // The collision flags we think are set in Bullet - protected CollisionFlags CurrentCollisionFlags { get; set; } - - // The collisions that have been collected this tick - protected CollisionEventUpdate CollisionCollection; - - // The simulation step is telling this object about a collision. - // Return 'true' if a collision was processed and should be sent up. - // Called at taint time from within the Step() function - public virtual bool Collide(uint collidingWith, BSPhysObject collidee, - OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) - { - bool ret = false; - - // The following lines make IsColliding() and IsCollidingGround() work - CollidingStep = PhysicsScene.SimulationStep; - if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) - { - CollidingGroundStep = PhysicsScene.SimulationStep; - } - - // prims in the same linkset cannot collide with each other - if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) - { - return ret; - } - - // if someone has subscribed for collision events.... - if (SubscribedEvents()) { - CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); - DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", - LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); - - ret = true; - } - return ret; - } - - // Send the collected collisions into the simulator. - // Called at taint time from within the Step() function thus no locking problems - // with CollisionCollection and ObjectsWithNoMoreCollisions. - // Return 'true' if there were some actual collisions passed up - public virtual bool SendCollisions() - { - bool ret = true; - // If the 'no collision' call, force it to happen right now so quick collision_end - bool force = (CollisionCollection.Count == 0); - - // throttle the collisions to the number of milliseconds specified in the subscription - if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) - { - NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs; - - // We are called if we previously had collisions. If there are no collisions - // this time, send up one last empty event so OpenSim can sense collision end. - if (CollisionCollection.Count == 0) - { - // If I have no collisions this time, remove me from the list of objects with collisions. - ret = false; - } - - // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); - base.SendCollisionUpdate(CollisionCollection); - - // The CollisionCollection instance is passed around in the simulator. - // Make sure we don't have a handle to that one and that a new one is used for next time. - // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, - // a race condition is created for the other users of this instance. - CollisionCollection = new CollisionEventUpdate(); - } - return ret; - } - - // Subscribe for collision events. - // Parameter is the millisecond rate the caller wishes collision events to occur. - public override void SubscribeEvents(int ms) { - // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms); - SubscribedEventsMs = ms; - if (ms > 0) - { - // make sure first collision happens - NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); - - PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() - { - if (PhysBody.HasPhysicalBody) - CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - }); - } - else - { - // Subscribing for zero or less is the same as unsubscribing - UnSubscribeEvents(); - } - } - public override void UnSubscribeEvents() { - // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); - SubscribedEventsMs = 0; - PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() - { - // Make sure there is a body there because sometimes destruction happens in an un-ideal order. - if (PhysBody.HasPhysicalBody) - CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - }); - } - // Return 'true' if the simulator wants collision events - public override bool SubscribedEvents() { - return (SubscribedEventsMs > 0); - } - - #endregion // Collisions - - #region Per Simulation Step actions - // There are some actions that must be performed for a physical object before each simulation step. - // These actions are optional so, rather than scanning all the physical objects and asking them - // if they have anything to do, a physical object registers for an event call before the step is performed. - // This bookkeeping makes it easy to add, remove and clean up after all these registrations. - private Dictionary RegisteredActions = new Dictionary(); - protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn) - { - string identifier = op + "-" + id.ToString(); - RegisteredActions[identifier] = actn; - PhysicsScene.BeforeStep += actn; - DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier); - } - - // Unregister a pre step action. Safe to call if the action has not been registered. - protected void UnRegisterPreStepAction(string op, uint id) - { - string identifier = op + "-" + id.ToString(); - bool removed = false; - if (RegisteredActions.ContainsKey(identifier)) - { - PhysicsScene.BeforeStep -= RegisteredActions[identifier]; - RegisteredActions.Remove(identifier); - removed = true; - } - DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed); - } - - protected void UnRegisterAllPreStepActions() - { - foreach (KeyValuePair kvp in RegisteredActions) - { - PhysicsScene.BeforeStep -= kvp.Value; - } - RegisteredActions.Clear(); - DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID); - } - - - #endregion // Per Simulation Step actions - - // High performance detailed logging routine used by the physical objects. - protected void DetailLog(string msg, params Object[] args) - { - if (PhysicsScene.PhysicsLogging.Enabled) - PhysicsScene.DetailLog(msg, args); - } - -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs deleted file mode 100644 index 75963ee..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ - /// - /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim. - /// This module interfaces to an unmanaged C++ library which makes the - /// actual calls into the Bullet physics engine. - /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/. - /// The unmanaged library is compiled and linked statically with Bullet - /// to create BulletSim.dll and libBulletSim.so (for both 32 and 64 bit). - /// -public class BSPlugin : IPhysicsPlugin -{ - //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - private BSScene _mScene; - - public BSPlugin() - { - } - - public bool Init() - { - return true; - } - - public PhysicsScene GetScene(String sceneIdentifier) - { - if (_mScene == null) - { - - // If not Windows, loading is performed by the - // Mono loader as specified in - // "bin/Physics/OpenSim.Region.Physics.BulletSNPlugin.dll.config". - - _mScene = new BSScene(sceneIdentifier); - } - return (_mScene); - } - - public string GetName() - { - return ("BulletSimN"); - } - - public void Dispose() - { - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs deleted file mode 100644 index aadb5b2..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs +++ /dev/null @@ -1,1494 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Reflection; -using System.Collections.Generic; -using System.Xml; -using log4net; -using OMV = OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; -using OpenSim.Region.Physics.ConvexDecompositionDotNet; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ - - [Serializable] -public sealed class BSPrim : BSPhysObject -{ - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static readonly string LogHeader = "[BULLETS PRIM]"; - - // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. - private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user - - private bool _grabbed; - private bool _isSelected; - private bool _isVolumeDetect; - private OMV.Vector3 _position; - private float _mass; // the mass of this object - private float _density; - private OMV.Vector3 _force; - private OMV.Vector3 _velocity; - private OMV.Vector3 _torque; - private float _collisionScore; - private OMV.Vector3 _acceleration; - private OMV.Quaternion _orientation; - private int _physicsActorType; - private bool _isPhysical; - private bool _flying; - private float _friction; - private float _restitution; - private bool _setAlwaysRun; - private bool _throttleUpdates; - private bool _isColliding; - private bool _collidingGround; - private bool _collidingObj; - private bool _floatOnWater; - private OMV.Vector3 _rotationalVelocity; - private bool _kinematic; - private float _buoyancy; - - private BSDynamics _vehicle; - - private OMV.Vector3 _PIDTarget; - private bool _usePID; - private float _PIDTau; - private bool _useHoverPID; - private float _PIDHoverHeight; - private PIDHoverType _PIDHoverType; - private float _PIDHoverTao; - - public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, - OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) - : base(parent_scene, localID, primName, "BSPrim") - { - // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); - _physicsActorType = (int)ActorTypes.Prim; - _position = pos; - _size = size; - Scale = size; // prims are the size the user wants them to be (different for BSCharactes). - _orientation = rotation; - _buoyancy = 1f; - _velocity = OMV.Vector3.Zero; - _rotationalVelocity = OMV.Vector3.Zero; - BaseShape = pbs; - _isPhysical = pisPhysical; - _isVolumeDetect = false; - - // Someday set default attributes based on the material but, for now, we don't know the prim material yet. - // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical); - _density = PhysicsScene.Params.defaultDensity; - _friction = PhysicsScene.Params.defaultFriction; - _restitution = PhysicsScene.Params.defaultRestitution; - - _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness - - _mass = CalculateMass(); - - Linkset.Refresh(this); - - DetailLog("{0},BSPrim.constructor,call", LocalID); - // do the actual object creation at taint time - PhysicsScene.TaintedObject("BSPrim.create", delegate() - { - CreateGeomAndObject(true); - - CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); - }); - } - - // called when this prim is being destroyed and we should free all the resources - public override void Destroy() - { - // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); - base.Destroy(); - - // Undo any links between me and any other object - BSPhysObject parentBefore = Linkset.LinksetRoot; - int childrenBefore = Linkset.NumberOfChildren; - - Linkset = Linkset.RemoveMeFromLinkset(this); - - DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", - LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); - - // Undo any vehicle properties - this.VehicleType = (int)Vehicle.TYPE_NONE; - - PhysicsScene.TaintedObject("BSPrim.destroy", delegate() - { - DetailLog("{0},BSPrim.Destroy,taint,", LocalID); - // If there are physical body and shape, release my use of same. - PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); - PhysBody.Clear(); - PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); - PhysShape.Clear(); - }); - } - - // No one uses this property. - public override bool Stopped { - get { return false; } - } - public override OMV.Vector3 Size { - get { return _size; } - set { - // We presume the scale and size are the same. If scale must be changed for - // the physical shape, that is done when the geometry is built. - _size = value; - Scale = _size; - ForceBodyShapeRebuild(false); - } - } - - public override PrimitiveBaseShape Shape { - set { - BaseShape = value; - ForceBodyShapeRebuild(false); - } - } - // Whatever the linkset wants is what I want. - public override BSPhysicsShapeType PreferredPhysicalShape - { get { return Linkset.PreferredPhysicalShape(this); } } - - public override bool ForceBodyShapeRebuild(bool inTaintTime) - { - LastAssetBuildFailed = false; - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() - { - _mass = CalculateMass(); // changing the shape changes the mass - CreateGeomAndObject(true); - }); - return true; - } - public override bool Grabbed { - set { _grabbed = value; - } - } - public override bool Selected { - set - { - if (value != _isSelected) - { - _isSelected = value; - PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() - { - DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); - SetObjectDynamic(false); - }); - } - } - } - public override void CrossingFailure() { return; } - - // link me to the specified parent - public override void link(PhysicsActor obj) { - BSPrim parent = obj as BSPrim; - if (parent != null) - { - BSPhysObject parentBefore = Linkset.LinksetRoot; - int childrenBefore = Linkset.NumberOfChildren; - - Linkset = parent.Linkset.AddMeToLinkset(this); - - DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", - LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); - } - return; - } - - // delink me from my linkset - public override void delink() { - // TODO: decide if this parent checking needs to happen at taint time - // Race condition here: if link() and delink() in same simulation tick, the delink will not happen - - BSPhysObject parentBefore = Linkset.LinksetRoot; - int childrenBefore = Linkset.NumberOfChildren; - - Linkset = Linkset.RemoveMeFromLinkset(this); - - DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", - LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); - return; - } - - // Set motion values to zero. - // Do it to the properties so the values get set in the physics engine. - // Push the setting of the values to the viewer. - // Called at taint time! - public override void ZeroMotion(bool inTaintTime) - { - _velocity = OMV.Vector3.Zero; - _acceleration = OMV.Vector3.Zero; - _rotationalVelocity = OMV.Vector3.Zero; - - // Zero some other properties in the physics engine - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() - { - if (PhysBody.HasPhysicalBody) - BulletSimAPI.ClearAllForces2(PhysBody.ptr); - }); - } - public override void ZeroAngularMotion(bool inTaintTime) - { - _rotationalVelocity = OMV.Vector3.Zero; - // Zero some other properties in the physics engine - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() - { - // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); - if (PhysBody.HasPhysicalBody) - { - BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity); - BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); - } - }); - } - - public override void LockAngularMotion(OMV.Vector3 axis) - { - DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); - return; - } - - public override OMV.Vector3 RawPosition - { - get { return _position; } - set { _position = value; } - } - public override OMV.Vector3 Position { - get { - /* NOTE: this refetch is not necessary. The simulator knows about linkset children - * and does not fetch this position info for children. Thus this is commented out. - // child prims move around based on their parent. Need to get the latest location - if (!Linkset.IsRoot(this)) - _position = Linkset.PositionGet(this); - */ - - // don't do the GetObjectPosition for root elements because this function is called a zillion times. - // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); - return _position; - } - set { - // If the position must be forced into the physics engine, use ForcePosition. - // All positions are given in world positions. - if (_position == value) - { - DetailLog("{0},BSPrim.setPosition,taint,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation); - return; - } - _position = value; - PositionSanityCheck(false); - - // A linkset might need to know if a component information changed. - Linkset.UpdateProperties(this, false); - - PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() - { - DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); - ForcePosition = _position; - }); - } - } - public override OMV.Vector3 ForcePosition { - get { - _position = BulletSimAPI.GetPosition2(PhysBody.ptr); - return _position; - } - set { - _position = value; - if (PhysBody.HasPhysicalBody) - { - BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); - ActivateIfPhysical(false); - } - } - } - - // Check that the current position is sane and, if not, modify the position to make it so. - // Check for being below terrain and being out of bounds. - // Returns 'true' of the position was made sane by some action. - private bool PositionSanityCheck(bool inTaintTime) - { - bool ret = false; - - if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) - { - // The physical object is out of the known/simulated area. - // Upper levels of code will handle the transition to other areas so, for - // the time, we just ignore the position. - return ret; - } - - float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); - OMV.Vector3 upForce = OMV.Vector3.Zero; - if (RawPosition.Z < terrainHeight) - { - DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); - float targetHeight = terrainHeight + (Size.Z / 2f); - // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. - upForce.Z = (terrainHeight - RawPosition.Z) * 1f; - ret = true; - } - - if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) - { - float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); - // TODO: a floating motor so object will bob in the water - if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) - { - // Upforce proportional to the distance away from the water. Correct the error in 1 sec. - upForce.Z = (waterHeight - RawPosition.Z) * 1f; - ret = true; - } - } - - // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. - // TODO: This should be intergrated with a geneal physics action mechanism. - // TODO: This should be moderated with PID'ness. - if (ret) - { - // Apply upforce and overcome gravity. - OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; - DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); - AddForce(correctionForce, false, inTaintTime); - } - return ret; - } - - // Return the effective mass of the object. - // The definition of this call is to return the mass of the prim. - // If the simulator cares about the mass of the linkset, it will sum it itself. - public override float Mass - { - get - { - return _mass; - } - } - - // used when we only want this prim's mass and not the linkset thing - public override float RawMass { - get { return _mass; } - } - // Set the physical mass to the passed mass. - // Note that this does not change _mass! - public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) - { - if (PhysBody.HasPhysicalBody) - { - if (IsStatic) - { - Inertia = OMV.Vector3.Zero; - BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia); - BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); - } - else - { - if (inWorld) - { - // Changing interesting properties doesn't change proxy and collision cache - // information. The Bullet solution is to re-add the object to the world - // after parameters are changed. - BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); - } - - Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); - BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia); - BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); - - // center of mass is at the zero of the object - // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation); - DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},inWorld={3}", LocalID, physMass, Inertia, inWorld); - - if (inWorld) - { - BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr,_position,_orientation); - } - - // Must set gravity after it has been added to the world because, for unknown reasons, - // adding the object resets the object's gravity to world gravity - OMV.Vector3 grav = PhysicsScene.DefaultGravity * (1f - Buoyancy); - BulletSimAPI.SetGravity2(PhysBody.ptr, grav); - - } - } - } - - // Is this used? - public override OMV.Vector3 CenterOfMass - { - get { return Linkset.CenterOfMass; } - } - - // Is this used? - public override OMV.Vector3 GeometricCenter - { - get { return Linkset.GeometricCenter; } - } - - public override OMV.Vector3 Force { - get { return _force; } - set { - _force = value; - if (_force != OMV.Vector3.Zero) - { - // If the force is non-zero, it must be reapplied each tick because - // Bullet clears the forces applied last frame. - RegisterPreStepAction("BSPrim.setForce", LocalID, - delegate(float timeStep) - { - DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); - if (PhysBody.HasPhysicalBody) - { - BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, _force); - ActivateIfPhysical(false); - } - } - ); - } - else - { - UnRegisterPreStepAction("BSPrim.setForce", LocalID); - } - } - } - - public override int VehicleType { - get { - return (int)_vehicle.Type; // if we are a vehicle, return that type - } - set { - Vehicle type = (Vehicle)value; - - PhysicsScene.TaintedObject("setVehicleType", delegate() - { - // Done at taint time so we're sure the physics engine is not using the variables - // Vehicle code changes the parameters for this vehicle type. - _vehicle.ProcessTypeChange(type); - ActivateIfPhysical(false); - - // If an active vehicle, register the vehicle code to be called before each step - if (_vehicle.Type == Vehicle.TYPE_NONE) - UnRegisterPreStepAction("BSPrim.Vehicle", LocalID); - else - RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step); - }); - } - } - public override void VehicleFloatParam(int param, float value) - { - PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() - { - _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); - ActivateIfPhysical(false); - }); - } - public override void VehicleVectorParam(int param, OMV.Vector3 value) - { - PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() - { - _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); - ActivateIfPhysical(false); - }); - } - public override void VehicleRotationParam(int param, OMV.Quaternion rotation) - { - PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() - { - _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); - ActivateIfPhysical(false); - }); - } - public override void VehicleFlags(int param, bool remove) - { - PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() - { - _vehicle.ProcessVehicleFlags(param, remove); - }); - } - - // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more - public override void SetVolumeDetect(int param) { - bool newValue = (param != 0); - if (_isVolumeDetect != newValue) - { - _isVolumeDetect = newValue; - PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() - { - // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); - SetObjectDynamic(true); - }); - } - return; - } - public override OMV.Vector3 Velocity { - get { return _velocity; } - set { - _velocity = value; - PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() - { - // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); - ForceVelocity = _velocity; - }); - } - } - public override OMV.Vector3 ForceVelocity { - get { return _velocity; } - set { - PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); - - _velocity = value; - if (PhysBody.HasPhysicalBody) - { - BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); - ActivateIfPhysical(false); - } - } - } - public override OMV.Vector3 Torque { - get { return _torque; } - set { - _torque = value; - if (_torque != OMV.Vector3.Zero) - { - // If the torque is non-zero, it must be reapplied each tick because - // Bullet clears the forces applied last frame. - RegisterPreStepAction("BSPrim.setTorque", LocalID, - delegate(float timeStep) - { - if (PhysBody.HasPhysicalBody) - AddAngularForce(_torque, false, true); - } - ); - } - else - { - UnRegisterPreStepAction("BSPrim.setTorque", LocalID); - } - // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); - } - } - public override float CollisionScore { - get { return _collisionScore; } - set { _collisionScore = value; - } - } - public override OMV.Vector3 Acceleration { - get { return _acceleration; } - set { _acceleration = value; } - } - public override OMV.Quaternion RawOrientation - { - get { return _orientation; } - set { _orientation = value; } - } - public override OMV.Quaternion Orientation { - get { - /* NOTE: this refetch is not necessary. The simulator knows about linkset children - * and does not fetch this position info for children. Thus this is commented out. - // Children move around because tied to parent. Get a fresh value. - if (!Linkset.IsRoot(this)) - { - _orientation = Linkset.OrientationGet(this); - } - */ - return _orientation; - } - set { - if (_orientation == value) - return; - _orientation = value; - - // A linkset might need to know if a component information changed. - Linkset.UpdateProperties(this, false); - - PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() - { - if (PhysBody.HasPhysicalBody) - { - // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); - // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); - BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); - } - }); - } - } - // Go directly to Bullet to get/set the value. - public override OMV.Quaternion ForceOrientation - { - get - { - _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); - return _orientation; - } - set - { - _orientation = value; - BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); - } - } - public override int PhysicsActorType { - get { return _physicsActorType; } - set { _physicsActorType = value; } - } - public override bool IsPhysical { - get { return _isPhysical; } - set { - if (_isPhysical != value) - { - _isPhysical = value; - PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() - { - // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); - SetObjectDynamic(true); - // whether phys-to-static or static-to-phys, the object is not moving. - ZeroMotion(true); - }); - } - } - } - - // An object is static (does not move) if selected or not physical - public override bool IsStatic - { - get { return _isSelected || !IsPhysical; } - } - - // An object is solid if it's not phantom and if it's not doing VolumeDetect - public override bool IsSolid - { - get { return !IsPhantom && !_isVolumeDetect; } - } - - // Make gravity work if the object is physical and not selected - // Called at taint-time!! - private void SetObjectDynamic(bool forceRebuild) - { - // Recreate the physical object if necessary - CreateGeomAndObject(forceRebuild); - } - - // Convert the simulator's physical properties into settings on BulletSim objects. - // There are four flags we're interested in: - // IsStatic: Object does not move, otherwise the object has mass and moves - // isSolid: other objects bounce off of this object - // isVolumeDetect: other objects pass through but can generate collisions - // collisionEvents: whether this object returns collision events - private void UpdatePhysicalParameters() - { - // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape); - - // Mangling all the physical properties requires the object not be in the physical world. - // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). - BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); - - // Set up the object physicalness (does gravity and collisions move this object) - MakeDynamic(IsStatic); - - // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) - _vehicle.Refresh(); - - // Arrange for collision events if the simulator wants them - EnableCollisions(SubscribedEvents()); - - // Make solid or not (do things bounce off or pass through this object). - MakeSolid(IsSolid); - - BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr, _position, _orientation); - - // Rebuild its shape - BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); - - // Collision filter can be set only when the object is in the world - PhysBody.ApplyCollisionMask(); - - // Recompute any linkset parameters. - // When going from non-physical to physical, this re-enables the constraints that - // had been automatically disabled when the mass was set to zero. - // For compound based linksets, this enables and disables interactions of the children. - Linkset.Refresh(this); - - DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", - LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape); - } - - // "Making dynamic" means changing to and from static. - // When static, gravity does not effect the object and it is fixed in space. - // When dynamic, the object can fall and be pushed by others. - // This is independent of its 'solidness' which controls what passes through - // this object and what interacts with it. - private void MakeDynamic(bool makeStatic) - { - if (makeStatic) - { - // Become a Bullet 'static' object type - CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); - // Stop all movement - ZeroMotion(true); - - // Set various physical properties so other object interact properly - MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); - BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction); - BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution); - - // Mass is zero which disables a bunch of physics stuff in Bullet - UpdatePhysicalMassProperties(0f, false); - // Set collision detection parameters - if (BSParam.CcdMotionThreshold > 0f) - { - BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold); - BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius); - } - - // The activation state is 'disabled' so Bullet will not try to act on it. - // BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); - // Start it out sleeping and physical actions could wake it up. - BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING); - - // This collides like a static object - PhysBody.collisionType = CollisionType.Static; - - // There can be special things needed for implementing linksets - Linkset.MakeStatic(this); - } - else - { - // Not a Bullet static object - CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); - - // Set various physical properties so other object interact properly - MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true); - BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction); - BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution); - - // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 - // Since this can be called multiple times, only zero forces when becoming physical - // BulletSimAPI.ClearAllForces2(BSBody.ptr); - - // For good measure, make sure the transform is set through to the motion state - BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); - - // Center of mass is at the center of the object - // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); - - // A dynamic object has mass - UpdatePhysicalMassProperties(RawMass, false); - - // Set collision detection parameters - if (BSParam.CcdMotionThreshold > 0f) - { - BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold); - BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius); - } - - // Various values for simulation limits - BulletSimAPI.SetDamping2(PhysBody.ptr, BSParam.LinearDamping, BSParam.AngularDamping); - BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, BSParam.DeactivationTime); - BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); - BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold); - - // This collides like an object. - PhysBody.collisionType = CollisionType.Dynamic; - - // Force activation of the object so Bullet will act on it. - // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. - BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); - - // There might be special things needed for implementing linksets. - Linkset.MakeDynamic(this); - } - } - - // "Making solid" means that other object will not pass through this object. - // To make transparent, we create a Bullet ghost object. - // Note: This expects to be called from the UpdatePhysicalParameters() routine as - // the functions after this one set up the state of a possibly newly created collision body. - private void MakeSolid(bool makeSolid) - { - CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr); - if (makeSolid) - { - // Verify the previous code created the correct shape for this type of thing. - if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0) - { - m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); - } - CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); - } - else - { - if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0) - { - m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); - } - CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); - - // Change collision info from a static object to a ghosty collision object - PhysBody.collisionType = CollisionType.VolumeDetect; - } - } - - // Enable physical actions. Bullet will keep sleeping non-moving physical objects so - // they need waking up when parameters are changed. - // Called in taint-time!! - private void ActivateIfPhysical(bool forceIt) - { - if (IsPhysical && PhysBody.HasPhysicalBody) - BulletSimAPI.Activate2(PhysBody.ptr, forceIt); - } - - // Turn on or off the flag controlling whether collision events are returned to the simulator. - private void EnableCollisions(bool wantsCollisionEvents) - { - if (wantsCollisionEvents) - { - CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - } - else - { - CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - } - } - - // prims don't fly - public override bool Flying { - get { return _flying; } - set { - _flying = value; - } - } - public override bool SetAlwaysRun { - get { return _setAlwaysRun; } - set { _setAlwaysRun = value; } - } - public override bool ThrottleUpdates { - get { return _throttleUpdates; } - set { _throttleUpdates = value; } - } - public override bool IsColliding { - get { return (CollidingStep == PhysicsScene.SimulationStep); } - set { _isColliding = value; } - } - public override bool CollidingGround { - get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } - set { _collidingGround = value; } - } - public override bool CollidingObj { - get { return _collidingObj; } - set { _collidingObj = value; } - } - public bool IsPhantom { - get { - // SceneObjectPart removes phantom objects from the physics scene - // so, although we could implement touching and such, we never - // are invoked as a phantom object - return false; - } - } - public override bool FloatOnWater { - set { - _floatOnWater = value; - PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() - { - if (_floatOnWater) - CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); - else - CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); - }); - } - } - public override OMV.Vector3 RotationalVelocity { - get { - return _rotationalVelocity; - } - set { - _rotationalVelocity = value; - // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); - PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() - { - DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); - ForceRotationalVelocity = _rotationalVelocity; - }); - } - } - public override OMV.Vector3 ForceRotationalVelocity { - get { - return _rotationalVelocity; - } - set { - _rotationalVelocity = value; - if (PhysBody.HasPhysicalBody) - { - BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); - ActivateIfPhysical(false); - } - } - } - public override bool Kinematic { - get { return _kinematic; } - set { _kinematic = value; - // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); - } - } - public override float Buoyancy { - get { return _buoyancy; } - set { - _buoyancy = value; - PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() - { - ForceBuoyancy = _buoyancy; - }); - } - } - public override float ForceBuoyancy { - get { return _buoyancy; } - set { - _buoyancy = value; - // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); - // Force the recalculation of the various inertia,etc variables in the object - UpdatePhysicalMassProperties(_mass, true); - ActivateIfPhysical(false); - } - } - - // Used for MoveTo - public override OMV.Vector3 PIDTarget { - set { _PIDTarget = value; } - } - public override bool PIDActive { - set { _usePID = value; } - } - public override float PIDTau { - set { _PIDTau = value; } - } - - // Used for llSetHoverHeight and maybe vehicle height - // Hover Height will override MoveTo target's Z - public override bool PIDHoverActive { - set { _useHoverPID = value; } - } - public override float PIDHoverHeight { - set { _PIDHoverHeight = value; } - } - public override PIDHoverType PIDHoverType { - set { _PIDHoverType = value; } - } - public override float PIDHoverTau { - set { _PIDHoverTao = value; } - } - - // For RotLookAt - public override OMV.Quaternion APIDTarget { set { return; } } - public override bool APIDActive { set { return; } } - public override float APIDStrength { set { return; } } - public override float APIDDamping { set { return; } } - - public override void AddForce(OMV.Vector3 force, bool pushforce) { - // Since this force is being applied in only one step, make this a force per second. - OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; - AddForce(addForce, pushforce, false); - } - // Applying a force just adds this to the total force on the object. - // This added force will only last the next simulation tick. - public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { - // for an object, doesn't matter if force is a pushforce or not - if (force.IsFinite()) - { - float magnitude = force.Length(); - if (magnitude > 20000f) - { - // Force has a limit - force = force / magnitude * 20000f; - } - - OMV.Vector3 addForce = force; - DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); - - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() - { - // Bullet adds this central force to the total force for this tick - DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); - if (PhysBody.HasPhysicalBody) - { - BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, addForce); - ActivateIfPhysical(false); - } - }); - } - else - { - m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); - return; - } - } - - public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { - AddAngularForce(force, pushforce, false); - } - public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) - { - if (force.IsFinite()) - { - OMV.Vector3 angForce = force; - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() - { - if (PhysBody.HasPhysicalBody) - { - BulletSimAPI.ApplyTorque2(PhysBody.ptr, angForce); - ActivateIfPhysical(false); - } - }); - } - else - { - m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); - return; - } - } - - // A torque impulse. - // ApplyTorqueImpulse adds torque directly to the angularVelocity. - // AddAngularForce accumulates the force and applied it to the angular velocity all at once. - // Computed as: angularVelocity += impulse * inertia; - public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) - { - OMV.Vector3 applyImpulse = impulse; - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() - { - if (PhysBody.HasPhysicalBody) - { - BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); - ActivateIfPhysical(false); - } - }); - } - - public override void SetMomentum(OMV.Vector3 momentum) { - // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); - } - #region Mass Calculation - - private float CalculateMass() - { - float volume = _size.X * _size.Y * _size.Z; // default - float tmp; - - float returnMass = 0; - float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f; - float hollowVolume = hollowAmount * hollowAmount; - - switch (BaseShape.ProfileShape) - { - case ProfileShape.Square: - // default box - - if (BaseShape.PathCurve == (byte)Extrusion.Straight) - { - if (hollowAmount > 0.0) - { - switch (BaseShape.HollowShape) - { - case HollowShape.Square: - case HollowShape.Same: - break; - - case HollowShape.Circle: - - hollowVolume *= 0.78539816339f; - break; - - case HollowShape.Triangle: - - hollowVolume *= (0.5f * .5f); - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - - else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) - { - //a tube - - volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX); - tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY); - volume -= volume*tmp*tmp; - - if (hollowAmount > 0.0) - { - hollowVolume *= hollowAmount; - - switch (BaseShape.HollowShape) - { - case HollowShape.Square: - case HollowShape.Same: - break; - - case HollowShape.Circle: - hollowVolume *= 0.78539816339f;; - break; - - case HollowShape.Triangle: - hollowVolume *= 0.5f * 0.5f; - break; - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - - break; - - case ProfileShape.Circle: - - if (BaseShape.PathCurve == (byte)Extrusion.Straight) - { - volume *= 0.78539816339f; // elipse base - - if (hollowAmount > 0.0) - { - switch (BaseShape.HollowShape) - { - case HollowShape.Same: - case HollowShape.Circle: - break; - - case HollowShape.Square: - hollowVolume *= 0.5f * 2.5984480504799f; - break; - - case HollowShape.Triangle: - hollowVolume *= .5f * 1.27323954473516f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - - else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) - { - volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX); - tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); - volume *= (1.0f - tmp * tmp); - - if (hollowAmount > 0.0) - { - - // calculate the hollow volume by it's shape compared to the prim shape - hollowVolume *= hollowAmount; - - switch (BaseShape.HollowShape) - { - case HollowShape.Same: - case HollowShape.Circle: - break; - - case HollowShape.Square: - hollowVolume *= 0.5f * 2.5984480504799f; - break; - - case HollowShape.Triangle: - hollowVolume *= .5f * 1.27323954473516f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - break; - - case ProfileShape.HalfCircle: - if (BaseShape.PathCurve == (byte)Extrusion.Curve1) - { - volume *= 0.52359877559829887307710723054658f; - } - break; - - case ProfileShape.EquilateralTriangle: - - if (BaseShape.PathCurve == (byte)Extrusion.Straight) - { - volume *= 0.32475953f; - - if (hollowAmount > 0.0) - { - - // calculate the hollow volume by it's shape compared to the prim shape - switch (BaseShape.HollowShape) - { - case HollowShape.Same: - case HollowShape.Triangle: - hollowVolume *= .25f; - break; - - case HollowShape.Square: - hollowVolume *= 0.499849f * 3.07920140172638f; - break; - - case HollowShape.Circle: - // Hollow shape is a perfect cyllinder in respect to the cube's scale - // Cyllinder hollow volume calculation - - hollowVolume *= 0.1963495f * 3.07920140172638f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) - { - volume *= 0.32475953f; - volume *= 0.01f * (float)(200 - BaseShape.PathScaleX); - tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); - volume *= (1.0f - tmp * tmp); - - if (hollowAmount > 0.0) - { - - hollowVolume *= hollowAmount; - - switch (BaseShape.HollowShape) - { - case HollowShape.Same: - case HollowShape.Triangle: - hollowVolume *= .25f; - break; - - case HollowShape.Square: - hollowVolume *= 0.499849f * 3.07920140172638f; - break; - - case HollowShape.Circle: - - hollowVolume *= 0.1963495f * 3.07920140172638f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - break; - - default: - break; - } - - - - float taperX1; - float taperY1; - float taperX; - float taperY; - float pathBegin; - float pathEnd; - float profileBegin; - float profileEnd; - - if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible) - { - taperX1 = BaseShape.PathScaleX * 0.01f; - if (taperX1 > 1.0f) - taperX1 = 2.0f - taperX1; - taperX = 1.0f - taperX1; - - taperY1 = BaseShape.PathScaleY * 0.01f; - if (taperY1 > 1.0f) - taperY1 = 2.0f - taperY1; - taperY = 1.0f - taperY1; - } - else - { - taperX = BaseShape.PathTaperX * 0.01f; - if (taperX < 0.0f) - taperX = -taperX; - taperX1 = 1.0f - taperX; - - taperY = BaseShape.PathTaperY * 0.01f; - if (taperY < 0.0f) - taperY = -taperY; - taperY1 = 1.0f - taperY; - - } - - - volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); - - pathBegin = (float)BaseShape.PathBegin * 2.0e-5f; - pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f; - volume *= (pathEnd - pathBegin); - - // this is crude aproximation - profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f; - profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; - volume *= (profileEnd - profileBegin); - - returnMass = _density * volume; - - /* Comment out code that computes the mass of the linkset. That is done in the Linkset class. - if (IsRootOfLinkset) - { - foreach (BSPrim prim in _childrenPrims) - { - returnMass += prim.CalculateMass(); - } - } - */ - - returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); - - return returnMass; - }// end CalculateMass - #endregion Mass Calculation - - // Rebuild the geometry and object. - // This is called when the shape changes so we need to recreate the mesh/hull. - // Called at taint-time!!! - public void CreateGeomAndObject(bool forceRebuild) - { - // If this prim is part of a linkset, we must remove and restore the physical - // links if the body is rebuilt. - bool needToRestoreLinkset = false; - bool needToRestoreVehicle = false; - - // Create the correct physical representation for this type of object. - // Updates PhysBody and PhysShape with the new information. - // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. - PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) - { - // Called if the current prim body is about to be destroyed. - // Remove all the physical dependencies on the old body. - // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) - needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); - needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); - }); - - if (needToRestoreLinkset) - { - // If physical body dependencies were removed, restore them - Linkset.RestoreBodyDependencies(this); - } - if (needToRestoreVehicle) - { - // If physical body dependencies were removed, restore them - _vehicle.RestoreBodyDependencies(this); - } - - // Make sure the properties are set on the new object - UpdatePhysicalParameters(); - return; - } - - // The physics engine says that properties have updated. Update same and inform - // the world that things have changed. - // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate() - enum UpdatedProperties { - Position = 1 << 0, - Rotation = 1 << 1, - Velocity = 1 << 2, - Acceleration = 1 << 3, - RotationalVel = 1 << 4 - } - - const float ROTATION_TOLERANCE = 0.01f; - const float VELOCITY_TOLERANCE = 0.001f; - const float POSITION_TOLERANCE = 0.05f; - const float ACCELERATION_TOLERANCE = 0.01f; - const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; - - public override void UpdateProperties(EntityProperties entprop) - { - // Updates only for individual prims and for the root object of a linkset. - if (Linkset.IsRoot(this)) - { - // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet - // TODO: handle physics introduced by Bullet with computed vehicle physics. - if (_vehicle.IsActive) - { - entprop.RotationalVelocity = OMV.Vector3.Zero; - } - - // Assign directly to the local variables so the normal set action does not happen - _position = entprop.Position; - _orientation = entprop.Rotation; - _velocity = entprop.Velocity; - _acceleration = entprop.Acceleration; - _rotationalVelocity = entprop.RotationalVelocity; - - // The sanity check can change the velocity and/or position. - if (IsPhysical && PositionSanityCheck(true)) - { - entprop.Position = _position; - entprop.Velocity = _velocity; - } - - OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG - DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", - LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); - - // remember the current and last set values - LastEntityProperties = CurrentEntityProperties; - CurrentEntityProperties = entprop; - - base.RequestPhysicsterseUpdate(); - } - /* - else - { - // For debugging, report the movement of children - DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", - LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, - entprop.Acceleration, entprop.RotationalVelocity); - } - */ - - // The linkset implimentation might want to know about this. - Linkset.UpdateProperties(this, true); - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs deleted file mode 100644 index 1a7c34b..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs +++ /dev/null @@ -1,957 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using OpenSim.Framework; -using OpenSim.Region.Framework; -using OpenSim.Region.CoreModules; -using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging; -using OpenSim.Region.Physics.Manager; -using Nini.Config; -using log4net; -using OpenMetaverse; - -// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) -// Based on material, set density and friction -// More efficient memory usage when passing hull information from BSPrim to BulletSim -// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect -// Implement LockAngularMotion -// Add PID movement operations. What does ScenePresence.MoveToTarget do? -// Check terrain size. 128 or 127? -// Raycast -// -namespace OpenSim.Region.Physics.BulletSNPlugin -{ -public sealed class BSScene : PhysicsScene, IPhysicsParameters -{ - private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - private static readonly string LogHeader = "[BULLETS SCENE]"; - - // The name of the region we're working for. - public string RegionName { get; private set; } - - public string BulletSimVersion = "?"; - - public Dictionary PhysObjects; - public BSShapeCollection Shapes; - - // Keeping track of the objects with collisions so we can report begin and end of a collision - public HashSet ObjectsWithCollisions = new HashSet(); - public HashSet ObjectsWithNoMoreCollisions = new HashSet(); - // Keep track of all the avatars so we can send them a collision event - // every tick so OpenSim will update its animation. - private HashSet m_avatars = new HashSet(); - - // let my minuions use my logger - public ILog Logger { get { return m_log; } } - - public IMesher mesher; - public uint WorldID { get; private set; } - public BulletWorld World { get; private set; } - - // All the constraints that have been allocated in this instance. - public BSConstraintCollection Constraints { get; private set; } - - // Simulation parameters - internal int m_maxSubSteps; - internal float m_fixedTimeStep; - internal long m_simulationStep = 0; - public long SimulationStep { get { return m_simulationStep; } } - internal int m_taintsToProcessPerStep; - internal float LastTimeStep { get; private set; } - - // Physical objects can register for prestep or poststep events - public delegate void PreStepAction(float timeStep); - public delegate void PostStepAction(float timeStep); - public event PreStepAction BeforeStep; - public event PreStepAction AfterStep; - - // A value of the time now so all the collision and update routines do not have to get their own - // Set to 'now' just before all the prims and actors are called for collisions and updates - public int SimulationNowTime { get; private set; } - - // True if initialized and ready to do simulation steps - private bool m_initialized = false; - - // Flag which is true when processing taints. - // Not guaranteed to be correct all the time (don't depend on this) but good for debugging. - public bool InTaintTime { get; private set; } - - // Pinned memory used to pass step information between managed and unmanaged - internal int m_maxCollisionsPerFrame; - private List m_collisionArray; - //private GCHandle m_collisionArrayPinnedHandle; - - internal int m_maxUpdatesPerFrame; - private List m_updateArray; - //private GCHandle m_updateArrayPinnedHandle; - - - public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero - public const uint GROUNDPLANE_ID = 1; - public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here - - public float SimpleWaterLevel { get; set; } - public BSTerrainManager TerrainManager { get; private set; } - - public ConfigurationParameters Params - { - get { return UnmanagedParams[0]; } - } - public Vector3 DefaultGravity - { - get { return new Vector3(0f, 0f, Params.gravity); } - } - // Just the Z value of the gravity - public float DefaultGravityZ - { - get { return Params.gravity; } - } - - // When functions in the unmanaged code must be called, it is only - // done at a known time just before the simulation step. The taint - // system saves all these function calls and executes them in - // order before the simulation. - public delegate void TaintCallback(); - private struct TaintCallbackEntry - { - public String ident; - public TaintCallback callback; - public TaintCallbackEntry(string i, TaintCallback c) - { - ident = i; - callback = c; - } - } - private Object _taintLock = new Object(); // lock for using the next object - private List _taintOperations; - private Dictionary _postTaintOperations; - private List _postStepOperations; - - // A pointer to an instance if this structure is passed to the C++ code - // Used to pass basic configuration values to the unmanaged code. - internal ConfigurationParameters[] UnmanagedParams; - //GCHandle m_paramsHandle; - - // Handle to the callback used by the unmanaged code to call into the managed code. - // Used for debug logging. - // Need to store the handle in a persistant variable so it won't be freed. - private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; - - // Sometimes you just have to log everything. - public Logging.LogWriter PhysicsLogging; - private bool m_physicsLoggingEnabled; - private string m_physicsLoggingDir; - private string m_physicsLoggingPrefix; - private int m_physicsLoggingFileMinutes; - private bool m_physicsLoggingDoFlush; - // 'true' of the vehicle code is to log lots of details - public bool VehicleLoggingEnabled { get; private set; } - public bool VehiclePhysicalLoggingEnabled { get; private set; } - - #region Construction and Initialization - public BSScene(string identifier) - { - m_initialized = false; - // we are passed the name of the region we're working for. - RegionName = identifier; - } - - public override void Initialise(IMesher meshmerizer, IConfigSource config) - { - mesher = meshmerizer; - _taintOperations = new List(); - _postTaintOperations = new Dictionary(); - _postStepOperations = new List(); - PhysObjects = new Dictionary(); - Shapes = new BSShapeCollection(this); - - // Allocate pinned memory to pass parameters. - UnmanagedParams = new ConfigurationParameters[1]; - //m_paramsHandle = GCHandle.Alloc(UnmanagedParams, GCHandleType.Pinned); - - // Set default values for physics parameters plus any overrides from the ini file - GetInitialParameterValues(config); - - // allocate more pinned memory close to the above in an attempt to get the memory all together - m_collisionArray = new List(); - //m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned); - m_updateArray = new List(); - //m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); - - // Enable very detailed logging. - // By creating an empty logger when not logging, the log message invocation code - // can be left in and every call doesn't have to check for null. - if (m_physicsLoggingEnabled) - { - PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); - PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages. - } - else - { - PhysicsLogging = new Logging.LogWriter(); - } - - // If Debug logging level, enable logging from the unmanaged code - m_DebugLogCallbackHandle = null; - if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) - { - m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); - if (PhysicsLogging.Enabled) - // The handle is saved in a variable to make sure it doesn't get freed after this call - m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); - else - m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); - } - - // Get the version of the DLL - // TODO: this doesn't work yet. Something wrong with marshaling the returned string. - // BulletSimVersion = BulletSimAPI.GetVersion(); - // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); - - // The bounding box for the simulated world. The origin is 0,0,0 unless we're - // a child in a mega-region. - // Bullet actually doesn't care about the extents of the simulated - // area. It tracks active objects no matter where they are. - Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); - - // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); - - World = new BulletWorld(0, this, BulletSimAPI.Initialize2(worldExtent, UnmanagedParams, - m_maxCollisionsPerFrame, ref m_collisionArray, - m_maxUpdatesPerFrame,ref m_updateArray, - m_DebugLogCallbackHandle)); - - Constraints = new BSConstraintCollection(World); - - TerrainManager = new BSTerrainManager(this); - TerrainManager.CreateInitialGroundPlaneAndTerrain(); - - m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); - - InTaintTime = false; - m_initialized = true; - } - - // All default parameter values are set here. There should be no values set in the - // variable definitions. - private void GetInitialParameterValues(IConfigSource config) - { - ConfigurationParameters parms = new ConfigurationParameters(); - UnmanagedParams[0] = parms; - - BSParam.SetParameterDefaultValues(this); - - if (config != null) - { - // If there are specifications in the ini file, use those values - IConfig pConfig = config.Configs["BulletSim"]; - if (pConfig != null) - { - BSParam.SetParameterConfigurationValues(this, pConfig); - - // Very detailed logging for physics debugging - m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); - m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); - m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); - m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); - m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false); - // Very detailed logging for vehicle debugging - VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); - VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false); - - // Do any replacements in the parameters - m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); - } - - // The material characteristics. - BSMaterials.InitializeFromDefaults(Params); - if (pConfig != null) - { - // Let the user add new and interesting material property values. - BSMaterials.InitializefromParameters(pConfig); - } - } - } - - // A helper function that handles a true/false parameter and returns the proper float number encoding - float ParamBoolean(IConfig config, string parmName, float deflt) - { - float ret = deflt; - if (config.Contains(parmName)) - { - ret = ConfigurationParameters.numericFalse; - if (config.GetBoolean(parmName, false)) - { - ret = ConfigurationParameters.numericTrue; - } - } - return ret; - } - - // Called directly from unmanaged code so don't do much - private void BulletLogger(string msg) - { - m_log.Debug("[BULLETS UNMANAGED]:" + msg); - } - - // Called directly from unmanaged code so don't do much - private void BulletLoggerPhysLog(string msg) - { - DetailLog("[BULLETS UNMANAGED]:" + msg); - } - - public override void Dispose() - { - // m_log.DebugFormat("{0}: Dispose()", LogHeader); - - // make sure no stepping happens while we're deleting stuff - m_initialized = false; - - foreach (KeyValuePair kvp in PhysObjects) - { - kvp.Value.Destroy(); - } - PhysObjects.Clear(); - - // Now that the prims are all cleaned up, there should be no constraints left - if (Constraints != null) - { - Constraints.Dispose(); - Constraints = null; - } - - if (Shapes != null) - { - Shapes.Dispose(); - Shapes = null; - } - - if (TerrainManager != null) - { - TerrainManager.ReleaseGroundPlaneAndTerrain(); - TerrainManager.Dispose(); - TerrainManager = null; - } - - // Anything left in the unmanaged code should be cleaned out - BulletSimAPI.Shutdown2(World.ptr); - - // Not logging any more - PhysicsLogging.Close(); - } - #endregion // Construction and Initialization - - #region Prim and Avatar addition and removal - - public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) - { - m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); - return null; - } - - public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying) - { - // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName); - - if (!m_initialized) return null; - - BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); - lock (PhysObjects) PhysObjects.Add(localID, actor); - - // TODO: Remove kludge someday. - // We must generate a collision for avatars whether they collide or not. - // This is required by OpenSim to update avatar animations, etc. - lock (m_avatars) m_avatars.Add(actor); - - return actor; - } - - public override void RemoveAvatar(PhysicsActor actor) - { - // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); - - if (!m_initialized) return; - - BSCharacter bsactor = actor as BSCharacter; - if (bsactor != null) - { - try - { - lock (PhysObjects) PhysObjects.Remove(actor.LocalID); - // Remove kludge someday - lock (m_avatars) m_avatars.Remove(bsactor); - } - catch (Exception e) - { - m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); - } - bsactor.Destroy(); - // bsactor.dispose(); - } - } - - public override void RemovePrim(PhysicsActor prim) - { - if (!m_initialized) return; - - BSPrim bsprim = prim as BSPrim; - if (bsprim != null) - { - DetailLog("{0},RemovePrim,call", bsprim.LocalID); - // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); - try - { - lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID); - } - catch (Exception e) - { - m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); - } - bsprim.Destroy(); - // bsprim.dispose(); - } - else - { - m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader); - } - } - - public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, - Vector3 size, Quaternion rotation, bool isPhysical, uint localID) - { - // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName); - - if (!m_initialized) return null; - - DetailLog("{0},AddPrimShape,call", localID); - - BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); - lock (PhysObjects) PhysObjects.Add(localID, prim); - return prim; - } - - // This is a call from the simulator saying that some physical property has been updated. - // The BulletSim driver senses the changing of relevant properties so this taint - // information call is not needed. - public override void AddPhysicsActorTaint(PhysicsActor prim) { } - - #endregion // Prim and Avatar addition and removal - - #region Simulation - // Simulate one timestep - public override float Simulate(float timeStep) - { - // prevent simulation until we've been initialized - if (!m_initialized) return 5.0f; - - LastTimeStep = timeStep; - - int updatedEntityCount = 0; - //Object updatedEntitiesPtr; - int collidersCount = 0; - //Object collidersPtr; - - int beforeTime = 0; - int simTime = 0; - - // update the prim states while we know the physics engine is not busy - int numTaints = _taintOperations.Count; - - InTaintTime = true; // Only used for debugging so locking is not necessary. - - ProcessTaints(); - - // Some of the physical objects requre individual, pre-step calls - TriggerPreStepEvent(timeStep); - - // the prestep actions might have added taints - ProcessTaints(); - - InTaintTime = false; // Only used for debugging so locking is not necessary. - - // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. - // Only enable this in a limited test world with few objects. - // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG - - // step the physical world one interval - m_simulationStep++; - int numSubSteps = 0; - - try - { - if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); - - numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, - out updatedEntityCount, out m_updateArray, out collidersCount, out m_collisionArray); - - if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); - DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", - DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, - updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); - } - catch (Exception e) - { - m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}", - LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e); - DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}", - DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); - updatedEntityCount = 0; - collidersCount = 0; - } - - // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in. - - // Get a value for 'now' so all the collision and update routines don't have to get their own. - SimulationNowTime = Util.EnvironmentTickCount(); - - // If there were collisions, process them by sending the event to the prim. - // Collisions must be processed before updates. - if (collidersCount > 0) - { - for (int ii = 0; ii < collidersCount; ii++) - { - uint cA = m_collisionArray[ii].aID; - uint cB = m_collisionArray[ii].bID; - Vector3 point = new Vector3(m_collisionArray[ii].point.X, m_collisionArray[ii].point.Y, - m_collisionArray[ii].point.Z); - Vector3 normal = new Vector3(m_collisionArray[ii].normal.X, m_collisionArray[ii].normal.Y, - m_collisionArray[ii].normal.Z); - SendCollision(cA, cB, point, normal, 0.01f); - SendCollision(cB, cA, point, -normal, 0.01f); - } - } - - // The above SendCollision's batch up the collisions on the objects. - // Now push the collisions into the simulator. - if (ObjectsWithCollisions.Count > 0) - { - foreach (BSPhysObject bsp in ObjectsWithCollisions) - if (!bsp.SendCollisions()) - { - // If the object is done colliding, see that it's removed from the colliding list - ObjectsWithNoMoreCollisions.Add(bsp); - } - } - - // This is a kludge to get avatar movement updates. - // The simulator expects collisions for avatars even if there are have been no collisions. - // The event updates avatar animations and stuff. - // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. - foreach (BSPhysObject bsp in m_avatars) - if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice - bsp.SendCollisions(); - - // Objects that are done colliding are removed from the ObjectsWithCollisions list. - // Not done above because it is inside an iteration of ObjectWithCollisions. - // This complex collision processing is required to create an empty collision - // event call after all collisions have happened on an object. This enables - // the simulator to generate the 'collision end' event. - if (ObjectsWithNoMoreCollisions.Count > 0) - { - foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) - ObjectsWithCollisions.Remove(po); - ObjectsWithNoMoreCollisions.Clear(); - } - // Done with collisions. - - // If any of the objects had updated properties, tell the object it has been changed by the physics engine - if (updatedEntityCount > 0) - { - for (int ii = 0; ii < updatedEntityCount; ii++) - { - - BulletXNA.EntityProperties entprop = m_updateArray[ii]; - BSPhysObject pobj; - if (PhysObjects.TryGetValue(entprop.ID, out pobj)) - { - EntityProperties prop = new EntityProperties() - { - Acceleration = new Vector3(entprop.Acceleration.X, entprop.Acceleration.Y, entprop.Acceleration.Z), - ID = entprop.ID, - Position = new Vector3(entprop.Position.X,entprop.Position.Y,entprop.Position.Z), - Rotation = new Quaternion(entprop.Rotation.X,entprop.Rotation.Y,entprop.Rotation.Z,entprop.Rotation.W), - RotationalVelocity = new Vector3(entprop.AngularVelocity.X,entprop.AngularVelocity.Y,entprop.AngularVelocity.Z), - Velocity = new Vector3(entprop.Velocity.X,entprop.Velocity.Y,entprop.Velocity.Z) - }; - //m_log.Debug(pobj.Name + ":" + prop.ToString() + "\n"); - pobj.UpdateProperties(prop); - } - } - } - - TriggerPostStepEvent(timeStep); - - // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. - // Only enable this in a limited test world with few objects. - // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG - - // The physics engine returns the number of milliseconds it simulated this call. - // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. - // Multiply by 55 to give a nominal frame rate of 55. - return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f; - } - - // Something has collided - private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration) - { - if (localID <= TerrainManager.HighestTerrainID) - { - return; // don't send collisions to the terrain - } - - BSPhysObject collider; - if (!PhysObjects.TryGetValue(localID, out collider)) - { - // If the object that is colliding cannot be found, just ignore the collision. - DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith); - return; - } - - // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. - BSPhysObject collidee = null; - PhysObjects.TryGetValue(collidingWith, out collidee); - - // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); - - if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) - { - // If a collision was posted, remember to send it to the simulator - ObjectsWithCollisions.Add(collider); - } - - return; - } - - #endregion // Simulation - - public override void GetResults() { } - - #region Terrain - - public override void SetTerrain(float[] heightMap) { - TerrainManager.SetTerrain(heightMap); - } - - public override void SetWaterLevel(float baseheight) - { - SimpleWaterLevel = baseheight; - } - - public override void DeleteTerrain() - { - // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); - } - - // Although no one seems to check this, I do support combining. - public override bool SupportsCombining() - { - return TerrainManager.SupportsCombining(); - } - // This call says I am a child to region zero in a mega-region. 'pScene' is that - // of region zero, 'offset' is my offset from regions zero's origin, and - // 'extents' is the largest XY that is handled in my region. - public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) - { - TerrainManager.Combine(pScene, offset, extents); - } - - // Unhook all the combining that I know about. - public override void UnCombine(PhysicsScene pScene) - { - TerrainManager.UnCombine(pScene); - } - - #endregion // Terrain - - public override Dictionary GetTopColliders() - { - return new Dictionary(); - } - - public override bool IsThreaded { get { return false; } } - - #region Taints - // The simulation execution order is: - // Simulate() - // DoOneTimeTaints - // TriggerPreStepEvent - // DoOneTimeTaints - // Step() - // ProcessAndForwardCollisions - // ProcessAndForwardPropertyUpdates - // TriggerPostStepEvent - - // Calls to the PhysicsActors can't directly call into the physics engine - // because it might be busy. We delay changes to a known time. - // We rely on C#'s closure to save and restore the context for the delegate. - public void TaintedObject(String ident, TaintCallback callback) - { - if (!m_initialized) return; - - lock (_taintLock) - { - _taintOperations.Add(new TaintCallbackEntry(ident, callback)); - } - - return; - } - - // Sometimes a potentially tainted operation can be used in and out of taint time. - // This routine executes the command immediately if in taint-time otherwise it is queued. - public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback) - { - if (inTaintTime) - callback(); - else - TaintedObject(ident, callback); - } - - private void TriggerPreStepEvent(float timeStep) - { - PreStepAction actions = BeforeStep; - if (actions != null) - actions(timeStep); - - } - - private void TriggerPostStepEvent(float timeStep) - { - PreStepAction actions = AfterStep; - if (actions != null) - actions(timeStep); - - } - - // When someone tries to change a property on a BSPrim or BSCharacter, the object queues - // a callback into itself to do the actual property change. That callback is called - // here just before the physics engine is called to step the simulation. - public void ProcessTaints() - { - ProcessRegularTaints(); - ProcessPostTaintTaints(); - } - - private void ProcessRegularTaints() - { - if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process - { - // swizzle a new list into the list location so we can process what's there - List oldList; - lock (_taintLock) - { - oldList = _taintOperations; - _taintOperations = new List(); - } - - foreach (TaintCallbackEntry tcbe in oldList) - { - try - { - DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG - tcbe.callback(); - } - catch (Exception e) - { - m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); - } - } - oldList.Clear(); - } - } - - // Schedule an update to happen after all the regular taints are processed. - // Note that new requests for the same operation ("ident") for the same object ("ID") - // will replace any previous operation by the same object. - public void PostTaintObject(String ident, uint ID, TaintCallback callback) - { - string uniqueIdent = ident + "-" + ID.ToString(); - lock (_taintLock) - { - _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback); - } - - return; - } - - // Taints that happen after the normal taint processing but before the simulation step. - private void ProcessPostTaintTaints() - { - if (_postTaintOperations.Count > 0) - { - Dictionary oldList; - lock (_taintLock) - { - oldList = _postTaintOperations; - _postTaintOperations = new Dictionary(); - } - - foreach (KeyValuePair kvp in oldList) - { - try - { - DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG - kvp.Value.callback(); - } - catch (Exception e) - { - m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e); - } - } - oldList.Clear(); - } - } - - // Only used for debugging. Does not change state of anything so locking is not necessary. - public bool AssertInTaintTime(string whereFrom) - { - if (!InTaintTime) - { - DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); - m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); - Util.PrintCallStack(DetailLog); - } - return InTaintTime; - } - - #endregion // Taints - - #region INI and command line parameter processing - - #region IPhysicsParameters - // Get the list of parameters this physics engine supports - public PhysParameterEntry[] GetParameterList() - { - BSParam.BuildParameterTable(); - return BSParam.SettableParameters; - } - - // Set parameter on a specific or all instances. - // Return 'false' if not able to set the parameter. - // Setting the value in the m_params block will change the value the physics engine - // will use the next time since it's pinned and shared memory. - // Some of the values require calling into the physics engine to get the new - // value activated ('terrainFriction' for instance). - public bool SetPhysicsParameter(string parm, float val, uint localID) - { - bool ret = false; - BSParam.ParameterDefn theParam; - if (BSParam.TryGetParameter(parm, out theParam)) - { - theParam.setter(this, parm, localID, val); - ret = true; - } - return ret; - } - - // update all the localIDs specified - // If the local ID is APPLY_TO_NONE, just change the default value - // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs - // If the localID is a specific object, apply the parameter change to only that object - internal delegate void AssignVal(float x); - internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val) - { - List objectIDs = new List(); - switch (localID) - { - case PhysParameterEntry.APPLY_TO_NONE: - setDefault(val); // setting only the default value - // This will cause a call into the physical world if some operation is specified (SetOnObject). - objectIDs.Add(TERRAIN_ID); - TaintedUpdateParameter(parm, objectIDs, val); - break; - case PhysParameterEntry.APPLY_TO_ALL: - setDefault(val); // setting ALL also sets the default value - lock (PhysObjects) objectIDs = new List(PhysObjects.Keys); - TaintedUpdateParameter(parm, objectIDs, val); - break; - default: - // setting only one localID - objectIDs.Add(localID); - TaintedUpdateParameter(parm, objectIDs, val); - break; - } - } - - // schedule the actual updating of the paramter to when the phys engine is not busy - private void TaintedUpdateParameter(string parm, List lIDs, float val) - { - float xval = val; - List xlIDs = lIDs; - string xparm = parm; - TaintedObject("BSScene.UpdateParameterSet", delegate() { - BSParam.ParameterDefn thisParam; - if (BSParam.TryGetParameter(xparm, out thisParam)) - { - if (thisParam.onObject != null) - { - foreach (uint lID in xlIDs) - { - BSPhysObject theObject = null; - PhysObjects.TryGetValue(lID, out theObject); - thisParam.onObject(this, theObject, xval); - } - } - } - }); - } - - // Get parameter. - // Return 'false' if not able to get the parameter. - public bool GetPhysicsParameter(string parm, out float value) - { - float val = 0f; - bool ret = false; - BSParam.ParameterDefn theParam; - if (BSParam.TryGetParameter(parm, out theParam)) - { - val = theParam.getter(this); - ret = true; - } - value = val; - return ret; - } - - #endregion IPhysicsParameters - - #endregion Runtime settable parameters - - // Invoke the detailed logger and output something if it's enabled. - public void DetailLog(string msg, params Object[] args) - { - PhysicsLogging.Write(msg, args); - // Add the Flush() if debugging crashes. Gets all the messages written out. - if (m_physicsLoggingDoFlush) PhysicsLogging.Flush(); - } - // Used to fill in the LocalID when there isn't one. It's the correct number of characters. - public const string DetailLogZero = "0000000000"; - -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs deleted file mode 100644 index 47fb768..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs +++ /dev/null @@ -1,1015 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using OMV = OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; -using OpenSim.Region.Physics.ConvexDecompositionDotNet; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ -public sealed class BSShapeCollection : IDisposable -{ - private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; - - private BSScene PhysicsScene { get; set; } - - private Object m_collectionActivityLock = new Object(); - - // Description of a Mesh - private struct MeshDesc - { - public Object ptr; - public int referenceCount; - public DateTime lastReferenced; - public UInt64 shapeKey; - } - - // Description of a hull. - // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. - private struct HullDesc - { - public Object ptr; - public int referenceCount; - public DateTime lastReferenced; - public UInt64 shapeKey; - } - - // The sharable set of meshes and hulls. Indexed by their shape hash. - private Dictionary Meshes = new Dictionary(); - private Dictionary Hulls = new Dictionary(); - - private bool DDetail = false; - - public BSShapeCollection(BSScene physScene) - { - PhysicsScene = physScene; - // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) - // While detailed debugging is still active, this is better than commenting out all the - // DetailLog statements. When debugging slows down, this and the protected logging - // statements can be commented/removed. - DDetail = true; - } - - public void Dispose() - { - // TODO!!!!!!!!! - } - - // Callbacks called just before either the body or shape is destroyed. - // Mostly used for changing bodies out from under Linksets. - // Useful for other cases where parameters need saving. - // Passing 'null' says no callback. - public delegate void ShapeDestructionCallback(BulletShape shape); - public delegate void BodyDestructionCallback(BulletBody body); - - // Called to update/change the body and shape for an object. - // First checks the shape and updates that if necessary then makes - // sure the body is of the right type. - // Return 'true' if either the body or the shape changed. - // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before - // the current shape or body is destroyed. This allows the caller to remove any - // higher level dependencies on the shape or body. Mostly used for LinkSets to - // remove the physical constraints before the body is destroyed. - // Called at taint-time!! - public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, - ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) - { - PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); - - bool ret = false; - - // This lock could probably be pushed down lower but building shouldn't take long - lock (m_collectionActivityLock) - { - // Do we have the correct geometry for this type of object? - // Updates prim.BSShape with information/pointers to shape. - // Returns 'true' of BSShape is changed to a new shape. - bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback); - // If we had to select a new shape geometry for the object, - // rebuild the body around it. - // Updates prim.BSBody with information/pointers to requested body - // Returns 'true' if BSBody was changed. - bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, - prim.PhysShape, bodyCallback); - ret = newGeom || newBody; - } - DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", - prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape); - - return ret; - } - - public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) - { - return GetBodyAndShape(forceRebuild, sim, prim, null, null); - } - - // Track another user of a body. - // We presume the caller has allocated the body. - // Bodies only have one user so the body is just put into the world if not already there. - public void ReferenceBody(BulletBody body, bool inTaintTime) - { - lock (m_collectionActivityLock) - { - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); - PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() - { - if (!BulletSimAPI.IsInWorld2(PhysicsScene.World.ptr, body.ptr)) - { - BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); - } - }); - } - } - - // Release the usage of a body. - // Called when releasing use of a BSBody. BSShape is handled separately. - public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) - { - if (!body.HasPhysicalBody) - return; - - lock (m_collectionActivityLock) - { - PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() - { - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", - body.ID, body, inTaintTime); - // If the caller needs to know the old body is going away, pass the event up. - if (bodyCallback != null) bodyCallback(body); - - if (BulletSimAPI.IsInWorld2(PhysicsScene.World.ptr, body.ptr)) - { - BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); - } - - // Zero any reference to the shape so it is not freed when the body is deleted. - BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, null); - BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); - }); - } - } - - // Track the datastructures and use count for a shape. - // When creating a hull, this is called first to reference the mesh - // and then again to reference the hull. - // Meshes and hulls for the same shape have the same hash key. - // NOTE that native shapes are not added to the mesh list or removed. - // Returns 'true' if this is the initial reference to the shape. Otherwise reused. - public bool ReferenceShape(BulletShape shape) - { - bool ret = false; - switch (shape.type) - { - case BSPhysicsShapeType.SHAPE_MESH: - MeshDesc meshDesc; - if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) - { - // There is an existing instance of this mesh. - meshDesc.referenceCount++; - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", - BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); - } - else - { - // This is a new reference to a mesh - meshDesc.ptr = shape.ptr; - meshDesc.shapeKey = shape.shapeKey; - // We keep a reference to the underlying IMesh data so a hull can be built - meshDesc.referenceCount = 1; - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", - BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); - ret = true; - } - meshDesc.lastReferenced = System.DateTime.Now; - Meshes[shape.shapeKey] = meshDesc; - break; - case BSPhysicsShapeType.SHAPE_HULL: - HullDesc hullDesc; - if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) - { - // There is an existing instance of this hull. - hullDesc.referenceCount++; - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", - BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); - } - else - { - // This is a new reference to a hull - hullDesc.ptr = shape.ptr; - hullDesc.shapeKey = shape.shapeKey; - hullDesc.referenceCount = 1; - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", - BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); - ret = true; - - } - hullDesc.lastReferenced = System.DateTime.Now; - Hulls[shape.shapeKey] = hullDesc; - break; - case BSPhysicsShapeType.SHAPE_UNKNOWN: - break; - default: - // Native shapes are not tracked and they don't go into any list - break; - } - return ret; - } - - // Release the usage of a shape. - public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) - { - if (!shape.HasPhysicalShape) - return; - - PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() - { - if (shape.HasPhysicalShape) - { - if (shape.isNativeShape) - { - // Native shapes are not tracked and are released immediately - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", - BSScene.DetailLogZero, shape.ptr.ToString(), inTaintTime); - if (shapeCallback != null) shapeCallback(shape); - BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); - } - else - { - switch (shape.type) - { - case BSPhysicsShapeType.SHAPE_HULL: - DereferenceHull(shape, shapeCallback); - break; - case BSPhysicsShapeType.SHAPE_MESH: - DereferenceMesh(shape, shapeCallback); - break; - case BSPhysicsShapeType.SHAPE_COMPOUND: - DereferenceCompound(shape, shapeCallback); - break; - case BSPhysicsShapeType.SHAPE_UNKNOWN: - break; - default: - break; - } - } - } - }); - } - - // Count down the reference count for a mesh shape - // Called at taint-time. - private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback) - { - MeshDesc meshDesc; - if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) - { - meshDesc.referenceCount--; - // TODO: release the Bullet storage - if (shapeCallback != null) shapeCallback(shape); - meshDesc.lastReferenced = System.DateTime.Now; - Meshes[shape.shapeKey] = meshDesc; - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", - BSScene.DetailLogZero, shape, meshDesc.referenceCount); - - } - } - - // Count down the reference count for a hull shape - // Called at taint-time. - private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback) - { - HullDesc hullDesc; - if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) - { - hullDesc.referenceCount--; - // TODO: release the Bullet storage (aging old entries?) - - // Tell upper layers that, if they have dependencies on this shape, this link is going away - if (shapeCallback != null) shapeCallback(shape); - - hullDesc.lastReferenced = System.DateTime.Now; - Hulls[shape.shapeKey] = hullDesc; - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", - BSScene.DetailLogZero, shape, hullDesc.referenceCount); - } - } - - // Remove a reference to a compound shape. - // Taking a compound shape apart is a little tricky because if you just delete the - // physical shape, it will free all the underlying children. We can't do that because - // they could be shared. So, this removes each of the children from the compound and - // dereferences them separately before destroying the compound collision object itself. - // Called at taint-time. - private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) - { - if (!BulletSimAPI.IsCompound2(shape.ptr)) - { - // Failed the sanity check!! - PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", - LogHeader, shape.type, shape.ptr.ToString()); - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", - BSScene.DetailLogZero, shape.type, shape.ptr.ToString()); - return; - } - - int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); - - for (int ii = numChildren - 1; ii >= 0; ii--) - { - Object childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); - DereferenceAnonCollisionShape(childShape); - } - BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); - } - - // Sometimes we have a pointer to a collision shape but don't know what type it is. - // Figure out type and call the correct dereference routine. - // Called at taint-time. - private void DereferenceAnonCollisionShape(Object cShape) - { - MeshDesc meshDesc; - HullDesc hullDesc; - - BulletShape shapeInfo = new BulletShape(cShape); - if (TryGetMeshByPtr(cShape, out meshDesc)) - { - shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; - shapeInfo.shapeKey = meshDesc.shapeKey; - } - else - { - if (TryGetHullByPtr(cShape, out hullDesc)) - { - shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; - shapeInfo.shapeKey = hullDesc.shapeKey; - } - else - { - if (BulletSimAPI.IsCompound2(cShape)) - { - shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; - } - else - { - if (BulletSimAPI.IsNativeShape2(cShape)) - { - shapeInfo.isNativeShape = true; - shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) - } - } - } - } - - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); - - if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) - { - DereferenceShape(shapeInfo, true, null); - } - else - { - PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", - LogHeader, PhysicsScene.RegionName, cShape.ToString()); - } - } - - // Create the geometry information in Bullet for later use. - // The objects needs a hull if it's physical otherwise a mesh is enough. - // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls, - // shared geometries will be used. If the parameters of the existing shape are the same - // as this request, the shape is not rebuilt. - // Info in prim.BSShape is updated to the new shape. - // Returns 'true' if the geometry was rebuilt. - // Called at taint-time! - private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - bool ret = false; - bool haveShape = false; - - if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) - { - // an avatar capsule is close to a native shape (it is not shared) - GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, - FixedShapeKey.KEY_CAPSULE, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); - ret = true; - haveShape = true; - } - - // Compound shapes are handled special as they are rebuilt from scratch. - // This isn't too great a hardship since most of the child shapes will have already been created. - if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) - { - ret = GetReferenceToCompoundShape(prim, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); - haveShape = true; - } - - if (!haveShape) - { - ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback); - } - - return ret; - } - - // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. - public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - bool ret = false; - bool haveShape = false; - bool nativeShapePossible = true; - PrimitiveBaseShape pbs = prim.BaseShape; - - // If the prim attributes are simple, this could be a simple Bullet native shape - if (!haveShape - && pbs != null - && nativeShapePossible - && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) - || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 - && pbs.ProfileHollow == 0 - && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 - && pbs.PathBegin == 0 && pbs.PathEnd == 0 - && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 - && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 - && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) - { - // Get the scale of any existing shape so we can see if the new shape is same native type and same size. - OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; - if (prim.PhysShape.HasPhysicalShape) - scaleOfExistingShape = BulletSimAPI.GetLocalScaling2(prim.PhysShape.ptr); - - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", - prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); - - // It doesn't look like Bullet scales spheres so make sure the scales are all equal - if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) - && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) - { - haveShape = true; - if (forceRebuild - || prim.Scale != scaleOfExistingShape - || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE - ) - { - ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, - FixedShapeKey.KEY_SPHERE, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", - prim.LocalID, forceRebuild, prim.PhysShape); - } - } - if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) - { - haveShape = true; - if (forceRebuild - || prim.Scale != scaleOfExistingShape - || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX - ) - { - ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, - FixedShapeKey.KEY_BOX, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", - prim.LocalID, forceRebuild, prim.PhysShape); - } - } - } - - // If a simple shape is not happening, create a mesh and possibly a hull. - if (!haveShape && pbs != null) - { - ret = CreateGeomMeshOrHull(prim, shapeCallback); - } - - return ret; - } - - public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - - bool ret = false; - // Note that if it's a native shape, the check for physical/non-physical is not - // made. Native shapes work in either case. - if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) - { - // Update prim.BSShape to reference a hull of this shape. - ret = GetReferenceToHull(prim,shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", - prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); - } - else - { - ret = GetReferenceToMesh(prim, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", - prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); - } - return ret; - } - - // Creates a native shape and assignes it to prim.BSShape. - // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). - private bool GetReferenceToNativeShape(BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey, - ShapeDestructionCallback shapeCallback) - { - // release any previous shape - DereferenceShape(prim.PhysShape, true, shapeCallback); - - BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); - - // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. - if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", - prim.LocalID, newShape, prim.Scale); - - // native shapes are scaled by Bullet - prim.PhysShape = newShape; - return true; - } - - private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType, - FixedShapeKey shapeKey) - { - BulletShape newShape; - // Need to make sure the passed shape information is for the native type. - ShapeData nativeShapeData = new ShapeData(); - nativeShapeData.Type = shapeType; - nativeShapeData.ID = prim.LocalID; - nativeShapeData.Scale = prim.Scale; - nativeShapeData.Size = prim.Scale; // unneeded, I think. - nativeShapeData.MeshKey = (ulong)shapeKey; - nativeShapeData.HullKey = (ulong)shapeKey; - - if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) - { - // The proper scale has been calculated in the prim. - newShape = new BulletShape( - BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) - , shapeType); - if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); - } - else - { - // Native shapes are scaled in Bullet so set the scaling to the size - newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); - } - if (!newShape.HasPhysicalShape) - { - PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", - LogHeader, prim.LocalID, shapeType); - } - newShape.shapeKey = (System.UInt64)shapeKey; - newShape.isNativeShape = true; - - return newShape; - } - - // Builds a mesh shape in the physical world and updates prim.BSShape. - // Dereferences previous shape in BSShape and adds a reference for this new shape. - // Returns 'true' of a mesh was actually built. Otherwise . - // Called at taint-time! - private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - BulletShape newShape = new BulletShape(); - - float lod; - System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - - // if this new shape is the same as last time, don't recreate the mesh - if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) - return false; - - if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", - prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); - - // Since we're recreating new, get rid of the reference to the previous shape - DereferenceShape(prim.PhysShape, true, shapeCallback); - - newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); - // Take evasive action if the mesh was not constructed. - newShape = VerifyMeshCreated(newShape, prim); - - ReferenceShape(newShape); - - prim.PhysShape = newShape; - - return true; // 'true' means a new shape has been added to this prim - } - - private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) - { - IMesh meshData = null; - Object meshPtr = null; - MeshDesc meshDesc; - if (Meshes.TryGetValue(newMeshKey, out meshDesc)) - { - // If the mesh has already been built just use it. - meshPtr = meshDesc.ptr; - } - else - { - meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false); - - if (meshData != null) - { - int[] indices = meshData.getIndexListAsInt(); - List vertices = meshData.getVertexList(); - - float[] verticesAsFloats = new float[vertices.Count * 3]; - int vi = 0; - foreach (OMV.Vector3 vv in vertices) - { - verticesAsFloats[vi++] = vv.X; - verticesAsFloats[vi++] = vv.Y; - verticesAsFloats[vi++] = vv.Z; - } - - // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", - // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); - - meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, - indices.GetLength(0), indices, vertices.Count, verticesAsFloats); - } - } - BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH); - newShape.shapeKey = newMeshKey; - - return newShape; - } - - // See that hull shape exists in the physical world and update prim.BSShape. - // We could be creating the hull because scale changed or whatever. - private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - BulletShape newShape; - - float lod; - System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - - // if the hull hasn't changed, don't rebuild it - if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) - return false; - - if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", - prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); - - // Remove usage of the previous shape. - DereferenceShape(prim.PhysShape, true, shapeCallback); - - newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); - newShape = VerifyMeshCreated(newShape, prim); - - ReferenceShape(newShape); - - prim.PhysShape = newShape; - return true; // 'true' means a new shape has been added to this prim - } - - List m_hulls; - private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) - { - - Object hullPtr = null; - HullDesc hullDesc; - if (Hulls.TryGetValue(newHullKey, out hullDesc)) - { - // If the hull shape already is created, just use it. - hullPtr = hullDesc.ptr; - } - else - { - // Build a new hull in the physical world - // Pass true for physicalness as this creates some sort of bounding box which we don't need - IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false); - if (meshData != null) - { - - int[] indices = meshData.getIndexListAsInt(); - List vertices = meshData.getVertexList(); - - //format conversion from IMesh format to DecompDesc format - List convIndices = new List(); - List convVertices = new List(); - for (int ii = 0; ii < indices.GetLength(0); ii++) - { - convIndices.Add(indices[ii]); - } - foreach (OMV.Vector3 vv in vertices) - { - convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); - } - - // setup and do convex hull conversion - m_hulls = new List(); - DecompDesc dcomp = new DecompDesc(); - dcomp.mIndices = convIndices; - dcomp.mVertices = convVertices; - ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); - // create the hull into the _hulls variable - convexBuilder.process(dcomp); - - // Convert the vertices and indices for passing to unmanaged. - // The hull information is passed as a large floating point array. - // The format is: - // convHulls[0] = number of hulls - // convHulls[1] = number of vertices in first hull - // convHulls[2] = hull centroid X coordinate - // convHulls[3] = hull centroid Y coordinate - // convHulls[4] = hull centroid Z coordinate - // convHulls[5] = first hull vertex X - // convHulls[6] = first hull vertex Y - // convHulls[7] = first hull vertex Z - // convHulls[8] = second hull vertex X - // ... - // convHulls[n] = number of vertices in second hull - // convHulls[n+1] = second hull centroid X coordinate - // ... - // - // TODO: is is very inefficient. Someday change the convex hull generator to return - // data structures that do not need to be converted in order to pass to Bullet. - // And maybe put the values directly into pinned memory rather than marshaling. - int hullCount = m_hulls.Count; - int totalVertices = 1; // include one for the count of the hulls - foreach (ConvexResult cr in m_hulls) - { - totalVertices += 4; // add four for the vertex count and centroid - totalVertices += cr.HullIndices.Count * 3; // we pass just triangles - } - float[] convHulls = new float[totalVertices]; - - convHulls[0] = (float)hullCount; - int jj = 1; - foreach (ConvexResult cr in m_hulls) - { - // copy vertices for index access - float3[] verts = new float3[cr.HullVertices.Count]; - int kk = 0; - foreach (float3 ff in cr.HullVertices) - { - verts[kk++] = ff; - } - - // add to the array one hull's worth of data - convHulls[jj++] = cr.HullIndices.Count; - convHulls[jj++] = 0f; // centroid x,y,z - convHulls[jj++] = 0f; - convHulls[jj++] = 0f; - foreach (int ind in cr.HullIndices) - { - convHulls[jj++] = verts[ind].x; - convHulls[jj++] = verts[ind].y; - convHulls[jj++] = verts[ind].z; - } - } - // create the hull data structure in Bullet - hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); - } - } - - BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL); - newShape.shapeKey = newHullKey; - - return newShape; - } - - // Callback from convex hull creater with a newly created hull. - // Just add it to our collection of hulls for this shape. - private void HullReturn(ConvexResult result) - { - m_hulls.Add(result); - return; - } - - // Compound shapes are always built from scratch. - // This shouldn't be to bad since most of the parts will be meshes that had been built previously. - private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - // Remove reference to the old shape - // Don't need to do this as the shape is freed when the new root shape is created below. - // DereferenceShape(prim.PhysShape, true, shapeCallback); - - BulletShape cShape = new BulletShape( - BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND); - - // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. - CreateGeomMeshOrHull(prim, shapeCallback); - BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); - if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", - prim.LocalID, cShape, prim.PhysShape); - - prim.PhysShape = cShape; - - return true; - } - - // Create a hash of all the shape parameters to be used as a key - // for this particular shape. - private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) - { - // level of detail based on size and type of the object - float lod = BSParam.MeshLOD; - if (pbs.SculptEntry) - lod = BSParam.SculptLOD; - - // Mega prims usually get more detail because one can interact with shape approximations at this size. - float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); - if (maxAxis > BSParam.MeshMegaPrimThreshold) - lod = BSParam.MeshMegaPrimLOD; - - retLod = lod; - return pbs.GetMeshKey(size, lod); - } - // For those who don't want the LOD - private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs) - { - float lod; - return ComputeShapeKey(size, pbs, out lod); - } - - // The creation of a mesh or hull can fail if an underlying asset is not available. - // There are two cases: 1) the asset is not in the cache and it needs to be fetched; - // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). - // The first case causes the asset to be fetched. The second case requires - // us to not loop forever. - // Called after creating a physical mesh or hull. If the physical shape was created, - // just return. - private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) - { - // If the shape was successfully created, nothing more to do - if (newShape.HasPhysicalShape) - return newShape; - - // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset - if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) - { - prim.LastAssetBuildFailed = true; - BSPhysObject xprim = prim; - DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", - LogHeader, prim.LocalID, prim.LastAssetBuildFailed); - Util.FireAndForget(delegate - { - RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; - if (assetProvider != null) - { - BSPhysObject yprim = xprim; // probably not necessary, but, just in case. - assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) - { - if (!yprim.BaseShape.SculptEntry) - return; - if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) - return; - - yprim.BaseShape.SculptData = asset.Data; - // This will cause the prim to see that the filler shape is not the right - // one and try again to build the object. - // No race condition with the normal shape setting since the rebuild is at taint time. - yprim.ForceBodyShapeRebuild(false); - - }); - } - }); - } - else - { - if (prim.LastAssetBuildFailed) - { - PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", - LogHeader, prim.LocalID, prim.BaseShape.SculptTexture); - } - } - - // While we figure out the real problem, stick a simple native shape on the object. - BulletShape fillinShape = - BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); - - return fillinShape; - } - - // Create a body object in Bullet. - // Updates prim.BSBody with the information about the new body if one is created. - // Returns 'true' if an object was actually created. - // Called at taint-time. - private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape, - BodyDestructionCallback bodyCallback) - { - bool ret = false; - - // the mesh, hull or native shape must have already been created in Bullet - bool mustRebuild = !prim.PhysBody.HasPhysicalBody; - - // If there is an existing body, verify it's of an acceptable type. - // If not a solid object, body is a GhostObject. Otherwise a RigidBody. - if (!mustRebuild) - { - CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); - if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY - || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) - { - // If the collisionObject is not the correct type for solidness, rebuild what's there - mustRebuild = true; - } - } - - if (mustRebuild || forceRebuild) - { - // Free any old body - DereferenceBody(prim.PhysBody, true, bodyCallback); - - BulletBody aBody; - Object bodyPtr = null; - if (prim.IsSolid) - { - bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, - prim.LocalID, prim.RawPosition, prim.RawOrientation); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString()); - } - else - { - bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, - prim.LocalID, prim.RawPosition, prim.RawOrientation); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString()); - } - aBody = new BulletBody(prim.LocalID, bodyPtr); - - ReferenceBody(aBody, true); - - prim.PhysBody = aBody; - - ret = true; - } - - return ret; - } - - private bool TryGetMeshByPtr(Object addr, out MeshDesc outDesc) - { - bool ret = false; - MeshDesc foundDesc = new MeshDesc(); - foreach (MeshDesc md in Meshes.Values) - { - if (md.ptr == addr) - { - foundDesc = md; - ret = true; - break; - } - - } - outDesc = foundDesc; - return ret; - } - - private bool TryGetHullByPtr(Object addr, out HullDesc outDesc) - { - bool ret = false; - HullDesc foundDesc = new HullDesc(); - foreach (HullDesc hd in Hulls.Values) - { - if (hd.ptr == addr) - { - foundDesc = hd; - ret = true; - break; - } - - } - outDesc = foundDesc; - return ret; - } - - private void DetailLog(string msg, params Object[] args) - { - if (PhysicsScene.PhysicsLogging.Enabled) - PhysicsScene.DetailLog(msg, args); - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs deleted file mode 100644 index 8ff0275..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ -public abstract class BSShape -{ - public Object ptr { get; set; } - public BSPhysicsShapeType type { get; set; } - public System.UInt64 key { get; set; } - public int referenceCount { get; set; } - public DateTime lastReferenced { get; set; } - - public BSShape() - { - ptr = null; - type = BSPhysicsShapeType.SHAPE_UNKNOWN; - key = 0; - referenceCount = 0; - lastReferenced = DateTime.Now; - } - - // Get a reference to a physical shape. Create if it doesn't exist - public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) - { - BSShape ret = null; - - if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) - { - // an avatar capsule is close to a native shape (it is not shared) - ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE, - FixedShapeKey.KEY_CAPSULE); - physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret); - } - - // Compound shapes are handled special as they are rebuilt from scratch. - // This isn't too great a hardship since most of the child shapes will already been created. - if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) - { - // Getting a reference to a compound shape gets you the compound shape with the root prim shape added - ret = BSShapeCompound.GetReference(prim); - physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); - } - - if (ret == null) - ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); - - return ret; - } - public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) - { - return null; - } - public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) - { - return null; - } - - // Release the use of a physical shape. - public abstract void Dereference(BSScene physicsScene); - - // All shapes have a static call to get a reference to the physical shape - // protected abstract static BSShape GetReference(); - - public override string ToString() - { - StringBuilder buff = new StringBuilder(); - buff.Append(""); - return buff.ToString(); - } -} - -public class BSShapeNull : BSShape -{ - public BSShapeNull() : base() - { - } - public static BSShape GetReference() { return new BSShapeNull(); } - public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } -} - -public class BSShapeNative : BSShape -{ - private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; - public BSShapeNative() : base() - { - } - public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) - { - // Native shapes are not shared and are always built anew. - return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); - } - - private BSShapeNative(BSScene physicsScene, BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) - { - ShapeData nativeShapeData = new ShapeData(); - nativeShapeData.Type = shapeType; - nativeShapeData.ID = prim.LocalID; - nativeShapeData.Scale = prim.Scale; - nativeShapeData.Size = prim.Scale; - nativeShapeData.MeshKey = (ulong)shapeKey; - nativeShapeData.HullKey = (ulong)shapeKey; - - - if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) - { - ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale); - physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); - } - else - { - ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData); - } - if (ptr == null) - { - physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", - LogHeader, prim.LocalID, shapeType); - } - type = shapeType; - key = (UInt64)shapeKey; - } - // Make this reference to the physical shape go away since native shapes are not shared. - public override void Dereference(BSScene physicsScene) - { - // Native shapes are not tracked and are released immediately - physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); - BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr); - ptr = null; - // Garbage collection will free up this instance. - } -} - -public class BSShapeMesh : BSShape -{ - private static string LogHeader = "[BULLETSIM SHAPE MESH]"; - private static Dictionary Meshes = new Dictionary(); - - public BSShapeMesh() : base() - { - } - public static BSShape GetReference() { return new BSShapeNull(); } - public override void Dereference(BSScene physicsScene) { } -} - -public class BSShapeHull : BSShape -{ - private static string LogHeader = "[BULLETSIM SHAPE HULL]"; - private static Dictionary Hulls = new Dictionary(); - - public BSShapeHull() : base() - { - } - public static BSShape GetReference() { return new BSShapeNull(); } - public override void Dereference(BSScene physicsScene) { } -} - -public class BSShapeCompound : BSShape -{ - private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; - public BSShapeCompound() : base() - { - } - public static BSShape GetReference(BSPhysObject prim) - { - return new BSShapeNull(); - } - public override void Dereference(BSScene physicsScene) { } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs deleted file mode 100644 index ba17059..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OpenSim.Framework; -using OpenSim.Region.Framework; -using OpenSim.Region.CoreModules; -using OpenSim.Region.Physics.Manager; - -using Nini.Config; -using log4net; - -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ -public sealed class BSTerrainHeightmap : BSTerrainPhys -{ - static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; - - BulletHeightMapInfo m_mapInfo = null; - - // Constructor to build a default, flat heightmap terrain. - public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) - : base(physicsScene, regionBase, id) - { - Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE); - Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION); - int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; - float[] initialMap = new float[totalHeights]; - for (int ii = 0; ii < totalHeights; ii++) - { - initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; - } - m_mapInfo = new BulletHeightMapInfo(id, initialMap, null); - m_mapInfo.minCoords = minTerrainCoords; - m_mapInfo.maxCoords = maxTerrainCoords; - m_mapInfo.terrainRegionBase = TerrainBase; - // Don't have to free any previous since we just got here. - BuildHeightmapTerrain(); - } - - // This minCoords and maxCoords passed in give the size of the terrain (min and max Z - // are the high and low points of the heightmap). - public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, - Vector3 minCoords, Vector3 maxCoords) - : base(physicsScene, regionBase, id) - { - m_mapInfo = new BulletHeightMapInfo(id, initialMap, null); - m_mapInfo.minCoords = minCoords; - m_mapInfo.maxCoords = maxCoords; - m_mapInfo.minZ = minCoords.Z; - m_mapInfo.maxZ = maxCoords.Z; - m_mapInfo.terrainRegionBase = TerrainBase; - - // Don't have to free any previous since we just got here. - BuildHeightmapTerrain(); - } - - public override void Dispose() - { - ReleaseHeightMapTerrain(); - } - - // Using the information in m_mapInfo, create the physical representation of the heightmap. - private void BuildHeightmapTerrain() - { - m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, - m_mapInfo.minCoords, m_mapInfo.maxCoords, - m_mapInfo.heightMap, BSParam.TerrainCollisionMargin); - - // Create the terrain shape from the mapInfo - m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), - BSPhysicsShapeType.SHAPE_TERRAIN); - - // The terrain object initial position is at the center of the object - Vector3 centerPos; - centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f); - centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); - centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f - 0.5f); - - m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID, - BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr, - m_mapInfo.ID, centerPos, Quaternion.Identity)); - - // Set current terrain attributes - BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainFriction); - BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainHitFraction); - BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, BSParam.TerrainRestitution); - BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); - - // Return the new terrain to the world of physical objects - BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr, centerPos, Quaternion.Identity); - - // redo its bounding box now that it is in the world - BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); - - m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; - m_mapInfo.terrainBody.ApplyCollisionMask(); - - // Make it so the terrain will not move or be considered for movement. - BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); - - return; - } - - // If there is information in m_mapInfo pointing to physical structures, release same. - private void ReleaseHeightMapTerrain() - { - if (m_mapInfo != null) - { - if (m_mapInfo.terrainBody.HasPhysicalBody) - { - BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); - // Frees both the body and the shape. - BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); - BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr); - } - } - m_mapInfo = null; - } - - // The passed position is relative to the base of the region. - public override float GetTerrainHeightAtXYZ(Vector3 pos) - { - float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; - - int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X; - try - { - ret = m_mapInfo.heightMap[mapIndex]; - } - catch - { - // Sometimes they give us wonky values of X and Y. Give a warning and return something. - PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", - LogHeader, m_mapInfo.terrainRegionBase, pos); - ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; - } - return ret; - } - - // The passed position is relative to the base of the region. - public override float GetWaterLevelAtXYZ(Vector3 pos) - { - return PhysicsScene.SimpleWaterLevel; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs deleted file mode 100644 index 66d62f0..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OpenSim.Framework; -using OpenSim.Region.Framework; -using OpenSim.Region.CoreModules; -using OpenSim.Region.Physics.Manager; - -using Nini.Config; -using log4net; - -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ - -// The physical implementation of the terrain is wrapped in this class. -public abstract class BSTerrainPhys : IDisposable -{ - public enum TerrainImplementation - { - Heightmap = 0, - Mesh = 1 - } - - public BSScene PhysicsScene { get; private set; } - // Base of the region in world coordinates. Coordinates inside the region are relative to this. - public Vector3 TerrainBase { get; private set; } - public uint ID { get; private set; } - - public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) - { - PhysicsScene = physicsScene; - TerrainBase = regionBase; - ID = id; - } - public abstract void Dispose(); - public abstract float GetTerrainHeightAtXYZ(Vector3 pos); - public abstract float GetWaterLevelAtXYZ(Vector3 pos); -} - -// ========================================================================================== -public sealed class BSTerrainManager : IDisposable -{ - static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; - - // These height values are fractional so the odd values will be - // noticable when debugging. - public const float HEIGHT_INITIALIZATION = 24.987f; - public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; - public const float HEIGHT_GETHEIGHT_RET = 24.765f; - public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f; - - // If the min and max height are equal, we reduce the min by this - // amount to make sure that a bounding box is built for the terrain. - public const float HEIGHT_EQUAL_FUDGE = 0.2f; - - // Until the whole simulator is changed to pass us the region size, we rely on constants. - public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); - - // The scene that I am part of - private BSScene PhysicsScene { get; set; } - - // The ground plane created to keep thing from falling to infinity. - private BulletBody m_groundPlane; - - // If doing mega-regions, if we're region zero we will be managing multiple - // region terrains since region zero does the physics for the whole mega-region. - private Dictionary m_terrains; - - // Flags used to know when to recalculate the height. - private bool m_terrainModified = false; - - // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. - // This is incremented before assigning to new region so it is the last ID allocated. - private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1; - public uint HighestTerrainID { get {return m_terrainCount; } } - - // If doing mega-regions, this holds our offset from region zero of - // the mega-regions. "parentScene" points to the PhysicsScene of region zero. - private Vector3 m_worldOffset; - // If the parent region (region 0), this is the extent of the combined regions - // relative to the origin of region zero - private Vector3 m_worldMax; - private PhysicsScene MegaRegionParentPhysicsScene { get; set; } - - public BSTerrainManager(BSScene physicsScene) - { - PhysicsScene = physicsScene; - m_terrains = new Dictionary(); - - // Assume one region of default size - m_worldOffset = Vector3.Zero; - m_worldMax = new Vector3(DefaultRegionSize); - MegaRegionParentPhysicsScene = null; - } - - public void Dispose() - { - ReleaseGroundPlaneAndTerrain(); - } - - // Create the initial instance of terrain and the underlying ground plane. - // This is called from the initialization routine so we presume it is - // safe to call Bullet in real time. We hope no one is moving prims around yet. - public void CreateInitialGroundPlaneAndTerrain() - { - // The ground plane is here to catch things that are trying to drop to negative infinity - BulletShape groundPlaneShape = new BulletShape( - BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, - BSParam.TerrainCollisionMargin), - BSPhysicsShapeType.SHAPE_GROUNDPLANE); - m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, - BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, - Vector3.Zero, Quaternion.Identity)); - BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr, Vector3.Zero, Quaternion.Identity); - BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr); - // Ground plane does not move - BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); - // Everything collides with the ground plane. - m_groundPlane.collisionType = CollisionType.Groundplane; - m_groundPlane.ApplyCollisionMask(); - - // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. - BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); - m_terrains.Add(Vector3.Zero, initialTerrain); - } - - // Release all the terrain structures we might have allocated - public void ReleaseGroundPlaneAndTerrain() - { - if (m_groundPlane.HasPhysicalBody) - { - if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) - { - BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); - } - m_groundPlane.Clear(); - } - - ReleaseTerrain(); - } - - // Release all the terrain we have allocated - public void ReleaseTerrain() - { - lock (m_terrains) - { - foreach (KeyValuePair kvp in m_terrains) - { - kvp.Value.Dispose(); - } - m_terrains.Clear(); - } - } - - // The simulator wants to set a new heightmap for the terrain. - public void SetTerrain(float[] heightMap) { - float[] localHeightMap = heightMap; - // If there are multiple requests for changes to the same terrain between ticks, - // only do that last one. - PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() - { - if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) - { - // If a child of a mega-region, we shouldn't have any terrain allocated for us - ReleaseGroundPlaneAndTerrain(); - // If doing the mega-prim stuff and we are the child of the zero region, - // the terrain is added to our parent - if (MegaRegionParentPhysicsScene is BSScene) - { - DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", - BSScene.DetailLogZero, m_worldOffset, m_worldMax); - ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( - BSScene.CHILDTERRAIN_ID, localHeightMap, - m_worldOffset, m_worldOffset + DefaultRegionSize, true); - } - } - else - { - // If not doing the mega-prim thing, just change the terrain - DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); - - UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, - m_worldOffset, m_worldOffset + DefaultRegionSize, true); - } - }); - } - - // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain - // based on the passed information. The 'id' should be either the terrain id or - // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. - // The latter feature is for creating child terrains for mega-regions. - // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new - // terrain shape is created and added to the body. - // This call is most often used to update the heightMap and parameters of the terrain. - // (The above does suggest that some simplification/refactoring is in order.) - // Called during taint-time. - private void UpdateTerrain(uint id, float[] heightMap, - Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) - { - DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}", - BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); - - // Find high and low points of passed heightmap. - // The min and max passed in is usually the area objects can be in (maximum - // object height, for instance). The terrain wants the bounding box for the - // terrain so replace passed min and max Z with the actual terrain min/max Z. - float minZ = float.MaxValue; - float maxZ = float.MinValue; - foreach (float height in heightMap) - { - if (height < minZ) minZ = height; - if (height > maxZ) maxZ = height; - } - if (minZ == maxZ) - { - // If min and max are the same, reduce min a little bit so a good bounding box is created. - minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE; - } - minCoords.Z = minZ; - maxCoords.Z = maxZ; - - Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); - - lock (m_terrains) - { - BSTerrainPhys terrainPhys; - if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) - { - // There is already a terrain in this spot. Free the old and build the new. - DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", - BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); - - // Remove old terrain from the collection - m_terrains.Remove(terrainRegionBase); - // Release any physical memory it may be using. - terrainPhys.Dispose(); - - if (MegaRegionParentPhysicsScene == null) - { - BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); - m_terrains.Add(terrainRegionBase, newTerrainPhys); - - m_terrainModified = true; - } - else - { - // It's possible that Combine() was called after this code was queued. - // If we are a child of combined regions, we don't create any terrain for us. - DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero); - - // Get rid of any terrain that may have been allocated for us. - ReleaseGroundPlaneAndTerrain(); - - // I hate doing this, but just bail - return; - } - } - else - { - // We don't know about this terrain so either we are creating a new terrain or - // our mega-prim child is giving us a new terrain to add to the phys world - - // if this is a child terrain, calculate a unique terrain id - uint newTerrainID = id; - if (newTerrainID >= BSScene.CHILDTERRAIN_ID) - newTerrainID = ++m_terrainCount; - - DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", - BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); - BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); - m_terrains.Add(terrainRegionBase, newTerrainPhys); - - m_terrainModified = true; - } - } - } - - // TODO: redo terrain implementation selection to allow other base types than heightMap. - private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) - { - PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", - LogHeader, PhysicsScene.RegionName, terrainRegionBase, - (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); - BSTerrainPhys newTerrainPhys = null; - switch ((int)BSParam.TerrainImplementation) - { - case (int)BSTerrainPhys.TerrainImplementation.Heightmap: - newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, - heightMap, minCoords, maxCoords); - break; - case (int)BSTerrainPhys.TerrainImplementation.Mesh: - newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, - heightMap, minCoords, maxCoords); - break; - default: - PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", - LogHeader, - (int)BSParam.TerrainImplementation, - BSParam.TerrainImplementation, - PhysicsScene.RegionName, terrainRegionBase); - break; - } - return newTerrainPhys; - } - - // Return 'true' of this position is somewhere in known physical terrain space - public bool IsWithinKnownTerrain(Vector3 pos) - { - Vector3 terrainBaseXYZ; - BSTerrainPhys physTerrain; - return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); - } - - // Given an X and Y, find the height of the terrain. - // Since we could be handling multiple terrains for a mega-region, - // the base of the region is calcuated assuming all regions are - // the same size and that is the default. - // Once the heightMapInfo is found, we have all the information to - // compute the offset into the array. - private float lastHeightTX = 999999f; - private float lastHeightTY = 999999f; - private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; - public float GetTerrainHeightAtXYZ(Vector3 pos) - { - float tX = pos.X; - float tY = pos.Y; - // You'd be surprized at the number of times this routine is called - // with the same parameters as last time. - if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY)) - return lastHeight; - m_terrainModified = false; - - lastHeightTX = tX; - lastHeightTY = tY; - float ret = HEIGHT_GETHEIGHT_RET; - - Vector3 terrainBaseXYZ; - BSTerrainPhys physTerrain; - if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) - { - ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ); - } - else - { - PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", - LogHeader, PhysicsScene.RegionName, tX, tY); - DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", - BSScene.DetailLogZero, pos, terrainBaseXYZ); - } - - lastHeight = ret; - return ret; - } - - public float GetWaterLevelAtXYZ(Vector3 pos) - { - float ret = WATER_HEIGHT_GETHEIGHT_RET; - - Vector3 terrainBaseXYZ; - BSTerrainPhys physTerrain; - if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) - { - ret = physTerrain.GetWaterLevelAtXYZ(pos); - } - else - { - PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", - LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); - } - return ret; - } - - // Given an address, return 'true' of there is a description of that terrain and output - // the descriptor class and the 'base' fo the addresses therein. - private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) - { - int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; - int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; - Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); - - BSTerrainPhys physTerrain = null; - lock (m_terrains) - { - m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); - } - outTerrainBase = terrainBaseXYZ; - outPhysTerrain = physTerrain; - return (physTerrain != null); - } - - // Although no one seems to check this, I do support combining. - public bool SupportsCombining() - { - return true; - } - - // This routine is called two ways: - // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum - // extent of the combined regions. This is to inform the parent of the size - // of the combined regions. - // and one with 'offset' as the offset of the child region to the base region, - // 'pScene' pointing to the parent and 'extents' of zero. This informs the - // child of its relative base and new parent. - public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) - { - m_worldOffset = offset; - m_worldMax = extents; - MegaRegionParentPhysicsScene = pScene; - if (pScene != null) - { - // We are a child. - // We want m_worldMax to be the highest coordinate of our piece of terrain. - m_worldMax = offset + DefaultRegionSize; - } - DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}", - BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax); - } - - // Unhook all the combining that I know about. - public void UnCombine(PhysicsScene pScene) - { - // Just like ODE, we don't do anything yet. - DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero); - } - - - private void DetailLog(string msg, params Object[] args) - { - PhysicsScene.PhysicsLogging.Write(msg, args); - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs deleted file mode 100644 index 6083dd4..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OpenSim.Framework; -using OpenSim.Region.Framework; -using OpenSim.Region.CoreModules; -using OpenSim.Region.Physics.Manager; - -using Nini.Config; -using log4net; - -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ -public sealed class BSTerrainMesh : BSTerrainPhys -{ - static string LogHeader = "[BULLETSIM TERRAIN MESH]"; - - private float[] m_savedHeightMap; - int m_sizeX; - int m_sizeY; - - BulletShape m_terrainShape; - BulletBody m_terrainBody; - - public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) - : base(physicsScene, regionBase, id) - { - } - - public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */) - : base(physicsScene, regionBase, id) - { - } - - // Create terrain mesh from a heightmap. - public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, - Vector3 minCoords, Vector3 maxCoords) - : base(physicsScene, regionBase, id) - { - int indicesCount; - int[] indices; - int verticesCount; - float[] vertices; - - m_savedHeightMap = initialMap; - - m_sizeX = (int)(maxCoords.X - minCoords.X); - m_sizeY = (int)(maxCoords.Y - minCoords.Y); - - if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap, - m_sizeX, m_sizeY, - (float)m_sizeX, (float)m_sizeY, - Vector3.Zero, 1.0f, - out indicesCount, out indices, out verticesCount, out vertices)) - { - // DISASTER!! - PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); - PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); - // Something is very messed up and a crash is in our future. - return; - } - PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", - ID, indicesCount, indices.Length, verticesCount, vertices.Length); - - m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, - indicesCount, indices, verticesCount, vertices), - BSPhysicsShapeType.SHAPE_MESH); - if (!m_terrainShape.HasPhysicalShape) - { - // DISASTER!! - PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); - physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); - // Something is very messed up and a crash is in our future. - return; - } - - Vector3 pos = regionBase; - Quaternion rot = Quaternion.Identity; - - m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); - if (!m_terrainBody.HasPhysicalBody) - { - // DISASTER!! - physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); - // Something is very messed up and a crash is in our future. - return; - } - - // Set current terrain attributes - BulletSimAPI.SetFriction2(m_terrainBody.ptr, BSParam.TerrainFriction); - BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, BSParam.TerrainHitFraction); - BulletSimAPI.SetRestitution2(m_terrainBody.ptr, BSParam.TerrainRestitution); - BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); - - // Static objects are not very massive. - BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); - - // Put the new terrain to the world of physical objects - BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr, pos, rot); - - // Redo its bounding box now that it is in the world - BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); - - m_terrainBody.collisionType = CollisionType.Terrain; - m_terrainBody.ApplyCollisionMask(); - - // Make it so the terrain will not move or be considered for movement. - BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); - } - - public override void Dispose() - { - if (m_terrainBody.HasPhysicalBody) - { - BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); - // Frees both the body and the shape. - BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr); - } - } - - public override float GetTerrainHeightAtXYZ(Vector3 pos) - { - // For the moment use the saved heightmap to get the terrain height. - // TODO: raycast downward to find the true terrain below the position. - float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; - - int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X; - try - { - ret = m_savedHeightMap[mapIndex]; - } - catch - { - // Sometimes they give us wonky values of X and Y. Give a warning and return something. - PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", - LogHeader, TerrainBase, pos); - ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; - } - return ret; - } - - // The passed position is relative to the base of the region. - public override float GetWaterLevelAtXYZ(Vector3 pos) - { - return PhysicsScene.SimpleWaterLevel; - } - - // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). - // Return 'true' if successfully created. - public static bool ConvertHeightmapToMesh( - BSScene physicsScene, - float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap - float extentX, float extentY, // zero based range for output vertices - Vector3 extentBase, // base to be added to all vertices - float magnification, // number of vertices to create between heightMap coords - out int indicesCountO, out int[] indicesO, - out int verticesCountO, out float[] verticesO) - { - bool ret = false; - - int indicesCount = 0; - int verticesCount = 0; - int[] indices = new int[0]; - float[] vertices = new float[0]; - - // Simple mesh creation which assumes magnification == 1. - // TODO: do a more general solution that scales, adds new vertices and smoothes the result. - - // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop - // from zero to <= sizeX). The triangle indices are then generated as two triangles - // per heightmap point. There are sizeX by sizeY of these squares. The extra row and - // column of vertices are used to complete the triangles of the last row and column - // of the heightmap. - try - { - // One vertice per heightmap value plus the vertices off the top and bottom edge. - int totalVertices = (sizeX + 1) * (sizeY + 1); - vertices = new float[totalVertices * 3]; - int totalIndices = sizeX * sizeY * 6; - indices = new int[totalIndices]; - - float magX = (float)sizeX / extentX; - float magY = (float)sizeY / extentY; - physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", - BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); - float minHeight = float.MaxValue; - // Note that sizeX+1 vertices are created since there is land between this and the next region. - for (int yy = 0; yy <= sizeY; yy++) - { - for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times - { - int offset = yy * sizeX + xx; - // Extend the height with the height from the last row or column - if (yy == sizeY) offset -= sizeX; - if (xx == sizeX) offset -= 1; - float height = heightMap[offset]; - minHeight = Math.Min(minHeight, height); - vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; - vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; - vertices[verticesCount + 2] = height + extentBase.Z; - verticesCount += 3; - } - } - verticesCount = verticesCount / 3; - - for (int yy = 0; yy < sizeY; yy++) - { - for (int xx = 0; xx < sizeX; xx++) - { - int offset = yy * (sizeX + 1) + xx; - // Each vertices is presumed to be the upper left corner of a box of two triangles - indices[indicesCount + 0] = offset; - indices[indicesCount + 1] = offset + 1; - indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column - indices[indicesCount + 3] = offset + 1; - indices[indicesCount + 4] = offset + sizeX + 2; - indices[indicesCount + 5] = offset + sizeX + 1; - indicesCount += 6; - } - } - - ret = true; - } - catch (Exception e) - { - physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", - LogHeader, physicsScene.RegionName, extentBase, e); - } - - indicesCountO = indicesCount; - indicesO = indices; - verticesCountO = verticesCount; - verticesO = vertices; - - return ret; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs deleted file mode 100644 index 93643c9..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs +++ /dev/null @@ -1,1603 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; -using BulletXNA; -using OpenMetaverse; -using BulletXNA.LinearMath; -using BulletXNA.BulletCollision; -using BulletXNA.BulletDynamics; -using BulletXNA.BulletCollision.CollisionDispatch; -using OpenSim.Framework; - -namespace OpenSim.Region.Physics.BulletSNPlugin { - -// Classes to allow some type checking for the API -// These hold pointers to allocated objects in the unmanaged space. - - - - // Constraint type values as defined by Bullet -public enum ConstraintType : int -{ - POINT2POINT_CONSTRAINT_TYPE = 3, - HINGE_CONSTRAINT_TYPE, - CONETWIST_CONSTRAINT_TYPE, - D6_CONSTRAINT_TYPE, - SLIDER_CONSTRAINT_TYPE, - CONTACT_CONSTRAINT_TYPE, - D6_SPRING_CONSTRAINT_TYPE, - MAX_CONSTRAINT_TYPE -} - -// =============================================================================== -[StructLayout(LayoutKind.Sequential)] -public struct ConvexHull -{ - Vector3 Offset; - int VertexCount; - Vector3[] Vertices; -} -public enum BSPhysicsShapeType -{ - SHAPE_UNKNOWN = 0, - SHAPE_CAPSULE = 1, - SHAPE_BOX = 2, - SHAPE_CONE = 3, - SHAPE_CYLINDER = 4, - SHAPE_SPHERE = 5, - SHAPE_MESH = 6, - SHAPE_HULL = 7, - // following defined by BulletSim - SHAPE_GROUNDPLANE = 20, - SHAPE_TERRAIN = 21, - SHAPE_COMPOUND = 22, - SHAPE_HEIGHTMAP = 23, -}; - -// The native shapes have predefined shape hash keys -public enum FixedShapeKey : ulong -{ - KEY_NONE = 0, - KEY_BOX = 1, - KEY_SPHERE = 2, - KEY_CONE = 3, - KEY_CYLINDER = 4, - KEY_CAPSULE = 5, -} - -[StructLayout(LayoutKind.Sequential)] -public struct ShapeData -{ - public uint ID; - public BSPhysicsShapeType Type; - public Vector3 Position; - public Quaternion Rotation; - public Vector3 Velocity; - public Vector3 Scale; - public float Mass; - public float Buoyancy; - public System.UInt64 HullKey; - public System.UInt64 MeshKey; - public float Friction; - public float Restitution; - public float Collidable; // true of things bump into this - public float Static; // true if a static object. Otherwise gravity, etc. - public float Solid; // true if object cannot be passed through - public Vector3 Size; - - // note that bools are passed as floats since bool size changes by language and architecture - public const float numericTrue = 1f; - public const float numericFalse = 0f; -} -[StructLayout(LayoutKind.Sequential)] -public struct SweepHit -{ - public uint ID; - public float Fraction; - public Vector3 Normal; - public Vector3 Point; -} -[StructLayout(LayoutKind.Sequential)] -public struct RaycastHit -{ - public uint ID; - public float Fraction; - public Vector3 Normal; -} -[StructLayout(LayoutKind.Sequential)] -public struct CollisionDesc -{ - public uint aID; - public uint bID; - public Vector3 point; - public Vector3 normal; -} -[StructLayout(LayoutKind.Sequential)] -public struct EntityProperties -{ - public uint ID; - public Vector3 Position; - public Quaternion Rotation; - public Vector3 Velocity; - public Vector3 Acceleration; - public Vector3 RotationalVelocity; - public override string ToString() - { - return string.Format("ID:{0}, Pos:<{1:F},{2:F},{3:F}>, Rot:<{4:F},{5:F},{6:F},{7:F}>, LVel:<{8:F},{9:F},{10:F}>, AVel:<{11:F},{12:F},{13:F}>", - ID.ToString(), - Position.X,Position.Y,Position.Z, - Rotation.X,Rotation.Y,Rotation.Z,Rotation.W, - Velocity.X,Velocity.Y,Velocity.Z, - RotationalVelocity.X,RotationalVelocity.Y,RotationalVelocity.Z - ); - } -} - -// Format of this structure must match the definition in the C++ code -// NOTE: adding the X causes compile breaks if used. These are unused symbols -// that can be removed from both here and the unmanaged definition of this structure. -[StructLayout(LayoutKind.Sequential)] -public struct ConfigurationParameters -{ - public float defaultFriction; - public float defaultDensity; - public float defaultRestitution; - public float collisionMargin; - public float gravity; - - public float XlinearDamping; - public float XangularDamping; - public float XdeactivationTime; - public float XlinearSleepingThreshold; - public float XangularSleepingThreshold; - public float XccdMotionThreshold; - public float XccdSweptSphereRadius; - public float XcontactProcessingThreshold; - - public float XterrainImplementation; - public float XterrainFriction; - public float XterrainHitFraction; - public float XterrainRestitution; - public float XterrainCollisionMargin; - - public float XavatarFriction; - public float XavatarStandingFriction; - public float XavatarDensity; - public float XavatarRestitution; - public float XavatarCapsuleWidth; - public float XavatarCapsuleDepth; - public float XavatarCapsuleHeight; - public float XavatarContactProcessingThreshold; - - public float XvehicleAngularDamping; - - public float maxPersistantManifoldPoolSize; - public float maxCollisionAlgorithmPoolSize; - public float shouldDisableContactPoolDynamicAllocation; - public float shouldForceUpdateAllAabbs; - public float shouldRandomizeSolverOrder; - public float shouldSplitSimulationIslands; - public float shouldEnableFrictionCaching; - public float numberOfSolverIterations; - - public float XlinksetImplementation; - public float XlinkConstraintUseFrameOffset; - public float XlinkConstraintEnableTransMotor; - public float XlinkConstraintTransMotorMaxVel; - public float XlinkConstraintTransMotorMaxForce; - public float XlinkConstraintERP; - public float XlinkConstraintCFM; - public float XlinkConstraintSolverIterations; - - public float physicsLoggingFrames; - - public const float numericTrue = 1f; - public const float numericFalse = 0f; -} - - -// The states a bullet collision object can have - -public enum ActivationState : uint -{ - UNDEFINED = 0, - ACTIVE_TAG = 1, - ISLAND_SLEEPING = 2, - WANTS_DEACTIVATION = 3, - DISABLE_DEACTIVATION = 4, - DISABLE_SIMULATION = 5, -} - -public enum CollisionObjectTypes : int -{ - CO_COLLISION_OBJECT = 1 << 0, - CO_RIGID_BODY = 1 << 1, - CO_GHOST_OBJECT = 1 << 2, - CO_SOFT_BODY = 1 << 3, - CO_HF_FLUID = 1 << 4, - CO_USER_TYPE = 1 << 5, -} - -// Values used by Bullet and BulletSim to control object properties. -// Bullet's "CollisionFlags" has more to do with operations on the -// object (if collisions happen, if gravity effects it, ...). - [Flags] -public enum CollisionFlags : uint -{ - CF_STATIC_OBJECT = 1 << 0, - CF_KINEMATIC_OBJECT = 1 << 1, - CF_NO_CONTACT_RESPONSE = 1 << 2, - CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3, - CF_CHARACTER_OBJECT = 1 << 4, - CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, - CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, - // Following used by BulletSim to control collisions and updates - BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, - BS_FLOATS_ON_WATER = 1 << 11, - BS_VEHICLE_COLLISIONS = 1 << 12, - BS_NONE = 0, - BS_ALL = 0xFFFFFFFF, - - // These are the collision flags switched depending on physical state. - // The other flags are used for other things and should not be fooled with. - BS_ACTIVE = CF_STATIC_OBJECT - | CF_KINEMATIC_OBJECT - | CF_NO_CONTACT_RESPONSE -}; - -// Values for collisions groups and masks -public enum CollisionFilterGroups : uint -{ - // Don't use the bit definitions!! Define the use in a - // filter/mask definition below. This way collision interactions - // are more easily debugged. - BNoneGroup = 0, - BDefaultGroup = 1 << 0, - BStaticGroup = 1 << 1, - BKinematicGroup = 1 << 2, - BDebrisGroup = 1 << 3, - BSensorTrigger = 1 << 4, - BCharacterGroup = 1 << 5, - BAllGroup = 0xFFFFFFFF, - // Filter groups defined by BulletSim - BGroundPlaneGroup = 1 << 10, - BTerrainGroup = 1 << 11, - BRaycastGroup = 1 << 12, - BSolidGroup = 1 << 13, - // BLinksetGroup = xx // a linkset proper is either static or dynamic - BLinksetChildGroup = 1 << 14, - // The collsion filters and masked are defined in one place -- don't want them scattered - AvatarGroup = BCharacterGroup, - AvatarMask = BAllGroup, - ObjectGroup = BSolidGroup, - ObjectMask = BAllGroup, - StaticObjectGroup = BStaticGroup, - StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much - LinksetGroup = BLinksetChildGroup, - LinksetMask = BAllGroup & ~BLinksetChildGroup, // linkset objects don't collide with each other - VolumeDetectGroup = BSensorTrigger, - VolumeDetectMask = ~BSensorTrigger, - TerrainGroup = BTerrainGroup, - TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide - GroundPlaneGroup = BGroundPlaneGroup, - GroundPlaneMask = BAllGroup - -}; - -// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 -// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. -public enum ConstraintParams : int -{ - BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730 - BT_CONSTRAINT_STOP_ERP, - BT_CONSTRAINT_CFM, - BT_CONSTRAINT_STOP_CFM, -}; -public enum ConstraintParamAxis : int -{ - AXIS_LINEAR_X = 0, - AXIS_LINEAR_Y, - AXIS_LINEAR_Z, - AXIS_ANGULAR_X, - AXIS_ANGULAR_Y, - AXIS_ANGULAR_Z, - AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls - AXIS_ANGULAR_ALL, - AXIS_ALL -}; - -// =============================================================================== -static class BulletSimAPI { - private static int m_collisionsThisFrame; - public delegate void DebugLogCallback(string msg); - /// - /// - /// - /// - /// - internal static bool RemoveObjectFromWorld2(object pWorld, object pBody) - { - DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; - RigidBody body = pBody as RigidBody; - world.RemoveRigidBody(body); - return true; - } - - internal static void SetRestitution2(object pBody, float pRestitution) - { - RigidBody body = pBody as RigidBody; - body.SetRestitution(pRestitution); - } - - internal static void SetMargin2(object pShape, float pMargin) - { - CollisionShape shape = pShape as CollisionShape; - shape.SetMargin(pMargin); - } - - internal static void SetLocalScaling2(object pShape, Vector3 pScale) - { - CollisionShape shape = pShape as CollisionShape; - IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); - shape.SetLocalScaling(ref vec); - - } - - internal static void SetContactProcessingThreshold2(object pBody, float contactprocessingthreshold) - { - RigidBody body = pBody as RigidBody; - body.SetContactProcessingThreshold(contactprocessingthreshold); - } - - internal static void SetCcdMotionThreshold2(object pBody, float pccdMotionThreashold) - { - RigidBody body = pBody as RigidBody; - body.SetCcdMotionThreshold(pccdMotionThreashold); - } - - internal static void SetCcdSweptSphereRadius2(object pBody, float pCcdSweptSphereRadius) - { - RigidBody body = pBody as RigidBody; - body.SetCcdSweptSphereRadius(pCcdSweptSphereRadius); - } - - internal static void SetAngularFactorV2(object pBody, Vector3 pAngularFactor) - { - RigidBody body = pBody as RigidBody; - body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z)); - } - - internal static CollisionFlags AddToCollisionFlags2(object pBody, CollisionFlags pcollisionFlags) - { - CollisionObject body = pBody as CollisionObject; - CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags(); - existingcollisionFlags |= pcollisionFlags; - body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); - return (CollisionFlags) (uint) existingcollisionFlags; - } - - internal static void AddObjectToWorld2(object pWorld, object pBody) - { - RigidBody body = pBody as RigidBody; - DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; - //if (!(body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE && body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE)) - - world.AddRigidBody(body); - - //if (body.GetBroadphaseHandle() != null) - // world.UpdateSingleAabb(body); - } - - internal static void AddObjectToWorld2(object pWorld, object pBody, Vector3 _position, Quaternion _orientation) - { - RigidBody body = pBody as RigidBody; - DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; - //if (!(body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE && body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE)) - - world.AddRigidBody(body); - IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); - IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, - _orientation.W); - IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); - mat._origin = vposition; - body.SetWorldTransform(mat); - //if (body.GetBroadphaseHandle() != null) - // world.UpdateSingleAabb(body); - } - - internal static void ForceActivationState2(object pBody, ActivationState pActivationState) - { - CollisionObject body = pBody as CollisionObject; - body.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState); - } - - internal static void UpdateSingleAabb2(object pWorld, object pBody) - { - CollisionObject body = pBody as CollisionObject; - DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; - world.UpdateSingleAabb(body); - } - - internal static bool SetCollisionGroupMask2(object pBody, uint pGroup, uint pMask) - { - RigidBody body = pBody as RigidBody; - body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; - body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; - if ((uint) body.GetBroadphaseHandle().m_collisionFilterGroup == 0) - return false; - return true; - } - - internal static void ClearAllForces2(object pBody) - { - CollisionObject body = pBody as CollisionObject; - IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0); - body.SetInterpolationLinearVelocity(ref zeroVector); - body.SetInterpolationAngularVelocity(ref zeroVector); - IndexedMatrix bodytransform = body.GetWorldTransform(); - - body.SetInterpolationWorldTransform(ref bodytransform); - - if (body is RigidBody) - { - RigidBody rigidbody = body as RigidBody; - rigidbody.SetLinearVelocity(zeroVector); - rigidbody.SetAngularVelocity(zeroVector); - rigidbody.ClearForces(); - } - } - - internal static void SetInterpolationAngularVelocity2(object pBody, Vector3 pVector3) - { - RigidBody body = pBody as RigidBody; - IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); - body.SetInterpolationAngularVelocity(ref vec); - } - - internal static void SetAngularVelocity2(object pBody, Vector3 pVector3) - { - RigidBody body = pBody as RigidBody; - IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); - body.SetAngularVelocity(ref vec); - } - - internal static void ClearForces2(object pBody) - { - RigidBody body = pBody as RigidBody; - body.ClearForces(); - } - - internal static void SetTranslation2(object pBody, Vector3 _position, Quaternion _orientation) - { - RigidBody body = pBody as RigidBody; - IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); - IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, - _orientation.W); - IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); - mat._origin = vposition; - body.SetWorldTransform(mat); - - } - - internal static Vector3 GetPosition2(object pBody) - { - RigidBody body = pBody as RigidBody; - IndexedVector3 pos = body.GetInterpolationWorldTransform()._origin; - return new Vector3(pos.X, pos.Y, pos.Z); - } - - internal static Vector3 CalculateLocalInertia2(object pShape, float pphysMass) - { - CollisionShape shape = pShape as CollisionShape; - IndexedVector3 inertia = IndexedVector3.Zero; - shape.CalculateLocalInertia(pphysMass, out inertia); - return new Vector3(inertia.X, inertia.Y, inertia.Z); - } - - internal static void SetMassProps2(object pBody, float pphysMass, Vector3 plocalInertia) - { - RigidBody body = pBody as RigidBody; - IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z); - body.SetMassProps(pphysMass, inertia); - } - - - internal static void SetObjectForce2(object pBody, Vector3 _force) - { - RigidBody body = pBody as RigidBody; - IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z); - body.SetTotalForce(ref force); - } - - internal static void SetFriction2(object pBody, float _currentFriction) - { - RigidBody body = pBody as RigidBody; - body.SetFriction(_currentFriction); - } - - internal static void SetLinearVelocity2(object pBody, Vector3 _velocity) - { - RigidBody body = pBody as RigidBody; - IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z); - body.SetLinearVelocity(velocity); - } - - internal static void Activate2(object pBody, bool pforceactivation) - { - RigidBody body = pBody as RigidBody; - body.Activate(pforceactivation); - - } - - internal static Quaternion GetOrientation2(object pBody) - { - RigidBody body = pBody as RigidBody; - IndexedQuaternion mat = body.GetInterpolationWorldTransform().GetRotation(); - return new Quaternion(mat.X, mat.Y, mat.Z, mat.W); - } - - internal static CollisionFlags RemoveFromCollisionFlags2(object pBody, CollisionFlags pcollisionFlags) - { - RigidBody body = pBody as RigidBody; - CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags(); - existingcollisionFlags &= ~pcollisionFlags; - body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); - return (CollisionFlags)(uint)existingcollisionFlags; - } - - internal static void SetGravity2(object pBody, Vector3 pGravity) - { - RigidBody body = pBody as RigidBody; - IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z); - body.SetGravity(gravity); - } - - internal static bool DestroyConstraint2(object pBody, object pConstraint) - { - RigidBody body = pBody as RigidBody; - TypedConstraint constraint = pConstraint as TypedConstraint; - body.RemoveConstraintRef(constraint); - return true; - } - - internal static bool SetLinearLimits2(object pConstraint, Vector3 low, Vector3 high) - { - Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; - IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); - IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); - constraint.SetLinearLowerLimit(lowlimit); - constraint.SetLinearUpperLimit(highlimit); - return true; - } - - internal static bool SetAngularLimits2(object pConstraint, Vector3 low, Vector3 high) - { - Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; - IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); - IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); - constraint.SetAngularLowerLimit(lowlimit); - constraint.SetAngularUpperLimit(highlimit); - return true; - } - - internal static void SetConstraintNumSolverIterations2(object pConstraint, float cnt) - { - Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; - constraint.SetOverrideNumSolverIterations((int)cnt); - } - - internal static void CalculateTransforms2(object pConstraint) - { - Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; - constraint.CalculateTransforms(); - } - - internal static void SetConstraintEnable2(object pConstraint, float p_2) - { - Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; - constraint.SetEnabled((p_2 == 0) ? false : true); - } - - - //BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,frame1, frame1rot,frame2, frame2rot,useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); - internal static object Create6DofConstraint2(object pWorld, object pBody1, object pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) - - { - DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; - RigidBody body1 = pBody1 as RigidBody; - RigidBody body2 = pBody2 as RigidBody; - IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); - IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); - IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); - frame1._origin = frame1v; - - IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); - IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); - IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); - frame2._origin = frame1v; - - Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, - puseLinearReferenceFrameA); - consttr.CalculateTransforms(); - world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); - - return consttr; - } - - - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - internal static object Create6DofConstraintToPoint2(object pWorld, object pBody1, object pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) - { - DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; - RigidBody body1 = pBody1 as RigidBody; - RigidBody body2 = pBody2 as RigidBody; - IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); - IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); - - IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); - IndexedMatrix mat = IndexedMatrix.Identity; - mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); - frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint; - frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint; - - Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); - consttr.CalculateTransforms(); - world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies); - - return consttr; - } - //SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); - internal static void SetFrames2(object pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot) - { - Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; - IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); - IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); - IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); - frame1._origin = frame1v; - - IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); - IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); - IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); - frame2._origin = frame1v; - constraint.SetFrames(ref frame1, ref frame2); - } - - - - - internal static bool IsInWorld2(object pWorld, object pShapeObj) - { - DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; - CollisionObject shape = pShapeObj as CollisionObject; - return world.IsInWorld(shape); - } - - internal static void SetInterpolationLinearVelocity2(object pBody, Vector3 VehicleVelocity) - { - RigidBody body = pBody as RigidBody; - IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z); - body.SetInterpolationLinearVelocity(ref velocity); - } - - internal static bool UseFrameOffset2(object pConstraint, float onOff) - { - Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; - constraint.SetUseFrameOffset((onOff == 0) ? false : true); - return true; - } - //SetBreakingImpulseThreshold2(m_constraint.ptr, threshold); - internal static bool SetBreakingImpulseThreshold2(object pConstraint, float threshold) - { - Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint; - constraint.SetBreakingImpulseThreshold(threshold); - return true; - } - //BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); - internal static void SetAngularDamping2(object pBody, float angularDamping) - { - RigidBody body = pBody as RigidBody; - float lineardamping = body.GetLinearDamping(); - body.SetDamping(lineardamping, angularDamping); - - } - - internal static void UpdateInertiaTensor2(object pBody) - { - RigidBody body = pBody as RigidBody; - body.UpdateInertiaTensor(); - } - - internal static void RecalculateCompoundShapeLocalAabb2( object pCompoundShape) - { - - CompoundShape shape = pCompoundShape as CompoundShape; - shape.RecalculateLocalAabb(); - } - - //BulletSimAPI.GetCollisionFlags2(PhysBody.ptr) - internal static CollisionFlags GetCollisionFlags2(object pBody) - { - RigidBody body = pBody as RigidBody; - uint flags = (uint)body.GetCollisionFlags(); - return (CollisionFlags) flags; - } - - internal static void SetDamping2(object pBody, float pLinear, float pAngular) - { - RigidBody body = pBody as RigidBody; - body.SetDamping(pLinear, pAngular); - } - //PhysBody.ptr, PhysicsScene.Params.deactivationTime); - internal static void SetDeactivationTime2(object pBody, float pDeactivationTime) - { - RigidBody body = pBody as RigidBody; - body.SetDeactivationTime(pDeactivationTime); - } - //SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); - internal static void SetSleepingThresholds2(object pBody, float plinearSleepingThreshold, float pangularSleepingThreshold) - { - RigidBody body = pBody as RigidBody; - body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold); - } - - internal static CollisionObjectTypes GetBodyType2(object pBody) - { - RigidBody body = pBody as RigidBody; - return (CollisionObjectTypes)(int) body.GetInternalType(); - } - - //BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); - internal static void ApplyCentralForce2(object pBody, Vector3 pfSum) - { - RigidBody body = pBody as RigidBody; - IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); - body.ApplyCentralForce(ref fSum); - } - internal static void ApplyCentralImpulse2(object pBody, Vector3 pfSum) - { - RigidBody body = pBody as RigidBody; - IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); - body.ApplyCentralImpulse(ref fSum); - } - internal static void ApplyTorque2(object pBody, Vector3 pfSum) - { - RigidBody body = pBody as RigidBody; - IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); - body.ApplyTorque(ref fSum); - } - internal static void ApplyTorqueImpulse2(object pBody, Vector3 pfSum) - { - RigidBody body = pBody as RigidBody; - IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); - body.ApplyTorqueImpulse(ref fSum); - } - - internal static void DumpRigidBody2(object p, object p_2) - { - //TODO: - } - - internal static void DumpCollisionShape2(object p, object p_2) - { - //TODO: - } - - internal static void DestroyObject2(object p, object p_2) - { - //TODO: - } - - internal static void Shutdown2(object pWorld) - { - DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; - world.Cleanup(); - } - - internal static void DeleteCollisionShape2(object p, object p_2) - { - //TODO: - } - //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); - - internal static object CreateBodyFromShape2(object pWorld, object pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) - { - CollisionWorld world = pWorld as CollisionWorld; - IndexedMatrix mat = - IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, - pRawOrientation.Z, pRawOrientation.W)); - mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); - CollisionShape shape = pShape as CollisionShape; - //UpdateSingleAabb2(world, shape); - // TODO: Feed Update array into null - RigidBody body = new RigidBody(0,new SimMotionState(world,pLocalID,mat,null),shape,IndexedVector3.Zero); - - body.SetUserPointer(pLocalID); - return body; - } - - - internal static object CreateBodyWithDefaultMotionState2( object pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) - { - - IndexedMatrix mat = - IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, - pRawOrientation.Z, pRawOrientation.W)); - mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); - - CollisionShape shape = pShape as CollisionShape; - - // TODO: Feed Update array into null - RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero); - body.SetWorldTransform(mat); - body.SetUserPointer(pLocalID); - return body; - } - //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); - internal static void SetCollisionFlags2(object pBody, CollisionFlags collisionFlags) - { - RigidBody body = pBody as RigidBody; - body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags); - } - //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); - internal static void SetHitFraction2(object pBody, float pHitFraction) - { - RigidBody body = pBody as RigidBody; - body.SetHitFraction(pHitFraction); - } - //BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale); - internal static object BuildCapsuleShape2(object pWorld, float pRadius, float pHeight, Vector3 pScale) - { - DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; - IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); - CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight); - capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin); - capsuleShapeZ.SetLocalScaling(ref scale); - - return capsuleShapeZ; - } - - public static object Initialize2(Vector3 worldExtent, ConfigurationParameters[] o, int mMaxCollisionsPerFrame, ref List collisionArray, int mMaxUpdatesPerFrame, ref List updateArray, object mDebugLogCallbackHandle) - { - CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); - - p.angularDamping = o[0].XangularDamping; - p.defaultFriction = o[0].defaultFriction; - p.defaultFriction = o[0].defaultFriction; - p.defaultDensity = o[0].defaultDensity; - p.defaultRestitution = o[0].defaultRestitution; - p.collisionMargin = o[0].collisionMargin; - p.gravity = o[0].gravity; - - p.linearDamping = o[0].XlinearDamping; - p.angularDamping = o[0].XangularDamping; - p.deactivationTime = o[0].XdeactivationTime; - p.linearSleepingThreshold = o[0].XlinearSleepingThreshold; - p.angularSleepingThreshold = o[0].XangularSleepingThreshold; - p.ccdMotionThreshold = o[0].XccdMotionThreshold; - p.ccdSweptSphereRadius = o[0].XccdSweptSphereRadius; - p.contactProcessingThreshold = o[0].XcontactProcessingThreshold; - - p.terrainImplementation = o[0].XterrainImplementation; - p.terrainFriction = o[0].XterrainFriction; - - p.terrainHitFraction = o[0].XterrainHitFraction; - p.terrainRestitution = o[0].XterrainRestitution; - p.terrainCollisionMargin = o[0].XterrainCollisionMargin; - - p.avatarFriction = o[0].XavatarFriction; - p.avatarStandingFriction = o[0].XavatarStandingFriction; - p.avatarDensity = o[0].XavatarDensity; - p.avatarRestitution = o[0].XavatarRestitution; - p.avatarCapsuleWidth = o[0].XavatarCapsuleWidth; - p.avatarCapsuleDepth = o[0].XavatarCapsuleDepth; - p.avatarCapsuleHeight = o[0].XavatarCapsuleHeight; - p.avatarContactProcessingThreshold = o[0].XavatarContactProcessingThreshold; - - p.vehicleAngularDamping = o[0].XvehicleAngularDamping; - - p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; - p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; - p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; - p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs; - p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder; - p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands; - p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching; - p.numberOfSolverIterations = o[0].numberOfSolverIterations; - - p.linksetImplementation = o[0].XlinksetImplementation; - p.linkConstraintUseFrameOffset = o[0].XlinkConstraintUseFrameOffset; - p.linkConstraintEnableTransMotor = o[0].XlinkConstraintEnableTransMotor; - p.linkConstraintTransMotorMaxVel = o[0].XlinkConstraintTransMotorMaxVel; - p.linkConstraintTransMotorMaxForce = o[0].XlinkConstraintTransMotorMaxForce; - p.linkConstraintERP = o[0].XlinkConstraintERP; - p.linkConstraintCFM = o[0].XlinkConstraintCFM; - p.linkConstraintSolverIterations = o[0].XlinkConstraintSolverIterations; - p.physicsLoggingFrames = o[0].physicsLoggingFrames; - DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); - - DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); - CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); - - - if (p.maxPersistantManifoldPoolSize > 0) - cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize; - if (p.shouldDisableContactPoolDynamicAllocation !=0) - m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION); - //if (p.maxCollisionAlgorithmPoolSize >0 ) - - DbvtBroadphase m_broadphase = new DbvtBroadphase(); - //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0); - //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256); - - //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true); - m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback()); - - SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver(); - - DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci); - world.UpdatedObjects = updateArray; - world.UpdatedCollisions = collisionArray; - world.WorldSettings.Params = p; - world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0); - world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD; - if (p.shouldRandomizeSolverOrder != 0) - world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER; - - world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0); - //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port - - if (p.shouldEnableFrictionCaching != 0) - world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING; - - if (p.numberOfSolverIterations > 0) - world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations; - - - world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping; - world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution; - world.GetSolverInfo().m_globalCfm = 0.0f; - world.GetSolverInfo().m_tau = 0.6f; - world.GetSolverInfo().m_friction = 0.3f; - world.GetSolverInfo().m_maxErrorReduction = 20f; - world.GetSolverInfo().m_numIterations = 10; - world.GetSolverInfo().m_erp = 0.2f; - world.GetSolverInfo().m_erp2 = 0.1f; - world.GetSolverInfo().m_sor = 1.0f; - world.GetSolverInfo().m_splitImpulse = false; - world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f; - world.GetSolverInfo().m_linearSlop = 0.0f; - world.GetSolverInfo().m_warmstartingFactor = 0.85f; - world.GetSolverInfo().m_restingContactRestitutionThreshold = 2; - world.SetForceUpdateAllAabbs(true); - - - world.SetGravity(new IndexedVector3(0,0,p.gravity)); - - return world; - } - //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL - internal static bool SetConstraintParam2(object pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis) - { - Generic6DofConstraint constrain = pConstraint as Generic6DofConstraint; - if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) - { - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0); - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1); - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2); - } - if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) - { - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3); - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4); - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5); - } - if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL) - { - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis); - } - return true; - } - - internal static bool PushUpdate2(object pCollisionObject) - { - bool ret = false; - RigidBody rb = pCollisionObject as RigidBody; - if (rb != null) - { - SimMotionState sms = rb.GetMotionState() as SimMotionState; - if (sms != null) - { - IndexedMatrix wt = IndexedMatrix.Identity; - sms.GetWorldTransform(out wt); - sms.SetWorldTransform(ref wt, true); - ret = true; - } - } - return ret; - - } - - internal static bool IsCompound2(object pShape) - { - CollisionShape shape = pShape as CollisionShape; - return shape.IsCompound(); - } - internal static bool IsPloyhedral2(object pShape) - { - CollisionShape shape = pShape as CollisionShape; - return shape.IsPolyhedral(); - } - internal static bool IsConvex2d2(object pShape) - { - CollisionShape shape = pShape as CollisionShape; - return shape.IsConvex2d(); - } - internal static bool IsConvex2(object pShape) - { - CollisionShape shape = pShape as CollisionShape; - return shape.IsConvex(); - } - internal static bool IsNonMoving2(object pShape) - { - CollisionShape shape = pShape as CollisionShape; - return shape.IsNonMoving(); - } - internal static bool IsConcave2(object pShape) - { - CollisionShape shape = pShape as CollisionShape; - return shape.IsConcave(); - } - internal static bool IsInfinite2(object pShape) - { - CollisionShape shape = pShape as CollisionShape; - return shape.IsInfinite(); - } - internal static bool IsNativeShape2(object pShape) - { - CollisionShape shape = pShape as CollisionShape; - bool ret; - switch (shape.GetShapeType()) - { - case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: - case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: - case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: - case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: - ret = true; - break; - default: - ret = false; - break; - } - return ret; - } - //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation - internal static object CreateGhostFromShape2(object pWorld, object pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) - { - IndexedMatrix bodyTransform = new IndexedMatrix(); - bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); - bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W)); - GhostObject gObj = new PairCachingGhostObject(); - gObj.SetWorldTransform(bodyTransform); - CollisionShape shape = pShape as CollisionShape; - gObj.SetCollisionShape(shape); - gObj.SetUserPointer(pLocalID); - // TODO: Add to Special CollisionObjects! - return gObj; - } - - public static void SetCollisionShape2(object pWorld, object pObj, object pShape) - { - var world = pWorld as DiscreteDynamicsWorld; - var obj = pObj as CollisionObject; - var shape = pShape as CollisionShape; - obj.SetCollisionShape(shape); - - } - //(PhysicsScene.World.ptr, nativeShapeData) - internal static object BuildNativeShape2(object pWorld, ShapeData pShapeData) - { - var world = pWorld as DiscreteDynamicsWorld; - CollisionShape shape = null; - switch (pShapeData.Type) - { - case BSPhysicsShapeType.SHAPE_BOX: - shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f)); - break; - case BSPhysicsShapeType.SHAPE_CONE: - shape = new ConeShapeZ(0.5f, 1.0f); - break; - case BSPhysicsShapeType.SHAPE_CYLINDER: - shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f)); - break; - case BSPhysicsShapeType.SHAPE_SPHERE: - shape = new SphereShape(0.5f); - break; - - } - if (shape != null) - { - IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z); - shape.SetMargin(world.WorldSettings.Params.collisionMargin); - shape.SetLocalScaling(ref scaling); - - } - return shape; - } - //PhysicsScene.World.ptr, false - internal static object CreateCompoundShape2(object pWorld, bool enableDynamicAabbTree) - { - return new CompoundShape(enableDynamicAabbTree); - } - - internal static int GetNumberOfCompoundChildren2(object pCompoundShape) - { - var compoundshape = pCompoundShape as CompoundShape; - return compoundshape.GetNumChildShapes(); - } - //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot - internal static void AddChildShapeToCompoundShape2(object pCShape, object paddShape, Vector3 displacementPos, Quaternion displacementRot) - { - IndexedMatrix relativeTransform = new IndexedMatrix(); - var compoundshape = pCShape as CompoundShape; - var addshape = paddShape as CollisionShape; - - relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z); - relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W)); - compoundshape.AddChildShape(ref relativeTransform, addshape); - - } - - internal static object RemoveChildShapeFromCompoundShapeIndex2(object pCShape, int pii) - { - var compoundshape = pCShape as CompoundShape; - CollisionShape ret = null; - ret = compoundshape.GetChildShape(pii); - compoundshape.RemoveChildShapeByIndex(pii); - return ret; - } - - internal static object CreateGroundPlaneShape2(uint pLocalId, float pheight, float pcollisionMargin) - { - StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight ); - m_planeshape.SetMargin(pcollisionMargin); - m_planeshape.SetUserPointer(pLocalId); - return m_planeshape; - } - - internal static object CreateHingeConstraint2(object pWorld, object pBody1, object ppBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) - { - HingeConstraint constrain = null; - var rb1 = pBody1 as RigidBody; - var rb2 = ppBody2 as RigidBody; - if (rb1 != null && rb2 != null) - { - IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); - IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); - IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); - IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); - var world = pWorld as DiscreteDynamicsWorld; - world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); - } - return constrain; - } - - internal static bool ReleaseHeightMapInfo2(object pMapInfo) - { - if (pMapInfo != null) - { - BulletHeightMapInfo mapinfo = pMapInfo as BulletHeightMapInfo; - if (mapinfo.heightMap != null) - mapinfo.heightMap = null; - - - } - return true; - } - - internal static object CreateHullShape2(object pWorld, int pHullCount, float[] pConvHulls) - { - CompoundShape compoundshape = new CompoundShape(false); - var world = pWorld as DiscreteDynamicsWorld; - - - compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); - int ii = 1; - - for (int i = 0; i < pHullCount; i++) - { - int vertexCount = (int) pConvHulls[ii]; - - IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]); - IndexedMatrix childTrans = IndexedMatrix.Identity; - childTrans._origin = centroid; - - List virts = new List(); - int ender = ((ii + 4) + (vertexCount*3)); - for (int iii = ii + 4; iii < ender; iii+=3) - { - - virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); - } - ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); - convexShape.SetMargin(world.WorldSettings.Params.collisionMargin); - compoundshape.AddChildShape(ref childTrans, convexShape); - ii += (vertexCount*3 + 4); - } - - - return compoundshape; - } - - internal static object CreateMeshShape2(object pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) - { - //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); - - for (int iter = 0; iter < pVerticesCount; iter++) - { - if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; - if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; - } - - ObjectArray indicesarr = new ObjectArray(indices); - ObjectArray vertices = new ObjectArray(verticesAsFloats); - DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); - var world = pWorld as DiscreteDynamicsWorld; - IndexedMesh mesh = new IndexedMesh(); - mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; - mesh.m_numTriangles = pIndicesCount/3; - mesh.m_numVertices = pVerticesCount; - mesh.m_triangleIndexBase = indicesarr; - mesh.m_vertexBase = vertices; - mesh.m_vertexStride = 3; - mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; - mesh.m_triangleIndexStride = 3; - - TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); - tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); - BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); - meshShape.SetMargin(world.WorldSettings.Params.collisionMargin); - // world.UpdateSingleAabb(meshShape); - return meshShape; - - } - public static void DumpRaw(ObjectArrayindices, ObjectArray vertices, int pIndicesCount,int pVerticesCount ) - { - - String fileName = "objTest3.raw"; - String completePath = System.IO.Path.Combine(Util.configDir(), fileName); - StreamWriter sw = new StreamWriter(completePath); - IndexedMesh mesh = new IndexedMesh(); - - mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; - mesh.m_numTriangles = pIndicesCount / 3; - mesh.m_numVertices = pVerticesCount; - mesh.m_triangleIndexBase = indices; - mesh.m_vertexBase = vertices; - mesh.m_vertexStride = 3; - mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; - mesh.m_triangleIndexStride = 3; - - TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); - tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); - - - - for (int i = 0; i < pVerticesCount; i++) - { - - string s = vertices[indices[i * 3]].ToString("0.0000"); - s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); - s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); - - sw.Write(s + "\n"); - } - - sw.Close(); - } - public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount) - { - - String fileName = "objTest6.raw"; - String completePath = System.IO.Path.Combine(Util.configDir(), fileName); - StreamWriter sw = new StreamWriter(completePath); - IndexedMesh mesh = new IndexedMesh(); - - mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; - mesh.m_numTriangles = pIndicesCount / 3; - mesh.m_numVertices = pVerticesCount; - mesh.m_triangleIndexBase = indices; - mesh.m_vertexBase = vertices; - mesh.m_vertexStride = 3; - mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; - mesh.m_triangleIndexStride = 3; - - TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); - tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); - - - sw.WriteLine("Indices"); - sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount)); - for (int iter = 0; iter < indices.Length; iter++) - { - sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter])); - } - sw.WriteLine("VerticesFloats"); - sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount)); - for (int iter = 0; iter < vertices.Length; iter++) - { - sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000"))); - } - - // for (int i = 0; i < pVerticesCount; i++) - // { - // - // string s = vertices[indices[i * 3]].ToString("0.0000"); - // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); - // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); - // - // sw.Write(s + "\n"); - //} - - sw.Close(); - } - //PhysicsScene.World.ptr, m_mapInfo.ID, m_mapInfo.minCoords, m_mapInfo.maxCoords, m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin - internal static object CreateHeightMapInfo2(object pWorld, uint pId, Vector3 pminCoords, Vector3 pmaxCoords, float[] pheightMap, float pCollisionMargin) - { - BulletHeightMapInfo mapInfo = new BulletHeightMapInfo(pId, pheightMap, null); - mapInfo.heightMap = null; - mapInfo.minCoords = pminCoords; - mapInfo.maxCoords = pmaxCoords; - mapInfo.sizeX = (int) (pmaxCoords.X - pminCoords.X); - mapInfo.sizeY = (int) (pmaxCoords.Y - pminCoords.Y); - mapInfo.ID = pId; - mapInfo.minZ = pminCoords.Z; - mapInfo.maxZ = pmaxCoords.Z; - mapInfo.collisionMargin = pCollisionMargin; - if (mapInfo.minZ == mapInfo.maxZ) - mapInfo.minZ -= 0.2f; - mapInfo.heightMap = pheightMap; - - return mapInfo; - - } - - internal static object CreateTerrainShape2(object pMapInfo) - { - BulletHeightMapInfo mapinfo = pMapInfo as BulletHeightMapInfo; - const int upAxis = 2; - const float scaleFactor = 1.0f; - HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)mapinfo.sizeX, (int)mapinfo.sizeY, - mapinfo.heightMap, scaleFactor, - mapinfo.minZ, mapinfo.maxZ, upAxis, - false); - terrainShape.SetMargin(mapinfo.collisionMargin + 0.5f); - terrainShape.SetUseDiamondSubdivision(true); - terrainShape.SetUserPointer(mapinfo.ID); - return terrainShape; - } - - internal static bool TranslationalLimitMotor2(object pConstraint, float ponOff, float targetVelocity, float maxMotorForce) - { - TypedConstraint tconstrain = pConstraint as TypedConstraint; - bool onOff = ponOff != 0; - bool ret = false; - - switch (tconstrain.GetConstraintType()) - { - case TypedConstraintType.D6_CONSTRAINT_TYPE: - Generic6DofConstraint constrain = pConstraint as Generic6DofConstraint; - constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff; - constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity; - constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce; - ret = true; - break; - } - - - return ret; - - } - - internal static int PhysicsStep2(object pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List updatedEntities, out int collidersCount, out Listcolliders) - { - int epic = PhysicsStepint2(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities, - out collidersCount, out colliders); - return epic; - } - - private static int PhysicsStepint2(object pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List updatedEntities, out int collidersCount, out List colliders) - { - int numSimSteps = 0; - - - //if (updatedEntities is null) - // updatedEntities = new List(); - - //if (colliders is null) - // colliders = new List(); - - - if (pWorld is DiscreteDynamicsWorld) - { - DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; - - numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep); - int updates = 0; - - updatedEntityCount = world.UpdatedObjects.Count; - updatedEntities = new List(world.UpdatedObjects); - updatedEntityCount = updatedEntities.Count; - world.UpdatedObjects.Clear(); - - - collidersCount = world.UpdatedCollisions.Count; - colliders = new List(world.UpdatedCollisions); - - world.UpdatedCollisions.Clear(); - m_collisionsThisFrame = 0; - int numManifolds = world.GetDispatcher().GetNumManifolds(); - for (int j = 0; j < numManifolds; j++) - { - PersistentManifold contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j); - int numContacts = contactManifold.GetNumContacts(); - if (numContacts == 0) - continue; - - CollisionObject objA = contactManifold.GetBody0() as CollisionObject; - CollisionObject objB = contactManifold.GetBody1() as CollisionObject; - - ManifoldPoint manifoldPoint = contactManifold.GetContactPoint(0); - IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB(); - IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A - - RecordCollision(world, objA, objB, contactPoint, contactNormal); - m_collisionsThisFrame ++; - if (m_collisionsThisFrame >= 9999999) - break; - - - } - - - } - else - { - //if (updatedEntities is null) - updatedEntities = new List(); - updatedEntityCount = 0; - //if (colliders is null) - colliders = new List(); - collidersCount = 0; - } - return numSimSteps; - } - - private static void RecordCollision(CollisionWorld world,CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm) - { - - IndexedVector3 contactNormal = norm; - if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && - (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) - { - return; - } - uint idA = (uint)objA.GetUserPointer(); - uint idB = (uint)objB.GetUserPointer(); - if (idA > idB) - { - uint temp = idA; - idA = idB; - idB = temp; - contactNormal = -contactNormal; - } - - ulong collisionID = ((ulong) idA << 32) | idB; - - BulletXNA.CollisionDesc cDesc = new BulletXNA.CollisionDesc() - { - aID = idA, - bID = idB, - point = contact, - normal = contactNormal - }; - world.UpdatedCollisions.Add(cDesc); - m_collisionsThisFrame++; - - - } - private static EntityProperties GetDebugProperties(object pWorld, object pBody) - { - EntityProperties ent = new EntityProperties(); - DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld; - RigidBody body = pBody as RigidBody; - IndexedMatrix transform = body.GetWorldTransform(); - IndexedVector3 LinearVelocity = body.GetInterpolationLinearVelocity(); - IndexedVector3 AngularVelocity = body.GetInterpolationAngularVelocity(); - IndexedQuaternion rotation = transform.GetRotation(); - ent.Acceleration = Vector3.Zero; - ent.ID = (uint)body.GetUserPointer(); - ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z); - ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W); - ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z); - ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z); - return ent; - - - } - - - internal static Vector3 GetLocalScaling2(object pBody) - { - CollisionShape shape = pBody as CollisionShape; - IndexedVector3 scale = shape.GetLocalScaling(); - return new Vector3(scale.X,scale.Y,scale.Z); - } - - internal static bool RayCastGround(object pWorld, Vector3 _RayOrigin, float pRayHeight, object NotMe) - { - DynamicsWorld world = pWorld as DynamicsWorld; - if (world != null) - { - if (NotMe is CollisionObject || NotMe is RigidBody) - { - CollisionObject AvoidBody = NotMe as CollisionObject; - - IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); - IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); - using ( - ClosestNotMeRayResultCallback rayCallback = new ClosestNotMeRayResultCallback(rOrigin, - rEnd, AvoidBody) - ) - { - world.RayTest(ref rOrigin, ref rEnd, rayCallback); - if (rayCallback.HasHit()) - { - IndexedVector3 hitLocation = rayCallback.m_hitPointWorld; - - } - return rayCallback.HasHit(); - } - } - } - return false; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs deleted file mode 100644 index f509dc4..0000000 --- a/OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using OMV = OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSNPlugin -{ -// Classes to allow some type checking for the API -// These hold pointers to allocated objects in the unmanaged space. - -// The physics engine controller class created at initialization -public struct BulletWorld -{ - public BulletWorld(uint worldId, BSScene bss, object xx) - { - ptr = xx; - worldID = worldId; - physicsScene = bss; - } - public object ptr; - public uint worldID; - // The scene is only in here so very low level routines have a handle to print debug/error messages - public BSScene physicsScene; -} - -// An allocated Bullet btRigidBody -public struct BulletBody -{ - public BulletBody(uint id) : this(id, null) - { - } - public BulletBody(uint id, object xx) - { - ID = id; - ptr = xx; - collisionType = CollisionType.Static; - } - public object ptr; - public uint ID; - public CollisionType collisionType; - - public void Clear() - { - ptr = null; - } - public bool HasPhysicalBody { get { return ptr != null; } } - - // Apply the specificed collision mask into the physical world - public void ApplyCollisionMask() - { - // Should assert the body has been added to the physical world. - // (The collision masks are stored in the collision proxy cache which only exists for - // a collision body that is in the world.) - BulletSimAPI.SetCollisionGroupMask2(ptr, - BulletSimData.CollisionTypeMasks[collisionType].group, - BulletSimData.CollisionTypeMasks[collisionType].mask); - } - - public override string ToString() - { - StringBuilder buff = new StringBuilder(); - buff.Append(""); - return buff.ToString(); - } -} - -public struct BulletShape -{ - public BulletShape(object xx) : this(xx, BSPhysicsShapeType.SHAPE_UNKNOWN) - { - } - public BulletShape(object xx, BSPhysicsShapeType typ) - { - ptr = xx; - type = typ; - shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; - isNativeShape = false; - } - public object ptr; - public BSPhysicsShapeType type; - public System.UInt64 shapeKey; - public bool isNativeShape; - - public void Clear() - { - ptr = null; - } - public bool HasPhysicalShape { get { return ptr != null; } } - - public override string ToString() - { - StringBuilder buff = new StringBuilder(); - buff.Append(""); - return buff.ToString(); - } -} - -// An allocated Bullet btConstraint -public struct BulletConstraint -{ - public BulletConstraint(object xx) - { - ptr = xx; - } - public object ptr; - - public void Clear() - { - ptr = null; - } - public bool HasPhysicalConstraint { get { return ptr != null; } } -} - -// An allocated HeightMapThing which holds various heightmap info. -// Made a class rather than a struct so there would be only one -// instance of this and C# will pass around pointers rather -// than making copies. -public class BulletHeightMapInfo -{ - public BulletHeightMapInfo(uint id, float[] hm, object xx) { - ID = id; - Ptr = xx; - heightMap = hm; - terrainRegionBase = OMV.Vector3.Zero; - minCoords = new OMV.Vector3(100f, 100f, 25f); - maxCoords = new OMV.Vector3(101f, 101f, 26f); - minZ = maxZ = 0f; - sizeX = sizeY = 256f; - } - public uint ID; - public object Ptr; - public float[] heightMap; - public OMV.Vector3 terrainRegionBase; - public OMV.Vector3 minCoords; - public OMV.Vector3 maxCoords; - public float sizeX, sizeY; - public float minZ, maxZ; - public BulletShape terrainShape; - public BulletBody terrainBody; - - public float collisionMargin { get; set; } -} - -// The general class of collsion object. -public enum CollisionType -{ - Avatar, - Groundplane, - Terrain, - Static, - Dynamic, - VolumeDetect, - // Linkset, // A linkset should be either Static or Dynamic - LinksetChild, - Unknown -}; - -// Hold specification of group and mask collision flags for a CollisionType -public struct CollisionTypeFilterGroup -{ - public CollisionTypeFilterGroup(CollisionType t, uint g, uint m) - { - type = t; - group = g; - mask = m; - } - public CollisionType type; - public uint group; - public uint mask; -}; - - /* NOTE: old definitions kept for reference. Delete when things are working. - // The collsion filters and masked are defined in one place -- don't want them scattered - AvatarGroup = BCharacterGroup, - AvatarMask = BAllGroup, - ObjectGroup = BSolidGroup, - ObjectMask = BAllGroup, - StaticObjectGroup = BStaticGroup, - StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much - LinksetGroup = BLinksetGroup, - LinksetMask = BAllGroup, - LinksetChildGroup = BLinksetChildGroup, - LinksetChildMask = BNoneGroup, // Linkset children disappear from the world - VolumeDetectGroup = BSensorTrigger, - VolumeDetectMask = ~BSensorTrigger, - TerrainGroup = BTerrainGroup, - TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide - GroundPlaneGroup = BGroundPlaneGroup, - GroundPlaneMask = BAllGroup - */ - -public static class BulletSimData -{ - -// Map of collisionTypes to flags for collision groups and masks. -// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code -// but, instead, use references to this dictionary. Finding and debugging -// collision flag problems will be made easier. -public static Dictionary CollisionTypeMasks - = new Dictionary() -{ - { CollisionType.Avatar, - new CollisionTypeFilterGroup(CollisionType.Avatar, - (uint)CollisionFilterGroups.BCharacterGroup, - (uint)CollisionFilterGroups.BAllGroup) - }, - { CollisionType.Groundplane, - new CollisionTypeFilterGroup(CollisionType.Groundplane, - (uint)CollisionFilterGroups.BGroundPlaneGroup, - (uint)CollisionFilterGroups.BAllGroup) - }, - { CollisionType.Terrain, - new CollisionTypeFilterGroup(CollisionType.Terrain, - (uint)CollisionFilterGroups.BTerrainGroup, - (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) - }, - { CollisionType.Static, - new CollisionTypeFilterGroup(CollisionType.Static, - (uint)CollisionFilterGroups.BStaticGroup, - (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) - }, - { CollisionType.Dynamic, - new CollisionTypeFilterGroup(CollisionType.Dynamic, - (uint)CollisionFilterGroups.BSolidGroup, - (uint)(CollisionFilterGroups.BAllGroup)) - }, - { CollisionType.VolumeDetect, - new CollisionTypeFilterGroup(CollisionType.VolumeDetect, - (uint)CollisionFilterGroups.BSensorTrigger, - (uint)(~CollisionFilterGroups.BSensorTrigger)) - }, - { CollisionType.LinksetChild, - new CollisionTypeFilterGroup(CollisionType.LinksetChild, - (uint)CollisionFilterGroups.BTerrainGroup, - (uint)(CollisionFilterGroups.BNoneGroup)) - }, -}; - -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs deleted file mode 100755 index 8c6e7d6..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs +++ /dev/null @@ -1,1839 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; - -using OpenSim.Framework; - -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -public sealed class BSAPIUnman : BSAPITemplate -{ - -private sealed class BulletWorldUnman : BulletWorld -{ - public IntPtr ptr; - public BulletWorldUnman(uint id, BSScene physScene, IntPtr xx) - : base(id, physScene) - { - ptr = xx; - } -} - -private sealed class BulletBodyUnman : BulletBody -{ - public IntPtr ptr; - public BulletBodyUnman(uint id, IntPtr xx) - : base(id) - { - ptr = xx; - } - public override bool HasPhysicalBody - { - get { return ptr != IntPtr.Zero; } - } - public override void Clear() - { - ptr = IntPtr.Zero; - } - public override string AddrString - { - get { return ptr.ToString("X"); } - } -} - -private sealed class BulletShapeUnman : BulletShape -{ - public IntPtr ptr; - public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) - : base() - { - ptr = xx; - type = typ; - } - public override bool HasPhysicalShape - { - get { return ptr != IntPtr.Zero; } - } - public override void Clear() - { - ptr = IntPtr.Zero; - } - public override BulletShape Clone() - { - return new BulletShapeUnman(ptr, type); - } - public override bool ReferenceSame(BulletShape other) - { - BulletShapeUnman otheru = other as BulletShapeUnman; - return (otheru != null) && (this.ptr == otheru.ptr); - - } - public override string AddrString - { - get { return ptr.ToString("X"); } - } -} -private sealed class BulletConstraintUnman : BulletConstraint -{ - public BulletConstraintUnman(IntPtr xx) : base() - { - ptr = xx; - } - public IntPtr ptr; - - public override void Clear() - { - ptr = IntPtr.Zero; - } - public override bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } } - - // Used for log messages for a unique display of the memory/object allocated to this instance - public override string AddrString - { - get { return ptr.ToString("X"); } - } -} - -// We pin the memory passed between the managed and unmanaged code. -GCHandle m_paramsHandle; -private GCHandle m_collisionArrayPinnedHandle; -private GCHandle m_updateArrayPinnedHandle; - -// Handle to the callback used by the unmanaged code to call into the managed code. -// Used for debug logging. -// Need to store the handle in a persistant variable so it won't be freed. -private BSAPICPP.DebugLogCallback m_DebugLogCallbackHandle; - -private BSScene PhysicsScene { get; set; } - -public override string BulletEngineName { get { return "BulletUnmanaged"; } } -public override string BulletEngineVersion { get; protected set; } - -public BSAPIUnman(string paramName, BSScene physScene) -{ - PhysicsScene = physScene; - - // Do something fancy with the paramName to get the right DLL implementation - // like "Bullet-2.80-OpenCL-Intel" loading the version for Intel based OpenCL implementation, etc. - if (Util.IsWindows()) - Util.LoadArchSpecificWindowsDll("BulletSim.dll"); - // If not Windows, loading is performed by the - // Mono loader as specified in - // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". -} - -// Initialization and simulation -public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, - int maxCollisions, ref CollisionDesc[] collisionArray, - int maxUpdates, ref EntityProperties[] updateArray - ) -{ - // Pin down the memory that will be used to pass object collisions and updates back from unmanaged code - m_paramsHandle = GCHandle.Alloc(parms, GCHandleType.Pinned); - m_collisionArrayPinnedHandle = GCHandle.Alloc(collisionArray, GCHandleType.Pinned); - m_updateArrayPinnedHandle = GCHandle.Alloc(updateArray, GCHandleType.Pinned); - - // If Debug logging level, enable logging from the unmanaged code - m_DebugLogCallbackHandle = null; - if (BSScene.m_log.IsDebugEnabled || PhysicsScene.PhysicsLogging.Enabled) - { - BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader); - if (PhysicsScene.PhysicsLogging.Enabled) - // The handle is saved in a variable to make sure it doesn't get freed after this call - m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLoggerPhysLog); - else - m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLogger); - } - - // Get the version of the DLL - // TODO: this doesn't work yet. Something wrong with marshaling the returned string. - // BulletEngineVersion = BulletSimAPI.GetVersion2(); - BulletEngineVersion = ""; - - // Call the unmanaged code with the buffers and other information - return new BulletWorldUnman(0, PhysicsScene, BSAPICPP.Initialize2(maxPosition, m_paramsHandle.AddrOfPinnedObject(), - maxCollisions, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), - maxUpdates, m_updateArrayPinnedHandle.AddrOfPinnedObject(), - m_DebugLogCallbackHandle)); - -} - -// Called directly from unmanaged code so don't do much -private void BulletLogger(string msg) -{ - BSScene.m_log.Debug("[BULLETS UNMANAGED]:" + msg); -} - -// Called directly from unmanaged code so don't do much -private void BulletLoggerPhysLog(string msg) -{ - PhysicsScene.DetailLog("[BULLETS UNMANAGED]:" + msg); -} - -public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, - out int updatedEntityCount, out int collidersCount) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount); -} - -public override void Shutdown(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.Shutdown2(worldu.ptr); -} - -public override bool PushUpdate(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.PushUpdate2(bodyu.ptr); -} - -public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return BSAPICPP.UpdateParameter2(worldu.ptr, localID, parm, value); -} - -// ===================================================================================== -// Mesh, hull, shape and body creation helper routines -public override BulletShape CreateMeshShape(BulletWorld world, - int indicesCount, int[] indices, - int verticesCount, float[] vertices) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return new BulletShapeUnman( - BSAPICPP.CreateMeshShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), - BSPhysicsShapeType.SHAPE_MESH); -} - -public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return new BulletShapeUnman( - BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), - BSPhysicsShapeType.SHAPE_HULL); -} - -public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletShapeUnman shapeu = meshShape as BulletShapeUnman; - return new BulletShapeUnman( - BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr), - BSPhysicsShapeType.SHAPE_HULL); -} - -public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type); -} - -public override bool IsNativeShape(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - if (shapeu != null && shapeu.HasPhysicalShape) - return BSAPICPP.IsNativeShape2(shapeu.ptr); - return false; -} - -public override void SetShapeCollisionMargin(BulletShape shape, float margin) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - if (shapeu != null && shapeu.HasPhysicalShape) - BSAPICPP.SetShapeCollisionMargin2(shapeu.ptr, margin); -} - -public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return new BulletShapeUnman( - BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale), - BSPhysicsShapeType.SHAPE_CAPSULE); -} - -public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return new BulletShapeUnman( - BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree), - BSPhysicsShapeType.SHAPE_COMPOUND); - -} - -public override int GetNumberOfCompoundChildren(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - if (shapeu != null && shapeu.HasPhysicalShape) - return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr); - return 0; -} - -public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - BulletShapeUnman addShapeu = addShape as BulletShapeUnman; - BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot); -} - -public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); -} - -public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); -} - -public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman; - BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr); -} - -public override void RecalculateCompoundShapeLocalAabb(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr); -} - -public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; - return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type); -} - -public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr); -} - -public override CollisionObjectTypes GetBodyType(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr); -} - -public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); -} - -public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot)); -} - -public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); -} - -public override void DestroyObject(BulletWorld world, BulletBody obj) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr); -} - -// ===================================================================================== -// Terrain creation and helper routines -public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin) -{ - return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE); -} - -public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, - float scaleFactor, float collisionMargin) -{ - return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin), - BSPhysicsShapeType.SHAPE_TERRAIN); -} - -// ===================================================================================== -// Constraint creation and helper routines -public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frame1loc, Quaternion frame1rot, - Vector3 frame2loc, Quaternion frame2rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; - BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, - frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); -} - -public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 joinPoint, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; - BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, - joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); -} - -public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 pivotinA, Vector3 pivotinB, - Vector3 axisInA, Vector3 axisInB, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; - BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, - pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); -} - -public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse); -} - -public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations); -} - -public override bool SetFrames(BulletConstraint constrain, - Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot); -} - -public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi); -} - -public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi); -} - -public override bool UseFrameOffset(BulletConstraint constrain, float enable) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable); -} - -public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce); -} - -public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold); -} - -public override bool CalculateTransforms(BulletConstraint constrain) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.CalculateTransforms2(constrainu.ptr); -} - -public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis); -} - -public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr); -} - -// ===================================================================================== -// btCollisionWorld entries -public override void UpdateSingleAabb(BulletWorld world, BulletBody obj) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr); -} - -public override void UpdateAabbs(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.UpdateAabbs2(worldu.ptr); -} - -public override bool GetForceUpdateAllAabbs(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr); -} - -public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force); -} - -// ===================================================================================== -// btDynamicsWorld entries -public override bool AddObjectToWorld(BulletWorld world, BulletBody obj) -{ - // Bullet resets several variables when an object is added to the world. - // Gravity is reset to world default depending on the static/dynamic - // type. Of course, the collision flags in the broadphase proxy are initialized to default. - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = obj as BulletBodyUnman; - - Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr); - - bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr); - - if (ret) - { - BSAPICPP.SetGravity2(bodyu.ptr, origGrav); - obj.ApplyCollisionMask(world.physicsScene); - } - return ret; -} - -public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr); -} - -public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects); -} - -public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr); -} -// ===================================================================================== -// btCollisionObject entries -public override Vector3 GetAnisotripicFriction(BulletConstraint constrain) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr); -} - -public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict); -} - -public override bool HasAnisotripicFriction(BulletConstraint constrain) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr); -} - -public override void SetContactProcessingThreshold(BulletBody obj, float val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val); -} - -public override float GetContactProcessingThreshold(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr); -} - -public override bool IsStaticObject(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.IsStaticObject2(bodyu.ptr); -} - -public override bool IsKinematicObject(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.IsKinematicObject2(bodyu.ptr); -} - -public override bool IsStaticOrKinematicObject(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr); -} - -public override bool HasContactResponse(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.HasContactResponse2(bodyu.ptr); -} - -public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BulletShapeUnman shapeu = shape as BulletShapeUnman; - if (worldu != null && bodyu != null) - { - // Special case to allow the caller to zero out the reference to any physical shape - if (shapeu != null) - BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr); - else - BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero); - } -} - -public override BulletShape GetCollisionShape(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN); -} - -public override int GetActivationState(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetActivationState2(bodyu.ptr); -} - -public override void SetActivationState(BulletBody obj, int state) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetActivationState2(bodyu.ptr, state); -} - -public override void SetDeactivationTime(BulletBody obj, float dtime) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime); -} - -public override float GetDeactivationTime(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetDeactivationTime2(bodyu.ptr); -} - -public override void ForceActivationState(BulletBody obj, ActivationState state) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ForceActivationState2(bodyu.ptr, state); -} - -public override void Activate(BulletBody obj, bool forceActivation) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.Activate2(bodyu.ptr, forceActivation); -} - -public override bool IsActive(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.IsActive2(bodyu.ptr); -} - -public override void SetRestitution(BulletBody obj, float val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetRestitution2(bodyu.ptr, val); -} - -public override float GetRestitution(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetRestitution2(bodyu.ptr); -} - -public override void SetFriction(BulletBody obj, float val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetFriction2(bodyu.ptr, val); -} - -public override float GetFriction(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetFriction2(bodyu.ptr); -} - -public override Vector3 GetPosition(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetPosition2(bodyu.ptr); -} - -public override Quaternion GetOrientation(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetOrientation2(bodyu.ptr); -} - -public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation); -} - - /* -public override IntPtr GetBroadphaseHandle(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr); -} - -public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetUserPointer2(bodyu.ptr, handle); -} - */ - -public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel); -} - -public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel); -} - -public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel); -} - -public override float GetHitFraction(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetHitFraction2(bodyu.ptr); -} - -public override void SetHitFraction(BulletBody obj, float val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetHitFraction2(bodyu.ptr, val); -} - -public override CollisionFlags GetCollisionFlags(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetCollisionFlags2(bodyu.ptr); -} - -public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags); -} - -public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags); -} - -public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags); -} - -public override float GetCcdMotionThreshold(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr); -} - - -public override void SetCcdMotionThreshold(BulletBody obj, float val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val); -} - -public override float GetCcdSweptSphereRadius(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr); -} - -public override void SetCcdSweptSphereRadius(BulletBody obj, float val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val); -} - -public override IntPtr GetUserPointer(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetUserPointer2(bodyu.ptr); -} - -public override void SetUserPointer(BulletBody obj, IntPtr val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetUserPointer2(bodyu.ptr, val); -} - -// ===================================================================================== -// btRigidBody entries -public override void ApplyGravity(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyGravity2(bodyu.ptr); -} - -public override void SetGravity(BulletBody obj, Vector3 val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetGravity2(bodyu.ptr, val); -} - -public override Vector3 GetGravity(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetGravity2(bodyu.ptr); -} - -public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping); -} - -public override void SetLinearDamping(BulletBody obj, float lin_damping) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping); -} - -public override void SetAngularDamping(BulletBody obj, float ang_damping) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping); -} - -public override float GetLinearDamping(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetLinearDamping2(bodyu.ptr); -} - -public override float GetAngularDamping(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetAngularDamping2(bodyu.ptr); -} - -public override float GetLinearSleepingThreshold(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr); -} - -public override void ApplyDamping(BulletBody obj, float timeStep) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep); -} - -public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia); -} - -public override Vector3 GetLinearFactor(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetLinearFactor2(bodyu.ptr); -} - -public override void SetLinearFactor(BulletBody obj, Vector3 factor) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetLinearFactor2(bodyu.ptr, factor); -} - -public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot); -} - -// Add a force to the object as if its mass is one. -public override void ApplyCentralForce(BulletBody obj, Vector3 force) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyCentralForce2(bodyu.ptr, force); -} - -// Set the force being applied to the object as if its mass is one. -public override void SetObjectForce(BulletBody obj, Vector3 force) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetObjectForce2(bodyu.ptr, force); -} - -public override Vector3 GetTotalForce(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetTotalForce2(bodyu.ptr); -} - -public override Vector3 GetTotalTorque(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetTotalTorque2(bodyu.ptr); -} - -public override Vector3 GetInvInertiaDiagLocal(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr); -} - -public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert); -} - -public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold); -} - -public override void ApplyTorque(BulletBody obj, Vector3 torque) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyTorque2(bodyu.ptr, torque); -} - -// Apply force at the given point. Will add torque to the object. -public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyForce2(bodyu.ptr, force, pos); -} - -// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. -public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp); -} - -// Apply impulse to the object's torque. Force is scaled by object's mass. -public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp); -} - -// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. -public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos); -} - -public override void ClearForces(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ClearForces2(bodyu.ptr); -} - -public override void ClearAllForces(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ClearAllForces2(bodyu.ptr); -} - -public override void UpdateInertiaTensor(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.UpdateInertiaTensor2(bodyu.ptr); -} - -public override Vector3 GetLinearVelocity(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetLinearVelocity2(bodyu.ptr); -} - -public override Vector3 GetAngularVelocity(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetAngularVelocity2(bodyu.ptr); -} - -public override void SetLinearVelocity(BulletBody obj, Vector3 vel) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel); -} - -public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity); -} - -public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos); -} - -public override void Translate(BulletBody obj, Vector3 trans) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.Translate2(bodyu.ptr, trans); -} - -public override void UpdateDeactivation(BulletBody obj, float timeStep) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep); -} - -public override bool WantsSleeping(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.WantsSleeping2(bodyu.ptr); -} - -public override void SetAngularFactor(BulletBody obj, float factor) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetAngularFactor2(bodyu.ptr, factor); -} - -public override void SetAngularFactorV(BulletBody obj, Vector3 factor) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor); -} - -public override Vector3 GetAngularFactor(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetAngularFactor2(bodyu.ptr); -} - -public override bool IsInWorld(BulletWorld world, BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.IsInWorld2(bodyu.ptr); -} - -public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr); -} - -public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr); -} - -public override BulletConstraint GetConstraintRef(BulletBody obj, int index) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index)); -} - -public override int GetNumConstraintRefs(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr); -} - -public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask) -{ - BulletBodyUnman bodyu = body as BulletBodyUnman; - return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask); -} - -// ===================================================================================== -// btCollisionShape entries - -public override float GetAngularMotionDisc(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr); -} - -public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor); -} - -public override bool IsPolyhedral(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsPolyhedral2(shapeu.ptr); -} - -public override bool IsConvex2d(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsConvex2d2(shapeu.ptr); -} - -public override bool IsConvex(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsConvex2(shapeu.ptr); -} - -public override bool IsNonMoving(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsNonMoving2(shapeu.ptr); -} - -public override bool IsConcave(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsConcave2(shapeu.ptr); -} - -public override bool IsCompound(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsCompound2(shapeu.ptr); -} - -public override bool IsSoftBody(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsSoftBody2(shapeu.ptr); -} - -public override bool IsInfinite(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsInfinite2(shapeu.ptr); -} - -public override void SetLocalScaling(BulletShape shape, Vector3 scale) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - BSAPICPP.SetLocalScaling2(shapeu.ptr, scale); -} - -public override Vector3 GetLocalScaling(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.GetLocalScaling2(shapeu.ptr); -} - -public override Vector3 CalculateLocalInertia(BulletShape shape, float mass) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass); -} - -public override int GetShapeType(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.GetShapeType2(shapeu.ptr); -} - -public override void SetMargin(BulletShape shape, float val) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - BSAPICPP.SetMargin2(shapeu.ptr, val); -} - -public override float GetMargin(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.GetMargin2(shapeu.ptr); -} - -// ===================================================================================== -// Debugging -public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = collisionObject as BulletBodyUnman; - BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr); -} - -public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletShapeUnman shapeu = collisionShape as BulletShapeUnman; - BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr); -} - -public override void DumpConstraint(BulletWorld world, BulletConstraint constrain) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr); -} - -public override void DumpActivationInfo(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.DumpActivationInfo2(worldu.ptr); -} - -public override void DumpAllInfo(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.DumpAllInfo2(worldu.ptr); -} - -public override void DumpPhysicsStatistics(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.DumpPhysicsStatistics2(worldu.ptr); -} - -// ===================================================================================== -// ===================================================================================== -// ===================================================================================== -// ===================================================================================== -// ===================================================================================== -// The actual interface to the unmanaged code -static class BSAPICPP -{ -// =============================================================================== -// Link back to the managed code for outputting log messages -[UnmanagedFunctionPointer(CallingConvention.Cdecl)] -public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); - -// =============================================================================== -// Initialization and simulation -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, - int maxCollisions, IntPtr collisionArray, - int maxUpdates, IntPtr updateArray, - DebugLogCallback logRoutine); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, - out int updatedEntityCount, out int collidersCount); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void Shutdown2(IntPtr sim); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool PushUpdate2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); - -// ===================================================================================== -// Mesh, hull, shape and body creation helper routines -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateMeshShape2(IntPtr world, - int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, - int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateHullShape2(IntPtr world, - int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsNativeShape2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern int GetNumberOfCompoundChildren2(IntPtr cShape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern int GetBodyType2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DestroyObject2(IntPtr sim, IntPtr obj); - -// ===================================================================================== -// Terrain creation and helper routines -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, - [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, - float scaleFactor, float collisionMargin); - -// ===================================================================================== -// Constraint creation and helper routines -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, - Vector3 frame1loc, Quaternion frame1rot, - Vector3 frame2loc, Quaternion frame2rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2, - Vector3 joinPoint, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, - Vector3 pivotinA, Vector3 pivotinB, - Vector3 axisInA, Vector3 axisInB, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SetFrames2(IntPtr constrain, - Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool UseFrameOffset2(IntPtr constrain, float enable); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool CalculateTransforms2(IntPtr constrain); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); - -// ===================================================================================== -// btCollisionWorld entries -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void UpdateAabbs2(IntPtr world); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool GetForceUpdateAllAabbs2(IntPtr world); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force); - -// ===================================================================================== -// btDynamicsWorld entries -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain); -// ===================================================================================== -// btCollisionObject entries -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool HasAnisotripicFriction2(IntPtr constrain); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetContactProcessingThreshold2(IntPtr obj, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetContactProcessingThreshold2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsStaticObject2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsKinematicObject2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsStaticOrKinematicObject2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool HasContactResponse2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr GetCollisionShape2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern int GetActivationState2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetActivationState2(IntPtr obj, int state); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetDeactivationTime2(IntPtr obj, float dtime); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetDeactivationTime2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ForceActivationState2(IntPtr obj, ActivationState state); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void Activate2(IntPtr obj, bool forceActivation); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsActive2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetRestitution2(IntPtr obj, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetRestitution2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetFriction2(IntPtr obj, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetFriction2(IntPtr obj); - - /* Haven't defined the type 'Transform' -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Transform GetWorldTransform2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void setWorldTransform2(IntPtr obj, Transform trans); - */ - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetPosition2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Quaternion GetOrientation2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr GetBroadphaseHandle2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle); - - /* -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Transform GetInterpolationWorldTransform2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans); - */ - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetHitFraction2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetHitFraction2(IntPtr obj, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetCcdMotionThreshold2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetCcdSweptSphereRadius2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr GetUserPointer2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetUserPointer2(IntPtr obj, IntPtr val); - -// ===================================================================================== -// btRigidBody entries -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyGravity2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetGravity2(IntPtr obj, Vector3 val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetGravity2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetLinearDamping2(IntPtr obj, float lin_damping); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetAngularDamping2(IntPtr obj, float ang_damping); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetLinearDamping2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetAngularDamping2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetLinearSleepingThreshold2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetAngularSleepingThreshold2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyDamping2(IntPtr obj, float timeStep); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetLinearFactor2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor); - - /* -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans); - */ - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot); - -// Add a force to the object as if its mass is one. -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force); - -// Set the force being applied to the object as if its mass is one. -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetObjectForce2(IntPtr obj, Vector3 force); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetTotalForce2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetTotalTorque2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyTorque2(IntPtr obj, Vector3 torque); - -// Apply force at the given point. Will add torque to the object. -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos); - -// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp); - -// Apply impulse to the object's torque. Force is scaled by object's mass. -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp); - -// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ClearForces2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ClearAllForces2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void UpdateInertiaTensor2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj); - - /* -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Transform GetCenterOfMassTransform2(IntPtr obj); - */ - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetLinearVelocity2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetAngularVelocity2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void Translate2(IntPtr obj, Vector3 trans); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void UpdateDeactivation2(IntPtr obj, float timeStep); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool WantsSleeping2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetAngularFactor2(IntPtr obj, float factor); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetAngularFactor2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsInWorld2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern int GetNumConstraintRefs2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask); - -// ===================================================================================== -// btCollisionShape entries - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetAngularMotionDisc2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsPolyhedral2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsConvex2d2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsConvex2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsNonMoving2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsConcave2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsCompound2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsSoftBody2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsInfinite2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetLocalScaling2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern int GetShapeType2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetMargin2(IntPtr shape, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetMargin2(IntPtr shape); - -// ===================================================================================== -// Debugging -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpActivationInfo2(IntPtr sim); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpAllInfo2(IntPtr sim); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpPhysicsStatistics2(IntPtr sim); - -} - -} - -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs deleted file mode 100755 index 30a7bee..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs +++ /dev/null @@ -1,1622 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -using OpenSim.Framework; - -using OpenMetaverse; - -using BulletXNA; -using BulletXNA.LinearMath; -using BulletXNA.BulletCollision; -using BulletXNA.BulletDynamics; -using BulletXNA.BulletCollision.CollisionDispatch; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -public sealed class BSAPIXNA : BSAPITemplate -{ -private sealed class BulletWorldXNA : BulletWorld -{ - public DiscreteDynamicsWorld world; - public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx) - : base(id, physScene) - { - world = xx; - } -} - -private sealed class BulletBodyXNA : BulletBody -{ - public CollisionObject body; - public RigidBody rigidBody { get { return RigidBody.Upcast(body); } } - - public BulletBodyXNA(uint id, CollisionObject xx) - : base(id) - { - body = xx; - } - public override bool HasPhysicalBody - { - get { return body != null; } - } - public override void Clear() - { - body = null; - } - public override string AddrString - { - get { return "XNARigidBody"; } - } -} - -private sealed class BulletShapeXNA : BulletShape -{ - public CollisionShape shape; - public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) - : base() - { - shape = xx; - type = typ; - } - public override bool HasPhysicalShape - { - get { return shape != null; } - } - public override void Clear() - { - shape = null; - } - public override BulletShape Clone() - { - return new BulletShapeXNA(shape, type); - } - public override bool ReferenceSame(BulletShape other) - { - BulletShapeXNA otheru = other as BulletShapeXNA; - return (otheru != null) && (this.shape == otheru.shape); - - } - public override string AddrString - { - get { return "XNACollisionShape"; } - } -} -private sealed class BulletConstraintXNA : BulletConstraint -{ - public TypedConstraint constrain; - public BulletConstraintXNA(TypedConstraint xx) : base() - { - constrain = xx; - } - - public override void Clear() - { - constrain = null; - } - public override bool HasPhysicalConstraint { get { return constrain != null; } } - - // Used for log messages for a unique display of the memory/object allocated to this instance - public override string AddrString - { - get { return "XNAConstraint"; } - } -} - - private static int m_collisionsThisFrame; - private BSScene PhysicsScene { get; set; } - - public override string BulletEngineName { get { return "BulletXNA"; } } - public override string BulletEngineVersion { get; protected set; } - - public BSAPIXNA(string paramName, BSScene physScene) - { - PhysicsScene = physScene; - } - - /// - /// - /// - /// - /// - public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody) - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - world.RemoveRigidBody(body); - return true; - } - - public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) - { - /* TODO */ - return false; - } - - public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain) - { - /* TODO */ - return false; - } - - public override void SetRestitution(BulletBody pBody, float pRestitution) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.SetRestitution(pRestitution); - } - - public override int GetShapeType(BulletShape pShape) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - return (int)shape.GetShapeType(); - } - public override void SetMargin(BulletShape pShape, float pMargin) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - shape.SetMargin(pMargin); - } - - public override float GetMargin(BulletShape pShape) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - return shape.GetMargin(); - } - - public override void SetLocalScaling(BulletShape pShape, Vector3 pScale) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); - shape.SetLocalScaling(ref vec); - - } - - public override void SetContactProcessingThreshold(BulletBody pBody, float contactprocessingthreshold) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.SetContactProcessingThreshold(contactprocessingthreshold); - } - - public override void SetCcdMotionThreshold(BulletBody pBody, float pccdMotionThreashold) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.SetCcdMotionThreshold(pccdMotionThreashold); - } - - public override void SetCcdSweptSphereRadius(BulletBody pBody, float pCcdSweptSphereRadius) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.SetCcdSweptSphereRadius(pCcdSweptSphereRadius); - } - - public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z)); - } - - public override CollisionFlags AddToCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags) - { - CollisionObject body = ((BulletBodyXNA)pBody).body; - CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags(); - existingcollisionFlags |= pcollisionFlags; - body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); - return (CollisionFlags) (uint) existingcollisionFlags; - } - - public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody) - { - // Bullet resets several variables when an object is added to the world. In particular, - // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic - // type. Of course, the collision flags in the broadphase proxy are initialized to default. - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - - IndexedMatrix origPos = body.GetWorldTransform(); - IndexedVector3 origGrav = body.GetGravity(); - - //if (!(body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE && body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE)) - - world.AddRigidBody(body); - - body.SetWorldTransform(origPos); - body.SetGravity(origGrav); - - pBody.ApplyCollisionMask(pWorld.physicsScene); - - //if (body.GetBroadphaseHandle() != null) - // world.UpdateSingleAabb(body); - return true; - } - - public override void ForceActivationState(BulletBody pBody, ActivationState pActivationState) - { - CollisionObject body = ((BulletBodyXNA)pBody).body; - body.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState); - } - - public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pBody) - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - CollisionObject body = ((BulletBodyXNA)pBody).body; - world.UpdateSingleAabb(body); - } - - public override void UpdateAabbs(BulletWorld world) { /* TODO */ } - public override bool GetForceUpdateAllAabbs(BulletWorld world) { /* TODO */ return false; } - public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) { /* TODO */ } - - public override bool SetCollisionGroupMask(BulletBody pBody, uint pGroup, uint pMask) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; - body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; - if ((uint) body.GetBroadphaseHandle().m_collisionFilterGroup == 0) - return false; - return true; - } - - public override void ClearAllForces(BulletBody pBody) - { - CollisionObject body = ((BulletBodyXNA)pBody).body; - IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0); - body.SetInterpolationLinearVelocity(ref zeroVector); - body.SetInterpolationAngularVelocity(ref zeroVector); - IndexedMatrix bodytransform = body.GetWorldTransform(); - - body.SetInterpolationWorldTransform(ref bodytransform); - - if (body is RigidBody) - { - RigidBody rigidbody = body as RigidBody; - rigidbody.SetLinearVelocity(zeroVector); - rigidbody.SetAngularVelocity(zeroVector); - rigidbody.ClearForces(); - } - } - - public override void SetInterpolationAngularVelocity(BulletBody pBody, Vector3 pVector3) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); - body.SetInterpolationAngularVelocity(ref vec); - } - - public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); - body.SetAngularVelocity(ref vec); - } - public override Vector3 GetTotalForce(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 iv3 = body.GetTotalForce(); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - public override Vector3 GetTotalTorque(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 iv3 = body.GetTotalTorque(); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 iv3 = body.GetInvInertiaDiagLocal(); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z); - body.SetInvInertiaDiagLocal(ref iv3); - } - public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z); - IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); - body.ApplyForce(ref forceiv3, ref posiv3); - } - public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z); - IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); - body.ApplyImpulse(ref impiv3, ref posiv3); - } - - public override void ClearForces(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.ClearForces(); - } - - public override void SetTranslation(BulletBody pBody, Vector3 _position, Quaternion _orientation) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); - IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, - _orientation.W); - IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); - mat._origin = vposition; - body.SetWorldTransform(mat); - - } - - public override Vector3 GetPosition(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 pos = body.GetInterpolationWorldTransform()._origin; - return new Vector3(pos.X, pos.Y, pos.Z); - } - - public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - IndexedVector3 inertia = IndexedVector3.Zero; - shape.CalculateLocalInertia(pphysMass, out inertia); - return new Vector3(inertia.X, inertia.Y, inertia.Z); - } - - public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z); - body.SetMassProps(pphysMass, inertia); - } - - - public override void SetObjectForce(BulletBody pBody, Vector3 _force) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z); - body.SetTotalForce(ref force); - } - - public override void SetFriction(BulletBody pBody, float _currentFriction) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.SetFriction(_currentFriction); - } - - public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z); - body.SetLinearVelocity(velocity); - } - - public override void Activate(BulletBody pBody, bool pforceactivation) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.Activate(pforceactivation); - - } - - public override Quaternion GetOrientation(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedQuaternion mat = body.GetInterpolationWorldTransform().GetRotation(); - return new Quaternion(mat.X, mat.Y, mat.Z, mat.W); - } - - public override CollisionFlags RemoveFromCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags(); - existingcollisionFlags &= ~pcollisionFlags; - body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); - return (CollisionFlags)(uint)existingcollisionFlags; - } - - public override float GetCcdMotionThreshold(BulletBody obj) { /* TODO */ return 0f; } - - public override float GetCcdSweptSphereRadius(BulletBody obj) { /* TODO */ return 0f; } - - public override IntPtr GetUserPointer(BulletBody obj) { /* TODO */ return IntPtr.Zero; } - - public override void SetUserPointer(BulletBody obj, IntPtr val) { /* TODO */ } - - public override void SetGravity(BulletBody pBody, Vector3 pGravity) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z); - body.SetGravity(gravity); - } - - public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint) - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - TypedConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain; - world.RemoveConstraint(constraint); - return true; - } - - public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) - { - Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; - IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); - IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); - constraint.SetLinearLowerLimit(lowlimit); - constraint.SetLinearUpperLimit(highlimit); - return true; - } - - public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) - { - Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; - IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); - IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); - constraint.SetAngularLowerLimit(lowlimit); - constraint.SetAngularUpperLimit(highlimit); - return true; - } - - public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt) - { - Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; - constraint.SetOverrideNumSolverIterations((int)cnt); - } - - public override bool CalculateTransforms(BulletConstraint pConstraint) - { - Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; - constraint.CalculateTransforms(); - return true; - } - - public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2) - { - Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; - constraint.SetEnabled((p_2 == 0) ? false : true); - } - - - //BulletSimAPI.Create6DofConstraint(m_world.ptr, m_body1.ptr, m_body2.ptr,frame1, frame1rot,frame2, frame2rot,useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); - public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) - - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody; - RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody; - IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); - IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); - IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); - frame1._origin = frame1v; - - IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); - IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); - IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); - frame2._origin = frame1v; - - Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, - puseLinearReferenceFrameA); - consttr.CalculateTransforms(); - world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); - - return new BulletConstraintXNA(consttr); - } - - - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody; - RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody; - IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); - IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); - - IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); - IndexedMatrix mat = IndexedMatrix.Identity; - mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); - frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint; - frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint; - - Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); - consttr.CalculateTransforms(); - world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies); - - return new BulletConstraintXNA(consttr); - } - //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); - public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot) - { - Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; - IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); - IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); - IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); - frame1._origin = frame1v; - - IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); - IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); - IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); - frame2._origin = frame1v; - constraint.SetFrames(ref frame1, ref frame2); - return true; - } - - public override Vector3 GetLinearVelocity(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 iv3 = body.GetLinearVelocity(); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - public override Vector3 GetAngularVelocity(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 iv3 = body.GetAngularVelocity(); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); - IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - public override void Translate(BulletBody pBody, Vector3 trans) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - } - public override void UpdateDeactivation(BulletBody pBody, float timeStep) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.UpdateDeactivation(timeStep); - } - - public override bool WantsSleeping(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - return body.WantsSleeping(); - } - - public override void SetAngularFactor(BulletBody pBody, float factor) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.SetAngularFactor(factor); - } - - public override Vector3 GetAngularFactor(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 iv3 = body.GetAngularFactor(); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - - public override bool IsInWorld(BulletWorld pWorld, BulletBody pBody) - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - CollisionObject body = ((BulletBodyXNA)pBody).body; - return world.IsInWorld(body); - } - - public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstrain) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain; - body.AddConstraintRef(constrain); - } - - public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstrain) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain; - body.RemoveConstraintRef(constrain); - } - - public override BulletConstraint GetConstraintRef(BulletBody pBody, int index) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - return new BulletConstraintXNA(body.GetConstraintRef(index)); - } - - public override int GetNumConstraintRefs(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - return body.GetNumConstraintRefs(); - } - - public override void SetInterpolationLinearVelocity(BulletBody pBody, Vector3 VehicleVelocity) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z); - body.SetInterpolationLinearVelocity(ref velocity); - } - - public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff) - { - Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; - constraint.SetUseFrameOffset((onOff == 0) ? false : true); - return true; - } - //SetBreakingImpulseThreshold(m_constraint.ptr, threshold); - public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold) - { - Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; - constraint.SetBreakingImpulseThreshold(threshold); - return true; - } - //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping); - public override void SetAngularDamping(BulletBody pBody, float angularDamping) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - float lineardamping = body.GetLinearDamping(); - body.SetDamping(lineardamping, angularDamping); - - } - - public override void UpdateInertiaTensor(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.UpdateInertiaTensor(); - } - - public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape) - { - CompoundShape shape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape; - shape.RecalculateLocalAabb(); - } - - //BulletSimAPI.GetCollisionFlags(PhysBody.ptr) - public override CollisionFlags GetCollisionFlags(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - uint flags = (uint)body.GetCollisionFlags(); - return (CollisionFlags) flags; - } - - public override void SetDamping(BulletBody pBody, float pLinear, float pAngular) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.SetDamping(pLinear, pAngular); - } - //PhysBody.ptr, PhysicsScene.Params.deactivationTime); - public override void SetDeactivationTime(BulletBody pBody, float pDeactivationTime) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.SetDeactivationTime(pDeactivationTime); - } - //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); - public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold); - } - - public override CollisionObjectTypes GetBodyType(BulletBody pBody) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - return (CollisionObjectTypes)(int) body.GetInternalType(); - } - - public override void ApplyGravity(BulletBody obj) { /* TODO */ } - - public override Vector3 GetGravity(BulletBody obj) { /* TODO */ return Vector3.Zero; } - - public override void SetLinearDamping(BulletBody obj, float lin_damping) { /* TODO */ } - - public override float GetLinearDamping(BulletBody obj) { /* TODO */ return 0f; } - - public override float GetAngularDamping(BulletBody obj) { /* TODO */ return 0f; } - - public override float GetLinearSleepingThreshold(BulletBody obj) { /* TODO */ return 0f; } - - public override void ApplyDamping(BulletBody obj, float timeStep) { /* TODO */ } - - public override Vector3 GetLinearFactor(BulletBody obj) { /* TODO */ return Vector3.Zero; } - - public override void SetLinearFactor(BulletBody obj, Vector3 factor) { /* TODO */ } - - public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) { /* TODO */ } - - //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum); - public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); - body.ApplyCentralForce(ref fSum); - } - public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); - body.ApplyCentralImpulse(ref fSum); - } - public override void ApplyTorque(BulletBody pBody, Vector3 pfSum) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); - body.ApplyTorque(ref fSum); - } - public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); - body.ApplyTorqueImpulse(ref fSum); - } - - public override void DumpRigidBody(BulletWorld p, BulletBody p_2) - { - //TODO: - } - - public override void DumpCollisionShape(BulletWorld p, BulletShape p_2) - { - //TODO: - } - public override void DumpConstraint(BulletWorld world, BulletConstraint constrain) - { - //TODO: - } - - public override void DumpActivationInfo(BulletWorld world) - { - //TODO: - } - - public override void DumpAllInfo(BulletWorld world) - { - //TODO: - } - - public override void DumpPhysicsStatistics(BulletWorld world) - { - //TODO: - } - - public override void DestroyObject(BulletWorld p, BulletBody p_2) - { - //TODO: - } - - public override void Shutdown(BulletWorld pWorld) - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - world.Cleanup(); - } - - public override BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id) - { - return null; - } - - public override bool DeleteCollisionShape(BulletWorld p, BulletShape p_2) - { - //TODO: - return false; - } - //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); - - public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) - { - CollisionWorld world = ((BulletWorldXNA)pWorld).world; - IndexedMatrix mat = - IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, - pRawOrientation.Z, pRawOrientation.W)); - mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - //UpdateSingleAabb(world, shape); - // TODO: Feed Update array into null - RigidBody body = new RigidBody(0,new SimMotionState(world,pLocalID,mat,null),shape,IndexedVector3.Zero); - - body.SetUserPointer(pLocalID); - return new BulletBodyXNA(pLocalID, body); - } - - - public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) - { - - IndexedMatrix mat = - IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, - pRawOrientation.Z, pRawOrientation.W)); - mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); - - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - - // TODO: Feed Update array into null - RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero); - body.SetWorldTransform(mat); - body.SetUserPointer(pLocalID); - return new BulletBodyXNA(pLocalID, body); - } - //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); - public override CollisionFlags SetCollisionFlags(BulletBody pBody, CollisionFlags collisionFlags) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags); - return (CollisionFlags)body.GetCollisionFlags(); - } - - public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return Vector3.Zero; } - public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } - public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; } - public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; } - public override bool IsStaticObject(BulletBody pBody) { /* TODO */ return false; } - public override bool IsKinematicObject(BulletBody pBody) { /* TODO */ return false; } - public override bool IsStaticOrKinematicObject(BulletBody pBody) { /* TODO */ return false; } - public override bool HasContactResponse(BulletBody pBody) { /* TODO */ return false; } - public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; } - public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ } - public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; } - public override bool IsActive(BulletBody pBody) { /* TODO */ return false; } - public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; } - public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; } - public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ } - public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; } - - //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); - public override void SetHitFraction(BulletBody pBody, float pHitFraction) - { - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - body.SetHitFraction(pHitFraction); - } - //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale); - public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale) - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); - CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight); - capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin); - capsuleShapeZ.SetLocalScaling(ref scale); - - return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ; - } - - public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, - int maxCollisions, ref CollisionDesc[] collisionArray, - int maxUpdates, ref EntityProperties[] updateArray - ) - { - /* TODO */ - return new BulletWorldXNA(1, null, null); - } - - private static object Initialize2(Vector3 worldExtent, - ConfigurationParameters[] o, - int mMaxCollisionsPerFrame, ref List collisionArray, - int mMaxUpdatesPerFrame, ref List updateArray, - object mDebugLogCallbackHandle) - { - CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); - - p.angularDamping = o[0].XangularDamping; - p.defaultFriction = o[0].defaultFriction; - p.defaultFriction = o[0].defaultFriction; - p.defaultDensity = o[0].defaultDensity; - p.defaultRestitution = o[0].defaultRestitution; - p.collisionMargin = o[0].collisionMargin; - p.gravity = o[0].gravity; - - p.linearDamping = o[0].XlinearDamping; - p.angularDamping = o[0].XangularDamping; - p.deactivationTime = o[0].XdeactivationTime; - p.linearSleepingThreshold = o[0].XlinearSleepingThreshold; - p.angularSleepingThreshold = o[0].XangularSleepingThreshold; - p.ccdMotionThreshold = o[0].XccdMotionThreshold; - p.ccdSweptSphereRadius = o[0].XccdSweptSphereRadius; - p.contactProcessingThreshold = o[0].XcontactProcessingThreshold; - - p.terrainImplementation = o[0].XterrainImplementation; - p.terrainFriction = o[0].XterrainFriction; - - p.terrainHitFraction = o[0].XterrainHitFraction; - p.terrainRestitution = o[0].XterrainRestitution; - p.terrainCollisionMargin = o[0].XterrainCollisionMargin; - - p.avatarFriction = o[0].XavatarFriction; - p.avatarStandingFriction = o[0].XavatarStandingFriction; - p.avatarDensity = o[0].XavatarDensity; - p.avatarRestitution = o[0].XavatarRestitution; - p.avatarCapsuleWidth = o[0].XavatarCapsuleWidth; - p.avatarCapsuleDepth = o[0].XavatarCapsuleDepth; - p.avatarCapsuleHeight = o[0].XavatarCapsuleHeight; - p.avatarContactProcessingThreshold = o[0].XavatarContactProcessingThreshold; - - p.vehicleAngularDamping = o[0].XvehicleAngularDamping; - - p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; - p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; - p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; - p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs; - p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder; - p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands; - p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching; - p.numberOfSolverIterations = o[0].numberOfSolverIterations; - - p.linksetImplementation = o[0].XlinksetImplementation; - p.linkConstraintUseFrameOffset = o[0].XlinkConstraintUseFrameOffset; - p.linkConstraintEnableTransMotor = o[0].XlinkConstraintEnableTransMotor; - p.linkConstraintTransMotorMaxVel = o[0].XlinkConstraintTransMotorMaxVel; - p.linkConstraintTransMotorMaxForce = o[0].XlinkConstraintTransMotorMaxForce; - p.linkConstraintERP = o[0].XlinkConstraintERP; - p.linkConstraintCFM = o[0].XlinkConstraintCFM; - p.linkConstraintSolverIterations = o[0].XlinkConstraintSolverIterations; - p.physicsLoggingFrames = o[0].XphysicsLoggingFrames; - DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); - - DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); - CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); - - - if (p.maxPersistantManifoldPoolSize > 0) - cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize; - if (p.shouldDisableContactPoolDynamicAllocation !=0) - m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION); - //if (p.maxCollisionAlgorithmPoolSize >0 ) - - DbvtBroadphase m_broadphase = new DbvtBroadphase(); - //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0); - //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256); - - //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true); - m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback()); - - SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver(); - - DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci); - world.UpdatedObjects = updateArray; - world.UpdatedCollisions = collisionArray; - world.WorldSettings.Params = p; - world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0); - world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD; - if (p.shouldRandomizeSolverOrder != 0) - world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER; - - world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0); - //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port - - if (p.shouldEnableFrictionCaching != 0) - world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING; - - if (p.numberOfSolverIterations > 0) - world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations; - - - world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping; - world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution; - world.GetSolverInfo().m_globalCfm = 0.0f; - world.GetSolverInfo().m_tau = 0.6f; - world.GetSolverInfo().m_friction = 0.3f; - world.GetSolverInfo().m_maxErrorReduction = 20f; - world.GetSolverInfo().m_numIterations = 10; - world.GetSolverInfo().m_erp = 0.2f; - world.GetSolverInfo().m_erp2 = 0.1f; - world.GetSolverInfo().m_sor = 1.0f; - world.GetSolverInfo().m_splitImpulse = false; - world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f; - world.GetSolverInfo().m_linearSlop = 0.0f; - world.GetSolverInfo().m_warmstartingFactor = 0.85f; - world.GetSolverInfo().m_restingContactRestitutionThreshold = 2; - world.SetForceUpdateAllAabbs(true); - - - world.SetGravity(new IndexedVector3(0,0,p.gravity)); - - return world; - } - //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL - public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis) - { - Generic6DofConstraint constrain = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; - if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) - { - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0); - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1); - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2); - } - if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) - { - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3); - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4); - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5); - } - if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL) - { - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis); - } - return true; - } - - public override bool PushUpdate(BulletBody pCollisionObject) - { - bool ret = false; - RigidBody rb = ((BulletBodyXNA)pCollisionObject).rigidBody; - if (rb != null) - { - SimMotionState sms = rb.GetMotionState() as SimMotionState; - if (sms != null) - { - IndexedMatrix wt = IndexedMatrix.Identity; - sms.GetWorldTransform(out wt); - sms.SetWorldTransform(ref wt, true); - ret = true; - } - } - return ret; - - } - - public override float GetAngularMotionDisc(BulletShape pShape) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - return shape.GetAngularMotionDisc(); - } - public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - return shape.GetContactBreakingThreshold(defaultFactor); - } - public override bool IsCompound(BulletShape pShape) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - return shape.IsCompound(); - } - public override bool IsSoftBody(BulletShape pShape) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - return shape.IsSoftBody(); - } - public override bool IsPolyhedral(BulletShape pShape) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - return shape.IsPolyhedral(); - } - public override bool IsConvex2d(BulletShape pShape) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - return shape.IsConvex2d(); - } - public override bool IsConvex(BulletShape pShape) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - return shape.IsConvex(); - } - public override bool IsNonMoving(BulletShape pShape) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - return shape.IsNonMoving(); - } - public override bool IsConcave(BulletShape pShape) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - return shape.IsConcave(); - } - public override bool IsInfinite(BulletShape pShape) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - return shape.IsInfinite(); - } - public override bool IsNativeShape(BulletShape pShape) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - bool ret; - switch (shape.GetShapeType()) - { - case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: - case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: - case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: - case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: - ret = true; - break; - default: - ret = false; - break; - } - return ret; - } - - public override void SetShapeCollisionMargin(BulletShape shape, float margin) { /* TODO */ } - - //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation - public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - IndexedMatrix bodyTransform = new IndexedMatrix(); - bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); - bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W)); - GhostObject gObj = new PairCachingGhostObject(); - gObj.SetWorldTransform(bodyTransform); - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - gObj.SetCollisionShape(shape); - gObj.SetUserPointer(pLocalID); - // TODO: Add to Special CollisionObjects! - return new BulletBodyXNA(pLocalID, gObj); - } - - public override void SetCollisionShape(BulletWorld pWorld, BulletBody pObj, BulletShape pShape) - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - CollisionObject obj = ((BulletBodyXNA)pObj).body; - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - obj.SetCollisionShape(shape); - - } - public override BulletShape GetCollisionShape(BulletBody obj) { /* TODO */ return null; } - - //(PhysicsScene.World.ptr, nativeShapeData) - public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData) - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - CollisionShape shape = null; - switch (pShapeData.Type) - { - case BSPhysicsShapeType.SHAPE_BOX: - shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f)); - break; - case BSPhysicsShapeType.SHAPE_CONE: - shape = new ConeShapeZ(0.5f, 1.0f); - break; - case BSPhysicsShapeType.SHAPE_CYLINDER: - shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f)); - break; - case BSPhysicsShapeType.SHAPE_SPHERE: - shape = new SphereShape(0.5f); - break; - - } - if (shape != null) - { - IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z); - shape.SetMargin(world.WorldSettings.Params.collisionMargin); - shape.SetLocalScaling(ref scaling); - - } - return new BulletShapeXNA(shape, pShapeData.Type); - } - //PhysicsScene.World.ptr, false - public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree) - { - return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND); - } - - public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape) - { - CompoundShape compoundshape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape; - return compoundshape.GetNumChildShapes(); - } - //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot - public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot) - { - IndexedMatrix relativeTransform = new IndexedMatrix(); - CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape; - CollisionShape addshape = ((BulletShapeXNA)paddShape).shape; - - relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z); - relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W)); - compoundshape.AddChildShape(ref relativeTransform, addshape); - - } - - public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii) - { - CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape; - CollisionShape ret = null; - ret = compoundshape.GetChildShape(pii); - compoundshape.RemoveChildShapeByIndex(pii); - return new BulletShapeXNA(ret, BSPhysicsShapeType.SHAPE_UNKNOWN); - } - - public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { /* TODO */ return null; } - public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ } - - public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin) - { - StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight ); - m_planeshape.SetMargin(pcollisionMargin); - m_planeshape.SetUserPointer(pLocalId); - return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); - } - - public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody ppBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) - { - HingeConstraint constrain = null; - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - RigidBody rb1 = ((BulletBodyXNA)pBody1).rigidBody; - RigidBody rb2 = ((BulletBodyXNA)ppBody2).rigidBody; - if (rb1 != null && rb2 != null) - { - IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); - IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); - IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); - IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); - world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); - } - return new BulletConstraintXNA(constrain); - } - - public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls) - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - CompoundShape compoundshape = new CompoundShape(false); - - compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); - int ii = 1; - - for (int i = 0; i < pHullCount; i++) - { - int vertexCount = (int) pConvHulls[ii]; - - IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]); - IndexedMatrix childTrans = IndexedMatrix.Identity; - childTrans._origin = centroid; - - List virts = new List(); - int ender = ((ii + 4) + (vertexCount*3)); - for (int iii = ii + 4; iii < ender; iii+=3) - { - - virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); - } - ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); - convexShape.SetMargin(world.WorldSettings.Params.collisionMargin); - compoundshape.AddChildShape(ref childTrans, convexShape); - ii += (vertexCount*3 + 4); - } - - return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); - } - - public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) { /* TODO */ return null; } - - public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) - { - //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); - - for (int iter = 0; iter < pVerticesCount; iter++) - { - if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; - if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; - } - - ObjectArray indicesarr = new ObjectArray(indices); - ObjectArray vertices = new ObjectArray(verticesAsFloats); - DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - IndexedMesh mesh = new IndexedMesh(); - mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; - mesh.m_numTriangles = pIndicesCount/3; - mesh.m_numVertices = pVerticesCount; - mesh.m_triangleIndexBase = indicesarr; - mesh.m_vertexBase = vertices; - mesh.m_vertexStride = 3; - mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; - mesh.m_triangleIndexStride = 3; - - TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); - tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); - BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); - meshShape.SetMargin(world.WorldSettings.Params.collisionMargin); - // world.UpdateSingleAabb(meshShape); - return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); - - } - public static void DumpRaw(ObjectArrayindices, ObjectArray vertices, int pIndicesCount,int pVerticesCount ) - { - - String fileName = "objTest3.raw"; - String completePath = System.IO.Path.Combine(Util.configDir(), fileName); - StreamWriter sw = new StreamWriter(completePath); - IndexedMesh mesh = new IndexedMesh(); - - mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; - mesh.m_numTriangles = pIndicesCount / 3; - mesh.m_numVertices = pVerticesCount; - mesh.m_triangleIndexBase = indices; - mesh.m_vertexBase = vertices; - mesh.m_vertexStride = 3; - mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; - mesh.m_triangleIndexStride = 3; - - TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); - tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); - - - - for (int i = 0; i < pVerticesCount; i++) - { - - string s = vertices[indices[i * 3]].ToString("0.0000"); - s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); - s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); - - sw.Write(s + "\n"); - } - - sw.Close(); - } - public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount) - { - - String fileName = "objTest6.raw"; - String completePath = System.IO.Path.Combine(Util.configDir(), fileName); - StreamWriter sw = new StreamWriter(completePath); - IndexedMesh mesh = new IndexedMesh(); - - mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; - mesh.m_numTriangles = pIndicesCount / 3; - mesh.m_numVertices = pVerticesCount; - mesh.m_triangleIndexBase = indices; - mesh.m_vertexBase = vertices; - mesh.m_vertexStride = 3; - mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; - mesh.m_triangleIndexStride = 3; - - TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); - tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); - - - sw.WriteLine("Indices"); - sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount)); - for (int iter = 0; iter < indices.Length; iter++) - { - sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter])); - } - sw.WriteLine("VerticesFloats"); - sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount)); - for (int iter = 0; iter < vertices.Length; iter++) - { - sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000"))); - } - - // for (int i = 0; i < pVerticesCount; i++) - // { - // - // string s = vertices[indices[i * 3]].ToString("0.0000"); - // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); - // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); - // - // sw.Write(s + "\n"); - //} - - sw.Close(); - } - - public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, - float scaleFactor, float collisionMargin) - { - const int upAxis = 2; - HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y, - heightMap, scaleFactor, - minHeight, maxHeight, upAxis, - false); - terrainShape.SetMargin(collisionMargin + 0.5f); - terrainShape.SetUseDiamondSubdivision(true); - terrainShape.SetUserPointer(id); - return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN); - } - - public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce) - { - TypedConstraint tconstrain = ((BulletConstraintXNA)pConstraint).constrain; - bool onOff = ponOff != 0; - bool ret = false; - - switch (tconstrain.GetConstraintType()) - { - case TypedConstraintType.D6_CONSTRAINT_TYPE: - Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint; - constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff; - constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity; - constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce; - ret = true; - break; - } - - - return ret; - - } - - public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, - out int updatedEntityCount, out int collidersCount) - { - /* TODO */ - updatedEntityCount = 0; - collidersCount = 0; - return 1; - } - - private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, - out int updatedEntityCount, out List updatedEntities, - out int collidersCount, out Listcolliders) - { - int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities, - out collidersCount, out colliders); - return epic; - } - - private static int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List updatedEntities, out int collidersCount, out List colliders) - { - int numSimSteps = 0; - - - //if (updatedEntities is null) - // updatedEntities = new List(); - - //if (colliders is null) - // colliders = new List(); - - - if (pWorld is BulletWorldXNA) - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - - numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep); - int updates = 0; - - updatedEntityCount = world.UpdatedObjects.Count; - updatedEntities = new List(world.UpdatedObjects); - updatedEntityCount = updatedEntities.Count; - world.UpdatedObjects.Clear(); - - - collidersCount = world.UpdatedCollisions.Count; - colliders = new List(world.UpdatedCollisions); - - world.UpdatedCollisions.Clear(); - m_collisionsThisFrame = 0; - int numManifolds = world.GetDispatcher().GetNumManifolds(); - for (int j = 0; j < numManifolds; j++) - { - PersistentManifold contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j); - int numContacts = contactManifold.GetNumContacts(); - if (numContacts == 0) - continue; - - CollisionObject objA = contactManifold.GetBody0() as CollisionObject; - CollisionObject objB = contactManifold.GetBody1() as CollisionObject; - - ManifoldPoint manifoldPoint = contactManifold.GetContactPoint(0); - IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB(); - IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A - - RecordCollision(world, objA, objB, contactPoint, contactNormal); - m_collisionsThisFrame ++; - if (m_collisionsThisFrame >= 9999999) - break; - - - } - - - } - else - { - //if (updatedEntities is null) - updatedEntities = new List(); - updatedEntityCount = 0; - //if (colliders is null) - colliders = new List(); - collidersCount = 0; - } - return numSimSteps; - } - - private static void RecordCollision(CollisionWorld world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm) - { - - IndexedVector3 contactNormal = norm; - if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && - (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) - { - return; - } - uint idA = (uint)objA.GetUserPointer(); - uint idB = (uint)objB.GetUserPointer(); - if (idA > idB) - { - uint temp = idA; - idA = idB; - idB = temp; - contactNormal = -contactNormal; - } - - ulong collisionID = ((ulong) idA << 32) | idB; - - BulletXNA.CollisionDesc cDesc = new BulletXNA.CollisionDesc() - { - aID = idA, - bID = idB, - point = contact, - normal = contactNormal - }; - world.UpdatedCollisions.Add(cDesc); - m_collisionsThisFrame++; - - - } - private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pBody) - { - EntityProperties ent = new EntityProperties(); - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - IndexedMatrix transform = body.GetWorldTransform(); - IndexedVector3 LinearVelocity = body.GetInterpolationLinearVelocity(); - IndexedVector3 AngularVelocity = body.GetInterpolationAngularVelocity(); - IndexedQuaternion rotation = transform.GetRotation(); - ent.Acceleration = Vector3.Zero; - ent.ID = (uint)body.GetUserPointer(); - ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z); - ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W); - ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z); - ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z); - return ent; - } - - public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ return false; } - - public override Vector3 GetLocalScaling(BulletShape pShape) - { - CollisionShape shape = ((BulletShapeXNA)pShape).shape; - IndexedVector3 scale = shape.GetLocalScaling(); - return new Vector3(scale.X,scale.Y,scale.Z); - } - - public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe) - { - DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; - if (world != null) - { - if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) - { - CollisionObject AvoidBody = ((BulletBodyXNA)NotMe).body; - - IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); - IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); - using ( - ClosestNotMeRayResultCallback rayCallback = - new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) - ) - { - world.RayTest(ref rOrigin, ref rEnd, rayCallback); - if (rayCallback.HasHit()) - { - IndexedVector3 hitLocation = rayCallback.m_hitPointWorld; - } - return rayCallback.HasHit(); - } - } - } - return false; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs deleted file mode 100644 index 8ad78ca..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs +++ /dev/null @@ -1,662 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin { - - // Constraint type values as defined by Bullet -public enum ConstraintType : int -{ - POINT2POINT_CONSTRAINT_TYPE = 3, - HINGE_CONSTRAINT_TYPE, - CONETWIST_CONSTRAINT_TYPE, - D6_CONSTRAINT_TYPE, - SLIDER_CONSTRAINT_TYPE, - CONTACT_CONSTRAINT_TYPE, - D6_SPRING_CONSTRAINT_TYPE, - MAX_CONSTRAINT_TYPE -} - -// =============================================================================== -[StructLayout(LayoutKind.Sequential)] -public struct ConvexHull -{ - Vector3 Offset; - int VertexCount; - Vector3[] Vertices; -} -public enum BSPhysicsShapeType -{ - SHAPE_UNKNOWN = 0, - SHAPE_CAPSULE = 1, - SHAPE_BOX = 2, - SHAPE_CONE = 3, - SHAPE_CYLINDER = 4, - SHAPE_SPHERE = 5, - SHAPE_MESH = 6, - SHAPE_HULL = 7, - // following defined by BulletSim - SHAPE_GROUNDPLANE = 20, - SHAPE_TERRAIN = 21, - SHAPE_COMPOUND = 22, - SHAPE_HEIGHTMAP = 23, - SHAPE_AVATAR = 24, -}; - -// The native shapes have predefined shape hash keys -public enum FixedShapeKey : ulong -{ - KEY_NONE = 0, - KEY_BOX = 1, - KEY_SPHERE = 2, - KEY_CONE = 3, - KEY_CYLINDER = 4, - KEY_CAPSULE = 5, - KEY_AVATAR = 6, -} - -[StructLayout(LayoutKind.Sequential)] -public struct ShapeData -{ - public uint ID; - public BSPhysicsShapeType Type; - public Vector3 Position; - public Quaternion Rotation; - public Vector3 Velocity; - public Vector3 Scale; - public float Mass; - public float Buoyancy; - public System.UInt64 HullKey; - public System.UInt64 MeshKey; - public float Friction; - public float Restitution; - public float Collidable; // true of things bump into this - public float Static; // true if a static object. Otherwise gravity, etc. - public float Solid; // true if object cannot be passed through - public Vector3 Size; - - // note that bools are passed as floats since bool size changes by language and architecture - public const float numericTrue = 1f; - public const float numericFalse = 0f; -} -[StructLayout(LayoutKind.Sequential)] -public struct SweepHit -{ - public uint ID; - public float Fraction; - public Vector3 Normal; - public Vector3 Point; -} -[StructLayout(LayoutKind.Sequential)] -public struct RaycastHit -{ - public uint ID; - public float Fraction; - public Vector3 Normal; -} -[StructLayout(LayoutKind.Sequential)] -public struct CollisionDesc -{ - public uint aID; - public uint bID; - public Vector3 point; - public Vector3 normal; -} -[StructLayout(LayoutKind.Sequential)] -public struct EntityProperties -{ - public uint ID; - public Vector3 Position; - public Quaternion Rotation; - public Vector3 Velocity; - public Vector3 Acceleration; - public Vector3 RotationalVelocity; -} - -// Format of this structure must match the definition in the C++ code -// NOTE: adding the X causes compile breaks if used. These are unused symbols -// that can be removed from both here and the unmanaged definition of this structure. -[StructLayout(LayoutKind.Sequential)] -public struct ConfigurationParameters -{ - public float defaultFriction; - public float defaultDensity; - public float defaultRestitution; - public float collisionMargin; - public float gravity; - - public float XlinearDamping; - public float XangularDamping; - public float XdeactivationTime; - public float XlinearSleepingThreshold; - public float XangularSleepingThreshold; - public float XccdMotionThreshold; - public float XccdSweptSphereRadius; - public float XcontactProcessingThreshold; - - public float XterrainImplementation; - public float XterrainFriction; - public float XterrainHitFraction; - public float XterrainRestitution; - public float XterrainCollisionMargin; - - public float XavatarFriction; - public float XavatarStandingFriction; - public float XavatarDensity; - public float XavatarRestitution; - public float XavatarCapsuleWidth; - public float XavatarCapsuleDepth; - public float XavatarCapsuleHeight; - public float XavatarContactProcessingThreshold; - - public float XvehicleAngularDamping; - - public float maxPersistantManifoldPoolSize; - public float maxCollisionAlgorithmPoolSize; - public float shouldDisableContactPoolDynamicAllocation; - public float shouldForceUpdateAllAabbs; - public float shouldRandomizeSolverOrder; - public float shouldSplitSimulationIslands; - public float shouldEnableFrictionCaching; - public float numberOfSolverIterations; - - public float XlinksetImplementation; - public float XlinkConstraintUseFrameOffset; - public float XlinkConstraintEnableTransMotor; - public float XlinkConstraintTransMotorMaxVel; - public float XlinkConstraintTransMotorMaxForce; - public float XlinkConstraintERP; - public float XlinkConstraintCFM; - public float XlinkConstraintSolverIterations; - - public float XphysicsLoggingFrames; - - public const float numericTrue = 1f; - public const float numericFalse = 0f; -} - - -// The states a bullet collision object can have -public enum ActivationState : uint -{ - ACTIVE_TAG = 1, - ISLAND_SLEEPING, - WANTS_DEACTIVATION, - DISABLE_DEACTIVATION, - DISABLE_SIMULATION, -} - -public enum CollisionObjectTypes : int -{ - CO_COLLISION_OBJECT = 1 << 0, - CO_RIGID_BODY = 1 << 1, - CO_GHOST_OBJECT = 1 << 2, - CO_SOFT_BODY = 1 << 3, - CO_HF_FLUID = 1 << 4, - CO_USER_TYPE = 1 << 5, -} - -// Values used by Bullet and BulletSim to control object properties. -// Bullet's "CollisionFlags" has more to do with operations on the -// object (if collisions happen, if gravity effects it, ...). -public enum CollisionFlags : uint -{ - CF_STATIC_OBJECT = 1 << 0, - CF_KINEMATIC_OBJECT = 1 << 1, - CF_NO_CONTACT_RESPONSE = 1 << 2, - CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3, - CF_CHARACTER_OBJECT = 1 << 4, - CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, - CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, - // Following used by BulletSim to control collisions and updates - BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, - BS_FLOATS_ON_WATER = 1 << 11, - BS_VEHICLE_COLLISIONS = 1 << 12, - BS_NONE = 0, - BS_ALL = 0xFFFFFFFF -}; - -// Values f collisions groups and masks -public enum CollisionFilterGroups : uint -{ - // Don't use the bit definitions!! Define the use in a - // filter/mask definition below. This way collision interactions - // are more easily found and debugged. - BNoneGroup = 0, - BDefaultGroup = 1 << 0, // 0001 - BStaticGroup = 1 << 1, // 0002 - BKinematicGroup = 1 << 2, // 0004 - BDebrisGroup = 1 << 3, // 0008 - BSensorTrigger = 1 << 4, // 0010 - BCharacterGroup = 1 << 5, // 0020 - BAllGroup = 0x000FFFFF, - // Filter groups defined by BulletSim - BGroundPlaneGroup = 1 << 10, // 0400 - BTerrainGroup = 1 << 11, // 0800 - BRaycastGroup = 1 << 12, // 1000 - BSolidGroup = 1 << 13, // 2000 - // BLinksetGroup = xx // a linkset proper is either static or dynamic - BLinksetChildGroup = 1 << 14, // 4000 -}; - -// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 -// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. -public enum ConstraintParams : int -{ - BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730 - BT_CONSTRAINT_STOP_ERP, - BT_CONSTRAINT_CFM, - BT_CONSTRAINT_STOP_CFM, -}; -public enum ConstraintParamAxis : int -{ - AXIS_LINEAR_X = 0, - AXIS_LINEAR_Y, - AXIS_LINEAR_Z, - AXIS_ANGULAR_X, - AXIS_ANGULAR_Y, - AXIS_ANGULAR_Z, - AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls - AXIS_ANGULAR_ALL, - AXIS_ALL -}; - -public abstract class BSAPITemplate -{ -// Returns the name of the underlying Bullet engine -public abstract string BulletEngineName { get; } -public abstract string BulletEngineVersion { get; protected set;} - -// Initialization and simulation -public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, - int maxCollisions, ref CollisionDesc[] collisionArray, - int maxUpdates, ref EntityProperties[] updateArray - ); - -public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, - out int updatedEntityCount, out int collidersCount); - -public abstract bool UpdateParameter(BulletWorld world, uint localID, String parm, float value); - -public abstract void Shutdown(BulletWorld sim); - -public abstract bool PushUpdate(BulletBody obj); - -// ===================================================================================== -// Mesh, hull, shape and body creation helper routines -public abstract BulletShape CreateMeshShape(BulletWorld world, - int indicesCount, int[] indices, - int verticesCount, float[] vertices ); - -public abstract BulletShape CreateHullShape(BulletWorld world, - int hullCount, float[] hulls); - -public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape); - -public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); - -public abstract bool IsNativeShape(BulletShape shape); - -public abstract void SetShapeCollisionMargin(BulletShape shape, float margin); - -public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale); - -public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree); - -public abstract int GetNumberOfCompoundChildren(BulletShape cShape); - -public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot); - -public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); - -public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); - -public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape); - -public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape); - -public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id); - -public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape); - -public abstract CollisionObjectTypes GetBodyType(BulletBody obj); - -public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot); - -public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot); - -public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot); - -public abstract void DestroyObject(BulletWorld sim, BulletBody obj); - -// ===================================================================================== -public abstract BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin); - -public abstract BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, - float scaleFactor, float collisionMargin); - -// ===================================================================================== -// Constraint creation and helper routines -public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frame1loc, Quaternion frame1rot, - Vector3 frame2loc, Quaternion frame2rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 joinPoint, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 pivotinA, Vector3 pivotinB, - Vector3 axisInA, Vector3 axisInB, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse); - -public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations); - -public abstract bool SetFrames(BulletConstraint constrain, - Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); - -public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); - -public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); - -public abstract bool UseFrameOffset(BulletConstraint constrain, float enable); - -public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce); - -public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold); - -public abstract bool CalculateTransforms(BulletConstraint constrain); - -public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); - -public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain); - -// ===================================================================================== -// btCollisionWorld entries -public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj); - -public abstract void UpdateAabbs(BulletWorld world); - -public abstract bool GetForceUpdateAllAabbs(BulletWorld world); - -public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force); - -// ===================================================================================== -// btDynamicsWorld entries -// public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot); -public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj); - -public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj); - -public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects); - -public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain); -// ===================================================================================== -// btCollisionObject entries -public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain); - -public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict); - -public abstract bool HasAnisotripicFriction(BulletConstraint constrain); - -public abstract void SetContactProcessingThreshold(BulletBody obj, float val); - -public abstract float GetContactProcessingThreshold(BulletBody obj); - -public abstract bool IsStaticObject(BulletBody obj); - -public abstract bool IsKinematicObject(BulletBody obj); - -public abstract bool IsStaticOrKinematicObject(BulletBody obj); - -public abstract bool HasContactResponse(BulletBody obj); - -public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape); - -public abstract BulletShape GetCollisionShape(BulletBody obj); - -public abstract int GetActivationState(BulletBody obj); - -public abstract void SetActivationState(BulletBody obj, int state); - -public abstract void SetDeactivationTime(BulletBody obj, float dtime); - -public abstract float GetDeactivationTime(BulletBody obj); - -public abstract void ForceActivationState(BulletBody obj, ActivationState state); - -public abstract void Activate(BulletBody obj, bool forceActivation); - -public abstract bool IsActive(BulletBody obj); - -public abstract void SetRestitution(BulletBody obj, float val); - -public abstract float GetRestitution(BulletBody obj); - -public abstract void SetFriction(BulletBody obj, float val); - -public abstract float GetFriction(BulletBody obj); - -public abstract Vector3 GetPosition(BulletBody obj); - -public abstract Quaternion GetOrientation(BulletBody obj); - -public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation); - -// public abstract IntPtr GetBroadphaseHandle(BulletBody obj); - -// public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle); - -public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel); - -public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel); - -public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel); - -public abstract float GetHitFraction(BulletBody obj); - -public abstract void SetHitFraction(BulletBody obj, float val); - -public abstract CollisionFlags GetCollisionFlags(BulletBody obj); - -public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags); - -public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags); - -public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags); - -public abstract float GetCcdMotionThreshold(BulletBody obj); - -public abstract void SetCcdMotionThreshold(BulletBody obj, float val); - -public abstract float GetCcdSweptSphereRadius(BulletBody obj); - -public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val); - -public abstract IntPtr GetUserPointer(BulletBody obj); - -public abstract void SetUserPointer(BulletBody obj, IntPtr val); - -// ===================================================================================== -// btRigidBody entries -public abstract void ApplyGravity(BulletBody obj); - -public abstract void SetGravity(BulletBody obj, Vector3 val); - -public abstract Vector3 GetGravity(BulletBody obj); - -public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping); - -public abstract void SetLinearDamping(BulletBody obj, float lin_damping); - -public abstract void SetAngularDamping(BulletBody obj, float ang_damping); - -public abstract float GetLinearDamping(BulletBody obj); - -public abstract float GetAngularDamping(BulletBody obj); - -public abstract float GetLinearSleepingThreshold(BulletBody obj); - -public abstract void ApplyDamping(BulletBody obj, float timeStep); - -public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia); - -public abstract Vector3 GetLinearFactor(BulletBody obj); - -public abstract void SetLinearFactor(BulletBody obj, Vector3 factor); - -public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot); - -// Add a force to the object as if its mass is one. -public abstract void ApplyCentralForce(BulletBody obj, Vector3 force); - -// Set the force being applied to the object as if its mass is one. -public abstract void SetObjectForce(BulletBody obj, Vector3 force); - -public abstract Vector3 GetTotalForce(BulletBody obj); - -public abstract Vector3 GetTotalTorque(BulletBody obj); - -public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj); - -public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert); - -public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold); - -public abstract void ApplyTorque(BulletBody obj, Vector3 torque); - -// Apply force at the given point. Will add torque to the object. -public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos); - -// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. -public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp); - -// Apply impulse to the object's torque. Force is scaled by object's mass. -public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp); - -// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. -public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos); - -public abstract void ClearForces(BulletBody obj); - -public abstract void ClearAllForces(BulletBody obj); - -public abstract void UpdateInertiaTensor(BulletBody obj); - -public abstract Vector3 GetLinearVelocity(BulletBody obj); - -public abstract Vector3 GetAngularVelocity(BulletBody obj); - -public abstract void SetLinearVelocity(BulletBody obj, Vector3 val); - -public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity); - -public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos); - -public abstract void Translate(BulletBody obj, Vector3 trans); - -public abstract void UpdateDeactivation(BulletBody obj, float timeStep); - -public abstract bool WantsSleeping(BulletBody obj); - -public abstract void SetAngularFactor(BulletBody obj, float factor); - -public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor); - -public abstract Vector3 GetAngularFactor(BulletBody obj); - -public abstract bool IsInWorld(BulletWorld world, BulletBody obj); - -public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain); - -public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain); - -public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index); - -public abstract int GetNumConstraintRefs(BulletBody obj); - -public abstract bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask); - -// ===================================================================================== -// btCollisionShape entries - -public abstract float GetAngularMotionDisc(BulletShape shape); - -public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor); - -public abstract bool IsPolyhedral(BulletShape shape); - -public abstract bool IsConvex2d(BulletShape shape); - -public abstract bool IsConvex(BulletShape shape); - -public abstract bool IsNonMoving(BulletShape shape); - -public abstract bool IsConcave(BulletShape shape); - -public abstract bool IsCompound(BulletShape shape); - -public abstract bool IsSoftBody(BulletShape shape); - -public abstract bool IsInfinite(BulletShape shape); - -public abstract void SetLocalScaling(BulletShape shape, Vector3 scale); - -public abstract Vector3 GetLocalScaling(BulletShape shape); - -public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass); - -public abstract int GetShapeType(BulletShape shape); - -public abstract void SetMargin(BulletShape shape, float val); - -public abstract float GetMargin(BulletShape shape); - -// ===================================================================================== -// Debugging -public abstract void DumpRigidBody(BulletWorld sim, BulletBody collisionObject); - -public abstract void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape); - -public abstract void DumpConstraint(BulletWorld sim, BulletConstraint constrain); - -public abstract void DumpActivationInfo(BulletWorld sim); - -public abstract void DumpAllInfo(BulletWorld sim); - -public abstract void DumpPhysicsStatistics(BulletWorld sim); - -}; -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs deleted file mode 100644 index 103d8fc..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ /dev/null @@ -1,827 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Reflection; -using log4net; -using OMV = OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -public sealed class BSCharacter : BSPhysObject -{ - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static readonly string LogHeader = "[BULLETS CHAR]"; - - // private bool _stopped; - private OMV.Vector3 _size; - private bool _grabbed; - private bool _selected; - private OMV.Vector3 _position; - private float _mass; - private float _avatarDensity; - private float _avatarVolume; - private OMV.Vector3 _force; - private OMV.Vector3 _velocity; - private OMV.Vector3 _torque; - private float _collisionScore; - private OMV.Vector3 _acceleration; - private OMV.Quaternion _orientation; - private int _physicsActorType; - private bool _isPhysical; - private bool _flying; - private bool _setAlwaysRun; - private bool _throttleUpdates; - private bool _isColliding; - private bool _collidingObj; - private bool _floatOnWater; - private OMV.Vector3 _rotationalVelocity; - private bool _kinematic; - private float _buoyancy; - - // The friction and velocity of the avatar is modified depending on whether walking or not. - private float _currentFriction; // the friction currently being used (changed by setVelocity). - - private BSVMotor _velocityMotor; - - private OMV.Vector3 _PIDTarget; - private bool _usePID; - private float _PIDTau; - private bool _useHoverPID; - private float _PIDHoverHeight; - private PIDHoverType _PIDHoverType; - private float _PIDHoverTao; - - public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) - : base(parent_scene, localID, avName, "BSCharacter") - { - _physicsActorType = (int)ActorTypes.Agent; - _position = pos; - - _flying = isFlying; - _orientation = OMV.Quaternion.Identity; - _velocity = OMV.Vector3.Zero; - _buoyancy = ComputeBuoyancyFromFlying(isFlying); - _currentFriction = BSParam.AvatarStandingFriction; - _avatarDensity = BSParam.AvatarDensity; - - // Old versions of ScenePresence passed only the height. If width and/or depth are zero, - // replace with the default values. - _size = size; - if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; - if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; - - // The dimensions of the physical capsule are kept in the scale. - // Physics creates a unit capsule which is scaled by the physics engine. - Scale = ComputeAvatarScale(_size); - // set _avatarVolume and _mass based on capsule size, _density and Scale - ComputeAvatarVolumeAndMass(); - - SetupMovementMotor(); - - DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", - LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); - - // do actual creation in taint time - PhysicsScene.TaintedObject("BSCharacter.create", delegate() - { - DetailLog("{0},BSCharacter.create,taint", LocalID); - // New body and shape into PhysBody and PhysShape - PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); - - SetPhysicalProperties(); - }); - return; - } - - // called when this character is being destroyed and the resources should be released - public override void Destroy() - { - base.Destroy(); - - DetailLog("{0},BSCharacter.Destroy", LocalID); - PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() - { - PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); - PhysBody.Clear(); - PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); - PhysShape.Clear(); - }); - } - - private void SetPhysicalProperties() - { - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); - - ZeroMotion(true); - ForcePosition = _position; - - // Set the velocity and compute the proper friction - _velocityMotor.Reset(); - _velocityMotor.SetTarget(_velocity); - _velocityMotor.SetCurrent(_velocity); - ForceVelocity = _velocity; - - // This will enable or disable the flying buoyancy of the avatar. - // Needs to be reset especially when an avatar is recreated after crossing a region boundry. - Flying = _flying; - - PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); - PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); - PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); - PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); - if (BSParam.CcdMotionThreshold > 0f) - { - PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); - PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); - } - - UpdatePhysicalMassProperties(RawMass, false); - - // Make so capsule does not fall over - PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); - - PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); - - PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); - - // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); - PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); - PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); - - // Do this after the object has been added to the world - PhysBody.collisionType = CollisionType.Avatar; - PhysBody.ApplyCollisionMask(PhysicsScene); - } - - // The avatar's movement is controlled by this motor that speeds up and slows down - // the avatar seeking to reach the motor's target speed. - // This motor runs as a prestep action for the avatar so it will keep the avatar - // standing as well as moving. Destruction of the avatar will destroy the pre-step action. - private void SetupMovementMotor() - { - - // Someday, use a PID motor for asymmetric speed up and slow down - // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); - - // Infinite decay and timescale values so motor only changes current to target values. - _velocityMotor = new BSVMotor("BSCharacter.Velocity", - 0.2f, // time scale - BSMotor.Infinite, // decay time scale - BSMotor.InfiniteVector, // friction timescale - 1f // efficiency - ); - // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. - - RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep) - { - // TODO: Decide if the step parameters should be changed depending on the avatar's - // state (flying, colliding, ...). There is code in ODE to do this. - - OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep); - - // If falling, we keep the world's downward vector no matter what the other axis specify. - if (!Flying && !IsColliding) - { - stepVelocity.Z = _velocity.Z; - // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); - } - - // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. - OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass / PhysicsScene.LastTimeStep; - - /* - // If moveForce is very small, zero things so we don't keep sending microscopic updates to the user - float moveForceMagnitudeSquared = moveForce.LengthSquared(); - if (moveForceMagnitudeSquared < 0.0001) - { - DetailLog("{0},BSCharacter.MoveMotor,zeroMovement,stepVel={1},vel={2},mass={3},magSq={4},moveForce={5}", - LocalID, stepVelocity, _velocity, Mass, moveForceMagnitudeSquared, moveForce); - ForceVelocity = OMV.Vector3.Zero; - } - else - { - AddForce(moveForce, false, true); - } - */ - // DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); - AddForce(moveForce, false, true); - }); - } - - public override void RequestPhysicsterseUpdate() - { - base.RequestPhysicsterseUpdate(); - } - // No one calls this method so I don't know what it could possibly mean - public override bool Stopped { get { return false; } } - - public override OMV.Vector3 Size { - get - { - // Avatar capsule size is kept in the scale parameter. - return _size; - } - - set { - _size = value; - // Old versions of ScenePresence passed only the height. If width and/or depth are zero, - // replace with the default values. - if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; - if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; - - Scale = ComputeAvatarScale(_size); - ComputeAvatarVolumeAndMass(); - DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", - LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); - - PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() - { - if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) - { - PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); - UpdatePhysicalMassProperties(RawMass, true); - // Make sure this change appears as a property update event - PhysicsScene.PE.PushUpdate(PhysBody); - } - }); - - } - } - - public override PrimitiveBaseShape Shape - { - set { BaseShape = value; } - } - // I want the physics engine to make an avatar capsule - public override BSPhysicsShapeType PreferredPhysicalShape - { - get {return BSPhysicsShapeType.SHAPE_CAPSULE; } - } - - public override bool Grabbed { - set { _grabbed = value; } - } - public override bool Selected { - set { _selected = value; } - } - public override void CrossingFailure() { return; } - public override void link(PhysicsActor obj) { return; } - public override void delink() { return; } - - // Set motion values to zero. - // Do it to the properties so the values get set in the physics engine. - // Push the setting of the values to the viewer. - // Called at taint time! - public override void ZeroMotion(bool inTaintTime) - { - _velocity = OMV.Vector3.Zero; - _acceleration = OMV.Vector3.Zero; - _rotationalVelocity = OMV.Vector3.Zero; - - // Zero some other properties directly into the physics engine - PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() - { - if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.ClearAllForces(PhysBody); - }); - } - public override void ZeroAngularMotion(bool inTaintTime) - { - _rotationalVelocity = OMV.Vector3.Zero; - - PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() - { - if (PhysBody.HasPhysicalBody) - { - PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); - PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); - // The next also get rid of applied linear force but the linear velocity is untouched. - PhysicsScene.PE.ClearForces(PhysBody); - } - }); - } - - - public override void LockAngularMotion(OMV.Vector3 axis) { return; } - - public override OMV.Vector3 RawPosition - { - get { return _position; } - set { _position = value; } - } - public override OMV.Vector3 Position { - get { - // Don't refetch the position because this function is called a zillion times - // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); - return _position; - } - set { - _position = value; - PositionSanityCheck(); - - PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() - { - DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); - if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); - }); - } - } - public override OMV.Vector3 ForcePosition { - get { - _position = PhysicsScene.PE.GetPosition(PhysBody); - return _position; - } - set { - _position = value; - PositionSanityCheck(); - PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); - } - } - - - // Check that the current position is sane and, if not, modify the position to make it so. - // Check for being below terrain or on water. - // Returns 'true' of the position was made sane by some action. - private bool PositionSanityCheck() - { - bool ret = false; - - // TODO: check for out of bounds - if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) - { - // The character is out of the known/simulated area. - // Upper levels of code will handle the transition to other areas so, for - // the time, we just ignore the position. - return ret; - } - - // If below the ground, move the avatar up - float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); - if (Position.Z < terrainHeight) - { - DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); - _position.Z = terrainHeight + 2.0f; - ret = true; - } - if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) - { - float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); - if (Position.Z < waterHeight) - { - _position.Z = waterHeight; - ret = true; - } - } - - return ret; - } - - // A version of the sanity check that also makes sure a new position value is - // pushed back to the physics engine. This routine would be used by anyone - // who is not already pushing the value. - private bool PositionSanityCheck(bool inTaintTime) - { - bool ret = false; - if (PositionSanityCheck()) - { - // The new position value must be pushed into the physics engine but we can't - // just assign to "Position" because of potential call loops. - PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() - { - DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); - if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); - }); - ret = true; - } - return ret; - } - - public override float Mass { get { return _mass; } } - - // used when we only want this prim's mass and not the linkset thing - public override float RawMass { - get {return _mass; } - } - public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) - { - OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); - PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); - } - - public override OMV.Vector3 Force { - get { return _force; } - set { - _force = value; - // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); - PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() - { - DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); - if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.SetObjectForce(PhysBody, _force); - }); - } - } - - // Avatars don't do vehicles - public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } } - public override void VehicleFloatParam(int param, float value) { } - public override void VehicleVectorParam(int param, OMV.Vector3 value) {} - public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } - public override void VehicleFlags(int param, bool remove) { } - - // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more - public override void SetVolumeDetect(int param) { return; } - - public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } - public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } - - // Sets the target in the motor. This starts the changing of the avatar's velocity. - public override OMV.Vector3 TargetVelocity - { - get - { - return _velocityMotor.TargetValue; - } - set - { - DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); - OMV.Vector3 targetVel = value; - if (_setAlwaysRun) - targetVel *= BSParam.AvatarAlwaysRunFactor; - - PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() - { - _velocityMotor.Reset(); - _velocityMotor.SetTarget(targetVel); - _velocityMotor.SetCurrent(_velocity); - _velocityMotor.Enabled = true; - }); - } - } - // Directly setting velocity means this is what the user really wants now. - public override OMV.Vector3 Velocity { - get { return _velocity; } - set { - _velocity = value; - // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); - PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() - { - _velocityMotor.Reset(); - _velocityMotor.SetCurrent(_velocity); - _velocityMotor.SetTarget(_velocity); - // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar. - _velocityMotor.Enabled = false; - - DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); - ForceVelocity = _velocity; - }); - } - } - public override OMV.Vector3 ForceVelocity { - get { return _velocity; } - set { - PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); - - _velocity = value; - // Depending on whether the avatar is moving or not, change the friction - // to keep the avatar from slipping around - if (_velocity.Length() == 0) - { - if (_currentFriction != BSParam.AvatarStandingFriction) - { - _currentFriction = BSParam.AvatarStandingFriction; - if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.SetFriction(PhysBody, _currentFriction); - } - } - else - { - if (_currentFriction != BSParam.AvatarFriction) - { - _currentFriction = BSParam.AvatarFriction; - if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.SetFriction(PhysBody, _currentFriction); - } - } - - PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); - PhysicsScene.PE.Activate(PhysBody, true); - } - } - public override OMV.Vector3 Torque { - get { return _torque; } - set { _torque = value; - } - } - public override float CollisionScore { - get { return _collisionScore; } - set { _collisionScore = value; - } - } - public override OMV.Vector3 Acceleration { - get { return _acceleration; } - set { _acceleration = value; } - } - public override OMV.Quaternion RawOrientation - { - get { return _orientation; } - set { _orientation = value; } - } - public override OMV.Quaternion Orientation { - get { return _orientation; } - set { - // Orientation is set zillions of times when an avatar is walking. It's like - // the viewer doesn't trust us. - if (_orientation != value) - { - _orientation = value; - PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() - { - ForceOrientation = _orientation; - }); - } - } - } - // Go directly to Bullet to get/set the value. - public override OMV.Quaternion ForceOrientation - { - get - { - _orientation = PhysicsScene.PE.GetOrientation(PhysBody); - return _orientation; - } - set - { - _orientation = value; - if (PhysBody.HasPhysicalBody) - { - // _position = PhysicsScene.PE.GetPosition(BSBody); - PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); - } - } - } - public override int PhysicsActorType { - get { return _physicsActorType; } - set { _physicsActorType = value; - } - } - public override bool IsPhysical { - get { return _isPhysical; } - set { _isPhysical = value; - } - } - public override bool IsSolid { - get { return true; } - } - public override bool IsStatic { - get { return false; } - } - public override bool Flying { - get { return _flying; } - set { - _flying = value; - - // simulate flying by changing the effect of gravity - Buoyancy = ComputeBuoyancyFromFlying(_flying); - } - } - // Flying is implimented by changing the avatar's buoyancy. - // Would this be done better with a vehicle type? - private float ComputeBuoyancyFromFlying(bool ifFlying) { - return ifFlying ? 1f : 0f; - } - public override bool - SetAlwaysRun { - get { return _setAlwaysRun; } - set { _setAlwaysRun = value; } - } - public override bool ThrottleUpdates { - get { return _throttleUpdates; } - set { _throttleUpdates = value; } - } - public override bool FloatOnWater { - set { - _floatOnWater = value; - PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() - { - if (PhysBody.HasPhysicalBody) - { - if (_floatOnWater) - CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); - else - CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); - } - }); - } - } - public override OMV.Vector3 RotationalVelocity { - get { return _rotationalVelocity; } - set { _rotationalVelocity = value; } - } - public override OMV.Vector3 ForceRotationalVelocity { - get { return _rotationalVelocity; } - set { _rotationalVelocity = value; } - } - public override bool Kinematic { - get { return _kinematic; } - set { _kinematic = value; } - } - // neg=fall quickly, 0=1g, 1=0g, pos=float up - public override float Buoyancy { - get { return _buoyancy; } - set { _buoyancy = value; - PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() - { - DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); - ForceBuoyancy = _buoyancy; - }); - } - } - public override float ForceBuoyancy { - get { return _buoyancy; } - set { - PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); - - _buoyancy = value; - DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); - // Buoyancy is faked by changing the gravity applied to the object - float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); - if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav)); - } - } - - // Used for MoveTo - public override OMV.Vector3 PIDTarget { - set { _PIDTarget = value; } - } - public override bool PIDActive { - set { _usePID = value; } - } - public override float PIDTau { - set { _PIDTau = value; } - } - - // Used for llSetHoverHeight and maybe vehicle height - // Hover Height will override MoveTo target's Z - public override bool PIDHoverActive { - set { _useHoverPID = value; } - } - public override float PIDHoverHeight { - set { _PIDHoverHeight = value; } - } - public override PIDHoverType PIDHoverType { - set { _PIDHoverType = value; } - } - public override float PIDHoverTau { - set { _PIDHoverTao = value; } - } - - // For RotLookAt - public override OMV.Quaternion APIDTarget { set { return; } } - public override bool APIDActive { set { return; } } - public override float APIDStrength { set { return; } } - public override float APIDDamping { set { return; } } - - public override void AddForce(OMV.Vector3 force, bool pushforce) - { - // Since this force is being applied in only one step, make this a force per second. - OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; - AddForce(addForce, pushforce, false); - } - private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { - if (force.IsFinite()) - { - float magnitude = force.Length(); - if (magnitude > BSParam.MaxAddForceMagnitude) - { - // Force has a limit - force = force / magnitude * BSParam.MaxAddForceMagnitude; - } - - OMV.Vector3 addForce = force; - // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); - - PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() - { - // Bullet adds this central force to the total force for this tick - // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); - if (PhysBody.HasPhysicalBody) - { - PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); - } - }); - } - else - { - m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID); - return; - } - } - - public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { - } - public override void SetMomentum(OMV.Vector3 momentum) { - } - - private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) - { - OMV.Vector3 newScale; - - // Bullet's capsule total height is the "passed height + radius * 2"; - // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) - // The number we pass in for 'scaling' is the multiplier to get that base - // shape to be the size desired. - // So, when creating the scale for the avatar height, we take the passed height - // (size.Z) and remove the caps. - // Another oddity of the Bullet capsule implementation is that it presumes the Y - // dimension is the radius of the capsule. Even though some of the code allows - // for a asymmetrical capsule, other parts of the code presume it is cylindrical. - - // Scale is multiplier of radius with one of "0.5" - newScale.X = size.X / 2f; - newScale.Y = size.Y / 2f; - - // The total scale height is the central cylindar plus the caps on the two ends. - newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; - // If smaller than the endcaps, just fake like we're almost that small - if (newScale.Z < 0) - newScale.Z = 0.1f; - - return newScale; - } - - // set _avatarVolume and _mass based on capsule size, _density and Scale - private void ComputeAvatarVolumeAndMass() - { - _avatarVolume = (float)( - Math.PI - * Size.X / 2f - * Size.Y / 2f // the area of capsule cylinder - * Size.Z // times height of capsule cylinder - + 1.33333333f - * Math.PI - * Size.X / 2f - * Math.Min(Size.X, Size.Y) / 2 - * Size.Y / 2f // plus the volume of the capsule end caps - ); - _mass = _avatarDensity * _avatarVolume; - } - - // The physics engine says that properties have updated. Update same and inform - // the world that things have changed. - public override void UpdateProperties(EntityProperties entprop) - { - _position = entprop.Position; - _orientation = entprop.Rotation; - _velocity = entprop.Velocity; - _acceleration = entprop.Acceleration; - _rotationalVelocity = entprop.RotationalVelocity; - - // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. - PositionSanityCheck(true); - - // remember the current and last set values - LastEntityProperties = CurrentEntityProperties; - CurrentEntityProperties = entprop; - - // Tell the linkset about value changes - Linkset.UpdateProperties(this, true); - - // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. - // base.RequestPhysicsterseUpdate(); - - DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", - LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs deleted file mode 100755 index b813974..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ - -public abstract class BSConstraint : IDisposable -{ - private static string LogHeader = "[BULLETSIM CONSTRAINT]"; - - protected BulletWorld m_world; - protected BSScene PhysicsScene; - protected BulletBody m_body1; - protected BulletBody m_body2; - protected BulletConstraint m_constraint; - protected bool m_enabled = false; - - public BulletBody Body1 { get { return m_body1; } } - public BulletBody Body2 { get { return m_body2; } } - public BulletConstraint Constraint { get { return m_constraint; } } - public abstract ConstraintType Type { get; } - public bool IsEnabled { get { return m_enabled; } } - - public BSConstraint(BulletWorld world) - { - m_world = world; - PhysicsScene = m_world.physicsScene; - } - - public virtual void Dispose() - { - if (m_enabled) - { - m_enabled = false; - if (m_constraint.HasPhysicalConstraint) - { - bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint); - m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", - BSScene.DetailLogZero, - m_body1.ID, m_body1.AddrString, - m_body2.ID, m_body2.AddrString, - success); - m_constraint.Clear(); - } - } - } - - public virtual bool SetLinearLimits(Vector3 low, Vector3 high) - { - bool ret = false; - if (m_enabled) - ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high); - return ret; - } - - public virtual bool SetAngularLimits(Vector3 low, Vector3 high) - { - bool ret = false; - if (m_enabled) - ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); - return ret; - } - - public virtual bool SetSolverIterations(float cnt) - { - bool ret = false; - if (m_enabled) - { - PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt); - ret = true; - } - return ret; - } - - public virtual bool CalculateTransforms() - { - bool ret = false; - if (m_enabled) - { - // Recompute the internal transforms - PhysicsScene.PE.CalculateTransforms(m_constraint); - ret = true; - } - return ret; - } - - // Reset this constraint making sure it has all its internal structures - // recomputed and is enabled and ready to go. - public virtual bool RecomputeConstraintVariables(float mass) - { - bool ret = false; - if (m_enabled) - { - ret = CalculateTransforms(); - if (ret) - { - // Setting an object's mass to zero (making it static like when it's selected) - // automatically disables the constraints. - // If the link is enabled, be sure to set the constraint itself to enabled. - PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true)); - } - else - { - m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID); - } - } - return ret; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs deleted file mode 100755 index ecb1b32..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ - -public sealed class BSConstraint6Dof : BSConstraint -{ - private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; - - public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } - - // Create a btGeneric6DofConstraint - public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frame1, Quaternion frame1rot, - Vector3 frame2, Quaternion frame2rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) - : base(world) - { - m_body1 = obj1; - m_body2 = obj2; - m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2, - frame1, frame1rot, - frame2, frame2rot, - useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); - m_enabled = true; - world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", - BSScene.DetailLogZero, world.worldID, - obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); - } - - public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 joinPoint, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) - : base(world) - { - m_body1 = obj1; - m_body2 = obj2; - if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody) - { - world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", - BSScene.DetailLogZero, world.worldID, - obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); - world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", - LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); - m_enabled = false; - } - else - { - m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2, - joinPoint, - useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); - PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", - BSScene.DetailLogZero, world.worldID, m_constraint.AddrString, - obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); - if (!m_constraint.HasPhysicalConstraint) - { - world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", - LogHeader, obj1.ID, obj2.ID); - m_enabled = false; - } - else - { - m_enabled = true; - } - } - } - - public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) - { - bool ret = false; - if (m_enabled) - { - PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot); - ret = true; - } - return ret; - } - - public bool SetCFMAndERP(float cfm, float erp) - { - bool ret = false; - if (m_enabled) - { - PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); - PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); - PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); - ret = true; - } - return ret; - } - - public bool UseFrameOffset(bool useOffset) - { - bool ret = false; - float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; - if (m_enabled) - ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff); - return ret; - } - - public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce) - { - bool ret = false; - float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; - if (m_enabled) - { - ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce); - m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", - BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); - } - return ret; - } - - public bool SetBreakingImpulseThreshold(float threshold) - { - bool ret = false; - if (m_enabled) - ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold); - return ret; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs deleted file mode 100755 index 2aeff25..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using log4net; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ - -public sealed class BSConstraintCollection : IDisposable -{ - // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]"; - - delegate bool ConstraintAction(BSConstraint constrain); - - private List m_constraints; - private BulletWorld m_world; - - public BSConstraintCollection(BulletWorld world) - { - m_world = world; - m_constraints = new List(); - } - - public void Dispose() - { - this.Clear(); - } - - public void Clear() - { - lock (m_constraints) - { - foreach (BSConstraint cons in m_constraints) - { - cons.Dispose(); - } - m_constraints.Clear(); - } - } - - public bool AddConstraint(BSConstraint cons) - { - lock (m_constraints) - { - // There is only one constraint between any bodies. Remove any old just to make sure. - RemoveAndDestroyConstraint(cons.Body1, cons.Body2); - - m_constraints.Add(cons); - } - - return true; - } - - // Get the constraint between two bodies. There can be only one. - // Return 'true' if a constraint was found. - public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint) - { - bool found = false; - BSConstraint foundConstraint = null; - - uint lookingID1 = body1.ID; - uint lookingID2 = body2.ID; - lock (m_constraints) - { - foreach (BSConstraint constrain in m_constraints) - { - if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2) - || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1)) - { - foundConstraint = constrain; - found = true; - break; - } - } - } - returnConstraint = foundConstraint; - return found; - } - - // Remove any constraint between the passed bodies. - // Presumed there is only one such constraint possible. - // Return 'true' if a constraint was found and destroyed. - public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2) - { - bool ret = false; - lock (m_constraints) - { - BSConstraint constrain; - if (this.TryGetConstraint(body1, body2, out constrain)) - { - // remove the constraint from our collection - RemoveAndDestroyConstraint(constrain); - ret = true; - } - } - - return ret; - } - - // The constraint MUST exist in the collection - public bool RemoveAndDestroyConstraint(BSConstraint constrain) - { - lock (m_constraints) - { - // remove the constraint from our collection - m_constraints.Remove(constrain); - } - // tell the engine that all its structures need to be freed - constrain.Dispose(); - // we destroyed something - return true; - } - - // Remove all constraints that reference the passed body. - // Return 'true' if any constraints were destroyed. - public bool RemoveAndDestroyConstraint(BulletBody body1) - { - List toRemove = new List(); - uint lookingID = body1.ID; - lock (m_constraints) - { - foreach (BSConstraint constrain in m_constraints) - { - if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID) - { - toRemove.Add(constrain); - } - } - foreach (BSConstraint constrain in toRemove) - { - m_constraints.Remove(constrain); - constrain.Dispose(); - } - } - return (toRemove.Count > 0); - } - - public bool RecalculateAllConstraints() - { - bool ret = false; - lock (m_constraints) - { - foreach (BSConstraint constrain in m_constraints) - { - constrain.CalculateTransforms(); - ret = true; - } - } - return ret; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs deleted file mode 100755 index 7714a03..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ - -public sealed class BSConstraintHinge : BSConstraint -{ - public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } - - public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 pivotInA, Vector3 pivotInB, - Vector3 axisInA, Vector3 axisInB, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) - : base(world) - { - m_body1 = obj1; - m_body2 = obj2; - m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2, - pivotInA, pivotInB, axisInA, axisInB, - useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); - m_enabled = true; - } - -} - -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs deleted file mode 100644 index 13c2539..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ /dev/null @@ -1,1383 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial - * are Copyright (c) 2009 Linden Research, Inc and are used under their license - * of Creative Commons Attribution-Share Alike 3.0 - * (http://creativecommons.org/licenses/by-sa/3.0/). - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using OpenMetaverse; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ - public sealed class BSDynamics - { - private static string LogHeader = "[BULLETSIM VEHICLE]"; - - private BSScene PhysicsScene { get; set; } - // the prim this dynamic controller belongs to - private BSPrim Prim { get; set; } - - // mass of the vehicle fetched each time we're calles - private float m_vehicleMass; - - // Vehicle properties - public Vehicle Type { get; set; } - - // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier - private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: - // HOVER_TERRAIN_ONLY - // HOVER_GLOBAL_HEIGHT - // NO_DEFLECTION_UP - // HOVER_WATER_ONLY - // HOVER_UP_ONLY - // LIMIT_MOTOR_UP - // LIMIT_ROLL_ONLY - private Vector3 m_BlockingEndPoint = Vector3.Zero; - private Quaternion m_RollreferenceFrame = Quaternion.Identity; - private Quaternion m_referenceFrame = Quaternion.Identity; - - // Linear properties - private BSVMotor m_linearMotor = new BSVMotor("LinearMotor"); - private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time - private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center - private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL - private Vector3 m_linearFrictionTimescale = Vector3.Zero; - private float m_linearMotorDecayTimescale = 0; - private float m_linearMotorTimescale = 0; - private Vector3 m_lastLinearVelocityVector = Vector3.Zero; - private Vector3 m_lastPositionVector = Vector3.Zero; - // private bool m_LinearMotorSetLastFrame = false; - // private Vector3 m_linearMotorOffset = Vector3.Zero; - - //Angular properties - private BSVMotor m_angularMotor = new BSVMotor("AngularMotor"); - private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor - // private int m_angularMotorApply = 0; // application frame counter - private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity - private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate - private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate - private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate - private Vector3 m_lastAngularVelocity = Vector3.Zero; - private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body - - //Deflection properties - private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection"); - private float m_angularDeflectionEfficiency = 0; - private float m_angularDeflectionTimescale = 0; - private float m_linearDeflectionEfficiency = 0; - private float m_linearDeflectionTimescale = 0; - - //Banking properties - private float m_bankingEfficiency = 0; - private float m_bankingMix = 0; - private float m_bankingTimescale = 0; - - //Hover and Buoyancy properties - private BSVMotor m_hoverMotor = new BSVMotor("Hover"); - private float m_VhoverHeight = 0f; - private float m_VhoverEfficiency = 0f; - private float m_VhoverTimescale = 0f; - private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height - private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. - // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) - // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. - // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. - - //Attractor properties - private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); - private float m_verticalAttractionEfficiency = 1.0f; // damped - private float m_verticalAttractionCutoff = 500f; // per the documentation - // Timescale > cutoff means no vert attractor. - private float m_verticalAttractionTimescale = 510f; - - // Just some recomputed constants: - static readonly float PIOverFour = ((float)Math.PI) / 4f; - static readonly float PIOverTwo = ((float)Math.PI) / 2f; - - public BSDynamics(BSScene myScene, BSPrim myPrim) - { - PhysicsScene = myScene; - Prim = myPrim; - Type = Vehicle.TYPE_NONE; - } - - // Return 'true' if this vehicle is doing vehicle things - public bool IsActive - { - get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; } - } - - internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) - { - VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); - switch (pParam) - { - case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: - m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); - break; - case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: - m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); - break; - case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: - m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); - m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; - break; - case Vehicle.ANGULAR_MOTOR_TIMESCALE: - m_angularMotorTimescale = Math.Max(pValue, 0.01f); - m_angularMotor.TimeScale = m_angularMotorTimescale; - break; - case Vehicle.BANKING_EFFICIENCY: - m_bankingEfficiency = ClampInRange(-1f, pValue, 1f); - break; - case Vehicle.BANKING_MIX: - m_bankingMix = Math.Max(pValue, 0.01f); - break; - case Vehicle.BANKING_TIMESCALE: - m_bankingTimescale = Math.Max(pValue, 0.01f); - break; - case Vehicle.BUOYANCY: - m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); - break; - case Vehicle.HOVER_EFFICIENCY: - m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); - break; - case Vehicle.HOVER_HEIGHT: - m_VhoverHeight = pValue; - break; - case Vehicle.HOVER_TIMESCALE: - m_VhoverTimescale = Math.Max(pValue, 0.01f); - break; - case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: - m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); - break; - case Vehicle.LINEAR_DEFLECTION_TIMESCALE: - m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); - break; - case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: - m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); - m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; - break; - case Vehicle.LINEAR_MOTOR_TIMESCALE: - m_linearMotorTimescale = Math.Max(pValue, 0.01f); - m_linearMotor.TimeScale = m_linearMotorTimescale; - break; - case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: - m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f); - m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; - break; - case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: - m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); - m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale; - break; - - // These are vector properties but the engine lets you use a single float value to - // set all of the components to the same value - case Vehicle.ANGULAR_FRICTION_TIMESCALE: - m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); - m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; - break; - case Vehicle.ANGULAR_MOTOR_DIRECTION: - m_angularMotorDirection = new Vector3(pValue, pValue, pValue); - m_angularMotor.SetTarget(m_angularMotorDirection); - break; - case Vehicle.LINEAR_FRICTION_TIMESCALE: - m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); - m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; - break; - case Vehicle.LINEAR_MOTOR_DIRECTION: - m_linearMotorDirection = new Vector3(pValue, pValue, pValue); - m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); - m_linearMotor.SetTarget(m_linearMotorDirection); - break; - case Vehicle.LINEAR_MOTOR_OFFSET: - m_linearMotorOffset = new Vector3(pValue, pValue, pValue); - break; - - } - }//end ProcessFloatVehicleParam - - internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) - { - VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); - switch (pParam) - { - case Vehicle.ANGULAR_FRICTION_TIMESCALE: - m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; - break; - case Vehicle.ANGULAR_MOTOR_DIRECTION: - // Limit requested angular speed to 2 rps= 4 pi rads/sec - pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f); - pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); - pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); - m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_angularMotor.SetTarget(m_angularMotorDirection); - break; - case Vehicle.LINEAR_FRICTION_TIMESCALE: - m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; - break; - case Vehicle.LINEAR_MOTOR_DIRECTION: - m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_linearMotor.SetTarget(m_linearMotorDirection); - break; - case Vehicle.LINEAR_MOTOR_OFFSET: - m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - case Vehicle.BLOCK_EXIT: - m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - } - }//end ProcessVectorVehicleParam - - internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) - { - VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); - switch (pParam) - { - case Vehicle.REFERENCE_FRAME: - m_referenceFrame = pValue; - break; - case Vehicle.ROLL_FRAME: - m_RollreferenceFrame = pValue; - break; - } - }//end ProcessRotationVehicleParam - - internal void ProcessVehicleFlags(int pParam, bool remove) - { - VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); - VehicleFlag parm = (VehicleFlag)pParam; - if (pParam == -1) - m_flags = (VehicleFlag)0; - else - { - if (remove) - m_flags &= ~parm; - else - m_flags |= parm; - } - } - - internal void ProcessTypeChange(Vehicle pType) - { - VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); - // Set Defaults For Type - Type = pType; - switch (pType) - { - case Vehicle.TYPE_NONE: - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 0; - m_linearMotorDecayTimescale = 0; - m_linearFrictionTimescale = new Vector3(0, 0, 0); - - m_angularMotorDirection = Vector3.Zero; - m_angularMotorDecayTimescale = 0; - m_angularMotorTimescale = 0; - m_angularFrictionTimescale = new Vector3(0, 0, 0); - - m_VhoverHeight = 0; - m_VhoverEfficiency = 0; - m_VhoverTimescale = 0; - m_VehicleBuoyancy = 0; - - m_linearDeflectionEfficiency = 1; - m_linearDeflectionTimescale = 1; - - m_angularDeflectionEfficiency = 0; - m_angularDeflectionTimescale = 1000; - - m_verticalAttractionEfficiency = 0; - m_verticalAttractionTimescale = 0; - - m_bankingEfficiency = 0; - m_bankingTimescale = 1000; - m_bankingMix = 1; - - m_referenceFrame = Quaternion.Identity; - m_flags = (VehicleFlag)0; - - break; - - case Vehicle.TYPE_SLED: - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 1000; - m_linearMotorDecayTimescale = 120; - m_linearFrictionTimescale = new Vector3(30, 1, 1000); - - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 1000; - m_angularMotorDecayTimescale = 120; - m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); - - m_VhoverHeight = 0; - m_VhoverEfficiency = 10; // TODO: this looks wrong!! - m_VhoverTimescale = 10; - m_VehicleBuoyancy = 0; - - m_linearDeflectionEfficiency = 1; - m_linearDeflectionTimescale = 1; - - m_angularDeflectionEfficiency = 1; - m_angularDeflectionTimescale = 1000; - - m_verticalAttractionEfficiency = 0; - m_verticalAttractionTimescale = 0; - - m_bankingEfficiency = 0; - m_bankingTimescale = 10; - m_bankingMix = 1; - - m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY - | VehicleFlag.HOVER_TERRAIN_ONLY - | VehicleFlag.HOVER_GLOBAL_HEIGHT - | VehicleFlag.HOVER_UP_ONLY); - m_flags |= (VehicleFlag.NO_DEFLECTION_UP - | VehicleFlag.LIMIT_ROLL_ONLY - | VehicleFlag.LIMIT_MOTOR_UP); - - break; - case Vehicle.TYPE_CAR: - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 1; - m_linearMotorDecayTimescale = 60; - m_linearFrictionTimescale = new Vector3(100, 2, 1000); - - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 1; - m_angularMotorDecayTimescale = 0.8f; - m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); - - m_VhoverHeight = 0; - m_VhoverEfficiency = 0; - m_VhoverTimescale = 1000; - m_VehicleBuoyancy = 0; - - m_linearDeflectionEfficiency = 1; - m_linearDeflectionTimescale = 2; - - m_angularDeflectionEfficiency = 0; - m_angularDeflectionTimescale = 10; - - m_verticalAttractionEfficiency = 1f; - m_verticalAttractionTimescale = 10f; - - m_bankingEfficiency = -0.2f; - m_bankingMix = 1; - m_bankingTimescale = 1; - - m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY - | VehicleFlag.HOVER_TERRAIN_ONLY - | VehicleFlag.HOVER_GLOBAL_HEIGHT); - m_flags |= (VehicleFlag.NO_DEFLECTION_UP - | VehicleFlag.LIMIT_ROLL_ONLY - | VehicleFlag.LIMIT_MOTOR_UP - | VehicleFlag.HOVER_UP_ONLY); - break; - case Vehicle.TYPE_BOAT: - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 5; - m_linearMotorDecayTimescale = 60; - m_linearFrictionTimescale = new Vector3(10, 3, 2); - - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 4; - m_angularMotorDecayTimescale = 4; - m_angularFrictionTimescale = new Vector3(10,10,10); - - m_VhoverHeight = 0; - m_VhoverEfficiency = 0.5f; - m_VhoverTimescale = 2; - m_VehicleBuoyancy = 1; - - m_linearDeflectionEfficiency = 0.5f; - m_linearDeflectionTimescale = 3; - - m_angularDeflectionEfficiency = 0.5f; - m_angularDeflectionTimescale = 5; - - m_verticalAttractionEfficiency = 0.5f; - m_verticalAttractionTimescale = 5f; - - m_bankingEfficiency = -0.3f; - m_bankingMix = 0.8f; - m_bankingTimescale = 1; - - m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY - | VehicleFlag.HOVER_GLOBAL_HEIGHT - | VehicleFlag.LIMIT_ROLL_ONLY - | VehicleFlag.HOVER_UP_ONLY); - m_flags |= (VehicleFlag.NO_DEFLECTION_UP - | VehicleFlag.LIMIT_MOTOR_UP - | VehicleFlag.HOVER_WATER_ONLY); - break; - case Vehicle.TYPE_AIRPLANE: - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 2; - m_linearMotorDecayTimescale = 60; - m_linearFrictionTimescale = new Vector3(200, 10, 5); - - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 4; - m_angularMotorDecayTimescale = 4; - m_angularFrictionTimescale = new Vector3(20, 20, 20); - - m_VhoverHeight = 0; - m_VhoverEfficiency = 0.5f; - m_VhoverTimescale = 1000; - m_VehicleBuoyancy = 0; - - m_linearDeflectionEfficiency = 0.5f; - m_linearDeflectionTimescale = 3; - - m_angularDeflectionEfficiency = 1; - m_angularDeflectionTimescale = 2; - - m_verticalAttractionEfficiency = 0.9f; - m_verticalAttractionTimescale = 2f; - - m_bankingEfficiency = 1; - m_bankingMix = 0.7f; - m_bankingTimescale = 2; - - m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY - | VehicleFlag.HOVER_TERRAIN_ONLY - | VehicleFlag.HOVER_GLOBAL_HEIGHT - | VehicleFlag.HOVER_UP_ONLY - | VehicleFlag.NO_DEFLECTION_UP - | VehicleFlag.LIMIT_MOTOR_UP); - m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); - break; - case Vehicle.TYPE_BALLOON: - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 5; - m_linearFrictionTimescale = new Vector3(5, 5, 5); - m_linearMotorDecayTimescale = 60; - - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 6; - m_angularFrictionTimescale = new Vector3(10, 10, 10); - m_angularMotorDecayTimescale = 10; - - m_VhoverHeight = 5; - m_VhoverEfficiency = 0.8f; - m_VhoverTimescale = 10; - m_VehicleBuoyancy = 1; - - m_linearDeflectionEfficiency = 0; - m_linearDeflectionTimescale = 5; - - m_angularDeflectionEfficiency = 0; - m_angularDeflectionTimescale = 5; - - m_verticalAttractionEfficiency = 1f; - m_verticalAttractionTimescale = 100f; - - m_bankingEfficiency = 0; - m_bankingMix = 0.7f; - m_bankingTimescale = 5; - - m_referenceFrame = Quaternion.Identity; - - m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY - | VehicleFlag.HOVER_TERRAIN_ONLY - | VehicleFlag.HOVER_UP_ONLY - | VehicleFlag.NO_DEFLECTION_UP - | VehicleFlag.LIMIT_MOTOR_UP); - m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY - | VehicleFlag.HOVER_GLOBAL_HEIGHT); - break; - } - - // Update any physical parameters based on this type. - Refresh(); - - m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, - m_linearMotorDecayTimescale, m_linearFrictionTimescale, - 1f); - m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) - - m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, - m_angularMotorDecayTimescale, m_angularFrictionTimescale, - 1f); - m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) - - m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, - BSMotor.Infinite, BSMotor.InfiniteVector, - m_verticalAttractionEfficiency); - // Z goes away and we keep X and Y - m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f); - m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) - } - - // Some of the properties of this prim may have changed. - // Do any updating needed for a vehicle - public void Refresh() - { - if (IsActive) - { - // Remember the mass so we don't have to fetch it every step - m_vehicleMass = Prim.Linkset.LinksetMass; - - // Friction affects are handled by this vehicle code - float friction = 0f; - PhysicsScene.PE.SetFriction(Prim.PhysBody, friction); - - // Moderate angular movement introduced by Bullet. - // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. - // Maybe compute linear and angular factor and damping from params. - float angularDamping = BSParam.VehicleAngularDamping; - PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, angularDamping); - - // Vehicles report collision events so we know when it's on the ground - PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); - - Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass); - PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, localInertia); - PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody); - - Vector3 grav = PhysicsScene.DefaultGravity * (1f - Prim.Buoyancy); - PhysicsScene.PE.SetGravity(Prim.PhysBody, grav); - - VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}", - Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping); - } - else - { - PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); - } - } - - public bool RemoveBodyDependencies(BSPhysObject prim) - { - // If active, we need to add our properties back when the body is rebuilt. - return IsActive; - } - - public void RestoreBodyDependencies(BSPhysObject prim) - { - if (Prim.LocalID != prim.LocalID) - { - // The call should be on us by our prim. Error if not. - PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}", - LogHeader, prim.LocalID, Prim.LocalID); - return; - } - Refresh(); - } - - #region Known vehicle value functions - // Vehicle physical parameters that we buffer from constant getting and setting. - // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set. - // Changing is remembered and the parameter is stored back into the physics engine only if updated. - // This does two things: 1) saves continuious calls into unmanaged code, and - // 2) signals when a physics property update must happen back to the simulator - // to update values modified for the vehicle. - private int m_knownChanged; - private int m_knownHas; - private float m_knownTerrainHeight; - private float m_knownWaterLevel; - private Vector3 m_knownPosition; - private Vector3 m_knownVelocity; - private Vector3 m_knownForce; - private Quaternion m_knownOrientation; - private Vector3 m_knownRotationalVelocity; - private Vector3 m_knownRotationalForce; - private Vector3 m_knownForwardVelocity; // vehicle relative forward speed - - private const int m_knownChangedPosition = 1 << 0; - private const int m_knownChangedVelocity = 1 << 1; - private const int m_knownChangedForce = 1 << 2; - private const int m_knownChangedOrientation = 1 << 3; - private const int m_knownChangedRotationalVelocity = 1 << 4; - private const int m_knownChangedRotationalForce = 1 << 5; - private const int m_knownChangedTerrainHeight = 1 << 6; - private const int m_knownChangedWaterLevel = 1 << 7; - private const int m_knownChangedForwardVelocity = 1 << 8; - - private void ForgetKnownVehicleProperties() - { - m_knownHas = 0; - m_knownChanged = 0; - } - // Push all the changed values back into the physics engine - private void PushKnownChanged() - { - if (m_knownChanged != 0) - { - if ((m_knownChanged & m_knownChangedPosition) != 0) - Prim.ForcePosition = m_knownPosition; - - if ((m_knownChanged & m_knownChangedOrientation) != 0) - Prim.ForceOrientation = m_knownOrientation; - - if ((m_knownChanged & m_knownChangedVelocity) != 0) - { - Prim.ForceVelocity = m_knownVelocity; - PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, VehicleVelocity); - } - - if ((m_knownChanged & m_knownChangedForce) != 0) - Prim.AddForce((Vector3)m_knownForce, false, true); - - if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) - { - Prim.ForceRotationalVelocity = m_knownRotationalVelocity; - // Fake out Bullet by making it think the velocity is the same as last time. - PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); - } - - if ((m_knownChanged & m_knownChangedRotationalForce) != 0) - Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true); - - // If we set one of the values (ie, the physics engine didn't do it) we must force - // an UpdateProperties event to send the changes up to the simulator. - PhysicsScene.PE.PushUpdate(Prim.PhysBody); - } - m_knownChanged = 0; - } - - // Since the computation of terrain height can be a little involved, this routine - // is used to fetch the height only once for each vehicle simulation step. - private float GetTerrainHeight(Vector3 pos) - { - if ((m_knownHas & m_knownChangedTerrainHeight) == 0) - { - m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); - m_knownHas |= m_knownChangedTerrainHeight; - } - return m_knownTerrainHeight; - } - - // Since the computation of water level can be a little involved, this routine - // is used ot fetch the level only once for each vehicle simulation step. - private float GetWaterLevel(Vector3 pos) - { - if ((m_knownHas & m_knownChangedWaterLevel) == 0) - { - m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); - m_knownHas |= m_knownChangedWaterLevel; - } - return (float)m_knownWaterLevel; - } - - private Vector3 VehiclePosition - { - get - { - if ((m_knownHas & m_knownChangedPosition) == 0) - { - m_knownPosition = Prim.ForcePosition; - m_knownHas |= m_knownChangedPosition; - } - return m_knownPosition; - } - set - { - m_knownPosition = value; - m_knownChanged |= m_knownChangedPosition; - m_knownHas |= m_knownChangedPosition; - } - } - - private Quaternion VehicleOrientation - { - get - { - if ((m_knownHas & m_knownChangedOrientation) == 0) - { - m_knownOrientation = Prim.ForceOrientation; - m_knownHas |= m_knownChangedOrientation; - } - return m_knownOrientation; - } - set - { - m_knownOrientation = value; - m_knownChanged |= m_knownChangedOrientation; - m_knownHas |= m_knownChangedOrientation; - } - } - - private Vector3 VehicleVelocity - { - get - { - if ((m_knownHas & m_knownChangedVelocity) == 0) - { - m_knownVelocity = Prim.ForceVelocity; - m_knownHas |= m_knownChangedVelocity; - } - return (Vector3)m_knownVelocity; - } - set - { - m_knownVelocity = value; - m_knownChanged |= m_knownChangedVelocity; - m_knownHas |= m_knownChangedVelocity; - } - } - - private void VehicleAddForce(Vector3 aForce) - { - if ((m_knownHas & m_knownChangedForce) == 0) - { - m_knownForce = Vector3.Zero; - } - m_knownForce += aForce; - m_knownChanged |= m_knownChangedForce; - m_knownHas |= m_knownChangedForce; - } - - private Vector3 VehicleRotationalVelocity - { - get - { - if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) - { - m_knownRotationalVelocity = Prim.ForceRotationalVelocity; - m_knownHas |= m_knownChangedRotationalVelocity; - } - return (Vector3)m_knownRotationalVelocity; - } - set - { - m_knownRotationalVelocity = value; - m_knownChanged |= m_knownChangedRotationalVelocity; - m_knownHas |= m_knownChangedRotationalVelocity; - } - } - private void VehicleAddAngularForce(Vector3 aForce) - { - if ((m_knownHas & m_knownChangedRotationalForce) == 0) - { - m_knownRotationalForce = Vector3.Zero; - } - m_knownRotationalForce += aForce; - m_knownChanged |= m_knownChangedRotationalForce; - m_knownHas |= m_knownChangedRotationalForce; - } - // Vehicle relative forward velocity - private Vector3 VehicleForwardVelocity - { - get - { - if ((m_knownHas & m_knownChangedForwardVelocity) == 0) - { - m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); - m_knownHas |= m_knownChangedForwardVelocity; - } - return m_knownForwardVelocity; - } - } - private float VehicleForwardSpeed - { - get - { - return VehicleForwardVelocity.X; - } - } - - #endregion // Known vehicle value functions - - // One step of the vehicle properties for the next 'pTimestep' seconds. - internal void Step(float pTimestep) - { - if (!IsActive) return; - - if (PhysicsScene.VehiclePhysicalLoggingEnabled) - PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); - - ForgetKnownVehicleProperties(); - - MoveLinear(pTimestep); - MoveAngular(pTimestep); - - LimitRotation(pTimestep); - - // remember the position so next step we can limit absolute movement effects - m_lastPositionVector = VehiclePosition; - - // If we forced the changing of some vehicle parameters, update the values and - // for the physics engine to note the changes so an UpdateProperties event will happen. - PushKnownChanged(); - - if (PhysicsScene.VehiclePhysicalLoggingEnabled) - PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); - - VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", - Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity); - } - - // Apply the effect of the linear motor and other linear motions (like hover and float). - private void MoveLinear(float pTimestep) - { - Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); - - // The movement computed in the linear motor is relative to the vehicle - // coordinates. Rotate the movement to world coordinates. - linearMotorContribution *= VehicleOrientation; - - // ================================================================== - // Buoyancy: force to overcome gravity. - // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; - // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity. - Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy; - - Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep); - - Vector3 hoverContribution = ComputeLinearHover(pTimestep); - - ComputeLinearBlockingEndPoint(pTimestep); - - Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep); - - // ================================================================== - Vector3 newVelocity = linearMotorContribution - + terrainHeightContribution - + hoverContribution - + limitMotorUpContribution; - - Vector3 newForce = buoyancyContribution; - - // If not changing some axis, reduce out velocity - if ((m_flags & (VehicleFlag.NO_X)) != 0) - newVelocity.X = 0; - if ((m_flags & (VehicleFlag.NO_Y)) != 0) - newVelocity.Y = 0; - if ((m_flags & (VehicleFlag.NO_Z)) != 0) - newVelocity.Z = 0; - - // ================================================================== - // Clamp high or low velocities - float newVelocityLengthSq = newVelocity.LengthSquared(); - if (newVelocityLengthSq > 1000f) - { - newVelocity /= newVelocity.Length(); - newVelocity *= 1000f; - } - else if (newVelocityLengthSq < 0.001f) - newVelocity = Vector3.Zero; - - // ================================================================== - // Stuff new linear velocity into the vehicle. - // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us. - VehicleVelocity = newVelocity; - - // Other linear forces are applied as forces. - Vector3 totalDownForce = newForce * m_vehicleMass; - if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f)) - { - VehicleAddForce(totalDownForce); - } - - VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}", - Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding); - VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}", - Prim.LocalID, - linearMotorContribution, terrainHeightContribution, hoverContribution, - limitMotorUpContribution, buoyancyContribution - ); - - } // end MoveLinear() - - public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep) - { - Vector3 ret = Vector3.Zero; - // If below the terrain, move us above the ground a little. - // TODO: Consider taking the rotated size of the object or possibly casting a ray. - if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) - { - // TODO: correct position by applying force rather than forcing position. - Vector3 newPosition = VehiclePosition; - newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; - VehiclePosition = newPosition; - VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", - Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); - } - return ret; - } - - public Vector3 ComputeLinearHover(float pTimestep) - { - Vector3 ret = Vector3.Zero; - - // m_VhoverEfficiency: 0=bouncy, 1=totally damped - // m_VhoverTimescale: time to achieve height - if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) - { - // We should hover, get the target height - if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) - { - m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight; - } - if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) - { - m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight; - } - if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) - { - m_VhoverTargetHeight = m_VhoverHeight; - } - - if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) - { - // If body is already heigher, use its height as target height - if (VehiclePosition.Z > m_VhoverTargetHeight) - m_VhoverTargetHeight = VehiclePosition.Z; - } - - if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) - { - if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) - { - Vector3 pos = VehiclePosition; - pos.Z = m_VhoverTargetHeight; - VehiclePosition = pos; - } - } - else - { - // Error is positive if below the target and negative if above. - float verticalError = m_VhoverTargetHeight - VehiclePosition.Z; - float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; - - // TODO: implement m_VhoverEfficiency correctly - if (Math.Abs(verticalError) > m_VhoverEfficiency) - { - ret = new Vector3(0f, 0f, verticalCorrectionVelocity); - } - } - - VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}", - Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight); - } - - return ret; - } - - public bool ComputeLinearBlockingEndPoint(float pTimestep) - { - bool changed = false; - - Vector3 pos = VehiclePosition; - Vector3 posChange = pos - m_lastPositionVector; - if (m_BlockingEndPoint != Vector3.Zero) - { - if (pos.X >= (m_BlockingEndPoint.X - (float)1)) - { - pos.X -= posChange.X + 1; - changed = true; - } - if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) - { - pos.Y -= posChange.Y + 1; - changed = true; - } - if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) - { - pos.Z -= posChange.Z + 1; - changed = true; - } - if (pos.X <= 0) - { - pos.X += posChange.X + 1; - changed = true; - } - if (pos.Y <= 0) - { - pos.Y += posChange.Y + 1; - changed = true; - } - if (changed) - { - VehiclePosition = pos; - VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", - Prim.LocalID, m_BlockingEndPoint, posChange, pos); - } - } - return changed; - } - - // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : - // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when - // used with conjunction with banking: the strength of the banking will decay when the - // vehicle no longer experiences collisions. The decay timescale is the same as - // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering - // when they are in mid jump. - // TODO: this code is wrong. Also, what should it do for boats (height from water)? - // This is just using the ground and a general collision check. Should really be using - // a downward raycast to find what is below. - public Vector3 ComputeLinearMotorUp(float pTimestep) - { - Vector3 ret = Vector3.Zero; - float distanceAboveGround = 0f; - - if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) - { - float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); - distanceAboveGround = VehiclePosition.Z - targetHeight; - // Not colliding if the vehicle is off the ground - if (!Prim.IsColliding) - { - // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); - ret = new Vector3(0, 0, -distanceAboveGround); - } - // TODO: this calculation is wrong. From the description at - // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce - // has a decay factor. This says this force should - // be computed with a motor. - // TODO: add interaction with banking. - } - VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", - Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); - return ret; - } - - // ======================================================================= - // ======================================================================= - // Apply the effect of the angular motor. - // The 'contribution' is how much angular correction velocity each function wants. - // All the contributions are added together and the resulting velocity is - // set directly on the vehicle. - private void MoveAngular(float pTimestep) - { - // The user wants this many radians per second angular change? - Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); - - // ================================================================== - // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : - // This flag prevents linear deflection parallel to world z-axis. This is useful - // for preventing ground vehicles with large linear deflection, like bumper cars, - // from climbing their linear deflection into the sky. - // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement - if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) - { - angularMotorContribution.X = 0f; - angularMotorContribution.Y = 0f; - VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution); - } - - Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(); - - Vector3 deflectionContribution = ComputeAngularDeflection(); - - Vector3 bankingContribution = ComputeAngularBanking(); - - // ================================================================== - m_lastVertAttractor = verticalAttractionContribution; - - m_lastAngularVelocity = angularMotorContribution - + verticalAttractionContribution - + deflectionContribution - + bankingContribution; - - // ================================================================== - // Apply the correction velocity. - // TODO: Should this be applied as an angular force (torque)? - if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) - { - VehicleRotationalVelocity = m_lastAngularVelocity; - - VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}", - Prim.LocalID, - angularMotorContribution, verticalAttractionContribution, - bankingContribution, deflectionContribution, - m_lastAngularVelocity - ); - } - else - { - // The vehicle is not adding anything angular wise. - VehicleRotationalVelocity = Vector3.Zero; - VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); - } - - // ================================================================== - //Offset section - if (m_linearMotorOffset != Vector3.Zero) - { - //Offset of linear velocity doesn't change the linear velocity, - // but causes a torque to be applied, for example... - // - // IIIII >>> IIIII - // IIIII >>> IIIII - // IIIII >>> IIIII - // ^ - // | Applying a force at the arrow will cause the object to move forward, but also rotate - // - // - // The torque created is the linear velocity crossed with the offset - - // TODO: this computation should be in the linear section - // because that is where we know the impulse being applied. - Vector3 torqueFromOffset = Vector3.Zero; - // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); - if (float.IsNaN(torqueFromOffset.X)) - torqueFromOffset.X = 0; - if (float.IsNaN(torqueFromOffset.Y)) - torqueFromOffset.Y = 0; - if (float.IsNaN(torqueFromOffset.Z)) - torqueFromOffset.Z = 0; - - VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); - VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); - } - - } - // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: - // Some vehicles, like boats, should always keep their up-side up. This can be done by - // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to - // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the - // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency, - // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An - // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an - // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. - public Vector3 ComputeAngularVerticalAttraction() - { - Vector3 ret = Vector3.Zero; - - // If vertical attaction timescale is reasonable - if (m_verticalAttractionTimescale < m_verticalAttractionCutoff) - { - // Take a vector pointing up and convert it from world to vehicle relative coords. - Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; - - // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) - // is now: - // leaning to one side: rotated around the X axis with the Y value going - // from zero (nearly straight up) to one (completely to the side)) or - // leaning front-to-back: rotated around the Y axis with the value of X being between - // zero and one. - // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. - - // Y error means needed rotation around X axis and visa versa. - // Since the error goes from zero to one, the asin is the corresponding angle. - ret.X = (float)Math.Asin(verticalError.Y); - // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) - ret.Y = -(float)Math.Asin(verticalError.X); - - // If verticalError.Z is negative, the vehicle is upside down. Add additional push. - if (verticalError.Z < 0f) - { - ret.X += PIOverFour; - ret.Y += PIOverFour; - } - - // 'ret' is now the necessary velocity to correct tilt in one second. - // Correction happens over a number of seconds. - Vector3 unscaledContrib = ret; - ret /= m_verticalAttractionTimescale; - - VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}", - Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret); - } - return ret; - } - - // Return the angular correction to correct the direction the vehicle is pointing to be - // the direction is should want to be pointing. - // The vehicle is moving in some direction and correct its orientation to it is pointing - // in that direction. - // TODO: implement reference frame. - public Vector3 ComputeAngularDeflection() - { - Vector3 ret = Vector3.Zero; - return ret; // DEBUG DEBUG DEBUG - // Disable angular deflection for the moment. - // Since angularMotorUp and angularDeflection are computed independently, they will calculate - // approximately the same X or Y correction. When added together (when contributions are combined) - // this creates an over-correction and then wabbling as the target is overshot. - // TODO: rethink how the different correction computations inter-relate. - - if (m_angularDeflectionEfficiency != 0) - { - // The direction the vehicle is moving - Vector3 movingDirection = VehicleVelocity; - movingDirection.Normalize(); - - // The direction the vehicle is pointing - Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; - pointingDirection.Normalize(); - - // The difference between what is and what should be. - Vector3 deflectionError = movingDirection - pointingDirection; - - // Don't try to correct very large errors (not our job) - if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f; - if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f; - if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f; - - // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); - - // Scale the correction by recovery timescale and efficiency - ret = (-deflectionError) * m_angularDeflectionEfficiency; - ret /= m_angularDeflectionTimescale; - - VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", - Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); - VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", - Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); - } - return ret; - } - - // Return an angular change to rotate the vehicle around the Z axis when the vehicle - // is tipped around the X axis. - // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: - // The vertical attractor feature must be enabled in order for the banking behavior to - // function. The way banking works is this: a rotation around the vehicle's roll-axis will - // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude - // of the yaw effect will be proportional to the - // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's - // velocity along its preferred axis of motion. - // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any - // positive rotation (by the right-hand rule) about the roll-axis will effect a - // (negative) torque around the yaw-axis, making it turn to the right--that is the - // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. - // Negating the banking coefficient will make it so that the vehicle leans to the - // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). - // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making - // banking vehicles do what you want rather than what the laws of physics allow. - // For example, consider a real motorcycle...it must be moving forward in order for - // it to turn while banking, however video-game motorcycles are often configured - // to turn in place when at a dead stop--because they are often easier to control - // that way using the limited interface of the keyboard or game controller. The - // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic - // banking by functioning as a slider between a banking that is correspondingly - // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the - // banking effect depends only on the vehicle's rotation about its roll-axis compared - // to "dynamic" where the banking is also proportional to its velocity along its - // roll-axis. Finding the best value of the "mixture" will probably require trial and error. - // The time it takes for the banking behavior to defeat a preexisting angular velocity about the - // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to - // bank quickly then give it a banking timescale of about a second or less, otherwise you can - // make a sluggish vehicle by giving it a timescale of several seconds. - public Vector3 ComputeAngularBanking() - { - Vector3 ret = Vector3.Zero; - - if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) - { - // This works by rotating a unit vector to the orientation of the vehicle. The - // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt - // up to one for full over). - Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation; - - // Figure out the yaw value for this much roll. - float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency; - // Keep the sign - if (rollComponents.Y < 0f) - turnComponent = -turnComponent; - - // TODO: there must be a better computation of the banking force. - float bankingTurnForce = turnComponent; - - // actual error = static turn error + dynamic turn error - float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed; - // TODO: the banking effect should not go to infinity but what to limit it to? - mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f); - - // Build the force vector to change rotation from what it is to what it should be - ret.Z = -mixedBankingError; - - // Don't do it all at once. - ret /= m_bankingTimescale; - - VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}", - Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret); - } - return ret; - } - - // This is from previous instantiations of XXXDynamics.cs. - // Applies roll reference frame. - // TODO: is this the right way to separate the code to do this operation? - // Should this be in MoveAngular()? - internal void LimitRotation(float timestep) - { - Quaternion rotq = VehicleOrientation; - Quaternion m_rot = rotq; - if (m_RollreferenceFrame != Quaternion.Identity) - { - if (rotq.X >= m_RollreferenceFrame.X) - { - m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); - } - if (rotq.Y >= m_RollreferenceFrame.Y) - { - m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); - } - if (rotq.X <= -m_RollreferenceFrame.X) - { - m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); - } - if (rotq.Y <= -m_RollreferenceFrame.Y) - { - m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); - } - } - if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) - { - m_rot.X = 0; - m_rot.Y = 0; - } - if (rotq != m_rot) - { - VehicleOrientation = m_rot; - VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); - } - - } - - private float ClampInRange(float low, float val, float high) - { - return Math.Max(low, Math.Min(val, high)); - // return Utils.Clamp(val, low, high); - } - - // Invoke the detailed logger and output something if it's enabled. - private void VDetailLog(string msg, params Object[] args) - { - if (Prim.PhysicsScene.VehicleLoggingEnabled) - Prim.PhysicsScene.DetailLog(msg, args); - } - } -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs deleted file mode 100755 index 756faed..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OMV = OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ - -// A BSPrim can get individual information about its linkedness attached -// to it through an instance of a subclass of LinksetInfo. -// Each type of linkset will define the information needed for its type. -public abstract class BSLinksetInfo -{ - public virtual void Clear() { } -} - -public abstract class BSLinkset -{ - // private static string LogHeader = "[BULLETSIM LINKSET]"; - - public enum LinksetImplementation - { - Constraint = 0, // linkset tied together with constraints - Compound = 1, // linkset tied together as a compound object - Manual = 2 // linkset tied together manually (code moves all the pieces) - } - // Create the correct type of linkset for this child - public static BSLinkset Factory(BSScene physScene, BSPhysObject parent) - { - BSLinkset ret = null; - - switch ((int)BSParam.LinksetImplementation) - { - case (int)LinksetImplementation.Constraint: - ret = new BSLinksetConstraints(physScene, parent); - break; - case (int)LinksetImplementation.Compound: - ret = new BSLinksetCompound(physScene, parent); - break; - case (int)LinksetImplementation.Manual: - // ret = new BSLinksetManual(physScene, parent); - break; - default: - ret = new BSLinksetCompound(physScene, parent); - break; - } - return ret; - } - - public BSPhysObject LinksetRoot { get; protected set; } - - public BSScene PhysicsScene { get; private set; } - - static int m_nextLinksetID = 1; - public int LinksetID { get; private set; } - - // The children under the root in this linkset. - protected HashSet m_children; - - // We lock the diddling of linkset classes to prevent any badness. - // This locks the modification of the instances of this class. Changes - // to the physical representation is done via the tainting mechenism. - protected object m_linksetActivityLock = new Object(); - - // Some linksets have a preferred physical shape. - // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. - public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) - { - return BSPhysicsShapeType.SHAPE_UNKNOWN; - } - - // We keep the prim's mass in the linkset structure since it could be dependent on other prims - public float LinksetMass { get; protected set; } - - public virtual bool LinksetIsColliding { get { return false; } } - - public OMV.Vector3 CenterOfMass - { - get { return ComputeLinksetCenterOfMass(); } - } - - public OMV.Vector3 GeometricCenter - { - get { return ComputeLinksetGeometricCenter(); } - } - - protected BSLinkset(BSScene scene, BSPhysObject parent) - { - // A simple linkset of one (no children) - LinksetID = m_nextLinksetID++; - // We create LOTS of linksets. - if (m_nextLinksetID <= 0) - m_nextLinksetID = 1; - PhysicsScene = scene; - LinksetRoot = parent; - m_children = new HashSet(); - LinksetMass = parent.RawMass; - Rebuilding = false; - } - - // Link to a linkset where the child knows the parent. - // Parent changing should not happen so do some sanity checking. - // We return the parent's linkset so the child can track its membership. - // Called at runtime. - public BSLinkset AddMeToLinkset(BSPhysObject child) - { - lock (m_linksetActivityLock) - { - // Don't add the root to its own linkset - if (!IsRoot(child)) - AddChildToLinkset(child); - LinksetMass = ComputeLinksetMass(); - } - return this; - } - - // Remove a child from a linkset. - // Returns a new linkset for the child which is a linkset of one (just the - // orphened child). - // Called at runtime. - public BSLinkset RemoveMeFromLinkset(BSPhysObject child) - { - lock (m_linksetActivityLock) - { - if (IsRoot(child)) - { - // Cannot remove the root from a linkset. - return this; - } - RemoveChildFromLinkset(child); - LinksetMass = ComputeLinksetMass(); - } - - // The child is down to a linkset of just itself - return BSLinkset.Factory(PhysicsScene, child); - } - - // Return 'true' if the passed object is the root object of this linkset - public bool IsRoot(BSPhysObject requestor) - { - return (requestor.LocalID == LinksetRoot.LocalID); - } - - public int NumberOfChildren { get { return m_children.Count; } } - - // Return 'true' if this linkset has any children (more than the root member) - public bool HasAnyChildren { get { return (m_children.Count > 0); } } - - // Return 'true' if this child is in this linkset - public bool HasChild(BSPhysObject child) - { - bool ret = false; - lock (m_linksetActivityLock) - { - ret = m_children.Contains(child); - /* Safer version but the above should work - foreach (BSPhysObject bp in m_children) - { - if (child.LocalID == bp.LocalID) - { - ret = true; - break; - } - } - */ - } - return ret; - } - - // Perform an action on each member of the linkset including root prim. - // Depends on the action on whether this should be done at taint time. - public delegate bool ForEachMemberAction(BSPhysObject obj); - public virtual bool ForEachMember(ForEachMemberAction action) - { - bool ret = false; - lock (m_linksetActivityLock) - { - action(LinksetRoot); - foreach (BSPhysObject po in m_children) - { - if (action(po)) - break; - } - } - return ret; - } - - // I am the root of a linkset and a new child is being added - // Called while LinkActivity is locked. - protected abstract void AddChildToLinkset(BSPhysObject child); - - // I am the root of a linkset and one of my children is being removed. - // Safe to call even if the child is not really in my linkset. - protected abstract void RemoveChildFromLinkset(BSPhysObject child); - - // When physical properties are changed the linkset needs to recalculate - // its internal properties. - // May be called at runtime or taint-time. - public virtual void Refresh(BSPhysObject requestor) - { - LinksetMass = ComputeLinksetMass(); - } - - // Flag denoting the linkset is in the process of being rebuilt. - // Used to know not the schedule a rebuild in the middle of a rebuild. - protected bool Rebuilding { get; set; } - - // The object is going dynamic (physical). Do any setup necessary - // for a dynamic linkset. - // Only the state of the passed object can be modified. The rest of the linkset - // has not yet been fully constructed. - // Return 'true' if any properties updated on the passed object. - // Called at taint-time! - public abstract bool MakeDynamic(BSPhysObject child); - - // The object is going static (non-physical). Do any setup necessary - // for a static linkset. - // Return 'true' if any properties updated on the passed object. - // Called at taint-time! - public abstract bool MakeStatic(BSPhysObject child); - - // Called when a parameter update comes from the physics engine for any object - // of the linkset is received. - // Passed flag is update came from physics engine (true) or the user (false). - // Called at taint-time!! - public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate); - - // Routine used when rebuilding the body of the root of the linkset - // Destroy all the constraints have have been made to root. - // This is called when the root body is changing. - // Returns 'true' of something was actually removed and would need restoring - // Called at taint-time!! - public abstract bool RemoveBodyDependencies(BSPrim child); - - // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', - // this routine will restore the removed constraints. - // Called at taint-time!! - public abstract void RestoreBodyDependencies(BSPrim child); - - // ================================================================ - protected virtual float ComputeLinksetMass() - { - float mass = LinksetRoot.RawMass; - if (HasAnyChildren) - { - lock (m_linksetActivityLock) - { - foreach (BSPhysObject bp in m_children) - { - mass += bp.RawMass; - } - } - } - return mass; - } - - protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() - { - OMV.Vector3 com; - lock (m_linksetActivityLock) - { - com = LinksetRoot.Position * LinksetRoot.RawMass; - float totalMass = LinksetRoot.RawMass; - - foreach (BSPhysObject bp in m_children) - { - com += bp.Position * bp.RawMass; - totalMass += bp.RawMass; - } - if (totalMass != 0f) - com /= totalMass; - } - - return com; - } - - protected virtual OMV.Vector3 ComputeLinksetGeometricCenter() - { - OMV.Vector3 com; - lock (m_linksetActivityLock) - { - com = LinksetRoot.Position; - - foreach (BSPhysObject bp in m_children) - { - com += bp.Position * bp.RawMass; - } - com /= (m_children.Count + 1); - } - - return com; - } - - // Invoke the detailed logger and output something if it's enabled. - protected void DetailLog(string msg, params Object[] args) - { - if (PhysicsScene.PhysicsLogging.Enabled) - PhysicsScene.DetailLog(msg, args); - } - -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs deleted file mode 100755 index bd03d31..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OpenSim.Framework; - -using OMV = OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ - -// When a child is linked, the relationship position of the child to the parent -// is remembered so the child's world position can be recomputed when it is -// removed from the linkset. -sealed class BSLinksetCompoundInfo : BSLinksetInfo -{ - public OMV.Vector3 OffsetPos; - public OMV.Quaternion OffsetRot; - public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r) - { - OffsetPos = p; - OffsetRot = r; - } - public override void Clear() - { - OffsetPos = OMV.Vector3.Zero; - OffsetRot = OMV.Quaternion.Identity; - } - public override string ToString() - { - StringBuilder buff = new StringBuilder(); - buff.Append(""); - return buff.ToString(); - } -}; - -public sealed class BSLinksetCompound : BSLinkset -{ - private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; - - public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent) - { - } - - // For compound implimented linksets, if there are children, use compound shape for the root. - public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) - { - // Returning 'unknown' means we don't have a preference. - BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - if (IsRoot(requestor) && HasAnyChildren) - { - ret = BSPhysicsShapeType.SHAPE_COMPOUND; - } - // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); - return ret; - } - - // When physical properties are changed the linkset needs to recalculate - // its internal properties. - public override void Refresh(BSPhysObject requestor) - { - base.Refresh(requestor); - - // Something changed so do the rebuilding thing - // ScheduleRebuild(); - } - - // Schedule a refresh to happen after all the other taint processing. - private void ScheduleRebuild(BSPhysObject requestor) - { - DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2}", - requestor.LocalID, Rebuilding, HasAnyChildren); - // When rebuilding, it is possible to set properties that would normally require a rebuild. - // If already rebuilding, don't request another rebuild. - // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. - if (!Rebuilding && HasAnyChildren) - { - PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() - { - if (HasAnyChildren) - RecomputeLinksetCompound(); - }); - } - } - - // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset. - // Only the state of the passed object can be modified. The rest of the linkset - // has not yet been fully constructed. - // Return 'true' if any properties updated on the passed object. - // Called at taint-time! - public override bool MakeDynamic(BSPhysObject child) - { - bool ret = false; - DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); - if (IsRoot(child)) - { - // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. - ScheduleRebuild(LinksetRoot); - } - else - { - // The origional prims are removed from the world as the shape of the root compound - // shape takes over. - PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); - PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION); - // We don't want collisions from the old linkset children. - PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - - child.PhysBody.collisionType = CollisionType.LinksetChild; - - ret = true; - } - return ret; - } - - // The object is going static (non-physical). Do any setup necessary for a static linkset. - // Return 'true' if any properties updated on the passed object. - // This doesn't normally happen -- OpenSim removes the objects from the physical - // world if it is a static linkset. - // Called at taint-time! - public override bool MakeStatic(BSPhysObject child) - { - bool ret = false; - DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); - if (IsRoot(child)) - { - ScheduleRebuild(LinksetRoot); - } - else - { - // The non-physical children can come back to life. - PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); - - child.PhysBody.collisionType = CollisionType.LinksetChild; - - // Don't force activation so setting of DISABLE_SIMULATION can stay if used. - PhysicsScene.PE.Activate(child.PhysBody, false); - ret = true; - } - return ret; - } - - public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate) - { - // The user moving a child around requires the rebuilding of the linkset compound shape - // One problem is this happens when a border is crossed -- the simulator implementation - // is to store the position into the group which causes the move of the object - // but it also means all the child positions get updated. - // What would cause an unnecessary rebuild so we make sure the linkset is in a - // region before bothering to do a rebuild. - if (!IsRoot(updated) - && !physicalUpdate - && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) - { - updated.LinksetInfo = null; - ScheduleRebuild(updated); - } - } - - // Routine called when rebuilding the body of some member of the linkset. - // Since we don't keep in world relationships, do nothing unless it's a child changing. - // Returns 'true' of something was actually removed and would need restoring - // Called at taint-time!! - public override bool RemoveBodyDependencies(BSPrim child) - { - bool ret = false; - - DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", - child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, IsRoot(child)); - - if (!IsRoot(child)) - { - // Because it is a convenient time, recompute child world position and rotation based on - // its position in the linkset. - RecomputeChildWorldPosition(child, true); - } - - // Cannot schedule a refresh/rebuild here because this routine is called when - // the linkset is being rebuilt. - // InternalRefresh(LinksetRoot); - - return ret; - } - - // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', - // this routine will restore the removed constraints. - // Called at taint-time!! - public override void RestoreBodyDependencies(BSPrim child) - { - } - - // When the linkset is built, the child shape is added to the compound shape relative to the - // root shape. The linkset then moves around but this does not move the actual child - // prim. The child prim's location must be recomputed based on the location of the root shape. - private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime) - { - BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; - if (lci != null) - { - if (inTaintTime) - { - OMV.Vector3 oldPos = child.RawPosition; - child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos; - child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; - DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", - child.LocalID, oldPos, lci, child.RawPosition); - } - else - { - // TaintedObject is not used here so the raw position is set now and not at taint-time. - child.Position = LinksetRoot.RawPosition + lci.OffsetPos; - child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; - } - } - else - { - // This happens when children have been added to the linkset but the linkset - // has not been constructed yet. So like, at taint time, adding children to a linkset - // and then changing properties of the children (makePhysical, for instance) - // but the post-print action of actually rebuilding the linkset has not yet happened. - // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", - // LogHeader, child.LocalID); - DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); - } - } - - // ================================================================ - - // Add a new child to the linkset. - // Called while LinkActivity is locked. - protected override void AddChildToLinkset(BSPhysObject child) - { - if (!HasChild(child)) - { - m_children.Add(child); - - DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); - - // Rebuild the compound shape with the new child shape included - ScheduleRebuild(child); - } - return; - } - - // Remove the specified child from the linkset. - // Safe to call even if the child is not really in the linkset. - protected override void RemoveChildFromLinkset(BSPhysObject child) - { - if (m_children.Remove(child)) - { - DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", - child.LocalID, - LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, - child.LocalID, child.PhysBody.AddrString); - - // Cause the child's body to be rebuilt and thus restored to normal operation - RecomputeChildWorldPosition(child, false); - child.ForceBodyShapeRebuild(false); - - if (!HasAnyChildren) - { - // The linkset is now empty. The root needs rebuilding. - LinksetRoot.ForceBodyShapeRebuild(false); - } - else - { - // Rebuild the compound shape with the child removed - ScheduleRebuild(child); - } - } - return; - } - - // Called before the simulation step to make sure the compound based linkset - // is all initialized. - // Constraint linksets are rebuilt every time. - // Note that this works for rebuilding just the root after a linkset is taken apart. - // Called at taint time!! - private void RecomputeLinksetCompound() - { - try - { - // Suppress rebuilding while rebuilding - Rebuilding = true; - - // Cause the root shape to be rebuilt as a compound object with just the root in it - LinksetRoot.ForceBodyShapeRebuild(true); - - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", - LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); - - // Add a shape for each of the other children in the linkset - ForEachMember(delegate(BSPhysObject cPrim) - { - if (!IsRoot(cPrim)) - { - // Compute the displacement of the child from the root of the linkset. - // This info is saved in the child prim so the relationship does not - // change over time and the new child position can be computed - // when the linkset is being disassembled (the linkset may have moved). - BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; - if (lci == null) - { - // Each child position and rotation is given relative to the root. - OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); - OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; - OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; - - // Save relative position for recomputing child's world position after moving linkset. - lci = new BSLinksetCompoundInfo(displacementPos, displacementRot); - cPrim.LinksetInfo = lci; - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci); - } - - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", - LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); - - if (cPrim.PhysShape.isNativeShape) - { - // A native shape is turning into a hull collision shape because native - // shapes are not shared so we have to hullify it so it will be tracked - // and freed at the correct time. This also solves the scaling problem - // (native shapes scaled but hull/meshes are assumed to not be). - // TODO: decide of the native shape can just be used in the compound shape. - // Use call to CreateGeomNonSpecial(). - BulletShape saveShape = cPrim.PhysShape; - cPrim.PhysShape.Clear(); // Don't let the create free the child's shape - // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null); - PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); - BulletShape newShape = cPrim.PhysShape; - cPrim.PhysShape = saveShape; - PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetPos, lci.OffsetRot); - } - else - { - // For the shared shapes (meshes and hulls), just use the shape in the child. - // The reference count added here will be decremented when the compound shape - // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). - if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) - { - PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", - LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); - } - PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); - } - } - return false; // 'false' says to move onto the next child in the list - }); - - // With all of the linkset packed into the root prim, it has the mass of everyone. - LinksetMass = ComputeLinksetMass(); - LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); - } - finally - { - Rebuilding = false; - } - - PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); - } -} -} \ No newline at end of file diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs deleted file mode 100755 index d0b2a56..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OMV = OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -public sealed class BSLinksetConstraints : BSLinkset -{ - // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; - - public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent) - { - } - - // When physical properties are changed the linkset needs to recalculate - // its internal properties. - // This is queued in the 'post taint' queue so the - // refresh will happen once after all the other taints are applied. - public override void Refresh(BSPhysObject requestor) - { - base.Refresh(requestor); - - if (HasAnyChildren && IsRoot(requestor)) - { - // Queue to happen after all the other taint processing - PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() - { - if (HasAnyChildren && IsRoot(requestor)) - RecomputeLinksetConstraints(); - }); - } - } - - // The object is going dynamic (physical). Do any setup necessary - // for a dynamic linkset. - // Only the state of the passed object can be modified. The rest of the linkset - // has not yet been fully constructed. - // Return 'true' if any properties updated on the passed object. - // Called at taint-time! - public override bool MakeDynamic(BSPhysObject child) - { - // What is done for each object in BSPrim is what we want. - return false; - } - - // The object is going static (non-physical). Do any setup necessary for a static linkset. - // Return 'true' if any properties updated on the passed object. - // This doesn't normally happen -- OpenSim removes the objects from the physical - // world if it is a static linkset. - // Called at taint-time! - public override bool MakeStatic(BSPhysObject child) - { - // What is done for each object in BSPrim is what we want. - return false; - } - - // Called at taint-time!! - public override void UpdateProperties(BSPhysObject updated, bool inTaintTime) - { - // Nothing to do for constraints on property updates - } - - // Routine called when rebuilding the body of some member of the linkset. - // Destroy all the constraints have have been made to root and set - // up to rebuild the constraints before the next simulation step. - // Returns 'true' of something was actually removed and would need restoring - // Called at taint-time!! - public override bool RemoveBodyDependencies(BSPrim child) - { - bool ret = false; - - DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", - child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); - - lock (m_linksetActivityLock) - { - // Just undo all the constraints for this linkset. Rebuild at the end of the step. - ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); - // Cause the constraints, et al to be rebuilt before the next simulation step. - Refresh(LinksetRoot); - } - return ret; - } - - // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', - // this routine will restore the removed constraints. - // Called at taint-time!! - public override void RestoreBodyDependencies(BSPrim child) - { - // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. - } - - // ================================================================ - - // Add a new child to the linkset. - // Called while LinkActivity is locked. - protected override void AddChildToLinkset(BSPhysObject child) - { - if (!HasChild(child)) - { - m_children.Add(child); - - DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); - - // Cause constraints and assorted properties to be recomputed before the next simulation step. - Refresh(LinksetRoot); - } - return; - } - - // Remove the specified child from the linkset. - // Safe to call even if the child is not really in my linkset. - protected override void RemoveChildFromLinkset(BSPhysObject child) - { - if (m_children.Remove(child)) - { - BSPhysObject rootx = LinksetRoot; // capture the root and body as of now - BSPhysObject childx = child; - - DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", - childx.LocalID, - rootx.LocalID, rootx.PhysBody.AddrString, - childx.LocalID, childx.PhysBody.AddrString); - - PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() - { - PhysicallyUnlinkAChildFromRoot(rootx, childx); - }); - // See that the linkset parameters are recomputed at the end of the taint time. - Refresh(LinksetRoot); - } - else - { - // Non-fatal occurance. - // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); - } - return; - } - - // Create a constraint between me (root of linkset) and the passed prim (the child). - // Called at taint time! - private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) - { - // Don't build the constraint when asked. Put it off until just before the simulation step. - Refresh(rootPrim); - } - - private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim) - { - // Zero motion for children so they don't interpolate - childPrim.ZeroMotion(true); - - // Relative position normalized to the root prim - // Essentually a vector pointing from center of rootPrim to center of childPrim - OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position; - - // real world coordinate of midpoint between the two objects - OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); - - DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", - rootPrim.LocalID, - rootPrim.LocalID, rootPrim.PhysBody.AddrString, - childPrim.LocalID, childPrim.PhysBody.AddrString, - rootPrim.Position, childPrim.Position, midPoint); - - // create a constraint that allows no freedom of movement between the two objects - // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 - - BSConstraint6Dof constrain = new BSConstraint6Dof( - PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); - // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); - - /* NOTE: below is an attempt to build constraint with full frame computation, etc. - * Using the midpoint is easier since it lets the Bullet code manipulate the transforms - * of the objects. - * Code left for future programmers. - // ================================================================================== - // relative position normalized to the root prim - OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); - OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation; - - // relative rotation of the child to the parent - OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; - OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); - - DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); - BS6DofConstraint constrain = new BS6DofConstraint( - PhysicsScene.World, rootPrim.Body, childPrim.Body, - OMV.Vector3.Zero, - OMV.Quaternion.Inverse(rootPrim.Orientation), - OMV.Vector3.Zero, - OMV.Quaternion.Inverse(childPrim.Orientation), - true, - true - ); - // ================================================================================== - */ - - PhysicsScene.Constraints.AddConstraint(constrain); - - // zero linear and angular limits makes the objects unable to move in relation to each other - constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); - constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); - - // tweek the constraint to increase stability - constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset)); - constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor), - BSParam.LinkConstraintTransMotorMaxVel, - BSParam.LinkConstraintTransMotorMaxForce); - constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP); - if (BSParam.LinkConstraintSolverIterations != 0f) - { - constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations); - } - return constrain; - } - - // Remove linkage between the linkset root and a particular child - // The root and child bodies are passed in because we need to remove the constraint between - // the bodies that were present at unlink time. - // Called at taint time! - private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) - { - bool ret = false; - DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", - rootPrim.LocalID, - rootPrim.LocalID, rootPrim.PhysBody.AddrString, - childPrim.LocalID, childPrim.PhysBody.AddrString); - - // Find the constraint for this link and get rid of it from the overall collection and from my list - if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) - { - // Make the child refresh its location - PhysicsScene.PE.PushUpdate(childPrim.PhysBody); - ret = true; - } - - return ret; - } - - // Remove linkage between myself and any possible children I might have. - // Returns 'true' of any constraints were destroyed. - // Called at taint time! - private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) - { - DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); - - return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); - } - - // Call each of the constraints that make up this linkset and recompute the - // various transforms and variables. Create constraints of not created yet. - // Called before the simulation step to make sure the constraint based linkset - // is all initialized. - // Called at taint time!! - private void RecomputeLinksetConstraints() - { - float linksetMass = LinksetMass; - LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true); - - DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", - LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); - - foreach (BSPhysObject child in m_children) - { - // A child in the linkset physically shows the mass of the whole linkset. - // This allows Bullet to apply enough force on the child to move the whole linkset. - // (Also do the mass stuff before recomputing the constraint so mass is not zero.) - child.UpdatePhysicalMassProperties(linksetMass, true); - - BSConstraint constrain; - if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) - { - // If constraint doesn't exist yet, create it. - constrain = BuildConstraint(LinksetRoot, child); - } - constrain.RecomputeConstraintVariables(linksetMass); - - // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG - } - - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs deleted file mode 100755 index 92d62ff..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using System.Reflection; -using Nini.Config; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ - -public struct MaterialAttributes -{ - // Material type values that correspond with definitions for LSL - public enum Material : int - { - Stone = 0, - Metal, - Glass, - Wood, - Flesh, - Plastic, - Rubber, - Light, - // Hereafter are BulletSim additions - Avatar, - NumberOfTypes // the count of types in the enum. - } - - // Names must be in the order of the above enum. - // These names must coorespond to the lower case field names in the MaterialAttributes - // structure as reflection is used to select the field to put the value in. - public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"}; - - public MaterialAttributes(string t, float d, float f, float r) - { - type = t; - density = d; - friction = f; - restitution = r; - } - public string type; - public float density; - public float friction; - public float restitution; -} - -public static class BSMaterials -{ - // Attributes for each material type - private static readonly MaterialAttributes[] Attributes; - - // Map of material name to material type code - public static readonly Dictionary MaterialMap; - - static BSMaterials() - { - // Attribute sets for both the non-physical and physical instances of materials. - Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; - - // Map of name to type code. - MaterialMap = new Dictionary(); - MaterialMap.Add("Stone", MaterialAttributes.Material.Stone); - MaterialMap.Add("Metal", MaterialAttributes.Material.Metal); - MaterialMap.Add("Glass", MaterialAttributes.Material.Glass); - MaterialMap.Add("Wood", MaterialAttributes.Material.Wood); - MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh); - MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic); - MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber); - MaterialMap.Add("Light", MaterialAttributes.Material.Light); - MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar); - } - - // This is where all the default material attributes are defined. - public static void InitializeFromDefaults(ConfigurationParameters parms) - { - // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL - float dDensity = parms.defaultDensity; - float dFriction = parms.defaultFriction; - float dRestitution = parms.defaultRestitution; - Attributes[(int)MaterialAttributes.Material.Stone] = - new MaterialAttributes("stone",dDensity, 0.8f, 0.4f); - Attributes[(int)MaterialAttributes.Material.Metal] = - new MaterialAttributes("metal",dDensity, 0.3f, 0.4f); - Attributes[(int)MaterialAttributes.Material.Glass] = - new MaterialAttributes("glass",dDensity, 0.2f, 0.7f); - Attributes[(int)MaterialAttributes.Material.Wood] = - new MaterialAttributes("wood",dDensity, 0.6f, 0.5f); - Attributes[(int)MaterialAttributes.Material.Flesh] = - new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f); - Attributes[(int)MaterialAttributes.Material.Plastic] = - new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f); - Attributes[(int)MaterialAttributes.Material.Rubber] = - new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f); - Attributes[(int)MaterialAttributes.Material.Light] = - new MaterialAttributes("light",dDensity, dFriction, dRestitution); - Attributes[(int)MaterialAttributes.Material.Avatar] = - new MaterialAttributes("avatar",3.5f, 0.2f, 0f); - - Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f); - Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("metalPhysical",dDensity, 0.3f, 0.4f); - Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f); - Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f); - Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f); - Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f); - Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 0.9f); - Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution); - Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("avatarPhysical",3.5f, 0.2f, 0f); - } - - // Under the [BulletSim] section, one can change the individual material - // attribute values. The format of the configuration parameter is: - // ["Physical"] = floatValue - // For instance: - // [BulletSim] - // StoneFriction = 0.2 - // FleshRestitutionPhysical = 0.8 - // Materials can have different parameters for their static and - // physical instantiations. When setting the non-physical value, - // both values are changed. Setting the physical value only changes - // the physical value. - public static void InitializefromParameters(IConfig pConfig) - { - foreach (KeyValuePair kvp in MaterialMap) - { - string matName = kvp.Key; - foreach (string attribName in MaterialAttributes.MaterialAttribs) - { - string paramName = matName + attribName; - if (pConfig.Contains(paramName)) - { - float paramValue = pConfig.GetFloat(paramName); - SetAttributeValue((int)kvp.Value, attribName, paramValue); - // set the physical value also - SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); - } - paramName += "Physical"; - if (pConfig.Contains(paramName)) - { - float paramValue = pConfig.GetFloat(paramName); - SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); - } - } - } - } - - // Use reflection to set the value in the attribute structure. - private static void SetAttributeValue(int matType, string attribName, float val) - { - MaterialAttributes thisAttrib = Attributes[matType]; - FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); - if (fieldInfo != null) - { - fieldInfo.SetValue(thisAttrib, val); - Attributes[matType] = thisAttrib; - } - } - - // Given a material type, return a structure of attributes. - public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) - { - int ind = (int)type; - if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; - return Attributes[ind]; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs deleted file mode 100755 index 817a5f7..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -using System; -using System.Collections.Generic; -using System.Text; -using OpenMetaverse; -using OpenSim.Framework; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -public abstract class BSMotor -{ - // Timescales and other things can be turned off by setting them to 'infinite'. - public const float Infinite = 12345.6f; - public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); - - public BSMotor(string useName) - { - UseName = useName; - PhysicsScene = null; - Enabled = true; - } - public virtual bool Enabled { get; set; } - public virtual void Reset() { } - public virtual void Zero() { } - public virtual void GenerateTestOutput(float timeStep) { } - - // A name passed at motor creation for easily identifyable debugging messages. - public string UseName { get; private set; } - - // Used only for outputting debug information. Might not be set so check for null. - public BSScene PhysicsScene { get; set; } - protected void MDetailLog(string msg, params Object[] parms) - { - if (PhysicsScene != null) - { - if (PhysicsScene.VehicleLoggingEnabled) - { - PhysicsScene.DetailLog(msg, parms); - } - } - } -} - -// Motor which moves CurrentValue to TargetValue over TimeScale seconds. -// The TargetValue decays in TargetValueDecayTimeScale and -// the CurrentValue will be held back by FrictionTimeScale. -// This motor will "zero itself" over time in that the targetValue will -// decay to zero and the currentValue will follow it to that zero. -// The overall effect is for the returned correction value to go from large -// values (the total difference between current and target minus friction) -// to small and eventually zero values. -// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. - -// For instance, if something is moving at speed X and the desired speed is Y, -// CurrentValue is X and TargetValue is Y. As the motor is stepped, new -// values of CurrentValue are returned that approach the TargetValue. -// The feature of decaying TargetValue is so vehicles will eventually -// come to a stop rather than run forever. This can be disabled by -// setting TargetValueDecayTimescale to 'infinite'. -// The change from CurrentValue to TargetValue is linear over TimeScale seconds. -public class BSVMotor : BSMotor -{ - // public Vector3 FrameOfReference { get; set; } - // public Vector3 Offset { get; set; } - - public virtual float TimeScale { get; set; } - public virtual float TargetValueDecayTimeScale { get; set; } - public virtual Vector3 FrictionTimescale { get; set; } - public virtual float Efficiency { get; set; } - - public virtual float ErrorZeroThreshold { get; set; } - - public virtual Vector3 TargetValue { get; protected set; } - public virtual Vector3 CurrentValue { get; protected set; } - public virtual Vector3 LastError { get; protected set; } - - public virtual bool ErrorIsZero - { get { - return (LastError == Vector3.Zero || LastError.LengthSquared() <= ErrorZeroThreshold); - } - } - - public BSVMotor(string useName) - : base(useName) - { - TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; - Efficiency = 1f; - FrictionTimescale = BSMotor.InfiniteVector; - CurrentValue = TargetValue = Vector3.Zero; - ErrorZeroThreshold = 0.001f; - } - public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) - : this(useName) - { - TimeScale = timeScale; - TargetValueDecayTimeScale = decayTimeScale; - FrictionTimescale = frictionTimeScale; - Efficiency = efficiency; - CurrentValue = TargetValue = Vector3.Zero; - } - public void SetCurrent(Vector3 current) - { - CurrentValue = current; - } - public void SetTarget(Vector3 target) - { - TargetValue = target; - } - public override void Zero() - { - base.Zero(); - CurrentValue = TargetValue = Vector3.Zero; - } - - // Compute the next step and return the new current value - public virtual Vector3 Step(float timeStep) - { - if (!Enabled) return TargetValue; - - Vector3 origTarget = TargetValue; // DEBUG - Vector3 origCurrVal = CurrentValue; // DEBUG - - Vector3 correction = Vector3.Zero; - Vector3 error = TargetValue - CurrentValue; - if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) - { - correction = Step(timeStep, error); - - CurrentValue += correction; - - // The desired value reduces to zero which also reduces the difference with current. - // If the decay time is infinite, don't decay at all. - float decayFactor = 0f; - if (TargetValueDecayTimeScale != BSMotor.Infinite) - { - decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; - TargetValue *= (1f - decayFactor); - } - - // The amount we can correct the error is reduced by the friction - Vector3 frictionFactor = Vector3.Zero; - if (FrictionTimescale != BSMotor.InfiniteVector) - { - // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; - // Individual friction components can be 'infinite' so compute each separately. - frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X); - frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y); - frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z); - frictionFactor *= timeStep; - CurrentValue *= (Vector3.One - frictionFactor); - } - - MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", - BSScene.DetailLogZero, UseName, origCurrVal, origTarget, - timeStep, error, correction); - MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", - BSScene.DetailLogZero, UseName, - TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, - TargetValue, CurrentValue); - } - else - { - // Difference between what we have and target is small. Motor is done. - CurrentValue = TargetValue; - MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", - BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); - } - - return CurrentValue; - } - public virtual Vector3 Step(float timeStep, Vector3 error) - { - if (!Enabled) return Vector3.Zero; - - LastError = error; - Vector3 returnCorrection = Vector3.Zero; - if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) - { - // correction = error / secondsItShouldTakeToCorrect - Vector3 correctionAmount; - if (TimeScale == 0f || TimeScale == BSMotor.Infinite) - correctionAmount = error * timeStep; - else - correctionAmount = error / TimeScale * timeStep; - - returnCorrection = correctionAmount; - MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", - BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); - } - return returnCorrection; - } - - // The user sets all the parameters and calls this which outputs values until error is zero. - public override void GenerateTestOutput(float timeStep) - { - // maximum number of outputs to generate. - int maxOutput = 50; - MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); - MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}", - BSScene.DetailLogZero, UseName, - TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, - CurrentValue, TargetValue); - - LastError = BSMotor.InfiniteVector; - while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) - { - Vector3 lastStep = Step(timeStep); - MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}", - BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); - } - MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); - - - } - - public override string ToString() - { - return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", - UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); - } -} - -public class BSFMotor : BSMotor -{ - public float TimeScale { get; set; } - public float DecayTimeScale { get; set; } - public float Friction { get; set; } - public float Efficiency { get; set; } - - public float Target { get; private set; } - public float CurrentValue { get; private set; } - - public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) - : base(useName) - { - } - public void SetCurrent(float target) - { - } - public void SetTarget(float target) - { - } - public virtual float Step(float timeStep) - { - return 0f; - } -} - -// Proportional, Integral, Derivitive Motor -// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. -public class BSPIDVMotor : BSVMotor -{ - // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10. - public Vector3 proportionFactor { get; set; } - public Vector3 integralFactor { get; set; } - public Vector3 derivFactor { get; set; } - - // Arbritrary factor range. - // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. - public float EfficiencyHigh = 0.4f; - public float EfficiencyLow = 4.0f; - - // Running integration of the error - Vector3 RunningIntegration { get; set; } - - public BSPIDVMotor(string useName) - : base(useName) - { - proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); - integralFactor = new Vector3(1.00f, 1.00f, 1.00f); - derivFactor = new Vector3(1.00f, 1.00f, 1.00f); - RunningIntegration = Vector3.Zero; - LastError = Vector3.Zero; - } - - public override void Zero() - { - base.Zero(); - } - - public override float Efficiency - { - get { return base.Efficiency; } - set - { - base.Efficiency = Util.Clamp(value, 0f, 1f); - // Compute factors based on efficiency. - // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. - // If efficiency is low (0f), use a factor value that overcorrects. - // TODO: might want to vary contribution of different factor depending on efficiency. - float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; - // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; - proportionFactor = new Vector3(factor, factor, factor); - integralFactor = new Vector3(factor, factor, factor); - derivFactor = new Vector3(factor, factor, factor); - } - } - - // Ignore Current and Target Values and just advance the PID computation on this error. - public override Vector3 Step(float timeStep, Vector3 error) - { - if (!Enabled) return Vector3.Zero; - - // Add up the error so we can integrate over the accumulated errors - RunningIntegration += error * timeStep; - - // A simple derivitive is the rate of change from the last error. - Vector3 derivFactor = (error - LastError) * timeStep; - LastError = error; - - // Correction = -(proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) - Vector3 ret = -( - error * proportionFactor - + RunningIntegration * integralFactor - + derivFactor * derivFactor - ); - - return ret; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs deleted file mode 100755 index 69ac8cd..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OpenSim.Region.Physics.Manager; - -using OpenMetaverse; -using Nini.Config; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -public static class BSParam -{ - // Level of Detail values kept as float because that's what the Meshmerizer wants - public static float MeshLOD { get; private set; } - public static float MeshMegaPrimLOD { get; private set; } - public static float MeshMegaPrimThreshold { get; private set; } - public static float SculptLOD { get; private set; } - - public static float MinimumObjectMass { get; private set; } - public static float MaximumObjectMass { get; private set; } - - public static float LinearDamping { get; private set; } - public static float AngularDamping { get; private set; } - public static float DeactivationTime { get; private set; } - public static float LinearSleepingThreshold { get; private set; } - public static float AngularSleepingThreshold { get; private set; } - public static float CcdMotionThreshold { get; private set; } - public static float CcdSweptSphereRadius { get; private set; } - public static float ContactProcessingThreshold { get; private set; } - - public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed - public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes - public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects - - public static float TerrainImplementation { get; private set; } - public static float TerrainFriction { get; private set; } - public static float TerrainHitFraction { get; private set; } - public static float TerrainRestitution { get; private set; } - public static float TerrainCollisionMargin { get; private set; } - - // Avatar parameters - public static float AvatarFriction { get; private set; } - public static float AvatarStandingFriction { get; private set; } - public static float AvatarAlwaysRunFactor { get; private set; } - public static float AvatarDensity { get; private set; } - public static float AvatarRestitution { get; private set; } - public static float AvatarCapsuleWidth { get; private set; } - public static float AvatarCapsuleDepth { get; private set; } - public static float AvatarCapsuleHeight { get; private set; } - public static float AvatarContactProcessingThreshold { get; private set; } - - public static float VehicleAngularDamping { get; private set; } - - public static float LinksetImplementation { get; private set; } - public static float LinkConstraintUseFrameOffset { get; private set; } - public static float LinkConstraintEnableTransMotor { get; private set; } - public static float LinkConstraintTransMotorMaxVel { get; private set; } - public static float LinkConstraintTransMotorMaxForce { get; private set; } - public static float LinkConstraintERP { get; private set; } - public static float LinkConstraintCFM { get; private set; } - public static float LinkConstraintSolverIterations { get; private set; } - - public static float PID_D { get; private set; } // derivative - public static float PID_P { get; private set; } // proportional - - // Various constants that come from that other virtual world that shall not be named - public const float MinGravityZ = -1f; - public const float MaxGravityZ = 28f; - public const float MinFriction = 0f; - public const float MaxFriction = 255f; - public const float MinDensity = 0f; - public const float MaxDensity = 22587f; - public const float MinRestitution = 0f; - public const float MaxRestitution = 1f; - public const float MaxAddForceMagnitude = 20000f; - - // =========================================================================== - public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); - public delegate float ParamGet(BSScene scene); - public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); - public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); - - public struct ParameterDefn - { - public string name; // string name of the parameter - public string desc; // a short description of what the parameter means - public float defaultValue; // default value if not specified anywhere else - public ParamUser userParam; // get the value from the configuration file - public ParamGet getter; // return the current value stored for this parameter - public ParamSet setter; // set the current value for this parameter - public SetOnObject onObject; // set the value on an object in the physical domain - public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) - { - name = n; - desc = d; - defaultValue = v; - userParam = u; - getter = g; - setter = s; - onObject = null; - } - public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) - { - name = n; - desc = d; - defaultValue = v; - userParam = u; - getter = g; - setter = s; - onObject = o; - } - } - - // List of all of the externally visible parameters. - // For each parameter, this table maps a text name to getter and setters. - // To add a new externally referencable/settable parameter, add the paramter storage - // location somewhere in the program and make an entry in this table with the - // getters and setters. - // It is easiest to find an existing definition and copy it. - // Parameter values are floats. Booleans are converted to a floating value. - // - // A ParameterDefn() takes the following parameters: - // -- the text name of the parameter. This is used for console input and ini file. - // -- a short text description of the parameter. This shows up in the console listing. - // -- a default value (float) - // -- a delegate for fetching the parameter from the ini file. - // Should handle fetching the right type from the ini file and converting it. - // -- a delegate for getting the value as a float - // -- a delegate for setting the value from a float - // -- an optional delegate to update the value in the world. Most often used to - // push the new value to an in-world object. - // - // The single letter parameters for the delegates are: - // s = BSScene - // o = BSPhysObject - // p = string parameter name - // l = localID of referenced object - // v = value (float) - // cf = parameter configuration class (for fetching values from ini file) - private static ParameterDefn[] ParameterDefinitions = - { - new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", - ConfigurationParameters.numericTrue, - (s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, - (s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); }, - (s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ), - new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", - ConfigurationParameters.numericFalse, - (s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, - (s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); }, - (s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ), - new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", - ConfigurationParameters.numericTrue, - (s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, - (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); }, - (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ), - - new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", - 8f, - (s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); }, - (s) => { return MeshLOD; }, - (s,p,l,v) => { MeshLOD = v; } ), - new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", - 16f, - (s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); }, - (s) => { return MeshMegaPrimLOD; }, - (s,p,l,v) => { MeshMegaPrimLOD = v; } ), - new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", - 10f, - (s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); }, - (s) => { return MeshMegaPrimThreshold; }, - (s,p,l,v) => { MeshMegaPrimThreshold = v; } ), - new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", - 32f, - (s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); }, - (s) => { return SculptLOD; }, - (s,p,l,v) => { SculptLOD = v; } ), - - new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", - 10f, - (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); }, - (s) => { return (float)s.m_maxSubSteps; }, - (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ), - new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", - 1f / 60f, - (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); }, - (s) => { return (float)s.m_fixedTimeStep; }, - (s,p,l,v) => { s.m_fixedTimeStep = v; } ), - new ParameterDefn("NominalFrameRate", "The base frame rate we claim", - 55f, - (s,cf,p,v) => { s.NominalFrameRate = cf.GetInt(p, (int)v); }, - (s) => { return (float)s.NominalFrameRate; }, - (s,p,l,v) => { s.NominalFrameRate = (int)v; } ), - new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", - 2048f, - (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); }, - (s) => { return (float)s.m_maxCollisionsPerFrame; }, - (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), - new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame", - 8000f, - (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, - (s) => { return (float)s.m_maxUpdatesPerFrame; }, - (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), - new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", - 500f, - (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, - (s) => { return (float)s.m_taintsToProcessPerStep; }, - (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), - new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)", - 0.0001f, - (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); }, - (s) => { return (float)MinimumObjectMass; }, - (s,p,l,v) => { MinimumObjectMass = v; } ), - new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", - 10000.01f, - (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); }, - (s) => { return (float)MaximumObjectMass; }, - (s,p,l,v) => { MaximumObjectMass = v; } ), - - new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", - 2200f, - (s,cf,p,v) => { PID_D = cf.GetFloat(p, v); }, - (s) => { return (float)PID_D; }, - (s,p,l,v) => { PID_D = v; } ), - new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", - 900f, - (s,cf,p,v) => { PID_P = cf.GetFloat(p, v); }, - (s) => { return (float)PID_P; }, - (s,p,l,v) => { PID_P = v; } ), - - new ParameterDefn("DefaultFriction", "Friction factor used on new objects", - 0.2f, - (s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].defaultFriction; }, - (s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ), - new ParameterDefn("DefaultDensity", "Density for new objects" , - 10.000006836f, // Aluminum g/cm3 - (s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].defaultDensity; }, - (s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ), - new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , - 0f, - (s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].defaultRestitution; }, - (s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ), - new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", - 0.04f, - (s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].collisionMargin; }, - (s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ), - new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)", - -9.80665f, - (s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].gravity; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); }, - (s,o,v) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,v)); } ), - - - new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", - 0f, - (s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); }, - (s) => { return LinearDamping; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); }, - (s,o,v) => { s.PE.SetDamping(o.PhysBody, v, AngularDamping); } ), - new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", - 0f, - (s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); }, - (s) => { return AngularDamping; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); }, - (s,o,v) => { s.PE.SetDamping(o.PhysBody, LinearDamping, v); } ), - new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", - 0.2f, - (s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); }, - (s) => { return DeactivationTime; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); }, - (s,o,v) => { s.PE.SetDeactivationTime(o.PhysBody, v); } ), - new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", - 0.8f, - (s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); }, - (s) => { return LinearSleepingThreshold; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); }, - (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ), - new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", - 1.0f, - (s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); }, - (s) => { return AngularSleepingThreshold; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); }, - (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ), - new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , - 0f, // set to zero to disable - (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); }, - (s) => { return CcdMotionThreshold; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); }, - (s,o,v) => { s.PE.SetCcdMotionThreshold(o.PhysBody, v); } ), - new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , - 0f, - (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); }, - (s) => { return CcdSweptSphereRadius; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); }, - (s,o,v) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, v); } ), - new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , - 0.1f, - (s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); }, - (s) => { return ContactProcessingThreshold; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); }, - (s,o,v) => { s.PE.SetContactProcessingThreshold(o.PhysBody, v); } ), - - new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", - (float)BSTerrainPhys.TerrainImplementation.Mesh, - (s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); }, - (s) => { return TerrainImplementation; }, - (s,p,l,v) => { TerrainImplementation = v; } ), - new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , - 0.3f, - (s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); }, - (s) => { return TerrainFriction; }, - (s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ), - new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , - 0.8f, - (s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); }, - (s) => { return TerrainHitFraction; }, - (s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ), - new ParameterDefn("TerrainRestitution", "Bouncyness" , - 0f, - (s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); }, - (s) => { return TerrainRestitution; }, - (s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ), - new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , - 0.04f, - (s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); }, - (s) => { return TerrainCollisionMargin; }, - (s,p,l,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ), - - new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", - 0.2f, - (s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); }, - (s) => { return AvatarFriction; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ), - new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", - 10.0f, - (s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); }, - (s) => { return AvatarStandingFriction; }, - (s,p,l,v) => { AvatarStandingFriction = v; } ), - new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", - 1.3f, - (s,cf,p,v) => { AvatarAlwaysRunFactor = cf.GetFloat(p, v); }, - (s) => { return AvatarAlwaysRunFactor; }, - (s,p,l,v) => { AvatarAlwaysRunFactor = v; } ), - new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", - 3.5f, - (s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); }, - (s) => { return AvatarDensity; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ), - new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", - 0f, - (s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); }, - (s) => { return AvatarRestitution; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ), - new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", - 0.6f, - (s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); }, - (s) => { return AvatarCapsuleWidth; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ), - new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", - 0.45f, - (s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); }, - (s) => { return AvatarCapsuleDepth; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ), - new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", - 1.5f, - (s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); }, - (s) => { return AvatarCapsuleHeight; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ), - new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", - 0.1f, - (s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); }, - (s) => { return AvatarContactProcessingThreshold; }, - (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ), - - new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", - 0.95f, - (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); }, - (s) => { return VehicleAngularDamping; }, - (s,p,l,v) => { VehicleAngularDamping = v; } ), - - new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", - 0f, - (s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; }, - (s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ), - new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", - 0f, - (s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; }, - (s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ), - new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", - ConfigurationParameters.numericFalse, - (s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; }, - (s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ), - new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", - ConfigurationParameters.numericFalse, - (s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; }, - (s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ), - new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", - ConfigurationParameters.numericTrue, - (s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; }, - (s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ), - new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", - ConfigurationParameters.numericTrue, - (s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; }, - (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ), - new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", - ConfigurationParameters.numericFalse, - (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; }, - (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ), - new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)", - 0f, // zero says use Bullet default - (s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); }, - (s) => { return s.UnmanagedParams[0].numberOfSolverIterations; }, - (s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ), - - new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", - (float)BSLinkset.LinksetImplementation.Compound, - (s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); }, - (s) => { return LinksetImplementation; }, - (s,p,l,v) => { LinksetImplementation = v; } ), - new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", - ConfigurationParameters.numericFalse, - (s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return LinkConstraintUseFrameOffset; }, - (s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ), - new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", - ConfigurationParameters.numericTrue, - (s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, - (s) => { return LinkConstraintEnableTransMotor; }, - (s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ), - new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", - 5.0f, - (s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); }, - (s) => { return LinkConstraintTransMotorMaxVel; }, - (s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ), - new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", - 0.1f, - (s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, - (s) => { return LinkConstraintTransMotorMaxForce; }, - (s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ), - new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", - 0.1f, - (s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); }, - (s) => { return LinkConstraintCFM; }, - (s,p,l,v) => { LinkConstraintCFM = v; } ), - new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", - 0.1f, - (s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); }, - (s) => { return LinkConstraintERP; }, - (s,p,l,v) => { LinkConstraintERP = v; } ), - new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", - 40, - (s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); }, - (s) => { return LinkConstraintSolverIterations; }, - (s,p,l,v) => { LinkConstraintSolverIterations = v; } ), - - new ParameterDefn("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", - 0f, - (s,cf,p,v) => { s.PhysicsMetricDumpFrames = cf.GetFloat(p, (int)v); }, - (s) => { return (float)s.PhysicsMetricDumpFrames; }, - (s,p,l,v) => { s.PhysicsMetricDumpFrames = (int)v; } ), - }; - - // Convert a boolean to our numeric true and false values - public static float NumericBool(bool b) - { - return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); - } - - // Convert numeric true and false values to a boolean - public static bool BoolNumeric(float b) - { - return (b == ConfigurationParameters.numericTrue ? true : false); - } - - // Search through the parameter definitions and return the matching - // ParameterDefn structure. - // Case does not matter as names are compared after converting to lower case. - // Returns 'false' if the parameter is not found. - internal static bool TryGetParameter(string paramName, out ParameterDefn defn) - { - bool ret = false; - ParameterDefn foundDefn = new ParameterDefn(); - string pName = paramName.ToLower(); - - foreach (ParameterDefn parm in ParameterDefinitions) - { - if (pName == parm.name.ToLower()) - { - foundDefn = parm; - ret = true; - break; - } - } - defn = foundDefn; - return ret; - } - - // Pass through the settable parameters and set the default values - internal static void SetParameterDefaultValues(BSScene physicsScene) - { - foreach (ParameterDefn parm in ParameterDefinitions) - { - parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue); - } - } - - // Get user set values out of the ini file. - internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg) - { - foreach (ParameterDefn parm in ParameterDefinitions) - { - parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue); - } - } - - internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; - - // This creates an array in the correct format for returning the list of - // parameters. This is used by the 'list' option of the 'physics' command. - internal static void BuildParameterTable() - { - if (SettableParameters.Length < ParameterDefinitions.Length) - { - List entries = new List(); - for (int ii = 0; ii < ParameterDefinitions.Length; ii++) - { - ParameterDefn pd = ParameterDefinitions[ii]; - entries.Add(new PhysParameterEntry(pd.name, pd.desc)); - } - - // make the list in alphabetical order for estetic reasons - entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2) - { - return ppe1.name.CompareTo(ppe2.name); - }); - - SettableParameters = entries.ToArray(); - } - } - - -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs deleted file mode 100755 index e7cb3e0..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OMV = OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -/* - * Class to wrap all objects. - * The rest of BulletSim doesn't need to keep checking for avatars or prims - * unless the difference is significant. - * - * Variables in the physicsl objects are in three forms: - * VariableName: used by the simulator and performs taint operations, etc - * RawVariableName: direct reference to the BulletSim storage for the variable value - * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. - * The last two (and certainly the last one) should be referenced only in taint-time. - */ - -/* - * As of 20121221, the following are the call sequences (going down) for different script physical functions: - * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce - * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce - * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse - * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v - * BS.ApplyCentralForce BS.ApplyTorque - */ - -public abstract class BSPhysObject : PhysicsActor -{ - protected BSPhysObject() - { - } - protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) - { - PhysicsScene = parentScene; - LocalID = localID; - PhysObjectName = name; - TypeName = typeName; - - // We don't have any physical representation yet. - PhysBody = new BulletBody(localID); - PhysShape = new BulletShape(); - - // A linkset of just me - Linkset = BSLinkset.Factory(PhysicsScene, this); - LastAssetBuildFailed = false; - - // Default material type - Material = MaterialAttributes.Material.Wood; - - CollisionCollection = new CollisionEventUpdate(); - SubscribedEventsMs = 0; - CollidingStep = 0; - CollidingGroundStep = 0; - } - - // Tell the object to clean up. - public virtual void Destroy() - { - UnRegisterAllPreStepActions(); - } - - public BSScene PhysicsScene { get; protected set; } - // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor - public string PhysObjectName { get; protected set; } - public string TypeName { get; protected set; } - - public BSLinkset Linkset { get; set; } - public BSLinksetInfo LinksetInfo { get; set; } - - // Return the object mass without calculating it or having side effects - public abstract float RawMass { get; } - // Set the raw mass but also update physical mass properties (inertia, ...) - // 'inWorld' true if the object has already been added to the dynamic world. - public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld); - - // The last value calculated for the prim's inertia - public OMV.Vector3 Inertia { get; set; } - - // Reference to the physical body (btCollisionObject) of this object - public BulletBody PhysBody; - // Reference to the physical shape (btCollisionShape) of this object - public BulletShape PhysShape; - - // 'true' if the mesh's underlying asset failed to build. - // This will keep us from looping after the first time the build failed. - public bool LastAssetBuildFailed { get; set; } - - // The objects base shape information. Null if not a prim type shape. - public PrimitiveBaseShape BaseShape { get; protected set; } - // Some types of objects have preferred physical representations. - // Returns SHAPE_UNKNOWN if there is no preference. - public virtual BSPhysicsShapeType PreferredPhysicalShape - { - get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } - } - - // When the physical properties are updated, an EntityProperty holds the update values. - // Keep the current and last EntityProperties to enable computation of differences - // between the current update and the previous values. - public EntityProperties CurrentEntityProperties { get; set; } - public EntityProperties LastEntityProperties { get; set; } - - public virtual OMV.Vector3 Scale { get; set; } - public abstract bool IsSolid { get; } - public abstract bool IsStatic { get; } - - // Materialness - public MaterialAttributes.Material Material { get; private set; } - public override void SetMaterial(int material) - { - Material = (MaterialAttributes.Material)material; - } - - // Stop all physical motion. - public abstract void ZeroMotion(bool inTaintTime); - public abstract void ZeroAngularMotion(bool inTaintTime); - - // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured. - public virtual void StepVehicle(float timeStep) { } - - // Update the physical location and motion of the object. Called with data from Bullet. - public abstract void UpdateProperties(EntityProperties entprop); - - public abstract OMV.Vector3 RawPosition { get; set; } - public abstract OMV.Vector3 ForcePosition { get; set; } - - public abstract OMV.Quaternion RawOrientation { get; set; } - public abstract OMV.Quaternion ForceOrientation { get; set; } - - // The system is telling us the velocity it wants to move at. - // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor - public override OMV.Vector3 TargetVelocity - { - get { return m_targetVelocity; } - set - { - m_targetVelocity = value; - Velocity = value; - } - } - public abstract OMV.Vector3 ForceVelocity { get; set; } - - public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } - - public abstract float ForceBuoyancy { get; set; } - - public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } - - #region Collisions - - // Requested number of milliseconds between collision events. Zero means disabled. - protected int SubscribedEventsMs { get; set; } - // Given subscription, the time that a collision may be passed up - protected int NextCollisionOkTime { get; set; } - // The simulation step that last had a collision - protected long CollidingStep { get; set; } - // The simulation step that last had a collision with the ground - protected long CollidingGroundStep { get; set; } - // The simulation step that last collided with an object - protected long CollidingObjectStep { get; set; } - // The collision flags we think are set in Bullet - protected CollisionFlags CurrentCollisionFlags { get; set; } - - public override bool IsColliding { - get { return (CollidingStep == PhysicsScene.SimulationStep); } - set { - if (value) - CollidingStep = PhysicsScene.SimulationStep; - else - CollidingStep = 0; - } - } - public override bool CollidingGround { - get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } - set - { - if (value) - CollidingGroundStep = PhysicsScene.SimulationStep; - else - CollidingGroundStep = 0; - } - } - public override bool CollidingObj { - get { return (CollidingObjectStep == PhysicsScene.SimulationStep); } - set { - if (value) - CollidingObjectStep = PhysicsScene.SimulationStep; - else - CollidingObjectStep = 0; - } - } - - // The collisions that have been collected this tick - protected CollisionEventUpdate CollisionCollection; - - // The simulation step is telling this object about a collision. - // Return 'true' if a collision was processed and should be sent up. - // Called at taint time from within the Step() function - public virtual bool Collide(uint collidingWith, BSPhysObject collidee, - OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) - { - bool ret = false; - - // The following lines make IsColliding(), CollidingGround() and CollidingObj work - CollidingStep = PhysicsScene.SimulationStep; - if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) - { - CollidingGroundStep = PhysicsScene.SimulationStep; - } - else - { - CollidingObjectStep = PhysicsScene.SimulationStep; - } - - // prims in the same linkset cannot collide with each other - if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) - { - return ret; - } - - // if someone has subscribed for collision events.... - if (SubscribedEvents()) { - CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); - DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", - LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); - - ret = true; - } - return ret; - } - - // Send the collected collisions into the simulator. - // Called at taint time from within the Step() function thus no locking problems - // with CollisionCollection and ObjectsWithNoMoreCollisions. - // Return 'true' if there were some actual collisions passed up - public virtual bool SendCollisions() - { - bool ret = true; - // If the 'no collision' call, force it to happen right now so quick collision_end - bool force = (CollisionCollection.Count == 0); - - // throttle the collisions to the number of milliseconds specified in the subscription - if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) - { - NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs; - - // We are called if we previously had collisions. If there are no collisions - // this time, send up one last empty event so OpenSim can sense collision end. - if (CollisionCollection.Count == 0) - { - // If I have no collisions this time, remove me from the list of objects with collisions. - ret = false; - } - - // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); - base.SendCollisionUpdate(CollisionCollection); - - // The CollisionCollection instance is passed around in the simulator. - // Make sure we don't have a handle to that one and that a new one is used for next time. - // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, - // a race condition is created for the other users of this instance. - CollisionCollection = new CollisionEventUpdate(); - } - return ret; - } - - // Subscribe for collision events. - // Parameter is the millisecond rate the caller wishes collision events to occur. - public override void SubscribeEvents(int ms) { - // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms); - SubscribedEventsMs = ms; - if (ms > 0) - { - // make sure first collision happens - NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); - - PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() - { - if (PhysBody.HasPhysicalBody) - CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - }); - } - else - { - // Subscribing for zero or less is the same as unsubscribing - UnSubscribeEvents(); - } - } - public override void UnSubscribeEvents() { - // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); - SubscribedEventsMs = 0; - PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() - { - // Make sure there is a body there because sometimes destruction happens in an un-ideal order. - if (PhysBody.HasPhysicalBody) - CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - }); - } - // Return 'true' if the simulator wants collision events - public override bool SubscribedEvents() { - return (SubscribedEventsMs > 0); - } - - #endregion // Collisions - - #region Per Simulation Step actions - // There are some actions that must be performed for a physical object before each simulation step. - // These actions are optional so, rather than scanning all the physical objects and asking them - // if they have anything to do, a physical object registers for an event call before the step is performed. - // This bookkeeping makes it easy to add, remove and clean up after all these registrations. - private Dictionary RegisteredActions = new Dictionary(); - protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn) - { - string identifier = op + "-" + id.ToString(); - RegisteredActions[identifier] = actn; - PhysicsScene.BeforeStep += actn; - DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier); - } - - // Unregister a pre step action. Safe to call if the action has not been registered. - protected void UnRegisterPreStepAction(string op, uint id) - { - string identifier = op + "-" + id.ToString(); - bool removed = false; - if (RegisteredActions.ContainsKey(identifier)) - { - PhysicsScene.BeforeStep -= RegisteredActions[identifier]; - RegisteredActions.Remove(identifier); - removed = true; - } - DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed); - } - - protected void UnRegisterAllPreStepActions() - { - foreach (KeyValuePair kvp in RegisteredActions) - { - PhysicsScene.BeforeStep -= kvp.Value; - } - RegisteredActions.Clear(); - DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID); - } - - - #endregion // Per Simulation Step actions - - // High performance detailed logging routine used by the physical objects. - protected void DetailLog(string msg, params Object[] args) - { - if (PhysicsScene.PhysicsLogging.Enabled) - PhysicsScene.DetailLog(msg, args); - } - -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs deleted file mode 100644 index 65be52a..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ - /// - /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim. - /// This module interfaces to an unmanaged C++ library which makes the - /// actual calls into the Bullet physics engine. - /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/. - /// The unmanaged library is compiled and linked statically with Bullet - /// to create BulletSim.dll and libBulletSim.so (for both 32 and 64 bit). - /// -public class BSPlugin : IPhysicsPlugin -{ - //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - private BSScene _mScene; - - public BSPlugin() - { - } - - public bool Init() - { - return true; - } - - public PhysicsScene GetScene(String sceneIdentifier) - { - if (_mScene == null) - { - _mScene = new BSScene(sceneIdentifier); - } - return (_mScene); - } - - public string GetName() - { - return ("BulletSim"); - } - - public void Dispose() - { - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs deleted file mode 100644 index 826261c..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ /dev/null @@ -1,1513 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Reflection; -using System.Collections.Generic; -using System.Xml; -using log4net; -using OMV = OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; -using OpenSim.Region.Physics.ConvexDecompositionDotNet; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ - - [Serializable] -public sealed class BSPrim : BSPhysObject -{ - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static readonly string LogHeader = "[BULLETS PRIM]"; - - // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. - private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user - - private bool _grabbed; - private bool _isSelected; - private bool _isVolumeDetect; - private OMV.Vector3 _position; - private float _mass; // the mass of this object - private float _density; - private OMV.Vector3 _force; - private OMV.Vector3 _velocity; - private OMV.Vector3 _torque; - private float _collisionScore; - private OMV.Vector3 _acceleration; - private OMV.Quaternion _orientation; - private int _physicsActorType; - private bool _isPhysical; - private bool _flying; - private float _friction; - private float _restitution; - private bool _setAlwaysRun; - private bool _throttleUpdates; - private bool _isColliding; - private bool _collidingGround; - private bool _collidingObj; - private bool _floatOnWater; - private OMV.Vector3 _rotationalVelocity; - private bool _kinematic; - private float _buoyancy; - - private BSDynamics _vehicle; - - private OMV.Vector3 _PIDTarget; - private bool _usePID; - private float _PIDTau; - private bool _useHoverPID; - private float _PIDHoverHeight; - private PIDHoverType _PIDHoverType; - private float _PIDHoverTao; - - public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, - OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) - : base(parent_scene, localID, primName, "BSPrim") - { - // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); - _physicsActorType = (int)ActorTypes.Prim; - _position = pos; - _size = size; - Scale = size; // prims are the size the user wants them to be (different for BSCharactes). - _orientation = rotation; - _buoyancy = 0f; - _velocity = OMV.Vector3.Zero; - _rotationalVelocity = OMV.Vector3.Zero; - BaseShape = pbs; - _isPhysical = pisPhysical; - _isVolumeDetect = false; - - // Someday set default attributes based on the material but, for now, we don't know the prim material yet. - // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical); - _density = PhysicsScene.Params.defaultDensity; - _friction = PhysicsScene.Params.defaultFriction; - _restitution = PhysicsScene.Params.defaultRestitution; - - _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness - - _mass = CalculateMass(); - - // Cause linkset variables to be initialized (like mass) - Linkset.Refresh(this); - - DetailLog("{0},BSPrim.constructor,call", LocalID); - // do the actual object creation at taint time - PhysicsScene.TaintedObject("BSPrim.create", delegate() - { - CreateGeomAndObject(true); - - CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); - }); - } - - // called when this prim is being destroyed and we should free all the resources - public override void Destroy() - { - // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); - base.Destroy(); - - // Undo any links between me and any other object - BSPhysObject parentBefore = Linkset.LinksetRoot; - int childrenBefore = Linkset.NumberOfChildren; - - Linkset = Linkset.RemoveMeFromLinkset(this); - - DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", - LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); - - // Undo any vehicle properties - this.VehicleType = (int)Vehicle.TYPE_NONE; - - PhysicsScene.TaintedObject("BSPrim.destroy", delegate() - { - DetailLog("{0},BSPrim.Destroy,taint,", LocalID); - // If there are physical body and shape, release my use of same. - PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); - PhysBody.Clear(); - PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); - PhysShape.Clear(); - }); - } - - // No one uses this property. - public override bool Stopped { - get { return false; } - } - public override OMV.Vector3 Size { - get { return _size; } - set { - // We presume the scale and size are the same. If scale must be changed for - // the physical shape, that is done when the geometry is built. - _size = value; - Scale = _size; - ForceBodyShapeRebuild(false); - } - } - - public override PrimitiveBaseShape Shape { - set { - BaseShape = value; - ForceBodyShapeRebuild(false); - } - } - // Whatever the linkset wants is what I want. - public override BSPhysicsShapeType PreferredPhysicalShape - { get { return Linkset.PreferredPhysicalShape(this); } } - - public override bool ForceBodyShapeRebuild(bool inTaintTime) - { - LastAssetBuildFailed = false; - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() - { - _mass = CalculateMass(); // changing the shape changes the mass - CreateGeomAndObject(true); - }); - return true; - } - public override bool Grabbed { - set { _grabbed = value; - } - } - public override bool Selected { - set - { - if (value != _isSelected) - { - _isSelected = value; - PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() - { - DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); - SetObjectDynamic(false); - }); - } - } - } - public override void CrossingFailure() { return; } - - // link me to the specified parent - public override void link(PhysicsActor obj) { - BSPrim parent = obj as BSPrim; - if (parent != null) - { - BSPhysObject parentBefore = Linkset.LinksetRoot; - int childrenBefore = Linkset.NumberOfChildren; - - Linkset = parent.Linkset.AddMeToLinkset(this); - - DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", - LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); - } - return; - } - - // delink me from my linkset - public override void delink() { - // TODO: decide if this parent checking needs to happen at taint time - // Race condition here: if link() and delink() in same simulation tick, the delink will not happen - - BSPhysObject parentBefore = Linkset.LinksetRoot; - int childrenBefore = Linkset.NumberOfChildren; - - Linkset = Linkset.RemoveMeFromLinkset(this); - - DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", - LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); - return; - } - - // Set motion values to zero. - // Do it to the properties so the values get set in the physics engine. - // Push the setting of the values to the viewer. - // Called at taint time! - public override void ZeroMotion(bool inTaintTime) - { - _velocity = OMV.Vector3.Zero; - _acceleration = OMV.Vector3.Zero; - _rotationalVelocity = OMV.Vector3.Zero; - - // Zero some other properties in the physics engine - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() - { - if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.ClearAllForces(PhysBody); - }); - } - public override void ZeroAngularMotion(bool inTaintTime) - { - _rotationalVelocity = OMV.Vector3.Zero; - // Zero some other properties in the physics engine - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() - { - // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); - if (PhysBody.HasPhysicalBody) - { - PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); - PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); - } - }); - } - - public override void LockAngularMotion(OMV.Vector3 axis) - { - DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); - return; - } - - public override OMV.Vector3 RawPosition - { - get { return _position; } - set { _position = value; } - } - public override OMV.Vector3 Position { - get { - /* NOTE: this refetch is not necessary. The simulator knows about linkset children - * and does not fetch this position info for children. Thus this is commented out. - // child prims move around based on their parent. Need to get the latest location - if (!Linkset.IsRoot(this)) - _position = Linkset.PositionGet(this); - */ - - // don't do the GetObjectPosition for root elements because this function is called a zillion times. - // _position = PhysicsScene.PE.GetObjectPosition2(PhysicsScene.World, BSBody); - return _position; - } - set { - // If the position must be forced into the physics engine, use ForcePosition. - // All positions are given in world positions. - if (_position == value) - { - DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation); - return; - } - _position = value; - PositionSanityCheck(false); - - // A linkset might need to know if a component information changed. - Linkset.UpdateProperties(this, false); - - PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() - { - DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); - ForcePosition = _position; - }); - } - } - public override OMV.Vector3 ForcePosition { - get { - _position = PhysicsScene.PE.GetPosition(PhysBody); - return _position; - } - set { - _position = value; - if (PhysBody.HasPhysicalBody) - { - PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); - ActivateIfPhysical(false); - } - } - } - - // Check that the current position is sane and, if not, modify the position to make it so. - // Check for being below terrain and being out of bounds. - // Returns 'true' of the position was made sane by some action. - private bool PositionSanityCheck(bool inTaintTime) - { - bool ret = false; - - if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) - { - // The physical object is out of the known/simulated area. - // Upper levels of code will handle the transition to other areas so, for - // the time, we just ignore the position. - return ret; - } - - float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); - OMV.Vector3 upForce = OMV.Vector3.Zero; - if (RawPosition.Z < terrainHeight) - { - DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); - float targetHeight = terrainHeight + (Size.Z / 2f); - // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. - upForce.Z = (terrainHeight - RawPosition.Z) * 1f; - ret = true; - } - - if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) - { - float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); - // TODO: a floating motor so object will bob in the water - if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) - { - // Upforce proportional to the distance away from the water. Correct the error in 1 sec. - upForce.Z = (waterHeight - RawPosition.Z) * 1f; - ret = true; - } - } - - // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. - // TODO: This should be intergrated with a geneal physics action mechanism. - // TODO: This should be moderated with PID'ness. - if (ret) - { - // Apply upforce and overcome gravity. - OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; - DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); - AddForce(correctionForce, false, inTaintTime); - } - return ret; - } - - // Return the effective mass of the object. - // The definition of this call is to return the mass of the prim. - // If the simulator cares about the mass of the linkset, it will sum it itself. - public override float Mass - { - get - { - return _mass; - } - } - - // used when we only want this prim's mass and not the linkset thing - public override float RawMass { - get { return _mass; } - } - // Set the physical mass to the passed mass. - // Note that this does not change _mass! - public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) - { - if (PhysBody.HasPhysicalBody) - { - if (IsStatic) - { - PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity); - Inertia = OMV.Vector3.Zero; - PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia); - PhysicsScene.PE.UpdateInertiaTensor(PhysBody); - } - else - { - OMV.Vector3 grav = ComputeGravity(); - - if (inWorld) - { - // Changing interesting properties doesn't change proxy and collision cache - // information. The Bullet solution is to re-add the object to the world - // after parameters are changed. - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); - } - - // The computation of mass props requires gravity to be set on the object. - PhysicsScene.PE.SetGravity(PhysBody, grav); - - Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); - PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); - PhysicsScene.PE.UpdateInertiaTensor(PhysBody); - - // center of mass is at the zero of the object - // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(PhysBody, ForcePosition, ForceOrientation); - DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", LocalID, physMass, Inertia, grav, inWorld); - - if (inWorld) - { - AddObjectToPhysicalWorld(); - } - - // Must set gravity after it has been added to the world because, for unknown reasons, - // adding the object resets the object's gravity to world gravity - PhysicsScene.PE.SetGravity(PhysBody, grav); - - } - } - } - - // Return what gravity should be set to this very moment - private OMV.Vector3 ComputeGravity() - { - OMV.Vector3 ret = PhysicsScene.DefaultGravity; - - if (!IsStatic) - ret *= (1f - Buoyancy); - - return ret; - } - - // Is this used? - public override OMV.Vector3 CenterOfMass - { - get { return Linkset.CenterOfMass; } - } - - // Is this used? - public override OMV.Vector3 GeometricCenter - { - get { return Linkset.GeometricCenter; } - } - - public override OMV.Vector3 Force { - get { return _force; } - set { - _force = value; - if (_force != OMV.Vector3.Zero) - { - // If the force is non-zero, it must be reapplied each tick because - // Bullet clears the forces applied last frame. - RegisterPreStepAction("BSPrim.setForce", LocalID, - delegate(float timeStep) - { - DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); - if (PhysBody.HasPhysicalBody) - { - PhysicsScene.PE.ApplyCentralForce(PhysBody, _force); - ActivateIfPhysical(false); - } - } - ); - } - else - { - UnRegisterPreStepAction("BSPrim.setForce", LocalID); - } - } - } - - public override int VehicleType { - get { - return (int)_vehicle.Type; // if we are a vehicle, return that type - } - set { - Vehicle type = (Vehicle)value; - - PhysicsScene.TaintedObject("setVehicleType", delegate() - { - // Done at taint time so we're sure the physics engine is not using the variables - // Vehicle code changes the parameters for this vehicle type. - _vehicle.ProcessTypeChange(type); - ActivateIfPhysical(false); - - // If an active vehicle, register the vehicle code to be called before each step - if (_vehicle.Type == Vehicle.TYPE_NONE) - UnRegisterPreStepAction("BSPrim.Vehicle", LocalID); - else - RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step); - }); - } - } - public override void VehicleFloatParam(int param, float value) - { - PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() - { - _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); - ActivateIfPhysical(false); - }); - } - public override void VehicleVectorParam(int param, OMV.Vector3 value) - { - PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() - { - _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); - ActivateIfPhysical(false); - }); - } - public override void VehicleRotationParam(int param, OMV.Quaternion rotation) - { - PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() - { - _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); - ActivateIfPhysical(false); - }); - } - public override void VehicleFlags(int param, bool remove) - { - PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() - { - _vehicle.ProcessVehicleFlags(param, remove); - }); - } - - // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more - public override void SetVolumeDetect(int param) { - bool newValue = (param != 0); - if (_isVolumeDetect != newValue) - { - _isVolumeDetect = newValue; - PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() - { - // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); - SetObjectDynamic(true); - }); - } - return; - } - public override OMV.Vector3 Velocity { - get { return _velocity; } - set { - _velocity = value; - PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() - { - // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); - ForceVelocity = _velocity; - }); - } - } - public override OMV.Vector3 ForceVelocity { - get { return _velocity; } - set { - PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); - - _velocity = value; - if (PhysBody.HasPhysicalBody) - { - PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); - ActivateIfPhysical(false); - } - } - } - public override OMV.Vector3 Torque { - get { return _torque; } - set { - _torque = value; - if (_torque != OMV.Vector3.Zero) - { - // If the torque is non-zero, it must be reapplied each tick because - // Bullet clears the forces applied last frame. - RegisterPreStepAction("BSPrim.setTorque", LocalID, - delegate(float timeStep) - { - if (PhysBody.HasPhysicalBody) - AddAngularForce(_torque, false, true); - } - ); - } - else - { - UnRegisterPreStepAction("BSPrim.setTorque", LocalID); - } - // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); - } - } - public override float CollisionScore { - get { return _collisionScore; } - set { _collisionScore = value; - } - } - public override OMV.Vector3 Acceleration { - get { return _acceleration; } - set { _acceleration = value; } - } - public override OMV.Quaternion RawOrientation - { - get { return _orientation; } - set { _orientation = value; } - } - public override OMV.Quaternion Orientation { - get { - /* NOTE: this refetch is not necessary. The simulator knows about linkset children - * and does not fetch this position info for children. Thus this is commented out. - // Children move around because tied to parent. Get a fresh value. - if (!Linkset.IsRoot(this)) - { - _orientation = Linkset.OrientationGet(this); - } - */ - return _orientation; - } - set { - if (_orientation == value) - return; - _orientation = value; - - // A linkset might need to know if a component information changed. - Linkset.UpdateProperties(this, false); - - PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() - { - if (PhysBody.HasPhysicalBody) - { - // _position = PhysicsScene.PE.GetObjectPosition(PhysicsScene.World, BSBody); - // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); - PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); - } - }); - } - } - // Go directly to Bullet to get/set the value. - public override OMV.Quaternion ForceOrientation - { - get - { - _orientation = PhysicsScene.PE.GetOrientation(PhysBody); - return _orientation; - } - set - { - _orientation = value; - PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); - } - } - public override int PhysicsActorType { - get { return _physicsActorType; } - set { _physicsActorType = value; } - } - public override bool IsPhysical { - get { return _isPhysical; } - set { - if (_isPhysical != value) - { - _isPhysical = value; - PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() - { - DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); - SetObjectDynamic(true); - // whether phys-to-static or static-to-phys, the object is not moving. - ZeroMotion(true); - }); - } - } - } - - // An object is static (does not move) if selected or not physical - public override bool IsStatic - { - get { return _isSelected || !IsPhysical; } - } - - // An object is solid if it's not phantom and if it's not doing VolumeDetect - public override bool IsSolid - { - get { return !IsPhantom && !_isVolumeDetect; } - } - - // Make gravity work if the object is physical and not selected - // Called at taint-time!! - private void SetObjectDynamic(bool forceRebuild) - { - // Recreate the physical object if necessary - CreateGeomAndObject(forceRebuild); - } - - // Convert the simulator's physical properties into settings on BulletSim objects. - // There are four flags we're interested in: - // IsStatic: Object does not move, otherwise the object has mass and moves - // isSolid: other objects bounce off of this object - // isVolumeDetect: other objects pass through but can generate collisions - // collisionEvents: whether this object returns collision events - private void UpdatePhysicalParameters() - { - // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape); - - // Mangling all the physical properties requires the object not be in the physical world. - // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); - - // Set up the object physicalness (does gravity and collisions move this object) - MakeDynamic(IsStatic); - - // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) - _vehicle.Refresh(); - - // Arrange for collision events if the simulator wants them - EnableCollisions(SubscribedEvents()); - - // Make solid or not (do things bounce off or pass through this object). - MakeSolid(IsSolid); - - AddObjectToPhysicalWorld(); - - // Rebuild its shape - PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); - - // Recompute any linkset parameters. - // When going from non-physical to physical, this re-enables the constraints that - // had been automatically disabled when the mass was set to zero. - // For compound based linksets, this enables and disables interactions of the children. - Linkset.Refresh(this); - - DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", - LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); - } - - // "Making dynamic" means changing to and from static. - // When static, gravity does not effect the object and it is fixed in space. - // When dynamic, the object can fall and be pushed by others. - // This is independent of its 'solidness' which controls what passes through - // this object and what interacts with it. - private void MakeDynamic(bool makeStatic) - { - if (makeStatic) - { - // Become a Bullet 'static' object type - CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); - // Stop all movement - ZeroMotion(true); - - // Set various physical properties so other object interact properly - MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); - PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction); - PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution); - - // Mass is zero which disables a bunch of physics stuff in Bullet - UpdatePhysicalMassProperties(0f, false); - // Set collision detection parameters - if (BSParam.CcdMotionThreshold > 0f) - { - PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); - PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); - } - - // The activation state is 'disabled' so Bullet will not try to act on it. - // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); - // Start it out sleeping and physical actions could wake it up. - PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); - - // This collides like a static object - PhysBody.collisionType = CollisionType.Static; - - // There can be special things needed for implementing linksets - Linkset.MakeStatic(this); - } - else - { - // Not a Bullet static object - CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); - - // Set various physical properties so other object interact properly - MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true); - PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction); - PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution); - - // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 - // Since this can be called multiple times, only zero forces when becoming physical - // PhysicsScene.PE.ClearAllForces(BSBody); - - // For good measure, make sure the transform is set through to the motion state - PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); - - // Center of mass is at the center of the object - // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(Linkset.LinksetRoot.PhysBody, _position, _orientation); - - // A dynamic object has mass - UpdatePhysicalMassProperties(RawMass, false); - - // Set collision detection parameters - if (BSParam.CcdMotionThreshold > 0f) - { - PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); - PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); - } - - // Various values for simulation limits - PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); - PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); - PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); - PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); - - // This collides like an object. - PhysBody.collisionType = CollisionType.Dynamic; - - // Force activation of the object so Bullet will act on it. - // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. - PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); - - // There might be special things needed for implementing linksets. - Linkset.MakeDynamic(this); - } - } - - // "Making solid" means that other object will not pass through this object. - // To make transparent, we create a Bullet ghost object. - // Note: This expects to be called from the UpdatePhysicalParameters() routine as - // the functions after this one set up the state of a possibly newly created collision body. - private void MakeSolid(bool makeSolid) - { - CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody); - if (makeSolid) - { - // Verify the previous code created the correct shape for this type of thing. - if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0) - { - m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); - } - CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); - } - else - { - if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0) - { - m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); - } - CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); - - // Change collision info from a static object to a ghosty collision object - PhysBody.collisionType = CollisionType.VolumeDetect; - } - } - - // Enable physical actions. Bullet will keep sleeping non-moving physical objects so - // they need waking up when parameters are changed. - // Called in taint-time!! - private void ActivateIfPhysical(bool forceIt) - { - if (IsPhysical && PhysBody.HasPhysicalBody) - PhysicsScene.PE.Activate(PhysBody, forceIt); - } - - // Turn on or off the flag controlling whether collision events are returned to the simulator. - private void EnableCollisions(bool wantsCollisionEvents) - { - if (wantsCollisionEvents) - { - CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - } - else - { - CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - } - } - - // Add me to the physical world. - // Object MUST NOT already be in the world. - // This routine exists because some assorted properties get mangled by adding to the world. - internal void AddObjectToPhysicalWorld() - { - if (PhysBody.HasPhysicalBody) - { - PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); - } - else - { - m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID); - DetailLog("{0},BSPrim.UpdatePhysicalParameters,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType); - } - } - - // prims don't fly - public override bool Flying { - get { return _flying; } - set { - _flying = value; - } - } - public override bool SetAlwaysRun { - get { return _setAlwaysRun; } - set { _setAlwaysRun = value; } - } - public override bool ThrottleUpdates { - get { return _throttleUpdates; } - set { _throttleUpdates = value; } - } - public bool IsPhantom { - get { - // SceneObjectPart removes phantom objects from the physics scene - // so, although we could implement touching and such, we never - // are invoked as a phantom object - return false; - } - } - public override bool FloatOnWater { - set { - _floatOnWater = value; - PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() - { - if (_floatOnWater) - CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); - else - CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); - }); - } - } - public override OMV.Vector3 RotationalVelocity { - get { - return _rotationalVelocity; - } - set { - _rotationalVelocity = value; - // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); - PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() - { - DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); - ForceRotationalVelocity = _rotationalVelocity; - }); - } - } - public override OMV.Vector3 ForceRotationalVelocity { - get { - return _rotationalVelocity; - } - set { - _rotationalVelocity = value; - if (PhysBody.HasPhysicalBody) - { - PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); - ActivateIfPhysical(false); - } - } - } - public override bool Kinematic { - get { return _kinematic; } - set { _kinematic = value; - // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); - } - } - public override float Buoyancy { - get { return _buoyancy; } - set { - _buoyancy = value; - PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() - { - ForceBuoyancy = _buoyancy; - }); - } - } - public override float ForceBuoyancy { - get { return _buoyancy; } - set { - _buoyancy = value; - // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); - // Force the recalculation of the various inertia,etc variables in the object - DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2}", LocalID, _buoyancy, _mass); - UpdatePhysicalMassProperties(_mass, true); - ActivateIfPhysical(false); - } - } - - // Used for MoveTo - public override OMV.Vector3 PIDTarget { - set { _PIDTarget = value; } - } - public override float PIDTau { - set { _PIDTau = value; } - } - public override bool PIDActive { - set { _usePID = value; } - } - - // Used for llSetHoverHeight and maybe vehicle height - // Hover Height will override MoveTo target's Z - public override bool PIDHoverActive { - set { _useHoverPID = value; } - } - public override float PIDHoverHeight { - set { _PIDHoverHeight = value; } - } - public override PIDHoverType PIDHoverType { - set { _PIDHoverType = value; } - } - public override float PIDHoverTau { - set { _PIDHoverTao = value; } - } - - // For RotLookAt - public override OMV.Quaternion APIDTarget { set { return; } } - public override bool APIDActive { set { return; } } - public override float APIDStrength { set { return; } } - public override float APIDDamping { set { return; } } - - public override void AddForce(OMV.Vector3 force, bool pushforce) { - // Since this force is being applied in only one step, make this a force per second. - OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; - AddForce(addForce, pushforce, false); - } - // Applying a force just adds this to the total force on the object. - // This added force will only last the next simulation tick. - public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { - // for an object, doesn't matter if force is a pushforce or not - if (force.IsFinite()) - { - float magnitude = force.Length(); - if (magnitude > BSParam.MaxAddForceMagnitude) - { - // Force has a limit - force = force / magnitude * BSParam.MaxAddForceMagnitude; - } - - OMV.Vector3 addForce = force; - DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); - - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() - { - // Bullet adds this central force to the total force for this tick - DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); - if (PhysBody.HasPhysicalBody) - { - PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); - ActivateIfPhysical(false); - } - }); - } - else - { - m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); - return; - } - } - - public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { - AddAngularForce(force, pushforce, false); - } - public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) - { - if (force.IsFinite()) - { - OMV.Vector3 angForce = force; - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() - { - if (PhysBody.HasPhysicalBody) - { - PhysicsScene.PE.ApplyTorque(PhysBody, angForce); - ActivateIfPhysical(false); - } - }); - } - else - { - m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); - return; - } - } - - // A torque impulse. - // ApplyTorqueImpulse adds torque directly to the angularVelocity. - // AddAngularForce accumulates the force and applied it to the angular velocity all at once. - // Computed as: angularVelocity += impulse * inertia; - public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) - { - OMV.Vector3 applyImpulse = impulse; - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() - { - if (PhysBody.HasPhysicalBody) - { - PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); - ActivateIfPhysical(false); - } - }); - } - - public override void SetMomentum(OMV.Vector3 momentum) { - // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); - } - #region Mass Calculation - - private float CalculateMass() - { - float volume = _size.X * _size.Y * _size.Z; // default - float tmp; - - float returnMass = 0; - float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f; - float hollowVolume = hollowAmount * hollowAmount; - - switch (BaseShape.ProfileShape) - { - case ProfileShape.Square: - // default box - - if (BaseShape.PathCurve == (byte)Extrusion.Straight) - { - if (hollowAmount > 0.0) - { - switch (BaseShape.HollowShape) - { - case HollowShape.Square: - case HollowShape.Same: - break; - - case HollowShape.Circle: - - hollowVolume *= 0.78539816339f; - break; - - case HollowShape.Triangle: - - hollowVolume *= (0.5f * .5f); - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - - else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) - { - //a tube - - volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX); - tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY); - volume -= volume*tmp*tmp; - - if (hollowAmount > 0.0) - { - hollowVolume *= hollowAmount; - - switch (BaseShape.HollowShape) - { - case HollowShape.Square: - case HollowShape.Same: - break; - - case HollowShape.Circle: - hollowVolume *= 0.78539816339f;; - break; - - case HollowShape.Triangle: - hollowVolume *= 0.5f * 0.5f; - break; - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - - break; - - case ProfileShape.Circle: - - if (BaseShape.PathCurve == (byte)Extrusion.Straight) - { - volume *= 0.78539816339f; // elipse base - - if (hollowAmount > 0.0) - { - switch (BaseShape.HollowShape) - { - case HollowShape.Same: - case HollowShape.Circle: - break; - - case HollowShape.Square: - hollowVolume *= 0.5f * 2.5984480504799f; - break; - - case HollowShape.Triangle: - hollowVolume *= .5f * 1.27323954473516f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - - else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) - { - volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX); - tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); - volume *= (1.0f - tmp * tmp); - - if (hollowAmount > 0.0) - { - - // calculate the hollow volume by it's shape compared to the prim shape - hollowVolume *= hollowAmount; - - switch (BaseShape.HollowShape) - { - case HollowShape.Same: - case HollowShape.Circle: - break; - - case HollowShape.Square: - hollowVolume *= 0.5f * 2.5984480504799f; - break; - - case HollowShape.Triangle: - hollowVolume *= .5f * 1.27323954473516f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - break; - - case ProfileShape.HalfCircle: - if (BaseShape.PathCurve == (byte)Extrusion.Curve1) - { - volume *= 0.52359877559829887307710723054658f; - } - break; - - case ProfileShape.EquilateralTriangle: - - if (BaseShape.PathCurve == (byte)Extrusion.Straight) - { - volume *= 0.32475953f; - - if (hollowAmount > 0.0) - { - - // calculate the hollow volume by it's shape compared to the prim shape - switch (BaseShape.HollowShape) - { - case HollowShape.Same: - case HollowShape.Triangle: - hollowVolume *= .25f; - break; - - case HollowShape.Square: - hollowVolume *= 0.499849f * 3.07920140172638f; - break; - - case HollowShape.Circle: - // Hollow shape is a perfect cyllinder in respect to the cube's scale - // Cyllinder hollow volume calculation - - hollowVolume *= 0.1963495f * 3.07920140172638f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) - { - volume *= 0.32475953f; - volume *= 0.01f * (float)(200 - BaseShape.PathScaleX); - tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); - volume *= (1.0f - tmp * tmp); - - if (hollowAmount > 0.0) - { - - hollowVolume *= hollowAmount; - - switch (BaseShape.HollowShape) - { - case HollowShape.Same: - case HollowShape.Triangle: - hollowVolume *= .25f; - break; - - case HollowShape.Square: - hollowVolume *= 0.499849f * 3.07920140172638f; - break; - - case HollowShape.Circle: - - hollowVolume *= 0.1963495f * 3.07920140172638f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - break; - - default: - break; - } - - - - float taperX1; - float taperY1; - float taperX; - float taperY; - float pathBegin; - float pathEnd; - float profileBegin; - float profileEnd; - - if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible) - { - taperX1 = BaseShape.PathScaleX * 0.01f; - if (taperX1 > 1.0f) - taperX1 = 2.0f - taperX1; - taperX = 1.0f - taperX1; - - taperY1 = BaseShape.PathScaleY * 0.01f; - if (taperY1 > 1.0f) - taperY1 = 2.0f - taperY1; - taperY = 1.0f - taperY1; - } - else - { - taperX = BaseShape.PathTaperX * 0.01f; - if (taperX < 0.0f) - taperX = -taperX; - taperX1 = 1.0f - taperX; - - taperY = BaseShape.PathTaperY * 0.01f; - if (taperY < 0.0f) - taperY = -taperY; - taperY1 = 1.0f - taperY; - - } - - - volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); - - pathBegin = (float)BaseShape.PathBegin * 2.0e-5f; - pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f; - volume *= (pathEnd - pathBegin); - - // this is crude aproximation - profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f; - profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; - volume *= (profileEnd - profileBegin); - - returnMass = _density * volume; - - /* Comment out code that computes the mass of the linkset. That is done in the Linkset class. - if (IsRootOfLinkset) - { - foreach (BSPrim prim in _childrenPrims) - { - returnMass += prim.CalculateMass(); - } - } - */ - - returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); - - return returnMass; - }// end CalculateMass - #endregion Mass Calculation - - // Rebuild the geometry and object. - // This is called when the shape changes so we need to recreate the mesh/hull. - // Called at taint-time!!! - public void CreateGeomAndObject(bool forceRebuild) - { - // If this prim is part of a linkset, we must remove and restore the physical - // links if the body is rebuilt. - bool needToRestoreLinkset = false; - bool needToRestoreVehicle = false; - - // Create the correct physical representation for this type of object. - // Updates PhysBody and PhysShape with the new information. - // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. - PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) - { - // Called if the current prim body is about to be destroyed. - // Remove all the physical dependencies on the old body. - // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) - needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); - needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); - }); - - if (needToRestoreLinkset) - { - // If physical body dependencies were removed, restore them - Linkset.RestoreBodyDependencies(this); - } - if (needToRestoreVehicle) - { - // If physical body dependencies were removed, restore them - _vehicle.RestoreBodyDependencies(this); - } - - // Make sure the properties are set on the new object - UpdatePhysicalParameters(); - return; - } - - // The physics engine says that properties have updated. Update same and inform - // the world that things have changed. - // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate() - enum UpdatedProperties { - Position = 1 << 0, - Rotation = 1 << 1, - Velocity = 1 << 2, - Acceleration = 1 << 3, - RotationalVel = 1 << 4 - } - - const float ROTATION_TOLERANCE = 0.01f; - const float VELOCITY_TOLERANCE = 0.001f; - const float POSITION_TOLERANCE = 0.05f; - const float ACCELERATION_TOLERANCE = 0.01f; - const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; - - public override void UpdateProperties(EntityProperties entprop) - { - // Updates only for individual prims and for the root object of a linkset. - if (Linkset.IsRoot(this)) - { - // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet - // TODO: handle physics introduced by Bullet with computed vehicle physics. - if (_vehicle.IsActive) - { - entprop.RotationalVelocity = OMV.Vector3.Zero; - } - - // Assign directly to the local variables so the normal set action does not happen - _position = entprop.Position; - _orientation = entprop.Rotation; - _velocity = entprop.Velocity; - _acceleration = entprop.Acceleration; - _rotationalVelocity = entprop.RotationalVelocity; - - // The sanity check can change the velocity and/or position. - if (IsPhysical && PositionSanityCheck(true)) - { - entprop.Position = _position; - entprop.Velocity = _velocity; - } - - OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG - DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", - LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); - - // remember the current and last set values - LastEntityProperties = CurrentEntityProperties; - CurrentEntityProperties = entprop; - - base.RequestPhysicsterseUpdate(); - } - /* - else - { - // For debugging, report the movement of children - DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", - LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, - entprop.Acceleration, entprop.RotationalVelocity); - } - */ - - // The linkset implimentation might want to know about this. - Linkset.UpdateProperties(this, true); - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs deleted file mode 100644 index 7017194..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ /dev/null @@ -1,946 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using OpenSim.Framework; -using OpenSim.Region.Framework; -using OpenSim.Region.CoreModules; -using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging; -using OpenSim.Region.Physics.Manager; -using Nini.Config; -using log4net; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -public sealed class BSScene : PhysicsScene, IPhysicsParameters -{ - internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - internal static readonly string LogHeader = "[BULLETS SCENE]"; - - // The name of the region we're working for. - public string RegionName { get; private set; } - - public string BulletSimVersion = "?"; - - // The handle to the underlying managed or unmanaged version of Bullet being used. - public string BulletEngineName { get; private set; } - public BSAPITemplate PE; - - public Dictionary PhysObjects; - public BSShapeCollection Shapes; - - // Keeping track of the objects with collisions so we can report begin and end of a collision - public HashSet ObjectsWithCollisions = new HashSet(); - public HashSet ObjectsWithNoMoreCollisions = new HashSet(); - // Keep track of all the avatars so we can send them a collision event - // every tick so OpenSim will update its animation. - private HashSet m_avatars = new HashSet(); - - // let my minuions use my logger - public ILog Logger { get { return m_log; } } - - public IMesher mesher; - public uint WorldID { get; private set; } - public BulletWorld World { get; private set; } - - // All the constraints that have been allocated in this instance. - public BSConstraintCollection Constraints { get; private set; } - - // Simulation parameters - internal int m_maxSubSteps; - internal float m_fixedTimeStep; - internal long m_simulationStep = 0; - internal float NominalFrameRate { get; set; } - public long SimulationStep { get { return m_simulationStep; } } - internal int m_taintsToProcessPerStep; - internal float LastTimeStep { get; private set; } - - // Physical objects can register for prestep or poststep events - public delegate void PreStepAction(float timeStep); - public delegate void PostStepAction(float timeStep); - public event PreStepAction BeforeStep; - public event PreStepAction AfterStep; - - // A value of the time now so all the collision and update routines do not have to get their own - // Set to 'now' just before all the prims and actors are called for collisions and updates - public int SimulationNowTime { get; private set; } - - // True if initialized and ready to do simulation steps - private bool m_initialized = false; - - // Flag which is true when processing taints. - // Not guaranteed to be correct all the time (don't depend on this) but good for debugging. - public bool InTaintTime { get; private set; } - - // Pinned memory used to pass step information between managed and unmanaged - internal int m_maxCollisionsPerFrame; - internal CollisionDesc[] m_collisionArray; - - internal int m_maxUpdatesPerFrame; - internal EntityProperties[] m_updateArray; - - public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero - public const uint GROUNDPLANE_ID = 1; - public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here - - public float SimpleWaterLevel { get; set; } - public BSTerrainManager TerrainManager { get; private set; } - - public ConfigurationParameters Params - { - get { return UnmanagedParams[0]; } - } - public Vector3 DefaultGravity - { - get { return new Vector3(0f, 0f, Params.gravity); } - } - // Just the Z value of the gravity - public float DefaultGravityZ - { - get { return Params.gravity; } - } - - // When functions in the unmanaged code must be called, it is only - // done at a known time just before the simulation step. The taint - // system saves all these function calls and executes them in - // order before the simulation. - public delegate void TaintCallback(); - private struct TaintCallbackEntry - { - public String ident; - public TaintCallback callback; - public TaintCallbackEntry(string i, TaintCallback c) - { - ident = i; - callback = c; - } - } - private Object _taintLock = new Object(); // lock for using the next object - private List _taintOperations; - private Dictionary _postTaintOperations; - private List _postStepOperations; - - // A pointer to an instance if this structure is passed to the C++ code - // Used to pass basic configuration values to the unmanaged code. - internal ConfigurationParameters[] UnmanagedParams; - - // Sometimes you just have to log everything. - public Logging.LogWriter PhysicsLogging; - private bool m_physicsLoggingEnabled; - private string m_physicsLoggingDir; - private string m_physicsLoggingPrefix; - private int m_physicsLoggingFileMinutes; - private bool m_physicsLoggingDoFlush; - private bool m_physicsPhysicalDumpEnabled; - public float PhysicsMetricDumpFrames { get; set; } - // 'true' of the vehicle code is to log lots of details - public bool VehicleLoggingEnabled { get; private set; } - public bool VehiclePhysicalLoggingEnabled { get; private set; } - - #region Construction and Initialization - public BSScene(string identifier) - { - m_initialized = false; - // we are passed the name of the region we're working for. - RegionName = identifier; - } - - public override void Initialise(IMesher meshmerizer, IConfigSource config) - { - mesher = meshmerizer; - _taintOperations = new List(); - _postTaintOperations = new Dictionary(); - _postStepOperations = new List(); - PhysObjects = new Dictionary(); - Shapes = new BSShapeCollection(this); - - // Allocate pinned memory to pass parameters. - UnmanagedParams = new ConfigurationParameters[1]; - - // Set default values for physics parameters plus any overrides from the ini file - GetInitialParameterValues(config); - - // Get the connection to the physics engine (could be native or one of many DLLs) - PE = SelectUnderlyingBulletEngine(BulletEngineName); - - // Enable very detailed logging. - // By creating an empty logger when not logging, the log message invocation code - // can be left in and every call doesn't have to check for null. - if (m_physicsLoggingEnabled) - { - PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); - PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages. - } - else - { - PhysicsLogging = new Logging.LogWriter(); - } - - // Allocate memory for returning of the updates and collisions from the physics engine - m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; - m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; - - // The bounding box for the simulated world. The origin is 0,0,0 unless we're - // a child in a mega-region. - // Bullet actually doesn't care about the extents of the simulated - // area. It tracks active objects no matter where they are. - Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); - - World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray); - - Constraints = new BSConstraintCollection(World); - - TerrainManager = new BSTerrainManager(this); - TerrainManager.CreateInitialGroundPlaneAndTerrain(); - - m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); - - InTaintTime = false; - m_initialized = true; - } - - // All default parameter values are set here. There should be no values set in the - // variable definitions. - private void GetInitialParameterValues(IConfigSource config) - { - ConfigurationParameters parms = new ConfigurationParameters(); - UnmanagedParams[0] = parms; - - BSParam.SetParameterDefaultValues(this); - - if (config != null) - { - // If there are specifications in the ini file, use those values - IConfig pConfig = config.Configs["BulletSim"]; - if (pConfig != null) - { - BSParam.SetParameterConfigurationValues(this, pConfig); - - // There are two Bullet implementations to choose from - BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged"); - - // Very detailed logging for physics debugging - // TODO: the boolean values can be moved to the normal parameter processing. - m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); - m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); - m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); - m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); - m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false); - m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false); - // Very detailed logging for vehicle debugging - VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); - VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false); - - // Do any replacements in the parameters - m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); - } - - // The material characteristics. - BSMaterials.InitializeFromDefaults(Params); - if (pConfig != null) - { - // Let the user add new and interesting material property values. - BSMaterials.InitializefromParameters(pConfig); - } - } - } - - // A helper function that handles a true/false parameter and returns the proper float number encoding - float ParamBoolean(IConfig config, string parmName, float deflt) - { - float ret = deflt; - if (config.Contains(parmName)) - { - ret = ConfigurationParameters.numericFalse; - if (config.GetBoolean(parmName, false)) - { - ret = ConfigurationParameters.numericTrue; - } - } - return ret; - } - - // Select the connection to the actual Bullet implementation. - // The main engine selection is the engineName up to the first hypen. - // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name - // is passed to the engine to do its special selection, etc. - private BSAPITemplate SelectUnderlyingBulletEngine(string engineName) - { - // For the moment, do a simple switch statement. - // Someday do fancyness with looking up the interfaces in the assembly. - BSAPITemplate ret = null; - - string selectionName = engineName.ToLower(); - int hyphenIndex = engineName.IndexOf("-"); - if (hyphenIndex > 0) - selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1); - - switch (selectionName) - { - case "bulletunmanaged": - ret = new BSAPIUnman(engineName, this); - break; - case "bulletxna": - ret = new BSAPIXNA(engineName, this); - break; - } - - if (ret == null) - { - m_log.ErrorFormat("{0) COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader); - } - else - { - m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); - } - - return ret; - } - - public override void Dispose() - { - // m_log.DebugFormat("{0}: Dispose()", LogHeader); - - // make sure no stepping happens while we're deleting stuff - m_initialized = false; - - foreach (KeyValuePair kvp in PhysObjects) - { - kvp.Value.Destroy(); - } - PhysObjects.Clear(); - - // Now that the prims are all cleaned up, there should be no constraints left - if (Constraints != null) - { - Constraints.Dispose(); - Constraints = null; - } - - if (Shapes != null) - { - Shapes.Dispose(); - Shapes = null; - } - - if (TerrainManager != null) - { - TerrainManager.ReleaseGroundPlaneAndTerrain(); - TerrainManager.Dispose(); - TerrainManager = null; - } - - // Anything left in the unmanaged code should be cleaned out - PE.Shutdown(World); - - // Not logging any more - PhysicsLogging.Close(); - } - #endregion // Construction and Initialization - - #region Prim and Avatar addition and removal - - public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) - { - m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); - return null; - } - - public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying) - { - // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName); - - if (!m_initialized) return null; - - BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); - lock (PhysObjects) PhysObjects.Add(localID, actor); - - // TODO: Remove kludge someday. - // We must generate a collision for avatars whether they collide or not. - // This is required by OpenSim to update avatar animations, etc. - lock (m_avatars) m_avatars.Add(actor); - - return actor; - } - - public override void RemoveAvatar(PhysicsActor actor) - { - // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); - - if (!m_initialized) return; - - BSCharacter bsactor = actor as BSCharacter; - if (bsactor != null) - { - try - { - lock (PhysObjects) PhysObjects.Remove(actor.LocalID); - // Remove kludge someday - lock (m_avatars) m_avatars.Remove(bsactor); - } - catch (Exception e) - { - m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); - } - bsactor.Destroy(); - // bsactor.dispose(); - } - } - - public override void RemovePrim(PhysicsActor prim) - { - if (!m_initialized) return; - - BSPrim bsprim = prim as BSPrim; - if (bsprim != null) - { - DetailLog("{0},RemovePrim,call", bsprim.LocalID); - // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); - try - { - lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID); - } - catch (Exception e) - { - m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); - } - bsprim.Destroy(); - // bsprim.dispose(); - } - else - { - m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader); - } - } - - public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, - Vector3 size, Quaternion rotation, bool isPhysical, uint localID) - { - // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName); - - if (!m_initialized) return null; - - DetailLog("{0},AddPrimShape,call", localID); - - BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); - lock (PhysObjects) PhysObjects.Add(localID, prim); - return prim; - } - - // This is a call from the simulator saying that some physical property has been updated. - // The BulletSim driver senses the changing of relevant properties so this taint - // information call is not needed. - public override void AddPhysicsActorTaint(PhysicsActor prim) { } - - #endregion // Prim and Avatar addition and removal - - #region Simulation - // Simulate one timestep - public override float Simulate(float timeStep) - { - // prevent simulation until we've been initialized - if (!m_initialized) return 5.0f; - - LastTimeStep = timeStep; - - int updatedEntityCount = 0; - int collidersCount = 0; - - int beforeTime = 0; - int simTime = 0; - - // update the prim states while we know the physics engine is not busy - int numTaints = _taintOperations.Count; - - InTaintTime = true; // Only used for debugging so locking is not necessary. - - ProcessTaints(); - - // Some of the physical objects requre individual, pre-step calls - TriggerPreStepEvent(timeStep); - - // the prestep actions might have added taints - numTaints += _taintOperations.Count; - ProcessTaints(); - - InTaintTime = false; // Only used for debugging so locking is not necessary. - - // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. - // Only enable this in a limited test world with few objects. - if (m_physicsPhysicalDumpEnabled) - PE.DumpAllInfo(World); - - // step the physical world one interval - m_simulationStep++; - int numSubSteps = 0; - try - { - if (PhysicsLogging.Enabled) - beforeTime = Util.EnvironmentTickCount(); - - numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); - - if (PhysicsLogging.Enabled) - { - simTime = Util.EnvironmentTickCountSubtract(beforeTime); - DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", - DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, - updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); - } - } - catch (Exception e) - { - m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}", - LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e); - DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}", - DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); - updatedEntityCount = 0; - collidersCount = 0; - } - - if ((m_simulationStep % PhysicsMetricDumpFrames) == 0) - PE.DumpPhysicsStatistics(World); - - // Get a value for 'now' so all the collision and update routines don't have to get their own. - SimulationNowTime = Util.EnvironmentTickCount(); - - // If there were collisions, process them by sending the event to the prim. - // Collisions must be processed before updates. - if (collidersCount > 0) - { - for (int ii = 0; ii < collidersCount; ii++) - { - uint cA = m_collisionArray[ii].aID; - uint cB = m_collisionArray[ii].bID; - Vector3 point = m_collisionArray[ii].point; - Vector3 normal = m_collisionArray[ii].normal; - SendCollision(cA, cB, point, normal, 0.01f); - SendCollision(cB, cA, point, -normal, 0.01f); - } - } - - // The above SendCollision's batch up the collisions on the objects. - // Now push the collisions into the simulator. - if (ObjectsWithCollisions.Count > 0) - { - foreach (BSPhysObject bsp in ObjectsWithCollisions) - if (!bsp.SendCollisions()) - { - // If the object is done colliding, see that it's removed from the colliding list - ObjectsWithNoMoreCollisions.Add(bsp); - } - } - - // This is a kludge to get avatar movement updates. - // The simulator expects collisions for avatars even if there are have been no collisions. - // The event updates avatar animations and stuff. - // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. - foreach (BSPhysObject bsp in m_avatars) - if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice - bsp.SendCollisions(); - - // Objects that are done colliding are removed from the ObjectsWithCollisions list. - // Not done above because it is inside an iteration of ObjectWithCollisions. - // This complex collision processing is required to create an empty collision - // event call after all real collisions have happened on an object. This enables - // the simulator to generate the 'collision end' event. - if (ObjectsWithNoMoreCollisions.Count > 0) - { - foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) - ObjectsWithCollisions.Remove(po); - ObjectsWithNoMoreCollisions.Clear(); - } - // Done with collisions. - - // If any of the objects had updated properties, tell the object it has been changed by the physics engine - if (updatedEntityCount > 0) - { - for (int ii = 0; ii < updatedEntityCount; ii++) - { - EntityProperties entprop = m_updateArray[ii]; - BSPhysObject pobj; - if (PhysObjects.TryGetValue(entprop.ID, out pobj)) - { - pobj.UpdateProperties(entprop); - } - } - } - - TriggerPostStepEvent(timeStep); - - // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. - // Only enable this in a limited test world with few objects. - if (m_physicsPhysicalDumpEnabled) - PE.DumpAllInfo(World); - - // The physics engine returns the number of milliseconds it simulated this call. - // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. - // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). - return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; - } - - // Something has collided - private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration) - { - if (localID <= TerrainManager.HighestTerrainID) - { - return; // don't send collisions to the terrain - } - - BSPhysObject collider; - if (!PhysObjects.TryGetValue(localID, out collider)) - { - // If the object that is colliding cannot be found, just ignore the collision. - DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith); - return; - } - - // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. - BSPhysObject collidee = null; - PhysObjects.TryGetValue(collidingWith, out collidee); - - // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); - - if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) - { - // If a collision was posted, remember to send it to the simulator - ObjectsWithCollisions.Add(collider); - } - - return; - } - - #endregion // Simulation - - public override void GetResults() { } - - #region Terrain - - public override void SetTerrain(float[] heightMap) { - TerrainManager.SetTerrain(heightMap); - } - - public override void SetWaterLevel(float baseheight) - { - SimpleWaterLevel = baseheight; - } - - public override void DeleteTerrain() - { - // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); - } - - // Although no one seems to check this, I do support combining. - public override bool SupportsCombining() - { - return TerrainManager.SupportsCombining(); - } - // This call says I am a child to region zero in a mega-region. 'pScene' is that - // of region zero, 'offset' is my offset from regions zero's origin, and - // 'extents' is the largest XY that is handled in my region. - public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) - { - TerrainManager.Combine(pScene, offset, extents); - } - - // Unhook all the combining that I know about. - public override void UnCombine(PhysicsScene pScene) - { - TerrainManager.UnCombine(pScene); - } - - #endregion // Terrain - - public override Dictionary GetTopColliders() - { - return new Dictionary(); - } - - public override bool IsThreaded { get { return false; } } - - #region Taints - // The simulation execution order is: - // Simulate() - // DoOneTimeTaints - // TriggerPreStepEvent - // DoOneTimeTaints - // Step() - // ProcessAndForwardCollisions - // ProcessAndForwardPropertyUpdates - // TriggerPostStepEvent - - // Calls to the PhysicsActors can't directly call into the physics engine - // because it might be busy. We delay changes to a known time. - // We rely on C#'s closure to save and restore the context for the delegate. - public void TaintedObject(String ident, TaintCallback callback) - { - if (!m_initialized) return; - - lock (_taintLock) - { - _taintOperations.Add(new TaintCallbackEntry(ident, callback)); - } - - return; - } - - // Sometimes a potentially tainted operation can be used in and out of taint time. - // This routine executes the command immediately if in taint-time otherwise it is queued. - public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback) - { - if (inTaintTime) - callback(); - else - TaintedObject(ident, callback); - } - - private void TriggerPreStepEvent(float timeStep) - { - PreStepAction actions = BeforeStep; - if (actions != null) - actions(timeStep); - - } - - private void TriggerPostStepEvent(float timeStep) - { - PreStepAction actions = AfterStep; - if (actions != null) - actions(timeStep); - - } - - // When someone tries to change a property on a BSPrim or BSCharacter, the object queues - // a callback into itself to do the actual property change. That callback is called - // here just before the physics engine is called to step the simulation. - public void ProcessTaints() - { - ProcessRegularTaints(); - ProcessPostTaintTaints(); - } - - private void ProcessRegularTaints() - { - if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process - { - // swizzle a new list into the list location so we can process what's there - List oldList; - lock (_taintLock) - { - oldList = _taintOperations; - _taintOperations = new List(); - } - - foreach (TaintCallbackEntry tcbe in oldList) - { - try - { - DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG - tcbe.callback(); - } - catch (Exception e) - { - m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); - } - } - oldList.Clear(); - } - } - - // Schedule an update to happen after all the regular taints are processed. - // Note that new requests for the same operation ("ident") for the same object ("ID") - // will replace any previous operation by the same object. - public void PostTaintObject(String ident, uint ID, TaintCallback callback) - { - string uniqueIdent = ident + "-" + ID.ToString(); - lock (_taintLock) - { - _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback); - } - - return; - } - - // Taints that happen after the normal taint processing but before the simulation step. - private void ProcessPostTaintTaints() - { - if (_postTaintOperations.Count > 0) - { - Dictionary oldList; - lock (_taintLock) - { - oldList = _postTaintOperations; - _postTaintOperations = new Dictionary(); - } - - foreach (KeyValuePair kvp in oldList) - { - try - { - DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG - kvp.Value.callback(); - } - catch (Exception e) - { - m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e); - } - } - oldList.Clear(); - } - } - - // Only used for debugging. Does not change state of anything so locking is not necessary. - public bool AssertInTaintTime(string whereFrom) - { - if (!InTaintTime) - { - DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); - m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); - Util.PrintCallStack(DetailLog); - } - return InTaintTime; - } - - #endregion // Taints - - #region INI and command line parameter processing - - #region IPhysicsParameters - // Get the list of parameters this physics engine supports - public PhysParameterEntry[] GetParameterList() - { - BSParam.BuildParameterTable(); - return BSParam.SettableParameters; - } - - // Set parameter on a specific or all instances. - // Return 'false' if not able to set the parameter. - // Setting the value in the m_params block will change the value the physics engine - // will use the next time since it's pinned and shared memory. - // Some of the values require calling into the physics engine to get the new - // value activated ('terrainFriction' for instance). - public bool SetPhysicsParameter(string parm, float val, uint localID) - { - bool ret = false; - BSParam.ParameterDefn theParam; - if (BSParam.TryGetParameter(parm, out theParam)) - { - theParam.setter(this, parm, localID, val); - ret = true; - } - return ret; - } - - // update all the localIDs specified - // If the local ID is APPLY_TO_NONE, just change the default value - // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs - // If the localID is a specific object, apply the parameter change to only that object - internal delegate void AssignVal(float x); - internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val) - { - List objectIDs = new List(); - switch (localID) - { - case PhysParameterEntry.APPLY_TO_NONE: - setDefault(val); // setting only the default value - // This will cause a call into the physical world if some operation is specified (SetOnObject). - objectIDs.Add(TERRAIN_ID); - TaintedUpdateParameter(parm, objectIDs, val); - break; - case PhysParameterEntry.APPLY_TO_ALL: - setDefault(val); // setting ALL also sets the default value - lock (PhysObjects) objectIDs = new List(PhysObjects.Keys); - TaintedUpdateParameter(parm, objectIDs, val); - break; - default: - // setting only one localID - objectIDs.Add(localID); - TaintedUpdateParameter(parm, objectIDs, val); - break; - } - } - - // schedule the actual updating of the paramter to when the phys engine is not busy - private void TaintedUpdateParameter(string parm, List lIDs, float val) - { - float xval = val; - List xlIDs = lIDs; - string xparm = parm; - TaintedObject("BSScene.UpdateParameterSet", delegate() { - BSParam.ParameterDefn thisParam; - if (BSParam.TryGetParameter(xparm, out thisParam)) - { - if (thisParam.onObject != null) - { - foreach (uint lID in xlIDs) - { - BSPhysObject theObject = null; - PhysObjects.TryGetValue(lID, out theObject); - thisParam.onObject(this, theObject, xval); - } - } - } - }); - } - - // Get parameter. - // Return 'false' if not able to get the parameter. - public bool GetPhysicsParameter(string parm, out float value) - { - float val = 0f; - bool ret = false; - BSParam.ParameterDefn theParam; - if (BSParam.TryGetParameter(parm, out theParam)) - { - val = theParam.getter(this); - ret = true; - } - value = val; - return ret; - } - - #endregion IPhysicsParameters - - #endregion Runtime settable parameters - - // Invoke the detailed logger and output something if it's enabled. - public void DetailLog(string msg, params Object[] args) - { - PhysicsLogging.Write(msg, args); - // Add the Flush() if debugging crashes. Gets all the messages written out. - if (m_physicsLoggingDoFlush) PhysicsLogging.Flush(); - } - // Used to fill in the LocalID when there isn't one. It's the correct number of characters. - public const string DetailLogZero = "0000000000"; - -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs deleted file mode 100755 index d361f18..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ /dev/null @@ -1,1009 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using OMV = OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; -using OpenSim.Region.Physics.ConvexDecompositionDotNet; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -public sealed class BSShapeCollection : IDisposable -{ - private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; - - private BSScene PhysicsScene { get; set; } - - private Object m_collectionActivityLock = new Object(); - - // Description of a Mesh - private struct MeshDesc - { - public BulletShape shape; - public int referenceCount; - public DateTime lastReferenced; - public UInt64 shapeKey; - } - - // Description of a hull. - // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. - private struct HullDesc - { - public BulletShape shape; - public int referenceCount; - public DateTime lastReferenced; - public UInt64 shapeKey; - } - - // The sharable set of meshes and hulls. Indexed by their shape hash. - private Dictionary Meshes = new Dictionary(); - private Dictionary Hulls = new Dictionary(); - - private bool DDetail = false; - - public BSShapeCollection(BSScene physScene) - { - PhysicsScene = physScene; - // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) - // While detailed debugging is still active, this is better than commenting out all the - // DetailLog statements. When debugging slows down, this and the protected logging - // statements can be commented/removed. - DDetail = true; - } - - public void Dispose() - { - // TODO!!!!!!!!! - } - - // Callbacks called just before either the body or shape is destroyed. - // Mostly used for changing bodies out from under Linksets. - // Useful for other cases where parameters need saving. - // Passing 'null' says no callback. - public delegate void ShapeDestructionCallback(BulletShape shape); - public delegate void BodyDestructionCallback(BulletBody body); - - // Called to update/change the body and shape for an object. - // First checks the shape and updates that if necessary then makes - // sure the body is of the right type. - // Return 'true' if either the body or the shape changed. - // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before - // the current shape or body is destroyed. This allows the caller to remove any - // higher level dependencies on the shape or body. Mostly used for LinkSets to - // remove the physical constraints before the body is destroyed. - // Called at taint-time!! - public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, - ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) - { - PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); - - bool ret = false; - - // This lock could probably be pushed down lower but building shouldn't take long - lock (m_collectionActivityLock) - { - // Do we have the correct geometry for this type of object? - // Updates prim.BSShape with information/pointers to shape. - // Returns 'true' of BSShape is changed to a new shape. - bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback); - // If we had to select a new shape geometry for the object, - // rebuild the body around it. - // Updates prim.BSBody with information/pointers to requested body - // Returns 'true' if BSBody was changed. - bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, - prim.PhysShape, bodyCallback); - ret = newGeom || newBody; - } - DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", - prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape); - - return ret; - } - - public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) - { - return GetBodyAndShape(forceRebuild, sim, prim, null, null); - } - - // Track another user of a body. - // We presume the caller has allocated the body. - // Bodies only have one user so the body is just put into the world if not already there. - public void ReferenceBody(BulletBody body, bool inTaintTime) - { - lock (m_collectionActivityLock) - { - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); - PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() - { - if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) - { - PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body); - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); - } - }); - } - } - - // Release the usage of a body. - // Called when releasing use of a BSBody. BSShape is handled separately. - public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) - { - if (!body.HasPhysicalBody) - return; - - lock (m_collectionActivityLock) - { - PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() - { - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", - body.ID, body, inTaintTime); - // If the caller needs to know the old body is going away, pass the event up. - if (bodyCallback != null) bodyCallback(body); - - if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) - { - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body); - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); - } - - // Zero any reference to the shape so it is not freed when the body is deleted. - PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null); - PhysicsScene.PE.DestroyObject(PhysicsScene.World, body); - }); - } - } - - // Track the datastructures and use count for a shape. - // When creating a hull, this is called first to reference the mesh - // and then again to reference the hull. - // Meshes and hulls for the same shape have the same hash key. - // NOTE that native shapes are not added to the mesh list or removed. - // Returns 'true' if this is the initial reference to the shape. Otherwise reused. - public bool ReferenceShape(BulletShape shape) - { - bool ret = false; - switch (shape.type) - { - case BSPhysicsShapeType.SHAPE_MESH: - MeshDesc meshDesc; - if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) - { - // There is an existing instance of this mesh. - meshDesc.referenceCount++; - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", - BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); - } - else - { - // This is a new reference to a mesh - meshDesc.shape = shape.Clone(); - meshDesc.shapeKey = shape.shapeKey; - // We keep a reference to the underlying IMesh data so a hull can be built - meshDesc.referenceCount = 1; - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", - BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); - ret = true; - } - meshDesc.lastReferenced = System.DateTime.Now; - Meshes[shape.shapeKey] = meshDesc; - break; - case BSPhysicsShapeType.SHAPE_HULL: - HullDesc hullDesc; - if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) - { - // There is an existing instance of this hull. - hullDesc.referenceCount++; - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", - BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); - } - else - { - // This is a new reference to a hull - hullDesc.shape = shape.Clone(); - hullDesc.shapeKey = shape.shapeKey; - hullDesc.referenceCount = 1; - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", - BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); - ret = true; - - } - hullDesc.lastReferenced = System.DateTime.Now; - Hulls[shape.shapeKey] = hullDesc; - break; - case BSPhysicsShapeType.SHAPE_UNKNOWN: - break; - default: - // Native shapes are not tracked and they don't go into any list - break; - } - return ret; - } - - // Release the usage of a shape. - public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) - { - if (!shape.HasPhysicalShape) - return; - - PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() - { - if (shape.HasPhysicalShape) - { - if (shape.isNativeShape) - { - // Native shapes are not tracked and are released immediately - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", - BSScene.DetailLogZero, shape.AddrString, inTaintTime); - if (shapeCallback != null) shapeCallback(shape); - PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); - } - else - { - switch (shape.type) - { - case BSPhysicsShapeType.SHAPE_HULL: - DereferenceHull(shape, shapeCallback); - break; - case BSPhysicsShapeType.SHAPE_MESH: - DereferenceMesh(shape, shapeCallback); - break; - case BSPhysicsShapeType.SHAPE_COMPOUND: - DereferenceCompound(shape, shapeCallback); - break; - case BSPhysicsShapeType.SHAPE_UNKNOWN: - break; - default: - break; - } - } - } - }); - } - - // Count down the reference count for a mesh shape - // Called at taint-time. - private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback) - { - MeshDesc meshDesc; - if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) - { - meshDesc.referenceCount--; - // TODO: release the Bullet storage - if (shapeCallback != null) shapeCallback(shape); - meshDesc.lastReferenced = System.DateTime.Now; - Meshes[shape.shapeKey] = meshDesc; - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", - BSScene.DetailLogZero, shape, meshDesc.referenceCount); - - } - } - - // Count down the reference count for a hull shape - // Called at taint-time. - private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback) - { - HullDesc hullDesc; - if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) - { - hullDesc.referenceCount--; - // TODO: release the Bullet storage (aging old entries?) - - // Tell upper layers that, if they have dependencies on this shape, this link is going away - if (shapeCallback != null) shapeCallback(shape); - - hullDesc.lastReferenced = System.DateTime.Now; - Hulls[shape.shapeKey] = hullDesc; - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", - BSScene.DetailLogZero, shape, hullDesc.referenceCount); - } - } - - // Remove a reference to a compound shape. - // Taking a compound shape apart is a little tricky because if you just delete the - // physical shape, it will free all the underlying children. We can't do that because - // they could be shared. So, this removes each of the children from the compound and - // dereferences them separately before destroying the compound collision object itself. - // Called at taint-time. - private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) - { - if (!PhysicsScene.PE.IsCompound(shape)) - { - // Failed the sanity check!! - PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", - LogHeader, shape.type, shape.AddrString); - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", - BSScene.DetailLogZero, shape.type, shape.AddrString); - return; - } - - int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape); - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); - - for (int ii = numChildren - 1; ii >= 0; ii--) - { - BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii); - DereferenceAnonCollisionShape(childShape); - } - PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); - } - - // Sometimes we have a pointer to a collision shape but don't know what type it is. - // Figure out type and call the correct dereference routine. - // Called at taint-time. - private void DereferenceAnonCollisionShape(BulletShape shapeInfo) - { - MeshDesc meshDesc; - HullDesc hullDesc; - - if (TryGetMeshByPtr(shapeInfo, out meshDesc)) - { - shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; - shapeInfo.shapeKey = meshDesc.shapeKey; - } - else - { - if (TryGetHullByPtr(shapeInfo, out hullDesc)) - { - shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; - shapeInfo.shapeKey = hullDesc.shapeKey; - } - else - { - if (PhysicsScene.PE.IsCompound(shapeInfo)) - { - shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; - } - else - { - if (PhysicsScene.PE.IsNativeShape(shapeInfo)) - { - shapeInfo.isNativeShape = true; - shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) - } - } - } - } - - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); - - if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) - { - DereferenceShape(shapeInfo, true, null); - } - else - { - PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", - LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString); - } - } - - // Create the geometry information in Bullet for later use. - // The objects needs a hull if it's physical otherwise a mesh is enough. - // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls, - // shared geometries will be used. If the parameters of the existing shape are the same - // as this request, the shape is not rebuilt. - // Info in prim.BSShape is updated to the new shape. - // Returns 'true' if the geometry was rebuilt. - // Called at taint-time! - private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - bool ret = false; - bool haveShape = false; - - if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) - { - // an avatar capsule is close to a native shape (it is not shared) - GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); - ret = true; - haveShape = true; - } - - // Compound shapes are handled special as they are rebuilt from scratch. - // This isn't too great a hardship since most of the child shapes will have already been created. - if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) - { - ret = GetReferenceToCompoundShape(prim, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); - haveShape = true; - } - - if (!haveShape) - { - ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback); - } - - return ret; - } - - // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. - public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - bool ret = false; - bool haveShape = false; - bool nativeShapePossible = true; - PrimitiveBaseShape pbs = prim.BaseShape; - - // If the prim attributes are simple, this could be a simple Bullet native shape - if (!haveShape - && pbs != null - && nativeShapePossible - && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) - || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 - && pbs.ProfileHollow == 0 - && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 - && pbs.PathBegin == 0 && pbs.PathEnd == 0 - && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 - && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 - && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) - { - // Get the scale of any existing shape so we can see if the new shape is same native type and same size. - OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; - if (prim.PhysShape.HasPhysicalShape) - scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape); - - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", - prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); - - // It doesn't look like Bullet scales spheres so make sure the scales are all equal - if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) - && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) - { - haveShape = true; - if (forceRebuild - || prim.Scale != scaleOfExistingShape - || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE - ) - { - ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, - FixedShapeKey.KEY_SPHERE, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", - prim.LocalID, forceRebuild, prim.PhysShape); - } - } - if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) - { - haveShape = true; - if (forceRebuild - || prim.Scale != scaleOfExistingShape - || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX - ) - { - ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, - FixedShapeKey.KEY_BOX, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", - prim.LocalID, forceRebuild, prim.PhysShape); - } - } - } - - // If a simple shape is not happening, create a mesh and possibly a hull. - if (!haveShape && pbs != null) - { - ret = CreateGeomMeshOrHull(prim, shapeCallback); - } - - return ret; - } - - public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - - bool ret = false; - // Note that if it's a native shape, the check for physical/non-physical is not - // made. Native shapes work in either case. - if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) - { - // Update prim.BSShape to reference a hull of this shape. - ret = GetReferenceToHull(prim,shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", - prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); - } - else - { - ret = GetReferenceToMesh(prim, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", - prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); - } - return ret; - } - - // Creates a native shape and assignes it to prim.BSShape. - // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). - private bool GetReferenceToNativeShape(BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey, - ShapeDestructionCallback shapeCallback) - { - // release any previous shape - DereferenceShape(prim.PhysShape, true, shapeCallback); - - BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); - - // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. - if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", - prim.LocalID, newShape, prim.Scale); - - // native shapes are scaled by Bullet - prim.PhysShape = newShape; - return true; - } - - private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType, - FixedShapeKey shapeKey) - { - BulletShape newShape; - // Need to make sure the passed shape information is for the native type. - ShapeData nativeShapeData = new ShapeData(); - nativeShapeData.Type = shapeType; - nativeShapeData.ID = prim.LocalID; - nativeShapeData.Scale = prim.Scale; - nativeShapeData.Size = prim.Scale; // unneeded, I think. - nativeShapeData.MeshKey = (ulong)shapeKey; - nativeShapeData.HullKey = (ulong)shapeKey; - - if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) - { - - newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale); - if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); - } - else - { - // Native shapes are scaled in Bullet so set the scaling to the size - newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData); - - } - if (!newShape.HasPhysicalShape) - { - PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", - LogHeader, prim.LocalID, shapeType); - } - newShape.shapeKey = (System.UInt64)shapeKey; - newShape.isNativeShape = true; - - return newShape; - } - - // Builds a mesh shape in the physical world and updates prim.BSShape. - // Dereferences previous shape in BSShape and adds a reference for this new shape. - // Returns 'true' of a mesh was actually built. Otherwise . - // Called at taint-time! - private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - BulletShape newShape = new BulletShape(); - - float lod; - System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - - // if this new shape is the same as last time, don't recreate the mesh - if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) - return false; - - if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", - prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); - - // Since we're recreating new, get rid of the reference to the previous shape - DereferenceShape(prim.PhysShape, true, shapeCallback); - - newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); - // Take evasive action if the mesh was not constructed. - newShape = VerifyMeshCreated(newShape, prim); - - ReferenceShape(newShape); - - prim.PhysShape = newShape; - - return true; // 'true' means a new shape has been added to this prim - } - - private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) - { - BulletShape newShape = new BulletShape(); - IMesh meshData = null; - - MeshDesc meshDesc; - if (Meshes.TryGetValue(newMeshKey, out meshDesc)) - { - // If the mesh has already been built just use it. - newShape = meshDesc.shape.Clone(); - } - else - { - meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false); - - if (meshData != null) - { - int[] indices = meshData.getIndexListAsInt(); - List vertices = meshData.getVertexList(); - - float[] verticesAsFloats = new float[vertices.Count * 3]; - int vi = 0; - foreach (OMV.Vector3 vv in vertices) - { - verticesAsFloats[vi++] = vv.X; - verticesAsFloats[vi++] = vv.Y; - verticesAsFloats[vi++] = vv.Z; - } - - // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", - // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); - - newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, - indices.GetLength(0), indices, vertices.Count, verticesAsFloats); - } - } - newShape.shapeKey = newMeshKey; - - return newShape; - } - - // See that hull shape exists in the physical world and update prim.BSShape. - // We could be creating the hull because scale changed or whatever. - private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - BulletShape newShape; - - float lod; - System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - - // if the hull hasn't changed, don't rebuild it - if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) - return false; - - if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", - prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); - - // Remove usage of the previous shape. - DereferenceShape(prim.PhysShape, true, shapeCallback); - - newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); - newShape = VerifyMeshCreated(newShape, prim); - - ReferenceShape(newShape); - - prim.PhysShape = newShape; - return true; // 'true' means a new shape has been added to this prim - } - - List m_hulls; - private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) - { - - BulletShape newShape = new BulletShape(); - IntPtr hullPtr = IntPtr.Zero; - - HullDesc hullDesc; - if (Hulls.TryGetValue(newHullKey, out hullDesc)) - { - // If the hull shape already is created, just use it. - newShape = hullDesc.shape.Clone(); - } - else - { - // Build a new hull in the physical world - // Pass true for physicalness as this creates some sort of bounding box which we don't need - IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false); - if (meshData != null) - { - - int[] indices = meshData.getIndexListAsInt(); - List vertices = meshData.getVertexList(); - - //format conversion from IMesh format to DecompDesc format - List convIndices = new List(); - List convVertices = new List(); - for (int ii = 0; ii < indices.GetLength(0); ii++) - { - convIndices.Add(indices[ii]); - } - foreach (OMV.Vector3 vv in vertices) - { - convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); - } - - // setup and do convex hull conversion - m_hulls = new List(); - DecompDesc dcomp = new DecompDesc(); - dcomp.mIndices = convIndices; - dcomp.mVertices = convVertices; - ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); - // create the hull into the _hulls variable - convexBuilder.process(dcomp); - - // Convert the vertices and indices for passing to unmanaged. - // The hull information is passed as a large floating point array. - // The format is: - // convHulls[0] = number of hulls - // convHulls[1] = number of vertices in first hull - // convHulls[2] = hull centroid X coordinate - // convHulls[3] = hull centroid Y coordinate - // convHulls[4] = hull centroid Z coordinate - // convHulls[5] = first hull vertex X - // convHulls[6] = first hull vertex Y - // convHulls[7] = first hull vertex Z - // convHulls[8] = second hull vertex X - // ... - // convHulls[n] = number of vertices in second hull - // convHulls[n+1] = second hull centroid X coordinate - // ... - // - // TODO: is is very inefficient. Someday change the convex hull generator to return - // data structures that do not need to be converted in order to pass to Bullet. - // And maybe put the values directly into pinned memory rather than marshaling. - int hullCount = m_hulls.Count; - int totalVertices = 1; // include one for the count of the hulls - foreach (ConvexResult cr in m_hulls) - { - totalVertices += 4; // add four for the vertex count and centroid - totalVertices += cr.HullIndices.Count * 3; // we pass just triangles - } - float[] convHulls = new float[totalVertices]; - - convHulls[0] = (float)hullCount; - int jj = 1; - foreach (ConvexResult cr in m_hulls) - { - // copy vertices for index access - float3[] verts = new float3[cr.HullVertices.Count]; - int kk = 0; - foreach (float3 ff in cr.HullVertices) - { - verts[kk++] = ff; - } - - // add to the array one hull's worth of data - convHulls[jj++] = cr.HullIndices.Count; - convHulls[jj++] = 0f; // centroid x,y,z - convHulls[jj++] = 0f; - convHulls[jj++] = 0f; - foreach (int ind in cr.HullIndices) - { - convHulls[jj++] = verts[ind].x; - convHulls[jj++] = verts[ind].y; - convHulls[jj++] = verts[ind].z; - } - } - // create the hull data structure in Bullet - newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls); - } - } - - newShape.shapeKey = newHullKey; - - return newShape; - } - - // Callback from convex hull creater with a newly created hull. - // Just add it to our collection of hulls for this shape. - private void HullReturn(ConvexResult result) - { - m_hulls.Add(result); - return; - } - - // Compound shapes are always built from scratch. - // This shouldn't be to bad since most of the parts will be meshes that had been built previously. - private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - // Remove reference to the old shape - // Don't need to do this as the shape is freed when the new root shape is created below. - // DereferenceShape(prim.PhysShape, true, shapeCallback); - - - BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false); - - // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. - CreateGeomMeshOrHull(prim, shapeCallback); - PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity); - if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", - prim.LocalID, cShape, prim.PhysShape); - - prim.PhysShape = cShape; - - return true; - } - - // Create a hash of all the shape parameters to be used as a key - // for this particular shape. - private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) - { - // level of detail based on size and type of the object - float lod = BSParam.MeshLOD; - if (pbs.SculptEntry) - lod = BSParam.SculptLOD; - - // Mega prims usually get more detail because one can interact with shape approximations at this size. - float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); - if (maxAxis > BSParam.MeshMegaPrimThreshold) - lod = BSParam.MeshMegaPrimLOD; - - retLod = lod; - return pbs.GetMeshKey(size, lod); - } - // For those who don't want the LOD - private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs) - { - float lod; - return ComputeShapeKey(size, pbs, out lod); - } - - // The creation of a mesh or hull can fail if an underlying asset is not available. - // There are two cases: 1) the asset is not in the cache and it needs to be fetched; - // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). - // The first case causes the asset to be fetched. The second case requires - // us to not loop forever. - // Called after creating a physical mesh or hull. If the physical shape was created, - // just return. - private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) - { - // If the shape was successfully created, nothing more to do - if (newShape.HasPhysicalShape) - return newShape; - - // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset - if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) - { - prim.LastAssetBuildFailed = true; - BSPhysObject xprim = prim; - DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", - LogHeader, prim.LocalID, prim.LastAssetBuildFailed); - Util.FireAndForget(delegate - { - RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; - if (assetProvider != null) - { - BSPhysObject yprim = xprim; // probably not necessary, but, just in case. - assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) - { - if (!yprim.BaseShape.SculptEntry) - return; - if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) - return; - - yprim.BaseShape.SculptData = asset.Data; - // This will cause the prim to see that the filler shape is not the right - // one and try again to build the object. - // No race condition with the normal shape setting since the rebuild is at taint time. - yprim.ForceBodyShapeRebuild(false); - - }); - } - }); - } - else - { - if (prim.LastAssetBuildFailed) - { - PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", - LogHeader, prim.LocalID, prim.BaseShape.SculptTexture); - } - } - - // While we figure out the real problem, stick a simple native shape on the object. - BulletShape fillinShape = - BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); - - return fillinShape; - } - - // Create a body object in Bullet. - // Updates prim.BSBody with the information about the new body if one is created. - // Returns 'true' if an object was actually created. - // Called at taint-time. - private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape, - BodyDestructionCallback bodyCallback) - { - bool ret = false; - - // the mesh, hull or native shape must have already been created in Bullet - bool mustRebuild = !prim.PhysBody.HasPhysicalBody; - - // If there is an existing body, verify it's of an acceptable type. - // If not a solid object, body is a GhostObject. Otherwise a RigidBody. - if (!mustRebuild) - { - CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody); - if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY - || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) - { - // If the collisionObject is not the correct type for solidness, rebuild what's there - mustRebuild = true; - } - } - - if (mustRebuild || forceRebuild) - { - // Free any old body - DereferenceBody(prim.PhysBody, true, bodyCallback); - - BulletBody aBody; - if (prim.IsSolid) - { - aBody = PhysicsScene.PE.CreateBodyFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody); - } - else - { - aBody = PhysicsScene.PE.CreateGhostFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); - } - - ReferenceBody(aBody, true); - - prim.PhysBody = aBody; - - ret = true; - } - - return ret; - } - - private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc) - { - bool ret = false; - MeshDesc foundDesc = new MeshDesc(); - foreach (MeshDesc md in Meshes.Values) - { - if (md.shape.ReferenceSame(shape)) - { - foundDesc = md; - ret = true; - break; - } - - } - outDesc = foundDesc; - return ret; - } - - private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc) - { - bool ret = false; - HullDesc foundDesc = new HullDesc(); - foreach (HullDesc hd in Hulls.Values) - { - if (hd.shape.ReferenceSame(shape)) - { - foundDesc = hd; - ret = true; - break; - } - - } - outDesc = foundDesc; - return ret; - } - - private void DetailLog(string msg, params Object[] args) - { - if (PhysicsScene.PhysicsLogging.Enabled) - PhysicsScene.DetailLog(msg, args); - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs deleted file mode 100755 index c75eb9b..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -public abstract class BSShape -{ - public IntPtr ptr { get; set; } - public BSPhysicsShapeType type { get; set; } - public System.UInt64 key { get; set; } - public int referenceCount { get; set; } - public DateTime lastReferenced { get; set; } - - public BSShape() - { - ptr = IntPtr.Zero; - type = BSPhysicsShapeType.SHAPE_UNKNOWN; - key = 0; - referenceCount = 0; - lastReferenced = DateTime.Now; - } - - // Get a reference to a physical shape. Create if it doesn't exist - public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) - { - BSShape ret = null; - - if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) - { - // an avatar capsule is close to a native shape (it is not shared) - ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE, - FixedShapeKey.KEY_CAPSULE); - physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret); - } - - // Compound shapes are handled special as they are rebuilt from scratch. - // This isn't too great a hardship since most of the child shapes will already been created. - if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) - { - // Getting a reference to a compound shape gets you the compound shape with the root prim shape added - ret = BSShapeCompound.GetReference(prim); - physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); - } - - if (ret == null) - ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); - - return ret; - } - public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) - { - return null; - } - public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) - { - return null; - } - - // Release the use of a physical shape. - public abstract void Dereference(BSScene physicsScene); - - // All shapes have a static call to get a reference to the physical shape - // protected abstract static BSShape GetReference(); - - // Returns a string for debugging that uniquily identifies the memory used by this instance - public string AddrString - { - get { return ptr.ToString("X"); } - } - - public override string ToString() - { - StringBuilder buff = new StringBuilder(); - buff.Append(""); - return buff.ToString(); - } -} - -public class BSShapeNull : BSShape -{ - public BSShapeNull() : base() - { - } - public static BSShape GetReference() { return new BSShapeNull(); } - public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } -} - -public class BSShapeNative : BSShape -{ - private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; - public BSShapeNative() : base() - { - } - public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) - { - // Native shapes are not shared and are always built anew. - //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); - return null; - } - - private BSShapeNative(BSScene physicsScene, BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) - { - ShapeData nativeShapeData = new ShapeData(); - nativeShapeData.Type = shapeType; - nativeShapeData.ID = prim.LocalID; - nativeShapeData.Scale = prim.Scale; - nativeShapeData.Size = prim.Scale; - nativeShapeData.MeshKey = (ulong)shapeKey; - nativeShapeData.HullKey = (ulong)shapeKey; - - - /* - if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) - { - ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); - physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); - } - else - { - ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); - } - if (ptr == IntPtr.Zero) - { - physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", - LogHeader, prim.LocalID, shapeType); - } - type = shapeType; - key = (UInt64)shapeKey; - */ - } - // Make this reference to the physical shape go away since native shapes are not shared. - public override void Dereference(BSScene physicsScene) - { - /* - // Native shapes are not tracked and are released immediately - physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); - PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this); - ptr = IntPtr.Zero; - // Garbage collection will free up this instance. - */ - } -} - -public class BSShapeMesh : BSShape -{ - private static string LogHeader = "[BULLETSIM SHAPE MESH]"; - private static Dictionary Meshes = new Dictionary(); - - public BSShapeMesh() : base() - { - } - public static BSShape GetReference() { return new BSShapeNull(); } - public override void Dereference(BSScene physicsScene) { } -} - -public class BSShapeHull : BSShape -{ - private static string LogHeader = "[BULLETSIM SHAPE HULL]"; - private static Dictionary Hulls = new Dictionary(); - - public BSShapeHull() : base() - { - } - public static BSShape GetReference() { return new BSShapeNull(); } - public override void Dereference(BSScene physicsScene) { } -} - -public class BSShapeCompound : BSShape -{ - private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; - public BSShapeCompound() : base() - { - } - public static BSShape GetReference(BSPhysObject prim) - { - return new BSShapeNull(); - } - public override void Dereference(BSScene physicsScene) { } -} - -public class BSShapeAvatar : BSShape -{ - private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; - public BSShapeAvatar() : base() - { - } - public static BSShape GetReference(BSPhysObject prim) - { - return new BSShapeNull(); - } - public override void Dereference(BSScene physicsScene) { } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs deleted file mode 100755 index e4fecc3..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OpenSim.Framework; -using OpenSim.Region.Framework; -using OpenSim.Region.CoreModules; -using OpenSim.Region.Physics.Manager; - -using Nini.Config; -using log4net; - -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -public sealed class BSTerrainHeightmap : BSTerrainPhys -{ - static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; - - BulletHMapInfo m_mapInfo = null; - - // Constructor to build a default, flat heightmap terrain. - public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) - : base(physicsScene, regionBase, id) - { - Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE); - Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION); - int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; - float[] initialMap = new float[totalHeights]; - for (int ii = 0; ii < totalHeights; ii++) - { - initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; - } - m_mapInfo = new BulletHMapInfo(id, initialMap); - m_mapInfo.minCoords = minTerrainCoords; - m_mapInfo.maxCoords = maxTerrainCoords; - m_mapInfo.terrainRegionBase = TerrainBase; - // Don't have to free any previous since we just got here. - BuildHeightmapTerrain(); - } - - // This minCoords and maxCoords passed in give the size of the terrain (min and max Z - // are the high and low points of the heightmap). - public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, - Vector3 minCoords, Vector3 maxCoords) - : base(physicsScene, regionBase, id) - { - m_mapInfo = new BulletHMapInfo(id, initialMap); - m_mapInfo.minCoords = minCoords; - m_mapInfo.maxCoords = maxCoords; - m_mapInfo.minZ = minCoords.Z; - m_mapInfo.maxZ = maxCoords.Z; - m_mapInfo.terrainRegionBase = TerrainBase; - - // Don't have to free any previous since we just got here. - BuildHeightmapTerrain(); - } - - public override void Dispose() - { - ReleaseHeightMapTerrain(); - } - - // Using the information in m_mapInfo, create the physical representation of the heightmap. - private void BuildHeightmapTerrain() - { - // Create the terrain shape from the mapInfo - m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID, - new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, - m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); - - - // The terrain object initial position is at the center of the object - Vector3 centerPos; - centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f); - centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); - centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); - - m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, - m_mapInfo.ID, centerPos, Quaternion.Identity); - - // Set current terrain attributes - PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); - PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); - PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); - PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); - - // Return the new terrain to the world of physical objects - PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody); - - // redo its bounding box now that it is in the world - PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody); - - m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; - m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene); - - // Make it so the terrain will not move or be considered for movement. - PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); - - return; - } - - // If there is information in m_mapInfo pointing to physical structures, release same. - private void ReleaseHeightMapTerrain() - { - if (m_mapInfo != null) - { - if (m_mapInfo.terrainBody.HasPhysicalBody) - { - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody); - // Frees both the body and the shape. - PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody); - } - } - m_mapInfo = null; - } - - // The passed position is relative to the base of the region. - public override float GetTerrainHeightAtXYZ(Vector3 pos) - { - float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; - - int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X; - try - { - ret = m_mapInfo.heightMap[mapIndex]; - } - catch - { - // Sometimes they give us wonky values of X and Y. Give a warning and return something. - PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", - LogHeader, m_mapInfo.terrainRegionBase, pos); - ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; - } - return ret; - } - - // The passed position is relative to the base of the region. - public override float GetWaterLevelAtXYZ(Vector3 pos) - { - return PhysicsScene.SimpleWaterLevel; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs deleted file mode 100755 index 2e9db39..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OpenSim.Framework; -using OpenSim.Region.Framework; -using OpenSim.Region.CoreModules; -using OpenSim.Region.Physics.Manager; - -using Nini.Config; -using log4net; - -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ - -// The physical implementation of the terrain is wrapped in this class. -public abstract class BSTerrainPhys : IDisposable -{ - public enum TerrainImplementation - { - Heightmap = 0, - Mesh = 1 - } - - public BSScene PhysicsScene { get; private set; } - // Base of the region in world coordinates. Coordinates inside the region are relative to this. - public Vector3 TerrainBase { get; private set; } - public uint ID { get; private set; } - - public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) - { - PhysicsScene = physicsScene; - TerrainBase = regionBase; - ID = id; - } - public abstract void Dispose(); - public abstract float GetTerrainHeightAtXYZ(Vector3 pos); - public abstract float GetWaterLevelAtXYZ(Vector3 pos); -} - -// ========================================================================================== -public sealed class BSTerrainManager : IDisposable -{ - static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; - - // These height values are fractional so the odd values will be - // noticable when debugging. - public const float HEIGHT_INITIALIZATION = 24.987f; - public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; - public const float HEIGHT_GETHEIGHT_RET = 24.765f; - public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f; - - // If the min and max height are equal, we reduce the min by this - // amount to make sure that a bounding box is built for the terrain. - public const float HEIGHT_EQUAL_FUDGE = 0.2f; - - // Until the whole simulator is changed to pass us the region size, we rely on constants. - public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); - - // The scene that I am part of - private BSScene PhysicsScene { get; set; } - - // The ground plane created to keep thing from falling to infinity. - private BulletBody m_groundPlane; - - // If doing mega-regions, if we're region zero we will be managing multiple - // region terrains since region zero does the physics for the whole mega-region. - private Dictionary m_terrains; - - // Flags used to know when to recalculate the height. - private bool m_terrainModified = false; - - // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. - // This is incremented before assigning to new region so it is the last ID allocated. - private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1; - public uint HighestTerrainID { get {return m_terrainCount; } } - - // If doing mega-regions, this holds our offset from region zero of - // the mega-regions. "parentScene" points to the PhysicsScene of region zero. - private Vector3 m_worldOffset; - // If the parent region (region 0), this is the extent of the combined regions - // relative to the origin of region zero - private Vector3 m_worldMax; - private PhysicsScene MegaRegionParentPhysicsScene { get; set; } - - public BSTerrainManager(BSScene physicsScene) - { - PhysicsScene = physicsScene; - m_terrains = new Dictionary(); - - // Assume one region of default size - m_worldOffset = Vector3.Zero; - m_worldMax = new Vector3(DefaultRegionSize); - MegaRegionParentPhysicsScene = null; - } - - public void Dispose() - { - ReleaseGroundPlaneAndTerrain(); - } - - // Create the initial instance of terrain and the underlying ground plane. - // This is called from the initialization routine so we presume it is - // safe to call Bullet in real time. We hope no one is moving prims around yet. - public void CreateInitialGroundPlaneAndTerrain() - { - // The ground plane is here to catch things that are trying to drop to negative infinity - BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); - m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, - BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); - - PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane); - PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane); - // Ground plane does not move - PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); - // Everything collides with the ground plane. - m_groundPlane.collisionType = CollisionType.Groundplane; - m_groundPlane.ApplyCollisionMask(PhysicsScene); - - // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. - BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); - m_terrains.Add(Vector3.Zero, initialTerrain); - } - - // Release all the terrain structures we might have allocated - public void ReleaseGroundPlaneAndTerrain() - { - if (m_groundPlane.HasPhysicalBody) - { - if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) - { - PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); - } - m_groundPlane.Clear(); - } - - ReleaseTerrain(); - } - - // Release all the terrain we have allocated - public void ReleaseTerrain() - { - lock (m_terrains) - { - foreach (KeyValuePair kvp in m_terrains) - { - kvp.Value.Dispose(); - } - m_terrains.Clear(); - } - } - - // The simulator wants to set a new heightmap for the terrain. - public void SetTerrain(float[] heightMap) { - float[] localHeightMap = heightMap; - // If there are multiple requests for changes to the same terrain between ticks, - // only do that last one. - PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() - { - if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) - { - // If a child of a mega-region, we shouldn't have any terrain allocated for us - ReleaseGroundPlaneAndTerrain(); - // If doing the mega-prim stuff and we are the child of the zero region, - // the terrain is added to our parent - if (MegaRegionParentPhysicsScene is BSScene) - { - DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", - BSScene.DetailLogZero, m_worldOffset, m_worldMax); - ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( - BSScene.CHILDTERRAIN_ID, localHeightMap, - m_worldOffset, m_worldOffset + DefaultRegionSize, true); - } - } - else - { - // If not doing the mega-prim thing, just change the terrain - DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); - - UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, - m_worldOffset, m_worldOffset + DefaultRegionSize, true); - } - }); - } - - // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain - // based on the passed information. The 'id' should be either the terrain id or - // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. - // The latter feature is for creating child terrains for mega-regions. - // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new - // terrain shape is created and added to the body. - // This call is most often used to update the heightMap and parameters of the terrain. - // (The above does suggest that some simplification/refactoring is in order.) - // Called during taint-time. - private void UpdateTerrain(uint id, float[] heightMap, - Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) - { - DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}", - BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); - - // Find high and low points of passed heightmap. - // The min and max passed in is usually the area objects can be in (maximum - // object height, for instance). The terrain wants the bounding box for the - // terrain so replace passed min and max Z with the actual terrain min/max Z. - float minZ = float.MaxValue; - float maxZ = float.MinValue; - foreach (float height in heightMap) - { - if (height < minZ) minZ = height; - if (height > maxZ) maxZ = height; - } - if (minZ == maxZ) - { - // If min and max are the same, reduce min a little bit so a good bounding box is created. - minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE; - } - minCoords.Z = minZ; - maxCoords.Z = maxZ; - - Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); - - lock (m_terrains) - { - BSTerrainPhys terrainPhys; - if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) - { - // There is already a terrain in this spot. Free the old and build the new. - DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", - BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); - - // Remove old terrain from the collection - m_terrains.Remove(terrainRegionBase); - // Release any physical memory it may be using. - terrainPhys.Dispose(); - - if (MegaRegionParentPhysicsScene == null) - { - BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); - m_terrains.Add(terrainRegionBase, newTerrainPhys); - - m_terrainModified = true; - } - else - { - // It's possible that Combine() was called after this code was queued. - // If we are a child of combined regions, we don't create any terrain for us. - DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero); - - // Get rid of any terrain that may have been allocated for us. - ReleaseGroundPlaneAndTerrain(); - - // I hate doing this, but just bail - return; - } - } - else - { - // We don't know about this terrain so either we are creating a new terrain or - // our mega-prim child is giving us a new terrain to add to the phys world - - // if this is a child terrain, calculate a unique terrain id - uint newTerrainID = id; - if (newTerrainID >= BSScene.CHILDTERRAIN_ID) - newTerrainID = ++m_terrainCount; - - DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", - BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); - BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); - m_terrains.Add(terrainRegionBase, newTerrainPhys); - - m_terrainModified = true; - } - } - } - - // TODO: redo terrain implementation selection to allow other base types than heightMap. - private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) - { - PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", - LogHeader, PhysicsScene.RegionName, terrainRegionBase, - (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); - BSTerrainPhys newTerrainPhys = null; - switch ((int)BSParam.TerrainImplementation) - { - case (int)BSTerrainPhys.TerrainImplementation.Heightmap: - newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, - heightMap, minCoords, maxCoords); - break; - case (int)BSTerrainPhys.TerrainImplementation.Mesh: - newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, - heightMap, minCoords, maxCoords); - break; - default: - PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", - LogHeader, - (int)BSParam.TerrainImplementation, - BSParam.TerrainImplementation, - PhysicsScene.RegionName, terrainRegionBase); - break; - } - return newTerrainPhys; - } - - // Return 'true' of this position is somewhere in known physical terrain space - public bool IsWithinKnownTerrain(Vector3 pos) - { - Vector3 terrainBaseXYZ; - BSTerrainPhys physTerrain; - return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); - } - - // Given an X and Y, find the height of the terrain. - // Since we could be handling multiple terrains for a mega-region, - // the base of the region is calcuated assuming all regions are - // the same size and that is the default. - // Once the heightMapInfo is found, we have all the information to - // compute the offset into the array. - private float lastHeightTX = 999999f; - private float lastHeightTY = 999999f; - private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; - public float GetTerrainHeightAtXYZ(Vector3 pos) - { - float tX = pos.X; - float tY = pos.Y; - // You'd be surprized at the number of times this routine is called - // with the same parameters as last time. - if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY)) - return lastHeight; - m_terrainModified = false; - - lastHeightTX = tX; - lastHeightTY = tY; - float ret = HEIGHT_GETHEIGHT_RET; - - Vector3 terrainBaseXYZ; - BSTerrainPhys physTerrain; - if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) - { - ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ); - } - else - { - PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", - LogHeader, PhysicsScene.RegionName, tX, tY); - DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", - BSScene.DetailLogZero, pos, terrainBaseXYZ); - } - - lastHeight = ret; - return ret; - } - - public float GetWaterLevelAtXYZ(Vector3 pos) - { - float ret = WATER_HEIGHT_GETHEIGHT_RET; - - Vector3 terrainBaseXYZ; - BSTerrainPhys physTerrain; - if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) - { - ret = physTerrain.GetWaterLevelAtXYZ(pos); - } - else - { - PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", - LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); - } - return ret; - } - - // Given an address, return 'true' of there is a description of that terrain and output - // the descriptor class and the 'base' fo the addresses therein. - private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) - { - int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; - int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; - Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); - - BSTerrainPhys physTerrain = null; - lock (m_terrains) - { - m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); - } - outTerrainBase = terrainBaseXYZ; - outPhysTerrain = physTerrain; - return (physTerrain != null); - } - - // Although no one seems to check this, I do support combining. - public bool SupportsCombining() - { - return true; - } - - // This routine is called two ways: - // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum - // extent of the combined regions. This is to inform the parent of the size - // of the combined regions. - // and one with 'offset' as the offset of the child region to the base region, - // 'pScene' pointing to the parent and 'extents' of zero. This informs the - // child of its relative base and new parent. - public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) - { - m_worldOffset = offset; - m_worldMax = extents; - MegaRegionParentPhysicsScene = pScene; - if (pScene != null) - { - // We are a child. - // We want m_worldMax to be the highest coordinate of our piece of terrain. - m_worldMax = offset + DefaultRegionSize; - } - DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}", - BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax); - } - - // Unhook all the combining that I know about. - public void UnCombine(PhysicsScene pScene) - { - // Just like ODE, we don't do anything yet. - DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero); - } - - - private void DetailLog(string msg, params Object[] args) - { - PhysicsScene.PhysicsLogging.Write(msg, args); - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs deleted file mode 100755 index 1d55ce3..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; - -using OpenSim.Framework; -using OpenSim.Region.Framework; -using OpenSim.Region.CoreModules; -using OpenSim.Region.Physics.Manager; - -using Nini.Config; -using log4net; - -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -public sealed class BSTerrainMesh : BSTerrainPhys -{ - static string LogHeader = "[BULLETSIM TERRAIN MESH]"; - - private float[] m_savedHeightMap; - int m_sizeX; - int m_sizeY; - - BulletShape m_terrainShape; - BulletBody m_terrainBody; - - public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) - : base(physicsScene, regionBase, id) - { - } - - public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */) - : base(physicsScene, regionBase, id) - { - } - - // Create terrain mesh from a heightmap. - public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, - Vector3 minCoords, Vector3 maxCoords) - : base(physicsScene, regionBase, id) - { - int indicesCount; - int[] indices; - int verticesCount; - float[] vertices; - - m_savedHeightMap = initialMap; - - m_sizeX = (int)(maxCoords.X - minCoords.X); - m_sizeY = (int)(maxCoords.Y - minCoords.Y); - - if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap, - m_sizeX, m_sizeY, - (float)m_sizeX, (float)m_sizeY, - Vector3.Zero, 1.0f, - out indicesCount, out indices, out verticesCount, out vertices)) - { - // DISASTER!! - PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); - PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); - // Something is very messed up and a crash is in our future. - return; - } - PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", - ID, indicesCount, indices.Length, verticesCount, vertices.Length); - - m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices); - if (!m_terrainShape.HasPhysicalShape) - { - // DISASTER!! - PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); - physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); - // Something is very messed up and a crash is in our future. - return; - } - - Vector3 pos = regionBase; - Quaternion rot = Quaternion.Identity; - - m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); - if (!m_terrainBody.HasPhysicalBody) - { - // DISASTER!! - physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); - // Something is very messed up and a crash is in our future. - return; - } - - // Set current terrain attributes - PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); - PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); - PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); - PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); - - // Static objects are not very massive. - PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); - - // Put the new terrain to the world of physical objects - PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody); - - // Redo its bounding box now that it is in the world - PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody); - - m_terrainBody.collisionType = CollisionType.Terrain; - m_terrainBody.ApplyCollisionMask(PhysicsScene); - - // Make it so the terrain will not move or be considered for movement. - PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); - } - - public override void Dispose() - { - if (m_terrainBody.HasPhysicalBody) - { - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody); - // Frees both the body and the shape. - PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody); - } - } - - public override float GetTerrainHeightAtXYZ(Vector3 pos) - { - // For the moment use the saved heightmap to get the terrain height. - // TODO: raycast downward to find the true terrain below the position. - float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; - - int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X; - try - { - ret = m_savedHeightMap[mapIndex]; - } - catch - { - // Sometimes they give us wonky values of X and Y. Give a warning and return something. - PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", - LogHeader, TerrainBase, pos); - ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; - } - return ret; - } - - // The passed position is relative to the base of the region. - public override float GetWaterLevelAtXYZ(Vector3 pos) - { - return PhysicsScene.SimpleWaterLevel; - } - - // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). - // Return 'true' if successfully created. - public static bool ConvertHeightmapToMesh( - BSScene physicsScene, - float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap - float extentX, float extentY, // zero based range for output vertices - Vector3 extentBase, // base to be added to all vertices - float magnification, // number of vertices to create between heightMap coords - out int indicesCountO, out int[] indicesO, - out int verticesCountO, out float[] verticesO) - { - bool ret = false; - - int indicesCount = 0; - int verticesCount = 0; - int[] indices = new int[0]; - float[] vertices = new float[0]; - - // Simple mesh creation which assumes magnification == 1. - // TODO: do a more general solution that scales, adds new vertices and smoothes the result. - - // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop - // from zero to <= sizeX). The triangle indices are then generated as two triangles - // per heightmap point. There are sizeX by sizeY of these squares. The extra row and - // column of vertices are used to complete the triangles of the last row and column - // of the heightmap. - try - { - // One vertice per heightmap value plus the vertices off the top and bottom edge. - int totalVertices = (sizeX + 1) * (sizeY + 1); - vertices = new float[totalVertices * 3]; - int totalIndices = sizeX * sizeY * 6; - indices = new int[totalIndices]; - - float magX = (float)sizeX / extentX; - float magY = (float)sizeY / extentY; - physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", - BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); - float minHeight = float.MaxValue; - // Note that sizeX+1 vertices are created since there is land between this and the next region. - for (int yy = 0; yy <= sizeY; yy++) - { - for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times - { - int offset = yy * sizeX + xx; - // Extend the height with the height from the last row or column - if (yy == sizeY) offset -= sizeX; - if (xx == sizeX) offset -= 1; - float height = heightMap[offset]; - minHeight = Math.Min(minHeight, height); - vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; - vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; - vertices[verticesCount + 2] = height + extentBase.Z; - verticesCount += 3; - } - } - verticesCount = verticesCount / 3; - - for (int yy = 0; yy < sizeY; yy++) - { - for (int xx = 0; xx < sizeX; xx++) - { - int offset = yy * (sizeX + 1) + xx; - // Each vertices is presumed to be the upper left corner of a box of two triangles - indices[indicesCount + 0] = offset; - indices[indicesCount + 1] = offset + 1; - indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column - indices[indicesCount + 3] = offset + 1; - indices[indicesCount + 4] = offset + sizeX + 2; - indices[indicesCount + 5] = offset + sizeX + 1; - indicesCount += 6; - } - } - - ret = true; - } - catch (Exception e) - { - physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", - LogHeader, physicsScene.RegionName, extentBase, e); - } - - indicesCountO = indicesCount; - indicesO = indices; - verticesCountO = verticesCount; - verticesO = vertices; - - return ret; - } -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs deleted file mode 100755 index 662dd68..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyrightD - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -using System; -using System.Collections.Generic; -using System.Text; -using OMV = OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -// Classes to allow some type checking for the API -// These hold pointers to allocated objects in the unmanaged space. -// These classes are subclassed by the various physical implementations of -// objects. In particular, there is a version for physical instances in -// unmanaged memory ("unman") and one for in managed memory ("XNA"). - -// Currently, the instances of these classes are a reference to a -// physical representation and this has no releationship to other -// instances. Someday, refarb the usage of these classes so each instance -// refers to a particular physical instance and this class controls reference -// counts and such. This should be done along with adding BSShapes. - -public class BulletWorld -{ - public BulletWorld(uint worldId, BSScene bss) - { - worldID = worldId; - physicsScene = bss; - } - public uint worldID; - // The scene is only in here so very low level routines have a handle to print debug/error messages - public BSScene physicsScene; -} - -// An allocated Bullet btRigidBody -public class BulletBody -{ - public BulletBody(uint id) - { - ID = id; - collisionType = CollisionType.Static; - } - public uint ID; - public CollisionType collisionType; - - public virtual void Clear() { } - public virtual bool HasPhysicalBody { get { return false; } } - - // Apply the specificed collision mask into the physical world - public virtual bool ApplyCollisionMask(BSScene physicsScene) - { - // Should assert the body has been added to the physical world. - // (The collision masks are stored in the collision proxy cache which only exists for - // a collision body that is in the world.) - return physicsScene.PE.SetCollisionGroupMask(this, - BulletSimData.CollisionTypeMasks[collisionType].group, - BulletSimData.CollisionTypeMasks[collisionType].mask); - } - - // Used for log messages for a unique display of the memory/object allocated to this instance - public virtual string AddrString - { - get { return "unknown"; } - } - - public override string ToString() - { - StringBuilder buff = new StringBuilder(); - buff.Append(""); - return buff.ToString(); - } -} - -public class BulletShape -{ - public BulletShape() - { - type = BSPhysicsShapeType.SHAPE_UNKNOWN; - shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; - isNativeShape = false; - } - public BSPhysicsShapeType type; - public System.UInt64 shapeKey; - public bool isNativeShape; - - public virtual void Clear() { } - public virtual bool HasPhysicalShape { get { return false; } } - // Make another reference to this physical object. - public virtual BulletShape Clone() { return new BulletShape(); } - // Return 'true' if this and other refer to the same physical object - public virtual bool ReferenceSame(BulletShape xx) { return false; } - - // Used for log messages for a unique display of the memory/object allocated to this instance - public virtual string AddrString - { - get { return "unknown"; } - } - - public override string ToString() - { - StringBuilder buff = new StringBuilder(); - buff.Append(""); - return buff.ToString(); - } -} - -// An allocated Bullet btConstraint -public class BulletConstraint -{ - public BulletConstraint() - { - } - public virtual void Clear() { } - public virtual bool HasPhysicalConstraint { get { return false; } } - - // Used for log messages for a unique display of the memory/object allocated to this instance - public virtual string AddrString - { - get { return "unknown"; } - } -} - -// An allocated HeightMapThing which holds various heightmap info. -// Made a class rather than a struct so there would be only one -// instance of this and C# will pass around pointers rather -// than making copies. -public class BulletHMapInfo -{ - public BulletHMapInfo(uint id, float[] hm) { - ID = id; - heightMap = hm; - terrainRegionBase = OMV.Vector3.Zero; - minCoords = new OMV.Vector3(100f, 100f, 25f); - maxCoords = new OMV.Vector3(101f, 101f, 26f); - minZ = maxZ = 0f; - sizeX = sizeY = 256f; - } - public uint ID; - public float[] heightMap; - public OMV.Vector3 terrainRegionBase; - public OMV.Vector3 minCoords; - public OMV.Vector3 maxCoords; - public float sizeX, sizeY; - public float minZ, maxZ; - public BulletShape terrainShape; - public BulletBody terrainBody; -} - -// The general class of collsion object. -public enum CollisionType -{ - Avatar, - Groundplane, - Terrain, - Static, - Dynamic, - VolumeDetect, - // Linkset, // A linkset should be either Static or Dynamic - LinksetChild, - Unknown -}; - -// Hold specification of group and mask collision flags for a CollisionType -public struct CollisionTypeFilterGroup -{ - public CollisionTypeFilterGroup(CollisionType t, uint g, uint m) - { - type = t; - group = g; - mask = m; - } - public CollisionType type; - public uint group; - public uint mask; -}; - -public static class BulletSimData -{ - -// Map of collisionTypes to flags for collision groups and masks. -// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code -// but, instead, use references to this dictionary. Finding and debugging -// collision flag problems will be made easier. -public static Dictionary CollisionTypeMasks - = new Dictionary() -{ - { CollisionType.Avatar, - new CollisionTypeFilterGroup(CollisionType.Avatar, - (uint)CollisionFilterGroups.BCharacterGroup, - (uint)CollisionFilterGroups.BAllGroup) - }, - { CollisionType.Groundplane, - new CollisionTypeFilterGroup(CollisionType.Groundplane, - (uint)CollisionFilterGroups.BGroundPlaneGroup, - (uint)CollisionFilterGroups.BAllGroup) - }, - { CollisionType.Terrain, - new CollisionTypeFilterGroup(CollisionType.Terrain, - (uint)CollisionFilterGroups.BTerrainGroup, - (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) - }, - { CollisionType.Static, - new CollisionTypeFilterGroup(CollisionType.Static, - (uint)CollisionFilterGroups.BStaticGroup, - (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) - }, - { CollisionType.Dynamic, - new CollisionTypeFilterGroup(CollisionType.Dynamic, - (uint)CollisionFilterGroups.BSolidGroup, - (uint)(CollisionFilterGroups.BAllGroup)) - }, - { CollisionType.VolumeDetect, - new CollisionTypeFilterGroup(CollisionType.VolumeDetect, - (uint)CollisionFilterGroups.BSensorTrigger, - (uint)(~CollisionFilterGroups.BSensorTrigger)) - }, - { CollisionType.LinksetChild, - new CollisionTypeFilterGroup(CollisionType.LinksetChild, - (uint)CollisionFilterGroups.BLinksetChildGroup, - (uint)(CollisionFilterGroups.BNoneGroup)) - // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) - }, -}; - -} -} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt deleted file mode 100755 index a8a4ff5..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ /dev/null @@ -1,272 +0,0 @@ -CURRENT PRIORITIES -================================================= -Redo BulletSimAPI to allow native C# implementation of Bullet option. -Avatar movement - flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle - walking up stairs is not calibrated correctly (stairs out of Kepler cabin) - avatar capsule rotation completed -llMoveToTarget -Enable vehicle border crossings (at least as poorly as ODE) - Terrain skirts - Avatar created in previous region and not new region when crossing border - Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) -Vehicle movement on terrain smoothness -Vehicle script tuning/debugging - Avanti speed script - Weapon shooter script -limitMotorUp calibration (more down?) -Boats float low in the water -Add material densities to the material types. - -CRASHES -================================================= -20121129.1411: editting/moving phys object across region boundries causes crash - getPos-> btRigidBody::upcast -> getBodyType -> BOOM -20121128.1600: mesh object not rezzing (no physics mesh). - Causes many errors. Doesn't stop after first error with box shape. - Eventually crashes when deleting the object. -20121206.1434: rez Sam-pan into OSGrid BulletSim11 region - Immediate simulator crash. Mono does not output any stacktrace and - log just stops after reporting taint-time linking of the linkset. - -VEHICLES TODO LIST: -================================================= -Angular motor direction is global coordinates rather than local coordinates -Border crossing with linked vehicle causes crash -Vehicles (Move smoothly) -Add vehicle collisions so IsColliding is properly reported. - Needed for banking, limitMotorUp, movementLimiting, ... -VehicleAddForce is not scaled by the simulation step but it is only - applied for one step. Should it be scaled? -Some vehicles should not be able to turn if no speed or off ground. -Cannot edit/move a vehicle being ridden: it jumps back to the origional position. -Neb car jiggling left and right - Happens on terrain and any other mesh object. Flat cubes are much smoother. - This has been reduced but not eliminated. -Implement referenceFrame for all the motion routines. -Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. - Verify that angular motion specified around Z moves in the vehicle coordinates. -Verify llGetVel() is returning a smooth and good value for vehicle movement. -llGetVel() should return the root's velocity if requested in a child prim. -Implement function efficiency for lineaar and angular motion. -After getting off a vehicle, the root prim is phantom (can be walked through) - Need to force a position update for the root prim after compound shape destruction -Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) -For limitMotorUp, use raycast down to find if vehicle is in the air. -Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). - A kludge that isn't fixing the real problem of Bullet adding extra motion. -Incorporate inter-relationship of angular corrections. For instance, angularDeflection - and angularMotorUp will compute same X or Y correction. When added together - creates over-correction and over-shoot and wabbling. - -BULLETSIM TODO LIST: -================================================= -Implement an avatar mesh shape. The Bullet capsule is way too limited. - Consider just hand creating a vertex/index array in a new BSShapeAvatar. -Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. -Duplicating a physical prim causes old prim to jump away - Dup a phys prim and the original become unselected and thus interacts w/ selected prim. -Scenes with hundred of thousands of static objects take a lot of physics CPU time. -BSPrim.Force should set a continious force on the prim. The force should be - applied each tick. Some limits? -Gun sending shooter flying. -Collision margin (gap between physical objects lying on each other) -Boundry checking (crashes related to crossing boundry) - Add check for border edge position for avatars and objects. - Verify the events are created for border crossings. -Avatar rotation (check out changes to ScenePresence for physical rotation) -Avatar running (what does phys engine need to do?) -Small physical objects do not interact correctly - Create chain of .5x.5x.1 torui and make all but top physical so to hang. - The chain will fall apart and pairs will dance around on ground - Chains of 1x1x.2 will stay connected but will dance. - Chains above 2x2x.4 are more stable and get stablier as torui get larger. -Add PID motor for avatar movement (slow to stop, ...) -setForce should set a constant force. Different than AddImpulse. -Implement raycast. -Implement ShapeCollection.Dispose() -Implement water as a plain so raycasting and collisions can happen with same. -Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE - Also osGetPhysicsEngineVerion() maybe. -Linkset.Position and Linkset.Orientation requre rewrite to properly return - child position. LinksetConstraint acts like it's at taint time!! -Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F) -Should the different PID factors have non-equal contributions for different - values of Efficiency? -Selecting and deselecting physical objects causes CPU processing time to jump - http://www.youtube.com/watch?v=Hjg57fWg8yI&hd=1 - put thousand physical objects, select and deselect same. CPU time will be large. -Re-implement buoyancy as a separate force on the object rather than diddling gravity. - Register a pre-step event to add the force. -More efficient memory usage when passing hull information from BSPrim to BulletSim -Avatar movement motor check for zero or small movement. Somehow suppress small movements - when avatar has stopped and is just standing. Simple test for near zero has - the problem of preventing starting up (increase from zero) especially when falling. -Physical and phantom will drop through the terrain - - -LINKSETS -====================================================== -Offset the center of the linkset to be the geometric center of all the prims - Not quite the same as the center-of-gravity -Linksets should allow collisions to individual children - Add LocalID to children shapes in LinksetCompound and create events for individuals -LinksetCompound: when one of the children changes orientation (like tires - turning on a vehicle, the whole compound object is rebuilt. Optimize this - so orientation/position of individual children can change without a rebuild. -Verify/think through scripts in children of linksets. What do they reference - and return when getting position, velocity, ... -Confirm constraint linksets still work after making all the changes for compound linksets. -Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt. - For compound linksets, add ability to remove or reposition individual child shapes. -Disable activity of passive linkset children. - Since the linkset is a compound object, the old prims are left lying - around and need to be phantomized so they don't collide, ... -Speed up creation of large physical linksets - For instance, sitting in Neb's car (130 prims) takes several seconds to become physical. - REALLY bad for very large physical linksets (freezes the sim for many seconds). -Eliminate collisions between objects in a linkset. (LinksetConstraint) - Have UserPointer point to struct with localID and linksetID? - Objects in original linkset still collide with each other? - -MORE -====================================================== -Test avatar walking up stairs. How does compare with SL. - Radius of the capsule affects ability to climb edges. -Debounce avatar contact so legs don't keep folding up when standing. -Implement LSL physics controls. Like STATUS_ROTATE_X. -Add border extensions to terrain to help region crossings and objects leaving region. -Use a different capsule shape for avatar when sitting - LL uses a pyrimidal shape scaled by the avatar's bounding box - http://wiki.secondlife.com/wiki/File:Avmeshforms.png - -Performance test with lots of avatars. Can BulletSim support a thousand? -Optimize collisions in C++: only send up to the object subscribed to collisions. - Use collision subscription and remove the collsion(A,B) and collision(B,A) -Check whether SimMotionState needs large if statement (see TODO). - -Implement 'top colliders' info. -Avatar jump -Performance measurement and changes to make quicker. -Implement detailed physics stats (GetStats()). - -Measure performance improvement from hulls -Test not using ghost objects for volume detect implementation. -Performance of closures and delegates for taint processing - Are there faster ways? - Is any slowdown introduced by the existing implementation significant? -Is there are more efficient method of implementing pre and post step actions? - See http://www.codeproject.com/Articles/29922/Weak-Events-in-C - -Physics Arena central pyramid: why is one side permiable? - -In SL, perfect spheres don't seem to have rolling friction. Add special case. -Enforce physical parameter min/max: - Gravity: [-1, 28] - Friction: [0, 255] - Density: [1, 22587] - Restitution [0, 1] - http://wiki.secondlife.com/wiki/Physics_Material_Settings_test -Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html - -INTERNAL IMPROVEMENT/CLEANUP -================================================= -Create the physical wrapper classes (BulletBody, BulletShape) by methods on - BSAPITemplate and make their actual implementation Bullet engine specific. - For the short term, just call the existing functions in ShapeCollection. -Consider moving prim/character body and shape destruction in destroy() - to postTimeTime rather than protecting all the potential sets that - might have been queued up. -Remove unused fields from ShapeData (not used in API2) -Remove unused fields from pinned memory shared parameter block - Create parameter variables in BSScene to replace same. -Breakout code for mesh/hull/compound/native into separate BSShape* classes - Standardize access to building and reference code. - The skeleton classes are in the sources but are not complete or linked in. -Make BSBody and BSShape real classes to centralize creation/changin/destruction - Convert state and parameter calls from BulletSimAPI direct calls to - calls on BSBody and BSShape -Generalize Dynamics and PID with standardized motors. -Generalize Linkset and vehicles into PropertyManagers - Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies - Potentially add events for shape destruction, etc. -Complete implemention of preStepActions - Replace vehicle step call with prestep event. - Is there a need for postStepActions? postStepTaints? -Implement linkset by setting position of children when root updated. (LinksetManual) - Linkset implementation using manual prim movement. -LinkablePrim class? Would that simplify/centralize the linkset logic? -BSScene.UpdateParameterSet() is broken. How to set params on objects? -Remove HeightmapInfo from terrain specification - Since C++ code does not need terrain height, this structure et al are not needed. -Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will - bob at the water level. BSPrim.PositionSanityCheck(). -Should taints check for existance or activeness of target? - When destroying linksets/etc, taints can be generated for objects that are - actually gone when the taint happens. Crashes don't happen because the taint closure - keeps the object from being freed, but that is just an accident. - Possibly have and 'active' flag that is checked by the taint processor? -Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones) -Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'? -There are TOO MANY interfaces from BulletSim core to Bullet itself - Think of something to eliminate one or more of the layers - -THREADING -================================================= -Do taint action immediately if not actually executing Bullet. - Add lock around Bullet execution and just do taint actions if simulation is not happening. - -DONE DONE DONE DONE -================================================= -Cleanup code in BSDynamics by using motors. (Resolution: started) -Consider implementing terrain with a mesh rather than heightmap. (Resolution: done) - Would have better and adjustable resolution. -Build terrain mesh so heighmap is height of the center of the square meter. - Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional. -Terrain as mesh. (Resolution: done) -How are static linksets seen by the physics engine? - Resolution: they are not linked in physics. When moved, all the children are repositioned. -Convert BSCharacter to use all API2 (Resolution: done) -Avatar pushing difficult (too heavy?) -Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done) -Remove old code in DLL (all non-API2 stuff). (Resolution: done) -Measurements of mega-physical prim performance (with graph) (Resolution: done, email) -Debug Bullet internal stats output (why is timing all wrong?) - Resolution: Bullet stats logging only works with a single instance of Bullet (one region). -Implement meshes or just verify that they work. (Resolution: they do!) -Do prim hash codes work for sculpties and meshes? (Resolution: yes) -Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound) - Compound shapes will need the LocalID in the shapes and collision - processing to get it from there. -Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.) -Package Bullet source mods for Bullet internal stats output - (Resolution: move code into WorldData.h rather than relying on patches) -Single prim vehicles don't seem to properly vehiclize. - (Resolution: mass was not getting set properly for single prim linksets) -Add material type linkage and input all the material property definitions. - Skeleton classes and table are in the sources but are not filled or used. - (Resolution: -Neb vehicle taking > 25ms of physics time!! - (Resolution: compound linksets were being rebuild WAY too often) -Avatar height off after unsitting (floats off ground) - Editting appearance then moving restores. - Must not be initializing height when recreating capsule after unsit. - (Resolution: confusion of scale vs size for native objects removed) -Light cycle falling over when driving (Resolution: implemented angularMotorUp) -Should vehicle angular/linear movement friction happen after all the components - or does it only apply to the basic movement? - (Resolution: friction added before returning newly computed motor value. - What is expected by some vehicles (turning up friction to moderate speed)) -Tune terrain/object friction to be closer to SL. - (Resolution: added material type with friction and resolution) -Smooth avatar movement with motor (DONE) - Should motor update be all at taint-time? (Yes, DONE) - Fix avatar slowly sliding when standing (zero motion when stopped) (DONE) - (Resolution: added BSVMotor for avatar starting and stopping) -llApplyImpulse() - Compare mass/movement in OS and SL. Calibrate actions. (DONE) - (Resolution: tested on SL and OS. AddForce scales the force for timestep) -llSetBuoyancy() (DONE) - (Resolution: Bullet resets object gravity when added to world. Moved set gravity) -Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE) - (Resolution: set default density to 3.5 (from 60) which is closer to SL) diff --git a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs deleted file mode 100644 index 0d1db3b..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenSim.Region.Physics.BulletSPlugin")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("http://opensimulator.org")] -[assembly: AssemblyProduct("OpenSim")] -[assembly: AssemblyCopyright("OpenSimulator developers")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("520ea11b-20cb-449d-ba05-c01015fed841")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs deleted file mode 100644 index 4d84c44..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs +++ /dev/null @@ -1,341 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class Wpoint - { - public float3 mPoint; - public float mWeight; - - public Wpoint(float3 p, float w) - { - mPoint = p; - mWeight = w; - } - } - - public class CTri - { - private const int WSCALE = 4; - - public float3 mP1; - public float3 mP2; - public float3 mP3; - public float3 mNear1; - public float3 mNear2; - public float3 mNear3; - public float3 mNormal; - public float mPlaneD; - public float mConcavity; - public float mC1; - public float mC2; - public float mC3; - public int mI1; - public int mI2; - public int mI3; - public int mProcessed; // already been added... - - public CTri(float3 p1, float3 p2, float3 p3, int i1, int i2, int i3) - { - mProcessed = 0; - mI1 = i1; - mI2 = i2; - mI3 = i3; - - mP1 = new float3(p1); - mP2 = new float3(p2); - mP3 = new float3(p3); - - mNear1 = new float3(); - mNear2 = new float3(); - mNear3 = new float3(); - - mNormal = new float3(); - mPlaneD = mNormal.ComputePlane(mP1, mP2, mP3); - } - - public float Facing(CTri t) - { - return float3.dot(mNormal, t.mNormal); - } - - public bool clip(float3 start, ref float3 end) - { - float3 sect = new float3(); - bool hit = lineIntersectsTriangle(start, end, mP1, mP2, mP3, ref sect); - - if (hit) - end = sect; - return hit; - } - - public bool Concave(float3 p, ref float distance, ref float3 n) - { - n.NearestPointInTriangle(p, mP1, mP2, mP3); - distance = p.Distance(n); - return true; - } - - public void addTri(int[] indices, int i1, int i2, int i3, ref int tcount) - { - indices[tcount * 3 + 0] = i1; - indices[tcount * 3 + 1] = i2; - indices[tcount * 3 + 2] = i3; - tcount++; - } - - public float getVolume() - { - int[] indices = new int[8 * 3]; - - int tcount = 0; - - addTri(indices, 0, 1, 2, ref tcount); - addTri(indices, 3, 4, 5, ref tcount); - - addTri(indices, 0, 3, 4, ref tcount); - addTri(indices, 0, 4, 1, ref tcount); - - addTri(indices, 1, 4, 5, ref tcount); - addTri(indices, 1, 5, 2, ref tcount); - - addTri(indices, 0, 3, 5, ref tcount); - addTri(indices, 0, 5, 2, ref tcount); - - List vertices = new List { mP1, mP2, mP3, mNear1, mNear2, mNear3 }; - List indexList = new List(indices); - - float v = Concavity.computeMeshVolume(vertices, indexList); - return v; - } - - public float raySect(float3 p, float3 dir, ref float3 sect) - { - float4 plane = new float4(); - - plane.x = mNormal.x; - plane.y = mNormal.y; - plane.z = mNormal.z; - plane.w = mPlaneD; - - float3 dest = p + dir * 100000f; - - intersect(p, dest, ref sect, plane); - - return sect.Distance(p); // return the intersection distance - } - - public float planeDistance(float3 p) - { - float4 plane = new float4(); - - plane.x = mNormal.x; - plane.y = mNormal.y; - plane.z = mNormal.z; - plane.w = mPlaneD; - - return DistToPt(p, plane); - } - - public bool samePlane(CTri t) - { - const float THRESH = 0.001f; - float dd = Math.Abs(t.mPlaneD - mPlaneD); - if (dd > THRESH) - return false; - dd = Math.Abs(t.mNormal.x - mNormal.x); - if (dd > THRESH) - return false; - dd = Math.Abs(t.mNormal.y - mNormal.y); - if (dd > THRESH) - return false; - dd = Math.Abs(t.mNormal.z - mNormal.z); - if (dd > THRESH) - return false; - return true; - } - - public bool hasIndex(int i) - { - if (i == mI1 || i == mI2 || i == mI3) - return true; - return false; - } - - public bool sharesEdge(CTri t) - { - bool ret = false; - uint count = 0; - - if (t.hasIndex(mI1)) - count++; - if (t.hasIndex(mI2)) - count++; - if (t.hasIndex(mI3)) - count++; - - if (count >= 2) - ret = true; - - return ret; - } - - public float area() - { - float a = mConcavity * mP1.Area(mP2, mP3); - return a; - } - - public void addWeighted(List list) - { - Wpoint p1 = new Wpoint(mP1, mC1); - Wpoint p2 = new Wpoint(mP2, mC2); - Wpoint p3 = new Wpoint(mP3, mC3); - - float3 d1 = mNear1 - mP1; - float3 d2 = mNear2 - mP2; - float3 d3 = mNear3 - mP3; - - d1 *= WSCALE; - d2 *= WSCALE; - d3 *= WSCALE; - - d1 = d1 + mP1; - d2 = d2 + mP2; - d3 = d3 + mP3; - - Wpoint p4 = new Wpoint(d1, mC1); - Wpoint p5 = new Wpoint(d2, mC2); - Wpoint p6 = new Wpoint(d3, mC3); - - list.Add(p1); - list.Add(p2); - list.Add(p3); - - list.Add(p4); - list.Add(p5); - list.Add(p6); - } - - private static float DistToPt(float3 p, float4 plane) - { - float x = p.x; - float y = p.y; - float z = p.z; - float d = x*plane.x + y*plane.y + z*plane.z + plane.w; - return d; - } - - private static void intersect(float3 p1, float3 p2, ref float3 split, float4 plane) - { - float dp1 = DistToPt(p1, plane); - - float3 dir = new float3(); - dir.x = p2[0] - p1[0]; - dir.y = p2[1] - p1[1]; - dir.z = p2[2] - p1[2]; - - float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2]; - float dot2 = dp1 - plane[3]; - - float t = -(plane[3] + dot2) / dot1; - - split.x = (dir[0] * t) + p1[0]; - split.y = (dir[1] * t) + p1[1]; - split.z = (dir[2] * t) + p1[2]; - } - - private static bool rayIntersectsTriangle(float3 p, float3 d, float3 v0, float3 v1, float3 v2, out float t) - { - t = 0f; - - float3 e1, e2, h, s, q; - float a, f, u, v; - - e1 = v1 - v0; - e2 = v2 - v0; - h = float3.cross(d, e2); - a = float3.dot(e1, h); - - if (a > -0.00001f && a < 0.00001f) - return false; - - f = 1f / a; - s = p - v0; - u = f * float3.dot(s, h); - - if (u < 0.0f || u > 1.0f) - return false; - - q = float3.cross(s, e1); - v = f * float3.dot(d, q); - if (v < 0.0f || u + v > 1.0f) - return false; - - // at this stage we can compute t to find out where - // the intersection point is on the line - t = f * float3.dot(e2, q); - if (t > 0f) // ray intersection - return true; - else // this means that there is a line intersection but not a ray intersection - return false; - } - - private static bool lineIntersectsTriangle(float3 rayStart, float3 rayEnd, float3 p1, float3 p2, float3 p3, ref float3 sect) - { - float3 dir = rayEnd - rayStart; - - float d = (float)Math.Sqrt(dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]); - float r = 1.0f / d; - - dir *= r; - - float t; - bool ret = rayIntersectsTriangle(rayStart, dir, p1, p2, p3, out t); - - if (ret) - { - if (t > d) - { - sect.x = rayStart.x + dir.x * t; - sect.y = rayStart.y + dir.y * t; - sect.z = rayStart.z + dir.z * t; - } - else - { - ret = false; - } - } - - return ret; - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs deleted file mode 100644 index cc6383a..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs +++ /dev/null @@ -1,233 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public static class Concavity - { - // compute's how 'concave' this object is and returns the total volume of the - // convex hull as well as the volume of the 'concavity' which was found. - public static float computeConcavity(List vertices, List indices, ref float4 plane, ref float volume) - { - float cret = 0f; - volume = 1f; - - HullResult result = new HullResult(); - HullDesc desc = new HullDesc(); - - desc.MaxFaces = 256; - desc.MaxVertices = 256; - desc.SetHullFlag(HullFlag.QF_TRIANGLES); - desc.Vertices = vertices; - - HullError ret = HullUtils.CreateConvexHull(desc, ref result); - - if (ret == HullError.QE_OK) - { - volume = computeMeshVolume2(result.OutputVertices, result.Indices); - - // ok..now..for each triangle on the original mesh.. - // we extrude the points to the nearest point on the hull. - List tris = new List(); - - for (int i = 0; i < result.Indices.Count / 3; i++) - { - int i1 = result.Indices[i * 3 + 0]; - int i2 = result.Indices[i * 3 + 1]; - int i3 = result.Indices[i * 3 + 2]; - - float3 p1 = result.OutputVertices[i1]; - float3 p2 = result.OutputVertices[i2]; - float3 p3 = result.OutputVertices[i3]; - - CTri t = new CTri(p1, p2, p3, i1, i2, i3); - tris.Add(t); - } - - // we have not pre-computed the plane equation for each triangle in the convex hull.. - float totalVolume = 0; - - List ftris = new List(); // 'feature' triangles. - List input_mesh = new List(); - - for (int i = 0; i < indices.Count / 3; i++) - { - int i1 = indices[i * 3 + 0]; - int i2 = indices[i * 3 + 1]; - int i3 = indices[i * 3 + 2]; - - float3 p1 = vertices[i1]; - float3 p2 = vertices[i2]; - float3 p3 = vertices[i3]; - - CTri t = new CTri(p1, p2, p3, i1, i2, i3); - input_mesh.Add(t); - } - - for (int i = 0; i < indices.Count / 3; i++) - { - int i1 = indices[i * 3 + 0]; - int i2 = indices[i * 3 + 1]; - int i3 = indices[i * 3 + 2]; - - float3 p1 = vertices[i1]; - float3 p2 = vertices[i2]; - float3 p3 = vertices[i3]; - - CTri t = new CTri(p1, p2, p3, i1, i2, i3); - - featureMatch(t, tris, input_mesh); - - if (t.mConcavity > 0.05f) - { - float v = t.getVolume(); - totalVolume += v; - ftris.Add(t); - } - } - - SplitPlane.computeSplitPlane(vertices, indices, ref plane); - cret = totalVolume; - } - - return cret; - } - - public static bool featureMatch(CTri m, List tris, List input_mesh) - { - bool ret = false; - float neardot = 0.707f; - m.mConcavity = 0; - - for (int i = 0; i < tris.Count; i++) - { - CTri t = tris[i]; - - if (t.samePlane(m)) - { - ret = false; - break; - } - - float dot = float3.dot(t.mNormal, m.mNormal); - - if (dot > neardot) - { - float d1 = t.planeDistance(m.mP1); - float d2 = t.planeDistance(m.mP2); - float d3 = t.planeDistance(m.mP3); - - if (d1 > 0.001f || d2 > 0.001f || d3 > 0.001f) // can't be near coplaner! - { - neardot = dot; - - t.raySect(m.mP1, m.mNormal, ref m.mNear1); - t.raySect(m.mP2, m.mNormal, ref m.mNear2); - t.raySect(m.mP3, m.mNormal, ref m.mNear3); - - ret = true; - } - } - } - - if (ret) - { - m.mC1 = m.mP1.Distance(m.mNear1); - m.mC2 = m.mP2.Distance(m.mNear2); - m.mC3 = m.mP3.Distance(m.mNear3); - - m.mConcavity = m.mC1; - - if (m.mC2 > m.mConcavity) - m.mConcavity = m.mC2; - if (m.mC3 > m.mConcavity) - m.mConcavity = m.mC3; - } - - return ret; - } - - private static float det(float3 p1, float3 p2, float3 p3) - { - return p1.x * p2.y * p3.z + p2.x * p3.y * p1.z + p3.x * p1.y * p2.z - p1.x * p3.y * p2.z - p2.x * p1.y * p3.z - p3.x * p2.y * p1.z; - } - - public static float computeMeshVolume(List vertices, List indices) - { - float volume = 0f; - - for (int i = 0; i < indices.Count / 3; i++) - { - float3 p1 = vertices[indices[i * 3 + 0]]; - float3 p2 = vertices[indices[i * 3 + 1]]; - float3 p3 = vertices[indices[i * 3 + 2]]; - - volume += det(p1, p2, p3); // compute the volume of the tetrahedran relative to the origin. - } - - volume *= (1.0f / 6.0f); - if (volume < 0f) - return -volume; - return volume; - } - - public static float computeMeshVolume2(List vertices, List indices) - { - float volume = 0f; - - float3 p0 = vertices[0]; - for (int i = 0; i < indices.Count / 3; i++) - { - float3 p1 = vertices[indices[i * 3 + 0]]; - float3 p2 = vertices[indices[i * 3 + 1]]; - float3 p3 = vertices[indices[i * 3 + 2]]; - - volume += tetVolume(p0, p1, p2, p3); // compute the volume of the tetrahedron relative to the root vertice - } - - return volume * (1.0f / 6.0f); - } - - private static float tetVolume(float3 p0, float3 p1, float3 p2, float3 p3) - { - float3 a = p1 - p0; - float3 b = p2 - p0; - float3 c = p3 - p0; - - float3 cross = float3.cross(b, c); - float volume = float3.dot(a, cross); - - if (volume < 0f) - return -volume; - return volume; - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs deleted file mode 100644 index dfaede1..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs +++ /dev/null @@ -1,411 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class DecompDesc - { - public List mVertices; - public List mIndices; - - // options - public uint mDepth; // depth to split, a maximum of 10, generally not over 7. - public float mCpercent; // the concavity threshold percentage. 0=20 is reasonable. - public float mPpercent; // the percentage volume conservation threshold to collapse hulls. 0-30 is reasonable. - - // hull output limits. - public uint mMaxVertices; // maximum number of vertices in the output hull. Recommended 32 or less. - public float mSkinWidth; // a skin width to apply to the output hulls. - - public ConvexDecompositionCallback mCallback; // the interface to receive back the results. - - public DecompDesc() - { - mDepth = 5; - mCpercent = 5; - mPpercent = 5; - mMaxVertices = 32; - } - } - - public class CHull - { - public float[] mMin = new float[3]; - public float[] mMax = new float[3]; - public float mVolume; - public float mDiagonal; - public ConvexResult mResult; - - public CHull(ConvexResult result) - { - mResult = new ConvexResult(result); - mVolume = Concavity.computeMeshVolume(result.HullVertices, result.HullIndices); - - mDiagonal = getBoundingRegion(result.HullVertices, mMin, mMax); - - float dx = mMax[0] - mMin[0]; - float dy = mMax[1] - mMin[1]; - float dz = mMax[2] - mMin[2]; - - dx *= 0.1f; // inflate 1/10th on each edge - dy *= 0.1f; // inflate 1/10th on each edge - dz *= 0.1f; // inflate 1/10th on each edge - - mMin[0] -= dx; - mMin[1] -= dy; - mMin[2] -= dz; - - mMax[0] += dx; - mMax[1] += dy; - mMax[2] += dz; - } - - public void Dispose() - { - mResult = null; - } - - public bool overlap(CHull h) - { - return overlapAABB(mMin, mMax, h.mMin, h.mMax); - } - - // returns the d1Giagonal distance - private static float getBoundingRegion(List points, float[] bmin, float[] bmax) - { - float3 first = points[0]; - - bmin[0] = first.x; - bmin[1] = first.y; - bmin[2] = first.z; - - bmax[0] = first.x; - bmax[1] = first.y; - bmax[2] = first.z; - - for (int i = 1; i < points.Count; i++) - { - float3 p = points[i]; - - if (p[0] < bmin[0]) bmin[0] = p[0]; - if (p[1] < bmin[1]) bmin[1] = p[1]; - if (p[2] < bmin[2]) bmin[2] = p[2]; - - if (p[0] > bmax[0]) bmax[0] = p[0]; - if (p[1] > bmax[1]) bmax[1] = p[1]; - if (p[2] > bmax[2]) bmax[2] = p[2]; - } - - float dx = bmax[0] - bmin[0]; - float dy = bmax[1] - bmin[1]; - float dz = bmax[2] - bmin[2]; - - return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz); - } - - // return true if the two AABB's overlap. - private static bool overlapAABB(float[] bmin1, float[] bmax1, float[] bmin2, float[] bmax2) - { - if (bmax2[0] < bmin1[0]) return false; // if the maximum is less than our minimum on any axis - if (bmax2[1] < bmin1[1]) return false; - if (bmax2[2] < bmin1[2]) return false; - - if (bmin2[0] > bmax1[0]) return false; // if the minimum is greater than our maximum on any axis - if (bmin2[1] > bmax1[1]) return false; // if the minimum is greater than our maximum on any axis - if (bmin2[2] > bmax1[2]) return false; // if the minimum is greater than our maximum on any axis - - return true; // the extents overlap - } - } - - public class ConvexBuilder - { - public List mChulls = new List(); - private ConvexDecompositionCallback mCallback; - - private int MAXDEPTH = 8; - private float CONCAVE_PERCENT = 1f; - private float MERGE_PERCENT = 2f; - - public ConvexBuilder(ConvexDecompositionCallback callback) - { - mCallback = callback; - } - - public void Dispose() - { - int i; - for (i = 0; i < mChulls.Count; i++) - { - CHull cr = mChulls[i]; - cr.Dispose(); - } - } - - public bool isDuplicate(uint i1, uint i2, uint i3, uint ci1, uint ci2, uint ci3) - { - uint dcount = 0; - - Debug.Assert(i1 != i2 && i1 != i3 && i2 != i3); - Debug.Assert(ci1 != ci2 && ci1 != ci3 && ci2 != ci3); - - if (i1 == ci1 || i1 == ci2 || i1 == ci3) - dcount++; - if (i2 == ci1 || i2 == ci2 || i2 == ci3) - dcount++; - if (i3 == ci1 || i3 == ci2 || i3 == ci3) - dcount++; - - return dcount == 3; - } - - public void getMesh(ConvexResult cr, VertexPool vc, List indices) - { - List src = cr.HullIndices; - - for (int i = 0; i < src.Count / 3; i++) - { - int i1 = src[i * 3 + 0]; - int i2 = src[i * 3 + 1]; - int i3 = src[i * 3 + 2]; - - float3 p1 = cr.HullVertices[i1]; - float3 p2 = cr.HullVertices[i2]; - float3 p3 = cr.HullVertices[i3]; - - i1 = vc.getIndex(p1); - i2 = vc.getIndex(p2); - i3 = vc.getIndex(p3); - } - } - - public CHull canMerge(CHull a, CHull b) - { - if (!a.overlap(b)) // if their AABB's (with a little slop) don't overlap, then return. - return null; - - CHull ret = null; - - // ok..we are going to combine both meshes into a single mesh - // and then we are going to compute the concavity... - - VertexPool vc = new VertexPool(); - - List indices = new List(); - - getMesh(a.mResult, vc, indices); - getMesh(b.mResult, vc, indices); - - int vcount = vc.GetSize(); - List vertices = vc.GetVertices(); - int tcount = indices.Count / 3; - - //don't do anything if hull is empty - if (tcount == 0) - { - vc.Clear(); - return null; - } - - HullResult hresult = new HullResult(); - HullDesc desc = new HullDesc(); - - desc.SetHullFlag(HullFlag.QF_TRIANGLES); - desc.Vertices = vertices; - - HullError hret = HullUtils.CreateConvexHull(desc, ref hresult); - - if (hret == HullError.QE_OK) - { - float combineVolume = Concavity.computeMeshVolume(hresult.OutputVertices, hresult.Indices); - float sumVolume = a.mVolume + b.mVolume; - - float percent = (sumVolume * 100) / combineVolume; - if (percent >= (100.0f - MERGE_PERCENT)) - { - ConvexResult cr = new ConvexResult(hresult.OutputVertices, hresult.Indices); - ret = new CHull(cr); - } - } - - vc.Clear(); - return ret; - } - - public bool combineHulls() - { - bool combine = false; - - sortChulls(mChulls); // sort the convex hulls, largest volume to least... - - List output = new List(); // the output hulls... - - int i; - for (i = 0; i < mChulls.Count && !combine; ++i) - { - CHull cr = mChulls[i]; - - int j; - for (j = 0; j < mChulls.Count; j++) - { - CHull match = mChulls[j]; - - if (cr != match) // don't try to merge a hull with itself, that be stoopid - { - - CHull merge = canMerge(cr, match); // if we can merge these two.... - - if (merge != null) - { - output.Add(merge); - - ++i; - while (i != mChulls.Count) - { - CHull cr2 = mChulls[i]; - if (cr2 != match) - { - output.Add(cr2); - } - i++; - } - - cr.Dispose(); - match.Dispose(); - combine = true; - break; - } - } - } - - if (combine) - { - break; - } - else - { - output.Add(cr); - } - } - - if (combine) - { - mChulls.Clear(); - mChulls = output; - output.Clear(); - } - - return combine; - } - - public int process(DecompDesc desc) - { - int ret = 0; - - MAXDEPTH = (int)desc.mDepth; - CONCAVE_PERCENT = desc.mCpercent; - MERGE_PERCENT = desc.mPpercent; - - ConvexDecomposition.calcConvexDecomposition(desc.mVertices, desc.mIndices, ConvexDecompResult, 0f, 0, MAXDEPTH, CONCAVE_PERCENT, MERGE_PERCENT); - - while (combineHulls()) // keep combinging hulls until I can't combine any more... - ; - - int i; - for (i = 0; i < mChulls.Count; i++) - { - CHull cr = mChulls[i]; - - // before we hand it back to the application, we need to regenerate the hull based on the - // limits given by the user. - - ConvexResult c = cr.mResult; // the high resolution hull... - - HullResult result = new HullResult(); - HullDesc hdesc = new HullDesc(); - - hdesc.SetHullFlag(HullFlag.QF_TRIANGLES); - - hdesc.Vertices = c.HullVertices; - hdesc.MaxVertices = desc.mMaxVertices; // maximum number of vertices allowed in the output - - if (desc.mSkinWidth != 0f) - { - hdesc.SkinWidth = desc.mSkinWidth; - hdesc.SetHullFlag(HullFlag.QF_SKIN_WIDTH); // do skin width computation. - } - - HullError ret2 = HullUtils.CreateConvexHull(hdesc, ref result); - - if (ret2 == HullError.QE_OK) - { - ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices); - - r.mHullVolume = Concavity.computeMeshVolume(result.OutputVertices, result.Indices); // the volume of the hull. - - // compute the best fit OBB - //computeBestFitOBB(result.mNumOutputVertices, result.mOutputVertices, sizeof(float) * 3, r.mOBBSides, r.mOBBTransform); - - //r.mOBBVolume = r.mOBBSides[0] * r.mOBBSides[1] * r.mOBBSides[2]; // compute the OBB volume. - - //fm_getTranslation(r.mOBBTransform, r.mOBBCenter); // get the translation component of the 4x4 matrix. - - //fm_matrixToQuat(r.mOBBTransform, r.mOBBOrientation); // extract the orientation as a quaternion. - - //r.mSphereRadius = computeBoundingSphere(result.mNumOutputVertices, result.mOutputVertices, r.mSphereCenter); - //r.mSphereVolume = fm_sphereVolume(r.mSphereRadius); - - mCallback(r); - } - - result = null; - cr.Dispose(); - } - - ret = mChulls.Count; - - mChulls.Clear(); - - return ret; - } - - public void ConvexDecompResult(ConvexResult result) - { - CHull ch = new CHull(result); - mChulls.Add(ch); - } - - public void sortChulls(List hulls) - { - hulls.Sort(delegate(CHull a, CHull b) { return a.mVolume.CompareTo(b.mVolume); }); - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs deleted file mode 100644 index 2e2bb70..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs +++ /dev/null @@ -1,200 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public delegate void ConvexDecompositionCallback(ConvexResult result); - - public class FaceTri - { - public float3 P1; - public float3 P2; - public float3 P3; - - public FaceTri() { } - - public FaceTri(List vertices, int i1, int i2, int i3) - { - P1 = new float3(vertices[i1]); - P2 = new float3(vertices[i2]); - P3 = new float3(vertices[i3]); - } - } - - public static class ConvexDecomposition - { - private static void addTri(VertexPool vl, List list, float3 p1, float3 p2, float3 p3) - { - int i1 = vl.getIndex(p1); - int i2 = vl.getIndex(p2); - int i3 = vl.getIndex(p3); - - // do *not* process degenerate triangles! - if ( i1 != i2 && i1 != i3 && i2 != i3 ) - { - list.Add(i1); - list.Add(i2); - list.Add(i3); - } - } - - public static void calcConvexDecomposition(List vertices, List indices, ConvexDecompositionCallback callback, float masterVolume, int depth, - int maxDepth, float concavePercent, float mergePercent) - { - float4 plane = new float4(); - bool split = false; - - if (depth < maxDepth) - { - float volume = 0f; - float c = Concavity.computeConcavity(vertices, indices, ref plane, ref volume); - - if (depth == 0) - { - masterVolume = volume; - } - - float percent = (c * 100.0f) / masterVolume; - - if (percent > concavePercent) // if great than 5% of the total volume is concave, go ahead and keep splitting. - { - split = true; - } - } - - if (depth >= maxDepth || !split) - { - HullResult result = new HullResult(); - HullDesc desc = new HullDesc(); - - desc.SetHullFlag(HullFlag.QF_TRIANGLES); - - desc.Vertices = vertices; - - HullError ret = HullUtils.CreateConvexHull(desc, ref result); - - if (ret == HullError.QE_OK) - { - ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices); - callback(r); - } - - return; - } - - List ifront = new List(); - List iback = new List(); - - VertexPool vfront = new VertexPool(); - VertexPool vback = new VertexPool(); - - // ok..now we are going to 'split' all of the input triangles against this plane! - for (int i = 0; i < indices.Count / 3; i++) - { - int i1 = indices[i * 3 + 0]; - int i2 = indices[i * 3 + 1]; - int i3 = indices[i * 3 + 2]; - - FaceTri t = new FaceTri(vertices, i1, i2, i3); - - float3[] front = new float3[4]; - float3[] back = new float3[4]; - - int fcount = 0; - int bcount = 0; - - PlaneTriResult result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount); - - if (fcount > 4 || bcount > 4) - { - result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount); - } - - switch (result) - { - case PlaneTriResult.PTR_FRONT: - Debug.Assert(fcount == 3); - addTri(vfront, ifront, front[0], front[1], front[2]); - break; - case PlaneTriResult.PTR_BACK: - Debug.Assert(bcount == 3); - addTri(vback, iback, back[0], back[1], back[2]); - break; - case PlaneTriResult.PTR_SPLIT: - Debug.Assert(fcount >= 3 && fcount <= 4); - Debug.Assert(bcount >= 3 && bcount <= 4); - - addTri(vfront, ifront, front[0], front[1], front[2]); - addTri(vback, iback, back[0], back[1], back[2]); - - if (fcount == 4) - { - addTri(vfront, ifront, front[0], front[2], front[3]); - } - - if (bcount == 4) - { - addTri(vback, iback, back[0], back[2], back[3]); - } - - break; - } - } - - // ok... here we recursively call - if (ifront.Count > 0) - { - int vcount = vfront.GetSize(); - List vertices2 = vfront.GetVertices(); - for (int i = 0; i < vertices2.Count; i++) - vertices2[i] = new float3(vertices2[i]); - int tcount = ifront.Count / 3; - - calcConvexDecomposition(vertices2, ifront, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent); - } - - ifront.Clear(); - vfront.Clear(); - - if (iback.Count > 0) - { - int vcount = vback.GetSize(); - List vertices2 = vback.GetVertices(); - int tcount = iback.Count / 3; - - calcConvexDecomposition(vertices2, iback, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent); - } - - iback.Clear(); - vback.Clear(); - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs deleted file mode 100644 index 87758b5..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs +++ /dev/null @@ -1,74 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class ConvexResult - { - public List HullVertices; - public List HullIndices; - - public float mHullVolume; // the volume of the convex hull. - - //public float[] OBBSides = new float[3]; // the width, height and breadth of the best fit OBB - //public float[] OBBCenter = new float[3]; // the center of the OBB - //public float[] OBBOrientation = new float[4]; // the quaternion rotation of the OBB. - //public float[] OBBTransform = new float[16]; // the 4x4 transform of the OBB. - //public float OBBVolume; // the volume of the OBB - - //public float SphereRadius; // radius and center of best fit sphere - //public float[] SphereCenter = new float[3]; - //public float SphereVolume; // volume of the best fit sphere - - public ConvexResult() - { - HullVertices = new List(); - HullIndices = new List(); - } - - public ConvexResult(List hvertices, List hindices) - { - HullVertices = hvertices; - HullIndices = hindices; - } - - public ConvexResult(ConvexResult r) - { - HullVertices = new List(r.HullVertices); - HullIndices = new List(r.HullIndices); - } - - public void Dispose() - { - HullVertices = null; - HullIndices = null; - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs deleted file mode 100644 index d81df26..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs +++ /dev/null @@ -1,171 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class HullResult - { - public bool Polygons = true; // true if indices represents polygons, false indices are triangles - public List OutputVertices = new List(); - public List Indices; - - // If triangles, then indices are array indexes into the vertex list. - // If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc.. - } - - public class PHullResult - { - public List Vertices = new List(); - public List Indices = new List(); - } - - [Flags] - public enum HullFlag : int - { - QF_DEFAULT = 0, - QF_TRIANGLES = (1 << 0), // report results as triangles, not polygons. - QF_SKIN_WIDTH = (1 << 2) // extrude hull based on this skin width - } - - public enum HullError : int - { - QE_OK, // success! - QE_FAIL // failed. - } - - public class HullDesc - { - public HullFlag Flags; // flags to use when generating the convex hull. - public List Vertices; - public float NormalEpsilon; // the epsilon for removing duplicates. This is a normalized value, if normalized bit is on. - public float SkinWidth; - public uint MaxVertices; // maximum number of vertices to be considered for the hull! - public uint MaxFaces; - - public HullDesc() - { - Flags = HullFlag.QF_DEFAULT; - Vertices = new List(); - NormalEpsilon = 0.001f; - MaxVertices = 4096; - MaxFaces = 4096; - SkinWidth = 0.01f; - } - - public HullDesc(HullFlag flags, List vertices) - { - Flags = flags; - Vertices = new List(vertices); - NormalEpsilon = 0.001f; - MaxVertices = 4096; - MaxFaces = 4096; - SkinWidth = 0.01f; - } - - public bool HasHullFlag(HullFlag flag) - { - return (Flags & flag) != 0; - } - - public void SetHullFlag(HullFlag flag) - { - Flags |= flag; - } - - public void ClearHullFlag(HullFlag flag) - { - Flags &= ~flag; - } - } - - public class ConvexH - { - public struct HalfEdge - { - public short ea; // the other half of the edge (index into edges list) - public byte v; // the vertex at the start of this edge (index into vertices list) - public byte p; // the facet on which this edge lies (index into facets list) - - public HalfEdge(short _ea, byte _v, byte _p) - { - ea = _ea; - v = _v; - p = _p; - } - - public HalfEdge(HalfEdge e) - { - ea = e.ea; - v = e.v; - p = e.p; - } - } - - public List vertices = new List(); - public List edges = new List(); - public List facets = new List(); - - public ConvexH(int vertices_size, int edges_size, int facets_size) - { - vertices = new List(vertices_size); - edges = new List(edges_size); - facets = new List(facets_size); - } - } - - public class VertFlag - { - public byte planetest; - public byte junk; - public byte undermap; - public byte overmap; - } - - public class EdgeFlag - { - public byte planetest; - public byte fixes; - public short undermap; - public short overmap; - } - - public class PlaneFlag - { - public byte undermap; - public byte overmap; - } - - public class Coplanar - { - public ushort ea; - public byte v0; - public byte v1; - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs deleted file mode 100644 index 1119a75..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs +++ /dev/null @@ -1,99 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class HullTriangle : int3 - { - public int3 n = new int3(); - public int id; - public int vmax; - public float rise; - private List tris; - - public HullTriangle(int a, int b, int c, List tris) - : base(a, b, c) - { - this.tris = tris; - - n = new int3(-1, -1, -1); - id = tris.Count; - tris.Add(this); - vmax = -1; - rise = 0.0f; - } - - public void Dispose() - { - Debug.Assert(tris[id] == this); - tris[id] = null; - } - - public int neib(int a, int b) - { - int i; - - for (i = 0; i < 3; i++) - { - int i1 = (i + 1) % 3; - int i2 = (i + 2) % 3; - if ((this)[i] == a && (this)[i1] == b) - return n[i2]; - if ((this)[i] == b && (this)[i1] == a) - return n[i2]; - } - - Debug.Assert(false); - return -1; - } - - public void setneib(int a, int b, int value) - { - int i; - - for (i = 0; i < 3; i++) - { - int i1 = (i + 1) % 3; - int i2 = (i + 2) % 3; - if ((this)[i] == a && (this)[i1] == b) - { - n[i2] = value; - return; - } - if ((this)[i] == b && (this)[i1] == a) - { - n[i2] = value; - return; - } - } - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs deleted file mode 100644 index c9ccfe2..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs +++ /dev/null @@ -1,1868 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public static class HullUtils - { - public static int argmin(float[] a, int n) - { - int r = 0; - for (int i = 1; i < n; i++) - { - if (a[i] < a[r]) - { - r = i; - } - } - return r; - } - - public static float clampf(float a) - { - return Math.Min(1.0f, Math.Max(0.0f, a)); - } - - public static float Round(float a, float precision) - { - return (float)Math.Floor(0.5f + a / precision) * precision; - } - - public static float Interpolate(float f0, float f1, float alpha) - { - return f0 * (1 - alpha) + f1 * alpha; - } - - public static void Swap(ref T a, ref T b) - { - T tmp = a; - a = b; - b = tmp; - } - - public static bool above(List vertices, int3 t, float3 p, float epsilon) - { - float3 vtx = vertices[t.x]; - float3 n = TriNormal(vtx, vertices[t.y], vertices[t.z]); - return (float3.dot(n, p - vtx) > epsilon); // EPSILON??? - } - - public static int hasedge(int3 t, int a, int b) - { - for (int i = 0; i < 3; i++) - { - int i1 = (i + 1) % 3; - if (t[i] == a && t[i1] == b) - return 1; - } - return 0; - } - - public static bool hasvert(int3 t, int v) - { - return (t[0] == v || t[1] == v || t[2] == v); - } - - public static int shareedge(int3 a, int3 b) - { - int i; - for (i = 0; i < 3; i++) - { - int i1 = (i + 1) % 3; - if (hasedge(a, b[i1], b[i]) != 0) - return 1; - } - return 0; - } - - public static void b2bfix(HullTriangle s, HullTriangle t, List tris) - { - int i; - for (i = 0; i < 3; i++) - { - int i1 = (i + 1) % 3; - int i2 = (i + 2) % 3; - int a = (s)[i1]; - int b = (s)[i2]; - Debug.Assert(tris[s.neib(a, b)].neib(b, a) == s.id); - Debug.Assert(tris[t.neib(a, b)].neib(b, a) == t.id); - tris[s.neib(a, b)].setneib(b, a, t.neib(b, a)); - tris[t.neib(b, a)].setneib(a, b, s.neib(a, b)); - } - } - - public static void removeb2b(HullTriangle s, HullTriangle t, List tris) - { - b2bfix(s, t, tris); - s.Dispose(); - t.Dispose(); - } - - public static void checkit(HullTriangle t, List tris) - { - int i; - Debug.Assert(tris[t.id] == t); - for (i = 0; i < 3; i++) - { - int i1 = (i + 1) % 3; - int i2 = (i + 2) % 3; - int a = (t)[i1]; - int b = (t)[i2]; - Debug.Assert(a != b); - Debug.Assert(tris[t.n[i]].neib(b, a) == t.id); - } - } - - public static void extrude(HullTriangle t0, int v, List tris) - { - int3 t = t0; - int n = tris.Count; - HullTriangle ta = new HullTriangle(v, t[1], t[2], tris); - ta.n = new int3(t0.n[0], n + 1, n + 2); - tris[t0.n[0]].setneib(t[1], t[2], n + 0); - HullTriangle tb = new HullTriangle(v, t[2], t[0], tris); - tb.n = new int3(t0.n[1], n + 2, n + 0); - tris[t0.n[1]].setneib(t[2], t[0], n + 1); - HullTriangle tc = new HullTriangle(v, t[0], t[1], tris); - tc.n = new int3(t0.n[2], n + 0, n + 1); - tris[t0.n[2]].setneib(t[0], t[1], n + 2); - checkit(ta, tris); - checkit(tb, tris); - checkit(tc, tris); - if (hasvert(tris[ta.n[0]], v)) - removeb2b(ta, tris[ta.n[0]], tris); - if (hasvert(tris[tb.n[0]], v)) - removeb2b(tb, tris[tb.n[0]], tris); - if (hasvert(tris[tc.n[0]], v)) - removeb2b(tc, tris[tc.n[0]], tris); - t0.Dispose(); - } - - public static HullTriangle extrudable(float epsilon, List tris) - { - int i; - HullTriangle t = null; - for (i = 0; i < tris.Count; i++) - { - if (t == null || (tris.Count > i && (object)tris[i] != null && t.rise < tris[i].rise)) - { - t = tris[i]; - } - } - return (t.rise > epsilon) ? t : null; - } - - public static Quaternion RotationArc(float3 v0, float3 v1) - { - Quaternion q = new Quaternion(); - v0 = float3.normalize(v0); // Comment these two lines out if you know its not needed. - v1 = float3.normalize(v1); // If vector is already unit length then why do it again? - float3 c = float3.cross(v0, v1); - float d = float3.dot(v0, v1); - if (d <= -1.0f) // 180 about x axis - { - return new Quaternion(1f, 0f, 0f, 0f); - } - float s = (float)Math.Sqrt((1 + d) * 2f); - q.x = c.x / s; - q.y = c.y / s; - q.z = c.z / s; - q.w = s / 2.0f; - return q; - } - - public static float3 PlaneLineIntersection(Plane plane, float3 p0, float3 p1) - { - // returns the point where the line p0-p1 intersects the plane n&d - float3 dif = p1 - p0; - float dn = float3.dot(plane.normal, dif); - float t = -(plane.dist + float3.dot(plane.normal, p0)) / dn; - return p0 + (dif * t); - } - - public static float3 LineProject(float3 p0, float3 p1, float3 a) - { - float3 w = new float3(); - w = p1 - p0; - float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z); - return p0 + w * t; - } - - public static float3 PlaneProject(Plane plane, float3 point) - { - return point - plane.normal * (float3.dot(point, plane.normal) + plane.dist); - } - - public static float LineProjectTime(float3 p0, float3 p1, float3 a) - { - float3 w = new float3(); - w = p1 - p0; - float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z); - return t; - } - - public static float3 ThreePlaneIntersection(Plane p0, Plane p1, Plane p2) - { - float3x3 mp = float3x3.Transpose(new float3x3(p0.normal, p1.normal, p2.normal)); - float3x3 mi = float3x3.Inverse(mp); - float3 b = new float3(p0.dist, p1.dist, p2.dist); - return -b * mi; - } - - public static bool PolyHit(List vert, float3 v0, float3 v1) - { - float3 impact = new float3(); - float3 normal = new float3(); - return PolyHit(vert, v0, v1, out impact, out normal); - } - - public static bool PolyHit(List vert, float3 v0, float3 v1, out float3 impact) - { - float3 normal = new float3(); - return PolyHit(vert, v0, v1, out impact, out normal); - } - - public static bool PolyHit(List vert, float3 v0, float3 v1, out float3 impact, out float3 normal) - { - float3 the_point = new float3(); - - impact = null; - normal = null; - - int i; - float3 nrml = new float3(0, 0, 0); - for (i = 0; i < vert.Count; i++) - { - int i1 = (i + 1) % vert.Count; - int i2 = (i + 2) % vert.Count; - nrml = nrml + float3.cross(vert[i1] - vert[i], vert[i2] - vert[i1]); - } - - float m = float3.magnitude(nrml); - if (m == 0.0) - { - return false; - } - nrml = nrml * (1.0f / m); - float dist = -float3.dot(nrml, vert[0]); - float d0; - float d1; - if ((d0 = float3.dot(v0, nrml) + dist) < 0 || (d1 = float3.dot(v1, nrml) + dist) > 0) - { - return false; - } - - // By using the cached plane distances d0 and d1 - // we can optimize the following: - // the_point = planelineintersection(nrml,dist,v0,v1); - float a = d0 / (d0 - d1); - the_point = v0 * (1 - a) + v1 * a; - - - bool inside = true; - for (int j = 0; inside && j < vert.Count; j++) - { - // let inside = 0 if outside - float3 pp1 = new float3(); - float3 pp2 = new float3(); - float3 side = new float3(); - pp1 = vert[j]; - pp2 = vert[(j + 1) % vert.Count]; - side = float3.cross((pp2 - pp1), (the_point - pp1)); - inside = (float3.dot(nrml, side) >= 0.0); - } - if (inside) - { - if (normal != null) - { - normal = nrml; - } - if (impact != null) - { - impact = the_point; - } - } - return inside; - } - - public static bool BoxInside(float3 p, float3 bmin, float3 bmax) - { - return (p.x >= bmin.x && p.x <= bmax.x && p.y >= bmin.y && p.y <= bmax.y && p.z >= bmin.z && p.z <= bmax.z); - } - - public static bool BoxIntersect(float3 v0, float3 v1, float3 bmin, float3 bmax, float3 impact) - { - if (BoxInside(v0, bmin, bmax)) - { - impact = v0; - return true; - } - if (v0.x <= bmin.x && v1.x >= bmin.x) - { - float a = (bmin.x - v0.x) / (v1.x - v0.x); - //v.x = bmin.x; - float vy = (1 - a) * v0.y + a * v1.y; - float vz = (1 - a) * v0.z + a * v1.z; - if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z) - { - impact.x = bmin.x; - impact.y = vy; - impact.z = vz; - return true; - } - } - else if (v0.x >= bmax.x && v1.x <= bmax.x) - { - float a = (bmax.x - v0.x) / (v1.x - v0.x); - //v.x = bmax.x; - float vy = (1 - a) * v0.y + a * v1.y; - float vz = (1 - a) * v0.z + a * v1.z; - if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z) - { - impact.x = bmax.x; - impact.y = vy; - impact.z = vz; - return true; - } - } - if (v0.y <= bmin.y && v1.y >= bmin.y) - { - float a = (bmin.y - v0.y) / (v1.y - v0.y); - float vx = (1 - a) * v0.x + a * v1.x; - //v.y = bmin.y; - float vz = (1 - a) * v0.z + a * v1.z; - if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z) - { - impact.x = vx; - impact.y = bmin.y; - impact.z = vz; - return true; - } - } - else if (v0.y >= bmax.y && v1.y <= bmax.y) - { - float a = (bmax.y - v0.y) / (v1.y - v0.y); - float vx = (1 - a) * v0.x + a * v1.x; - // vy = bmax.y; - float vz = (1 - a) * v0.z + a * v1.z; - if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z) - { - impact.x = vx; - impact.y = bmax.y; - impact.z = vz; - return true; - } - } - if (v0.z <= bmin.z && v1.z >= bmin.z) - { - float a = (bmin.z - v0.z) / (v1.z - v0.z); - float vx = (1 - a) * v0.x + a * v1.x; - float vy = (1 - a) * v0.y + a * v1.y; - // v.z = bmin.z; - if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x) - { - impact.x = vx; - impact.y = vy; - impact.z = bmin.z; - return true; - } - } - else if (v0.z >= bmax.z && v1.z <= bmax.z) - { - float a = (bmax.z - v0.z) / (v1.z - v0.z); - float vx = (1 - a) * v0.x + a * v1.x; - float vy = (1 - a) * v0.y + a * v1.y; - // v.z = bmax.z; - if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x) - { - impact.x = vx; - impact.y = vy; - impact.z = bmax.z; - return true; - } - } - return false; - } - - public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint) - { - return DistanceBetweenLines(ustart, udir, vstart, vdir, upoint, null); - } - - public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir) - { - return DistanceBetweenLines(ustart, udir, vstart, vdir, null, null); - } - - public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint, float3 vpoint) - { - float3 cp = float3.normalize(float3.cross(udir, vdir)); - - float distu = -float3.dot(cp, ustart); - float distv = -float3.dot(cp, vstart); - float dist = (float)Math.Abs(distu - distv); - if (upoint != null) - { - Plane plane = new Plane(); - plane.normal = float3.normalize(float3.cross(vdir, cp)); - plane.dist = -float3.dot(plane.normal, vstart); - upoint = PlaneLineIntersection(plane, ustart, ustart + udir); - } - if (vpoint != null) - { - Plane plane = new Plane(); - plane.normal = float3.normalize(float3.cross(udir, cp)); - plane.dist = -float3.dot(plane.normal, ustart); - vpoint = PlaneLineIntersection(plane, vstart, vstart + vdir); - } - return dist; - } - - public static float3 TriNormal(float3 v0, float3 v1, float3 v2) - { - // return the normal of the triangle - // inscribed by v0, v1, and v2 - float3 cp = float3.cross(v1 - v0, v2 - v1); - float m = float3.magnitude(cp); - if (m == 0) - return new float3(1, 0, 0); - return cp * (1.0f / m); - } - - public static int PlaneTest(Plane p, float3 v, float planetestepsilon) - { - float a = float3.dot(v, p.normal) + p.dist; - int flag = (a > planetestepsilon) ? (2) : ((a < -planetestepsilon) ? (1) : (0)); - return flag; - } - - public static int SplitTest(ref ConvexH convex, Plane plane, float planetestepsilon) - { - int flag = 0; - for (int i = 0; i < convex.vertices.Count; i++) - { - flag |= PlaneTest(plane, convex.vertices[i], planetestepsilon); - } - return flag; - } - - public static Quaternion VirtualTrackBall(float3 cop, float3 cor, float3 dir1, float3 dir2) - { - // routine taken from game programming gems. - // Implement track ball functionality to spin stuf on the screen - // cop center of projection - // cor center of rotation - // dir1 old mouse direction - // dir2 new mouse direction - // pretend there is a sphere around cor. Then find the points - // where dir1 and dir2 intersect that sphere. Find the - // rotation that takes the first point to the second. - float m; - // compute plane - float3 nrml = cor - cop; - float fudgefactor = 1.0f / (float3.magnitude(nrml) * 0.25f); // since trackball proportional to distance from cop - nrml = float3.normalize(nrml); - float dist = -float3.dot(nrml, cor); - float3 u = PlaneLineIntersection(new Plane(nrml, dist), cop, cop + dir1); - u = u - cor; - u = u * fudgefactor; - m = float3.magnitude(u); - if (m > 1) - { - u /= m; - } - else - { - u = u - (nrml * (float)Math.Sqrt(1 - m * m)); - } - float3 v = PlaneLineIntersection(new Plane(nrml, dist), cop, cop + dir2); - v = v - cor; - v = v * fudgefactor; - m = float3.magnitude(v); - if (m > 1) - { - v /= m; - } - else - { - v = v - (nrml * (float)Math.Sqrt(1 - m * m)); - } - return RotationArc(u, v); - } - - public static bool AssertIntact(ConvexH convex, float planetestepsilon) - { - int i; - int estart = 0; - for (i = 0; i < convex.edges.Count; i++) - { - if (convex.edges[estart].p != convex.edges[i].p) - { - estart = i; - } - int inext = i + 1; - if (inext >= convex.edges.Count || convex.edges[inext].p != convex.edges[i].p) - { - inext = estart; - } - Debug.Assert(convex.edges[inext].p == convex.edges[i].p); - int nb = convex.edges[i].ea; - Debug.Assert(nb != 255); - if (nb == 255 || nb == -1) - return false; - Debug.Assert(nb != -1); - Debug.Assert(i == convex.edges[nb].ea); - } - for (i = 0; i < convex.edges.Count; i++) - { - Debug.Assert((0) == PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon)); - if ((0) != PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon)) - return false; - if (convex.edges[estart].p != convex.edges[i].p) - { - estart = i; - } - int i1 = i + 1; - if (i1 >= convex.edges.Count || convex.edges[i1].p != convex.edges[i].p) - { - i1 = estart; - } - int i2 = i1 + 1; - if (i2 >= convex.edges.Count || convex.edges[i2].p != convex.edges[i].p) - { - i2 = estart; - } - if (i == i2) // i sliced tangent to an edge and created 2 meaningless edges - continue; - float3 localnormal = TriNormal(convex.vertices[convex.edges[i].v], convex.vertices[convex.edges[i1].v], convex.vertices[convex.edges[i2].v]); - Debug.Assert(float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) > 0); - if (float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) <= 0) - return false; - } - return true; - } - - public static ConvexH test_btbq(float planetestepsilon) - { - // back to back quads - ConvexH convex = new ConvexH(4, 8, 2); - convex.vertices[0] = new float3(0, 0, 0); - convex.vertices[1] = new float3(1, 0, 0); - convex.vertices[2] = new float3(1, 1, 0); - convex.vertices[3] = new float3(0, 1, 0); - convex.facets[0] = new Plane(new float3(0, 0, 1), 0); - convex.facets[1] = new Plane(new float3(0, 0, -1), 0); - convex.edges[0] = new ConvexH.HalfEdge(7, 0, 0); - convex.edges[1] = new ConvexH.HalfEdge(6, 1, 0); - convex.edges[2] = new ConvexH.HalfEdge(5, 2, 0); - convex.edges[3] = new ConvexH.HalfEdge(4, 3, 0); - - convex.edges[4] = new ConvexH.HalfEdge(3, 0, 1); - convex.edges[5] = new ConvexH.HalfEdge(2, 3, 1); - convex.edges[6] = new ConvexH.HalfEdge(1, 2, 1); - convex.edges[7] = new ConvexH.HalfEdge(0, 1, 1); - AssertIntact(convex, planetestepsilon); - return convex; - } - - public static ConvexH test_cube() - { - ConvexH convex = new ConvexH(8, 24, 6); - convex.vertices[0] = new float3(0, 0, 0); - convex.vertices[1] = new float3(0, 0, 1); - convex.vertices[2] = new float3(0, 1, 0); - convex.vertices[3] = new float3(0, 1, 1); - convex.vertices[4] = new float3(1, 0, 0); - convex.vertices[5] = new float3(1, 0, 1); - convex.vertices[6] = new float3(1, 1, 0); - convex.vertices[7] = new float3(1, 1, 1); - - convex.facets[0] = new Plane(new float3(-1, 0, 0), 0); - convex.facets[1] = new Plane(new float3(1, 0, 0), -1); - convex.facets[2] = new Plane(new float3(0, -1, 0), 0); - convex.facets[3] = new Plane(new float3(0, 1, 0), -1); - convex.facets[4] = new Plane(new float3(0, 0, -1), 0); - convex.facets[5] = new Plane(new float3(0, 0, 1), -1); - - convex.edges[0] = new ConvexH.HalfEdge(11, 0, 0); - convex.edges[1] = new ConvexH.HalfEdge(23, 1, 0); - convex.edges[2] = new ConvexH.HalfEdge(15, 3, 0); - convex.edges[3] = new ConvexH.HalfEdge(16, 2, 0); - - convex.edges[4] = new ConvexH.HalfEdge(13, 6, 1); - convex.edges[5] = new ConvexH.HalfEdge(21, 7, 1); - convex.edges[6] = new ConvexH.HalfEdge(9, 5, 1); - convex.edges[7] = new ConvexH.HalfEdge(18, 4, 1); - - convex.edges[8] = new ConvexH.HalfEdge(19, 0, 2); - convex.edges[9] = new ConvexH.HalfEdge(6, 4, 2); - convex.edges[10] = new ConvexH.HalfEdge(20, 5, 2); - convex.edges[11] = new ConvexH.HalfEdge(0, 1, 2); - - convex.edges[12] = new ConvexH.HalfEdge(22, 3, 3); - convex.edges[13] = new ConvexH.HalfEdge(4, 7, 3); - convex.edges[14] = new ConvexH.HalfEdge(17, 6, 3); - convex.edges[15] = new ConvexH.HalfEdge(2, 2, 3); - - convex.edges[16] = new ConvexH.HalfEdge(3, 0, 4); - convex.edges[17] = new ConvexH.HalfEdge(14, 2, 4); - convex.edges[18] = new ConvexH.HalfEdge(7, 6, 4); - convex.edges[19] = new ConvexH.HalfEdge(8, 4, 4); - - convex.edges[20] = new ConvexH.HalfEdge(10, 1, 5); - convex.edges[21] = new ConvexH.HalfEdge(5, 5, 5); - convex.edges[22] = new ConvexH.HalfEdge(12, 7, 5); - convex.edges[23] = new ConvexH.HalfEdge(1, 3, 5); - - return convex; - } - - public static ConvexH ConvexHMakeCube(float3 bmin, float3 bmax) - { - ConvexH convex = test_cube(); - convex.vertices[0] = new float3(bmin.x, bmin.y, bmin.z); - convex.vertices[1] = new float3(bmin.x, bmin.y, bmax.z); - convex.vertices[2] = new float3(bmin.x, bmax.y, bmin.z); - convex.vertices[3] = new float3(bmin.x, bmax.y, bmax.z); - convex.vertices[4] = new float3(bmax.x, bmin.y, bmin.z); - convex.vertices[5] = new float3(bmax.x, bmin.y, bmax.z); - convex.vertices[6] = new float3(bmax.x, bmax.y, bmin.z); - convex.vertices[7] = new float3(bmax.x, bmax.y, bmax.z); - - convex.facets[0] = new Plane(new float3(-1, 0, 0), bmin.x); - convex.facets[1] = new Plane(new float3(1, 0, 0), -bmax.x); - convex.facets[2] = new Plane(new float3(0, -1, 0), bmin.y); - convex.facets[3] = new Plane(new float3(0, 1, 0), -bmax.y); - convex.facets[4] = new Plane(new float3(0, 0, -1), bmin.z); - convex.facets[5] = new Plane(new float3(0, 0, 1), -bmax.z); - return convex; - } - - public static ConvexH ConvexHCrop(ref ConvexH convex, Plane slice, float planetestepsilon) - { - int i; - int vertcountunder = 0; - int vertcountover = 0; - List vertscoplanar = new List(); // existing vertex members of convex that are coplanar - List edgesplit = new List(); // existing edges that members of convex that cross the splitplane - - Debug.Assert(convex.edges.Count < 480); - - EdgeFlag[] edgeflag = new EdgeFlag[512]; - VertFlag[] vertflag = new VertFlag[256]; - PlaneFlag[] planeflag = new PlaneFlag[128]; - ConvexH.HalfEdge[] tmpunderedges = new ConvexH.HalfEdge[512]; - Plane[] tmpunderplanes = new Plane[128]; - Coplanar[] coplanaredges = new Coplanar[512]; - int coplanaredges_num = 0; - - List createdverts = new List(); - - // do the side-of-plane tests - for (i = 0; i < convex.vertices.Count; i++) - { - vertflag[i].planetest = (byte)PlaneTest(slice, convex.vertices[i], planetestepsilon); - if (vertflag[i].planetest == (0)) - { - // ? vertscoplanar.Add(i); - vertflag[i].undermap = (byte)vertcountunder++; - vertflag[i].overmap = (byte)vertcountover++; - } - else if (vertflag[i].planetest == (1)) - { - vertflag[i].undermap = (byte)vertcountunder++; - } - else - { - Debug.Assert(vertflag[i].planetest == (2)); - vertflag[i].overmap = (byte)vertcountover++; - vertflag[i].undermap = 255; // for debugging purposes - } - } - int vertcountunderold = vertcountunder; // for debugging only - - int under_edge_count = 0; - int underplanescount = 0; - int e0 = 0; - - for (int currentplane = 0; currentplane < convex.facets.Count; currentplane++) - { - int estart = e0; - int enextface = 0; - int planeside = 0; - int e1 = e0 + 1; - int vout = -1; - int vin = -1; - int coplanaredge = -1; - do - { - - if (e1 >= convex.edges.Count || convex.edges[e1].p != currentplane) - { - enextface = e1; - e1 = estart; - } - ConvexH.HalfEdge edge0 = convex.edges[e0]; - ConvexH.HalfEdge edge1 = convex.edges[e1]; - ConvexH.HalfEdge edgea = convex.edges[edge0.ea]; - - planeside |= vertflag[edge0.v].planetest; - //if((vertflag[edge0.v].planetest & vertflag[edge1.v].planetest) == COPLANAR) { - // assert(ecop==-1); - // ecop=e; - //} - - if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (2)) - { - // both endpoints over plane - edgeflag[e0].undermap = -1; - } - else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (1)) - { - // at least one endpoint under, the other coplanar or under - - edgeflag[e0].undermap = (short)under_edge_count; - tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap; - tmpunderedges[under_edge_count].p = (byte)underplanescount; - if (edge0.ea < e0) - { - // connect the neighbors - Debug.Assert(edgeflag[edge0.ea].undermap != -1); - tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; - tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; - } - under_edge_count++; - } - else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (0)) - { - // both endpoints coplanar - // must check a 3rd point to see if UNDER - int e2 = e1 + 1; - if (e2 >= convex.edges.Count || convex.edges[e2].p != currentplane) - { - e2 = estart; - } - Debug.Assert(convex.edges[e2].p == currentplane); - ConvexH.HalfEdge edge2 = convex.edges[e2]; - if (vertflag[edge2.v].planetest == (1)) - { - - edgeflag[e0].undermap = (short)under_edge_count; - tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap; - tmpunderedges[under_edge_count].p = (byte)underplanescount; - tmpunderedges[under_edge_count].ea = -1; - // make sure this edge is added to the "coplanar" list - coplanaredge = under_edge_count; - vout = vertflag[edge0.v].undermap; - vin = vertflag[edge1.v].undermap; - under_edge_count++; - } - else - { - edgeflag[e0].undermap = -1; - } - } - else if (vertflag[edge0.v].planetest == (1) && vertflag[edge1.v].planetest == (2)) - { - // first is under 2nd is over - - edgeflag[e0].undermap = (short)under_edge_count; - tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap; - tmpunderedges[under_edge_count].p = (byte)underplanescount; - if (edge0.ea < e0) - { - Debug.Assert(edgeflag[edge0.ea].undermap != -1); - // connect the neighbors - tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; - tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; - vout = tmpunderedges[edgeflag[edge0.ea].undermap].v; - } - else - { - Plane p0 = convex.facets[edge0.p]; - Plane pa = convex.facets[edgea.p]; - createdverts.Add(ThreePlaneIntersection(p0, pa, slice)); - //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]))); - //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])); - vout = vertcountunder++; - } - under_edge_count++; - /// hmmm something to think about: i might be able to output this edge regarless of - // wheter or not we know v-in yet. ok i;ll try this now: - tmpunderedges[under_edge_count].v = (byte)vout; - tmpunderedges[under_edge_count].p = (byte)underplanescount; - tmpunderedges[under_edge_count].ea = -1; - coplanaredge = under_edge_count; - under_edge_count++; - - if (vin != -1) - { - // we previously processed an edge where we came under - // now we know about vout as well - - // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! - } - - } - else if (vertflag[edge0.v].planetest == (0) && vertflag[edge1.v].planetest == (2)) - { - // first is coplanar 2nd is over - - edgeflag[e0].undermap = -1; - vout = vertflag[edge0.v].undermap; - // I hate this but i have to make sure part of this face is UNDER before ouputting this vert - int k = estart; - Debug.Assert(edge0.p == currentplane); - while (!((planeside & 1) != 0) && k < convex.edges.Count && convex.edges[k].p == edge0.p) - { - planeside |= vertflag[convex.edges[k].v].planetest; - k++; - } - if ((planeside & 1) != 0) - { - tmpunderedges[under_edge_count].v = (byte)vout; - tmpunderedges[under_edge_count].p = (byte)underplanescount; - tmpunderedges[under_edge_count].ea = -1; - coplanaredge = under_edge_count; // hmmm should make a note of the edge # for later on - under_edge_count++; - - } - } - else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (1)) - { - // first is over next is under - // new vertex!!! - Debug.Assert(vin == -1); - if (e0 < edge0.ea) - { - Plane p0 = convex.facets[edge0.p]; - Plane pa = convex.facets[edgea.p]; - createdverts.Add(ThreePlaneIntersection(p0, pa, slice)); - //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])); - //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]))); - vin = vertcountunder++; - } - else - { - // find the new vertex that was created by edge[edge0.ea] - int nea = edgeflag[edge0.ea].undermap; - Debug.Assert(tmpunderedges[nea].p == tmpunderedges[nea + 1].p); - vin = tmpunderedges[nea + 1].v; - Debug.Assert(vin < vertcountunder); - Debug.Assert(vin >= vertcountunderold); // for debugging only - } - if (vout != -1) - { - // we previously processed an edge where we went over - // now we know vin too - // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! - } - // output edge - tmpunderedges[under_edge_count].v = (byte)vin; - tmpunderedges[under_edge_count].p = (byte)underplanescount; - edgeflag[e0].undermap = (short)under_edge_count; - if (e0 > edge0.ea) - { - Debug.Assert(edgeflag[edge0.ea].undermap != -1); - // connect the neighbors - tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; - tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; - } - Debug.Assert(edgeflag[e0].undermap == under_edge_count); - under_edge_count++; - } - else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (0)) - { - // first is over next is coplanar - - edgeflag[e0].undermap = -1; - vin = vertflag[edge1.v].undermap; - Debug.Assert(vin != -1); - if (vout != -1) - { - // we previously processed an edge where we came under - // now we know both endpoints - // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! - } - - } - else - { - Debug.Assert(false); - } - - - e0 = e1; - e1++; // do the modulo at the beginning of the loop - - } while (e0 != estart); - e0 = enextface; - if ((planeside & 1) != 0) - { - planeflag[currentplane].undermap = (byte)underplanescount; - tmpunderplanes[underplanescount] = convex.facets[currentplane]; - underplanescount++; - } - else - { - planeflag[currentplane].undermap = 0; - } - if (vout >= 0 && (planeside & 1) != 0) - { - Debug.Assert(vin >= 0); - Debug.Assert(coplanaredge >= 0); - Debug.Assert(coplanaredge != 511); - coplanaredges[coplanaredges_num].ea = (ushort)coplanaredge; - coplanaredges[coplanaredges_num].v0 = (byte)vin; - coplanaredges[coplanaredges_num].v1 = (byte)vout; - coplanaredges_num++; - } - } - - // add the new plane to the mix: - if (coplanaredges_num > 0) - { - tmpunderplanes[underplanescount++] = slice; - } - for (i = 0; i < coplanaredges_num - 1; i++) - { - if (coplanaredges[i].v1 != coplanaredges[i + 1].v0) - { - int j = 0; - for (j = i + 2; j < coplanaredges_num; j++) - { - if (coplanaredges[i].v1 == coplanaredges[j].v0) - { - Coplanar tmp = coplanaredges[i + 1]; - coplanaredges[i + 1] = coplanaredges[j]; - coplanaredges[j] = tmp; - break; - } - } - if (j >= coplanaredges_num) - { - Debug.Assert(j < coplanaredges_num); - return null; - } - } - } - - ConvexH punder = new ConvexH(vertcountunder, under_edge_count + coplanaredges_num, underplanescount); - ConvexH under = punder; - - { - int k = 0; - for (i = 0; i < convex.vertices.Count; i++) - { - if (vertflag[i].planetest != (2)) - { - under.vertices[k++] = convex.vertices[i]; - } - } - i = 0; - while (k < vertcountunder) - { - under.vertices[k++] = createdverts[i++]; - } - Debug.Assert(i == createdverts.Count); - } - - for (i = 0; i < coplanaredges_num; i++) - { - ConvexH.HalfEdge edge = under.edges[under_edge_count + i]; - edge.p = (byte)(underplanescount - 1); - edge.ea = (short)coplanaredges[i].ea; - edge.v = (byte)coplanaredges[i].v0; - under.edges[under_edge_count + i] = edge; - - tmpunderedges[coplanaredges[i].ea].ea = (short)(under_edge_count + i); - } - - under.edges = new List(tmpunderedges); - under.facets = new List(tmpunderplanes); - return punder; - } - - public static ConvexH ConvexHDup(ConvexH src) - { - ConvexH dst = new ConvexH(src.vertices.Count, src.edges.Count, src.facets.Count); - dst.vertices = new List(src.vertices.Count); - foreach (float3 f in src.vertices) - dst.vertices.Add(new float3(f)); - dst.edges = new List(src.edges.Count); - foreach (ConvexH.HalfEdge e in src.edges) - dst.edges.Add(new ConvexH.HalfEdge(e)); - dst.facets = new List(src.facets.Count); - foreach (Plane p in src.facets) - dst.facets.Add(new Plane(p)); - return dst; - } - - public static int candidateplane(List planes, int planes_count, ConvexH convex, float epsilon) - { - int p = 0; - float md = 0; - int i; - for (i = 0; i < planes_count; i++) - { - float d = 0; - for (int j = 0; j < convex.vertices.Count; j++) - { - d = Math.Max(d, float3.dot(convex.vertices[j], planes[i].normal) + planes[i].dist); - } - if (i == 0 || d > md) - { - p = i; - md = d; - } - } - return (md > epsilon) ? p : -1; - } - - public static float3 orth(float3 v) - { - float3 a = float3.cross(v, new float3(0f, 0f, 1f)); - float3 b = float3.cross(v, new float3(0f, 1f, 0f)); - return float3.normalize((float3.magnitude(a) > float3.magnitude(b)) ? a : b); - } - - public static int maxdir(List p, int count, float3 dir) - { - Debug.Assert(count != 0); - int m = 0; - float currDotm = float3.dot(p[0], dir); - for (int i = 1; i < count; i++) - { - float currDoti = float3.dot(p[i], dir); - if (currDoti > currDotm) - { - currDotm = currDoti; - m = i; - } - } - return m; - } - - public static int maxdirfiltered(List p, int count, float3 dir, byte[] allow) - { - //Debug.Assert(count != 0); - int m = 0; - float currDotm = float3.dot(p[0], dir); - float currDoti; - - while (allow[m] == 0) - m++; - - for (int i = 1; i < count; i++) - { - if (allow[i] != 0) - { - currDoti = float3.dot(p[i], dir); - if (currDoti > currDotm) - { - currDotm = currDoti; - m = i; - } - } - } - //Debug.Assert(m != -1); - return m; - } - - public static int maxdirsterid(List p, int count, float3 dir, byte[] allow) - { - int m = -1; - while (m == -1) - { - m = maxdirfiltered(p, count, dir, allow); - if (allow[m] == 3) - return m; - float3 u = orth(dir); - float3 v = float3.cross(u, dir); - int ma = -1; - for (float x = 0.0f; x <= 360.0f; x += 45.0f) - { - int mb; - { - float s = (float)Math.Sin((3.14159264f / 180.0f) * (x)); - float c = (float)Math.Cos((3.14159264f / 180.0f) * (x)); - mb = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow); - } - if (ma == m && mb == m) - { - allow[m] = 3; - return m; - } - if (ma != -1 && ma != mb) // Yuck - this is really ugly - { - int mc = ma; - for (float xx = x - 40.0f; xx <= x; xx += 5.0f) - { - float s = (float)Math.Sin((3.14159264f / 180.0f) * (xx)); - float c = (float)Math.Cos((3.14159264f / 180.0f) * (xx)); - int md = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow); - if (mc == m && md == m) - { - allow[m] = 3; - return m; - } - mc = md; - } - } - ma = mb; - } - allow[m] = 0; - m = -1; - } - - Debug.Assert(false); - return m; - } - - public static int4 FindSimplex(List verts, byte[] allow) - { - float3[] basis = new float3[3]; - basis[0] = new float3(0.01f, 0.02f, 1.0f); - int p0 = maxdirsterid(verts, verts.Count, basis[0], allow); - int p1 = maxdirsterid(verts, verts.Count, -basis[0], allow); - basis[0] = verts[p0] - verts[p1]; - if (p0 == p1 || basis[0] == new float3(0, 0, 0)) - return new int4(-1, -1, -1, -1); - basis[1] = float3.cross(new float3(1, 0.02f, 0), basis[0]); - basis[2] = float3.cross(new float3(-0.02f, 1, 0), basis[0]); - basis[1] = float3.normalize((float3.magnitude(basis[1]) > float3.magnitude(basis[2])) ? basis[1] : basis[2]); - int p2 = maxdirsterid(verts, verts.Count, basis[1], allow); - if (p2 == p0 || p2 == p1) - { - p2 = maxdirsterid(verts, verts.Count, -basis[1], allow); - } - if (p2 == p0 || p2 == p1) - return new int4(-1, -1, -1, -1); - basis[1] = verts[p2] - verts[p0]; - basis[2] = float3.normalize(float3.cross(basis[1], basis[0])); - int p3 = maxdirsterid(verts, verts.Count, basis[2], allow); - if (p3 == p0 || p3 == p1 || p3 == p2) - p3 = maxdirsterid(verts, verts.Count, -basis[2], allow); - if (p3 == p0 || p3 == p1 || p3 == p2) - return new int4(-1, -1, -1, -1); - Debug.Assert(!(p0 == p1 || p0 == p2 || p0 == p3 || p1 == p2 || p1 == p3 || p2 == p3)); - if (float3.dot(verts[p3] - verts[p0], float3.cross(verts[p1] - verts[p0], verts[p2] - verts[p0])) < 0) - { - Swap(ref p2, ref p3); - } - return new int4(p0, p1, p2, p3); - } - - public static float GetDist(float px, float py, float pz, float3 p2) - { - float dx = px - p2.x; - float dy = py - p2.y; - float dz = pz - p2.z; - - return dx * dx + dy * dy + dz * dz; - } - - public static void ReleaseHull(PHullResult result) - { - if (result.Indices != null) - result.Indices = null; - if (result.Vertices != null) - result.Vertices = null; - } - - public static int calchullgen(List verts, int vlimit, List tris) - { - if (verts.Count < 4) - return 0; - if (vlimit == 0) - vlimit = 1000000000; - int j; - float3 bmin = new float3(verts[0]); - float3 bmax = new float3(verts[0]); - List isextreme = new List(verts.Count); - byte[] allow = new byte[verts.Count]; - for (j = 0; j < verts.Count; j++) - { - allow[j] = 1; - isextreme.Add(0); - bmin = float3.VectorMin(bmin, verts[j]); - bmax = float3.VectorMax(bmax, verts[j]); - } - float epsilon = float3.magnitude(bmax - bmin) * 0.001f; - - int4 p = FindSimplex(verts, allow); - if (p.x == -1) // simplex failed - return 0; - - float3 center = (verts[p[0]] + verts[p[1]] + verts[p[2]] + verts[p[3]]) / 4.0f; // a valid interior point - HullTriangle t0 = new HullTriangle(p[2], p[3], p[1], tris); - t0.n = new int3(2, 3, 1); - HullTriangle t1 = new HullTriangle(p[3], p[2], p[0], tris); - t1.n = new int3(3, 2, 0); - HullTriangle t2 = new HullTriangle(p[0], p[1], p[3], tris); - t2.n = new int3(0, 1, 3); - HullTriangle t3 = new HullTriangle(p[1], p[0], p[2], tris); - t3.n = new int3(1, 0, 2); - isextreme[p[0]] = isextreme[p[1]] = isextreme[p[2]] = isextreme[p[3]] = 1; - checkit(t0, tris); - checkit(t1, tris); - checkit(t2, tris); - checkit(t3, tris); - - for (j = 0; j < tris.Count; j++) - { - HullTriangle t = tris[j]; - Debug.Assert((object)t != null); - Debug.Assert(t.vmax < 0); - float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]); - t.vmax = maxdirsterid(verts, verts.Count, n, allow); - t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]); - } - HullTriangle te; - vlimit -= 4; - while (vlimit > 0 && (te = extrudable(epsilon, tris)) != null) - { - int3 ti = te; - int v = te.vmax; - Debug.Assert(isextreme[v] == 0); // wtf we've already done this vertex - isextreme[v] = 1; - //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already - j = tris.Count; - while (j-- != 0) - { - if (tris.Count <= j || (object)tris[j] == null) - continue; - int3 t = tris[j]; - if (above(verts, t, verts[v], 0.01f * epsilon)) - { - extrude(tris[j], v, tris); - } - } - // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle - j = tris.Count; - while (j-- != 0) - { - if (tris.Count <= j || (object)tris[j] == null) - continue; - if (!hasvert(tris[j], v)) - break; - int3 nt = tris[j]; - if (above(verts, nt, center, 0.01f * epsilon) || float3.magnitude(float3.cross(verts[nt[1]] - verts[nt[0]], verts[nt[2]] - verts[nt[1]])) < epsilon * epsilon * 0.1f) - { - HullTriangle nb = tris[tris[j].n[0]]; - Debug.Assert(nb != null); - Debug.Assert(!hasvert(nb, v)); - Debug.Assert(nb.id < j); - extrude(nb, v, tris); - j = tris.Count; - } - } - j = tris.Count; - while (j-- != 0) - { - HullTriangle t = tris[j]; - if (t == null) - continue; - if (t.vmax >= 0) - break; - float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]); - t.vmax = maxdirsterid(verts, verts.Count, n, allow); - if (isextreme[t.vmax] != 0) - { - t.vmax = -1; // already done that vertex - algorithm needs to be able to terminate. - } - else - { - t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]); - } - } - vlimit--; - } - return 1; - } - - public static bool calchull(List verts, out List tris_out, int vlimit, List tris) - { - tris_out = null; - - int rc = calchullgen(verts, vlimit, tris); - if (rc == 0) - return false; - List ts = new List(); - for (int i = 0; i < tris.Count; i++) - { - if ((object)tris[i] != null) - { - for (int j = 0; j < 3; j++) - ts.Add((tris[i])[j]); - tris[i] = null; - } - } - - tris_out = ts; - tris.Clear(); - return true; - } - - public static int calchullpbev(List verts, int vlimit, out List planes, float bevangle, List tris) - { - int i; - int j; - planes = new List(); - int rc = calchullgen(verts, vlimit, tris); - if (rc == 0) - return 0; - for (i = 0; i < tris.Count; i++) - { - if (tris[i] != null) - { - Plane p = new Plane(); - HullTriangle t = tris[i]; - p.normal = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]); - p.dist = -float3.dot(p.normal, verts[(t)[0]]); - planes.Add(p); - for (j = 0; j < 3; j++) - { - if (t.n[j] < t.id) - continue; - HullTriangle s = tris[t.n[j]]; - float3 snormal = TriNormal(verts[(s)[0]], verts[(s)[1]], verts[(s)[2]]); - if (float3.dot(snormal, p.normal) >= Math.Cos(bevangle * (3.14159264f / 180.0f))) - continue; - float3 n = float3.normalize(snormal + p.normal); - planes.Add(new Plane(n, -float3.dot(n, verts[maxdir(verts, verts.Count, n)]))); - } - } - } - - tris.Clear(); - return 1; - } - - public static int overhull(List planes, List verts, int maxplanes, out List verts_out, out List faces_out, float inflate) - { - verts_out = null; - faces_out = null; - - int i; - int j; - if (verts.Count < 4) - return 0; - maxplanes = Math.Min(maxplanes, planes.Count); - float3 bmin = new float3(verts[0]); - float3 bmax = new float3(verts[0]); - for (i = 0; i < verts.Count; i++) - { - bmin = float3.VectorMin(bmin, verts[i]); - bmax = float3.VectorMax(bmax, verts[i]); - } - // float diameter = magnitude(bmax-bmin); - // inflate *=diameter; // RELATIVE INFLATION - bmin -= new float3(inflate, inflate, inflate); - bmax += new float3(inflate, inflate, inflate); - for (i = 0; i < planes.Count; i++) - { - planes[i].dist -= inflate; - } - float3 emin = new float3(bmin); - float3 emax = new float3(bmax); - float epsilon = float3.magnitude(emax - emin) * 0.025f; - float planetestepsilon = float3.magnitude(emax - emin) * (0.001f); - // todo: add bounding cube planes to force bevel. or try instead not adding the diameter expansion ??? must think. - // ConvexH *convex = ConvexHMakeCube(bmin - float3(diameter,diameter,diameter),bmax+float3(diameter,diameter,diameter)); - ConvexH c = ConvexHMakeCube(new float3(bmin), new float3(bmax)); - int k; - while (maxplanes-- != 0 && (k = candidateplane(planes, planes.Count, c, epsilon)) >= 0) - { - ConvexH tmp = c; - c = ConvexHCrop(ref tmp, planes[k], planetestepsilon); - if (c == null) // might want to debug this case better!!! - { - c = tmp; - break; - } - if (AssertIntact(c, planetestepsilon) == false) // might want to debug this case better too!!! - { - c = tmp; - break; - } - tmp.edges = null; - tmp.facets = null; - tmp.vertices = null; - } - - Debug.Assert(AssertIntact(c, planetestepsilon)); - //return c; - //C++ TO C# CONVERTER TODO TASK: The memory management function 'malloc' has no equivalent in C#: - faces_out = new List(); //(int)malloc(sizeof(int) * (1 + c.facets.Count + c.edges.Count)); // new int[1+c->facets.count+c->edges.count]; - int faces_count_out = 0; - i = 0; - faces_out[faces_count_out++] = -1; - k = 0; - while (i < c.edges.Count) - { - j = 1; - while (j + i < c.edges.Count && c.edges[i].p == c.edges[i + j].p) - { - j++; - } - faces_out[faces_count_out++] = j; - while (j-- != 0) - { - faces_out[faces_count_out++] = c.edges[i].v; - i++; - } - k++; - } - faces_out[0] = k; // number of faces. - Debug.Assert(k == c.facets.Count); - Debug.Assert(faces_count_out == 1 + c.facets.Count + c.edges.Count); - verts_out = c.vertices; // new float3[c->vertices.count]; - int verts_count_out = c.vertices.Count; - for (i = 0; i < c.vertices.Count; i++) - { - verts_out[i] = new float3(c.vertices[i]); - } - - c.edges = null; - c.facets = null; - c.vertices = null; - return 1; - } - - public static int overhullv(List verts, int maxplanes, out List verts_out, out List faces_out, float inflate, float bevangle, int vlimit, List tris) - { - verts_out = null; - faces_out = null; - - if (verts.Count == 0) - return 0; - List planes = new List(); - int rc = calchullpbev(verts, vlimit, out planes, bevangle, tris); - if (rc == 0) - return 0; - return overhull(planes, verts, maxplanes, out verts_out, out faces_out, inflate); - } - - public static void addPoint(ref uint vcount, List p, float x, float y, float z) - { - p.Add(new float3(x, y, z)); - vcount++; - } - - public static bool ComputeHull(List vertices, ref PHullResult result, int vlimit, float inflate) - { - List tris = new List(); - List faces; - List verts_out; - - if (inflate == 0.0f) - { - List tris_out; - bool ret = calchull(vertices, out tris_out, vlimit, tris); - if (ret == false) - return false; - - result.Indices = tris_out; - result.Vertices = vertices; - return true; - } - else - { - int ret = overhullv(vertices, 35, out verts_out, out faces, inflate, 120.0f, vlimit, tris); - if (ret == 0) - return false; - - List tris2 = new List(); - int n = faces[0]; - int k = 1; - for (int i = 0; i < n; i++) - { - int pn = faces[k++]; - for (int j = 2; j < pn; j++) - tris2.Add(new int3(faces[k], faces[k + j - 1], faces[k + j])); - k += pn; - } - Debug.Assert(tris2.Count == faces.Count - 1 - (n * 3)); - - result.Indices = new List(tris2.Count * 3); - for (int i = 0; i < tris2.Count; i++) - { - result.Indices.Add(tris2[i].x); - result.Indices.Add(tris2[i].y); - result.Indices.Add(tris2[i].z); - } - result.Vertices = verts_out; - - return true; - } - } - - private static bool CleanupVertices(List svertices, out List vertices, float normalepsilon, out float3 scale) - { - const float EPSILON = 0.000001f; - - vertices = new List(); - scale = new float3(1f, 1f, 1f); - - if (svertices.Count == 0) - return false; - - uint vcount = 0; - - float[] recip = new float[3]; - - float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue }; - float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue }; - - for (int i = 0; i < svertices.Count; i++) - { - float3 p = svertices[i]; - - for (int j = 0; j < 3; j++) - { - if (p[j] < bmin[j]) - bmin[j] = p[j]; - if (p[j] > bmax[j]) - bmax[j] = p[j]; - } - } - - float dx = bmax[0] - bmin[0]; - float dy = bmax[1] - bmin[1]; - float dz = bmax[2] - bmin[2]; - - float3 center = new float3(); - - center.x = dx * 0.5f + bmin[0]; - center.y = dy * 0.5f + bmin[1]; - center.z = dz * 0.5f + bmin[2]; - - if (dx < EPSILON || dy < EPSILON || dz < EPSILON || svertices.Count < 3) - { - float len = Single.MaxValue; - - if (dx > EPSILON && dx < len) - len = dx; - if (dy > EPSILON && dy < len) - len = dy; - if (dz > EPSILON && dz < len) - len = dz; - - if (len == Single.MaxValue) - { - dx = dy = dz = 0.01f; // one centimeter - } - else - { - if (dx < EPSILON) // 1/5th the shortest non-zero edge. - dx = len * 0.05f; - if (dy < EPSILON) - dy = len * 0.05f; - if (dz < EPSILON) - dz = len * 0.05f; - } - - float x1 = center[0] - dx; - float x2 = center[0] + dx; - - float y1 = center[1] - dy; - float y2 = center[1] + dy; - - float z1 = center[2] - dz; - float z2 = center[2] + dz; - - addPoint(ref vcount, vertices, x1, y1, z1); - addPoint(ref vcount, vertices, x2, y1, z1); - addPoint(ref vcount, vertices, x2, y2, z1); - addPoint(ref vcount, vertices, x1, y2, z1); - addPoint(ref vcount, vertices, x1, y1, z2); - addPoint(ref vcount, vertices, x2, y1, z2); - addPoint(ref vcount, vertices, x2, y2, z2); - addPoint(ref vcount, vertices, x1, y2, z2); - - return true; // return cube - } - else - { - scale.x = dx; - scale.y = dy; - scale.z = dz; - - recip[0] = 1f / dx; - recip[1] = 1f / dy; - recip[2] = 1f / dz; - - center.x *= recip[0]; - center.y *= recip[1]; - center.z *= recip[2]; - } - - for (int i = 0; i < svertices.Count; i++) - { - float3 p = svertices[i]; - - float px = p[0]; - float py = p[1]; - float pz = p[2]; - - px = px * recip[0]; // normalize - py = py * recip[1]; // normalize - pz = pz * recip[2]; // normalize - - if (true) - { - int j; - - for (j = 0; j < vcount; j++) - { - float3 v = vertices[j]; - - float x = v[0]; - float y = v[1]; - float z = v[2]; - - float dx1 = Math.Abs(x - px); - float dy1 = Math.Abs(y - py); - float dz1 = Math.Abs(z - pz); - - if (dx1 < normalepsilon && dy1 < normalepsilon && dz1 < normalepsilon) - { - // ok, it is close enough to the old one - // now let us see if it is further from the center of the point cloud than the one we already recorded. - // in which case we keep this one instead. - float dist1 = GetDist(px, py, pz, center); - float dist2 = GetDist(v[0], v[1], v[2], center); - - if (dist1 > dist2) - { - v.x = px; - v.y = py; - v.z = pz; - } - - break; - } - } - - if (j == vcount) - { - float3 dest = new float3(px, py, pz); - vertices.Add(dest); - vcount++; - } - } - } - - // ok..now make sure we didn't prune so many vertices it is now invalid. - if (true) - { - float[] bmin2 = { Single.MaxValue, Single.MaxValue, Single.MaxValue }; - float[] bmax2 = { Single.MinValue, Single.MinValue, Single.MinValue }; - - for (int i = 0; i < vcount; i++) - { - float3 p = vertices[i]; - for (int j = 0; j < 3; j++) - { - if (p[j] < bmin2[j]) - bmin2[j] = p[j]; - if (p[j] > bmax2[j]) - bmax2[j] = p[j]; - } - } - - float dx2 = bmax2[0] - bmin2[0]; - float dy2 = bmax2[1] - bmin2[1]; - float dz2 = bmax2[2] - bmin2[2]; - - if (dx2 < EPSILON || dy2 < EPSILON || dz2 < EPSILON || vcount < 3) - { - float cx = dx2 * 0.5f + bmin2[0]; - float cy = dy2 * 0.5f + bmin2[1]; - float cz = dz2 * 0.5f + bmin2[2]; - - float len = Single.MaxValue; - - if (dx2 >= EPSILON && dx2 < len) - len = dx2; - if (dy2 >= EPSILON && dy2 < len) - len = dy2; - if (dz2 >= EPSILON && dz2 < len) - len = dz2; - - if (len == Single.MaxValue) - { - dx2 = dy2 = dz2 = 0.01f; // one centimeter - } - else - { - if (dx2 < EPSILON) // 1/5th the shortest non-zero edge. - dx2 = len * 0.05f; - if (dy2 < EPSILON) - dy2 = len * 0.05f; - if (dz2 < EPSILON) - dz2 = len * 0.05f; - } - - float x1 = cx - dx2; - float x2 = cx + dx2; - - float y1 = cy - dy2; - float y2 = cy + dy2; - - float z1 = cz - dz2; - float z2 = cz + dz2; - - vcount = 0; // add box - - addPoint(ref vcount, vertices, x1, y1, z1); - addPoint(ref vcount, vertices, x2, y1, z1); - addPoint(ref vcount, vertices, x2, y2, z1); - addPoint(ref vcount, vertices, x1, y2, z1); - addPoint(ref vcount, vertices, x1, y1, z2); - addPoint(ref vcount, vertices, x2, y1, z2); - addPoint(ref vcount, vertices, x2, y2, z2); - addPoint(ref vcount, vertices, x1, y2, z2); - - return true; - } - } - - return true; - } - - private static void BringOutYourDead(List verts, out List overts, List indices) - { - int[] used = new int[verts.Count]; - int ocount = 0; - - overts = new List(); - - for (int i = 0; i < indices.Count; i++) - { - int v = indices[i]; // original array index - - Debug.Assert(v >= 0 && v < verts.Count); - - if (used[v] != 0) // if already remapped - { - indices[i] = used[v] - 1; // index to new array - } - else - { - indices[i] = ocount; // new index mapping - - overts.Add(verts[v]); // copy old vert to new vert array - - ocount++; // increment output vert count - - Debug.Assert(ocount >= 0 && ocount <= verts.Count); - - used[v] = ocount; // assign new index remapping - } - } - } - - public static HullError CreateConvexHull(HullDesc desc, ref HullResult result) - { - HullError ret = HullError.QE_FAIL; - - PHullResult hr = new PHullResult(); - - uint vcount = (uint)desc.Vertices.Count; - if (vcount < 8) - vcount = 8; - - List vsource; - float3 scale = new float3(); - - bool ok = CleanupVertices(desc.Vertices, out vsource, desc.NormalEpsilon, out scale); // normalize point cloud, remove duplicates! - - if (ok) - { - if (true) // scale vertices back to their original size. - { - for (int i = 0; i < vsource.Count; i++) - { - float3 v = vsource[i]; - v.x *= scale[0]; - v.y *= scale[1]; - v.z *= scale[2]; - } - } - - float skinwidth = 0; - if (desc.HasHullFlag(HullFlag.QF_SKIN_WIDTH)) - skinwidth = desc.SkinWidth; - - ok = ComputeHull(vsource, ref hr, (int)desc.MaxVertices, skinwidth); - - if (ok) - { - List vscratch; - BringOutYourDead(hr.Vertices, out vscratch, hr.Indices); - - ret = HullError.QE_OK; - - if (desc.HasHullFlag(HullFlag.QF_TRIANGLES)) // if he wants the results as triangle! - { - result.Polygons = false; - result.Indices = hr.Indices; - result.OutputVertices = vscratch; - } - else - { - result.Polygons = true; - result.OutputVertices = vscratch; - - if (true) - { - List source = hr.Indices; - List dest = new List(); - for (int i = 0; i < hr.Indices.Count / 3; i++) - { - dest.Add(3); - dest.Add(source[i * 3 + 0]); - dest.Add(source[i * 3 + 1]); - dest.Add(source[i * 3 + 2]); - } - - result.Indices = dest; - } - } - } - } - - return ret; - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt b/OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt deleted file mode 100644 index 714ae89..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt +++ /dev/null @@ -1,28 +0,0 @@ -ConvexDecompositionDotNet -------------------------- - -The MIT License - -Copyright (c) 2010 Intel Corporation. -All rights reserved. - -Based on the convexdecomposition library from - by John W. Ratcliff and Stan Melax. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs deleted file mode 100644 index d099676..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs +++ /dev/null @@ -1,99 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class Plane - { - public float3 normal = new float3(); - public float dist; // distance below origin - the D from plane equasion Ax+By+Cz+D=0 - - public Plane(float3 n, float d) - { - normal = new float3(n); - dist = d; - } - - public Plane(Plane p) - { - normal = new float3(p.normal); - dist = p.dist; - } - - public Plane() - { - dist = 0; - } - - public void Transform(float3 position, Quaternion orientation) - { - // Transforms the plane to the space defined by the - // given position/orientation - float3 newNormal = Quaternion.Inverse(orientation) * normal; - float3 origin = Quaternion.Inverse(orientation) * (-normal * dist - position); - - normal = newNormal; - dist = -float3.dot(newNormal, origin); - } - - public override int GetHashCode() - { - return normal.GetHashCode() ^ dist.GetHashCode(); - } - - public override bool Equals(object obj) - { - Plane p = obj as Plane; - if (p == null) - return false; - - return this == p; - } - - public static bool operator ==(Plane a, Plane b) - { - return (a.normal == b.normal && a.dist == b.dist); - } - - public static bool operator !=(Plane a, Plane b) - { - return !(a == b); - } - - public static Plane PlaneFlip(Plane plane) - { - return new Plane(-plane.normal, -plane.dist); - } - - public static bool coplanar(Plane a, Plane b) - { - return (a == b || a == PlaneFlip(b)); - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs deleted file mode 100644 index 31f0182..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs +++ /dev/null @@ -1,211 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public enum PlaneTriResult : int - { - PTR_FRONT, - PTR_BACK, - PTR_SPLIT - } - - public static class PlaneTri - { - private static float DistToPt(float3 p, float4 plane) - { - return p.x * plane.x + p.y * plane.y + p.z * plane.z + plane.w; - } - - private static PlaneTriResult getSidePlane(float3 p, float4 plane, float epsilon) - { - float d = DistToPt(p, plane); - - if ((d + epsilon) > 0f) - return PlaneTriResult.PTR_FRONT; // it is 'in front' within the provided epsilon value. - - return PlaneTriResult.PTR_BACK; - } - - private static void add(float3 p, float3[] dest, ref int pcount) - { - dest[pcount++] = new float3(p); - Debug.Assert(pcount <= 4); - } - - // assumes that the points are on opposite sides of the plane! - private static void intersect(float3 p1, float3 p2, float3 split, float4 plane) - { - float dp1 = DistToPt(p1, plane); - float[] dir = new float[3]; - - dir[0] = p2[0] - p1[0]; - dir[1] = p2[1] - p1[1]; - dir[2] = p2[2] - p1[2]; - - float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2]; - float dot2 = dp1 - plane[3]; - - float t = -(plane[3] + dot2) / dot1; - - split.x = (dir[0] * t) + p1[0]; - split.y = (dir[1] * t) + p1[1]; - split.z = (dir[2] * t) + p1[2]; - } - - public static PlaneTriResult planeTriIntersection(float4 plane, FaceTri triangle, float epsilon, ref float3[] front, out int fcount, ref float3[] back, out int bcount) - { - fcount = 0; - bcount = 0; - - // get the three vertices of the triangle. - float3 p1 = triangle.P1; - float3 p2 = triangle.P2; - float3 p3 = triangle.P3; - - PlaneTriResult r1 = getSidePlane(p1, plane, epsilon); // compute the side of the plane each vertex is on - PlaneTriResult r2 = getSidePlane(p2, plane, epsilon); - PlaneTriResult r3 = getSidePlane(p3, plane, epsilon); - - if (r1 == r2 && r1 == r3) // if all three vertices are on the same side of the plane. - { - if (r1 == PlaneTriResult.PTR_FRONT) // if all three are in front of the plane, then copy to the 'front' output triangle. - { - add(p1, front, ref fcount); - add(p2, front, ref fcount); - add(p3, front, ref fcount); - } - else - { - add(p1, back, ref bcount); // if all three are in 'back' then copy to the 'back' output triangle. - add(p2, back, ref bcount); - add(p3, back, ref bcount); - } - return r1; // if all three points are on the same side of the plane return result - } - - // ok.. we need to split the triangle at the plane. - - // First test ray segment P1 to P2 - if (r1 == r2) // if these are both on the same side... - { - if (r1 == PlaneTriResult.PTR_FRONT) - { - add(p1, front, ref fcount); - add(p2, front, ref fcount); - } - else - { - add(p1, back, ref bcount); - add(p2, back, ref bcount); - } - } - else - { - float3 split = new float3(); - intersect(p1, p2, split, plane); - - if (r1 == PlaneTriResult.PTR_FRONT) - { - - add(p1, front, ref fcount); - add(split, front, ref fcount); - - add(split, back, ref bcount); - add(p2, back, ref bcount); - - } - else - { - add(p1, back, ref bcount); - add(split, back, ref bcount); - - add(split, front, ref fcount); - add(p2, front, ref fcount); - } - - } - - // Next test ray segment P2 to P3 - if (r2 == r3) // if these are both on the same side... - { - if (r3 == PlaneTriResult.PTR_FRONT) - { - add(p3, front, ref fcount); - } - else - { - add(p3, back, ref bcount); - } - } - else - { - float3 split = new float3(); // split the point - intersect(p2, p3, split, plane); - - if (r3 == PlaneTriResult.PTR_FRONT) - { - add(split, front, ref fcount); - add(split, back, ref bcount); - - add(p3, front, ref fcount); - } - else - { - add(split, front, ref fcount); - add(split, back, ref bcount); - - add(p3, back, ref bcount); - } - } - - // Next test ray segment P3 to P1 - if (r3 != r1) // if these are both on the same side... - { - float3 split = new float3(); // split the point - intersect(p3, p1, split, plane); - - if (r1 == PlaneTriResult.PTR_FRONT) - { - add(split, front, ref fcount); - add(split, back, ref bcount); - } - else - { - add(split, front, ref fcount); - add(split, back, ref bcount); - } - } - - return PlaneTriResult.PTR_SPLIT; - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs deleted file mode 100644 index 5ff945d..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ConvexDecompositionDotNet")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Intel Corporation")] -[assembly: AssemblyProduct("ConvexDecompositionDotNet")] -[assembly: AssemblyCopyright("Copyright © Intel Corporation 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("2a1c9467-1a17-4c8d-bf9f-4b4d86dd0cbb")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs deleted file mode 100644 index 0ba8f17..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs +++ /dev/null @@ -1,209 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class Quaternion : float4 - { - public Quaternion() - { - x = y = z = 0.0f; - w = 1.0f; - } - - public Quaternion(float3 v, float t) - { - v = float3.normalize(v); - w = (float)Math.Cos(t / 2.0f); - v = v * (float)Math.Sin(t / 2.0f); - x = v.x; - y = v.y; - z = v.z; - } - - public Quaternion(float _x, float _y, float _z, float _w) - { - x = _x; - y = _y; - z = _z; - w = _w; - } - - public float angle() - { - return (float)Math.Acos(w) * 2.0f; - } - - public float3 axis() - { - float3 a = new float3(x, y, z); - if (Math.Abs(angle()) < 0.0000001f) - return new float3(1f, 0f, 0f); - return a * (1 / (float)Math.Sin(angle() / 2.0f)); - } - - public float3 xdir() - { - return new float3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y)); - } - - public float3 ydir() - { - return new float3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x)); - } - - public float3 zdir() - { - return new float3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y)); - } - - public float3x3 getmatrix() - { - return new float3x3(xdir(), ydir(), zdir()); - } - - public static implicit operator float3x3(Quaternion q) - { - return q.getmatrix(); - } - - public static Quaternion operator *(Quaternion a, Quaternion b) - { - Quaternion c = new Quaternion(); - c.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z; - c.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y; - c.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x; - c.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w; - return c; - } - - public static float3 operator *(Quaternion q, float3 v) - { - // The following is equivalent to: - //return (q.getmatrix() * v); - float qx2 = q.x * q.x; - float qy2 = q.y * q.y; - float qz2 = q.z * q.z; - - float qxqy = q.x * q.y; - float qxqz = q.x * q.z; - float qxqw = q.x * q.w; - float qyqz = q.y * q.z; - float qyqw = q.y * q.w; - float qzqw = q.z * q.w; - return new float3((1 - 2 * (qy2 + qz2)) * v.x + (2 * (qxqy - qzqw)) * v.y + (2 * (qxqz + qyqw)) * v.z, (2 * (qxqy + qzqw)) * v.x + (1 - 2 * (qx2 + qz2)) * v.y + (2 * (qyqz - qxqw)) * v.z, (2 * (qxqz - qyqw)) * v.x + (2 * (qyqz + qxqw)) * v.y + (1 - 2 * (qx2 + qy2)) * v.z); - } - - public static Quaternion operator +(Quaternion a, Quaternion b) - { - return new Quaternion(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); - } - - public static Quaternion operator *(Quaternion a, float b) - { - return new Quaternion(a.x *b, a.y *b, a.z *b, a.w *b); - } - - public static Quaternion normalize(Quaternion a) - { - float m = (float)Math.Sqrt(a.w * a.w + a.x * a.x + a.y * a.y + a.z * a.z); - if (m < 0.000000001f) - { - a.w = 1; - a.x = a.y = a.z = 0; - return a; - } - return a * (1f / m); - } - - public static float dot(Quaternion a, Quaternion b) - { - return (a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z); - } - - public static Quaternion slerp(Quaternion a, Quaternion b, float interp) - { - if (dot(a, b) < 0.0) - { - a.w = -a.w; - a.x = -a.x; - a.y = -a.y; - a.z = -a.z; - } - float d = dot(a, b); - if (d >= 1.0) - { - return a; - } - float theta = (float)Math.Acos(d); - if (theta == 0.0f) - { - return (a); - } - return a * ((float)Math.Sin(theta - interp * theta) / (float)Math.Sin(theta)) + b * ((float)Math.Sin(interp * theta) / (float)Math.Sin(theta)); - } - - public static Quaternion Interpolate(Quaternion q0, Quaternion q1, float alpha) - { - return slerp(q0, q1, alpha); - } - - public static Quaternion Inverse(Quaternion q) - { - return new Quaternion(-q.x, -q.y, -q.z, q.w); - } - - public static Quaternion YawPitchRoll(float yaw, float pitch, float roll) - { - roll *= (3.14159264f / 180.0f); - yaw *= (3.14159264f / 180.0f); - pitch *= (3.14159264f / 180.0f); - return new Quaternion(new float3(0.0f, 0.0f, 1.0f), yaw) * new Quaternion(new float3(1.0f, 0.0f, 0.0f), pitch) * new Quaternion(new float3(0.0f, 1.0f, 0.0f), roll); - } - - public static float Yaw(Quaternion q) - { - float3 v = q.ydir(); - return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f); - } - - public static float Pitch(Quaternion q) - { - float3 v = q.ydir(); - return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f); - } - - public static float Roll(Quaternion q) - { - q = new Quaternion(new float3(0.0f, 0.0f, 1.0f), -Yaw(q) * (3.14159264f / 180.0f)) * q; - q = new Quaternion(new float3(1.0f, 0.0f, 0.0f), -Pitch(q) * (3.14159264f / 180.0f)) * q; - return (float)Math.Atan2(-q.xdir().z, q.xdir().x) * (180.0f / 3.14159264f); - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt b/OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt deleted file mode 100644 index fc53ae7..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt +++ /dev/null @@ -1,7 +0,0 @@ -ConvexDecompositionDotNet -========================= - -A C# port of the ConvexDecomposition library by John W. Ratcliff and Stan Melax. -The original C++ version is available at . -See the blog post at -for a thorough explanation of generating convex hulls from concave meshes. diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs deleted file mode 100644 index 9f06a9a..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs +++ /dev/null @@ -1,265 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class Rect3d - { - public float[] mMin = new float[3]; - public float[] mMax = new float[3]; - - public Rect3d() - { - } - - public Rect3d(float[] bmin, float[] bmax) - { - mMin[0] = bmin[0]; - mMin[1] = bmin[1]; - mMin[2] = bmin[2]; - - mMax[0] = bmax[0]; - mMax[1] = bmax[1]; - mMax[2] = bmax[2]; - } - - public void SetMin(float[] bmin) - { - mMin[0] = bmin[0]; - mMin[1] = bmin[1]; - mMin[2] = bmin[2]; - } - - public void SetMax(float[] bmax) - { - mMax[0] = bmax[0]; - mMax[1] = bmax[1]; - mMax[2] = bmax[2]; - } - - public void SetMin(float x, float y, float z) - { - mMin[0] = x; - mMin[1] = y; - mMin[2] = z; - } - - public void SetMax(float x, float y, float z) - { - mMax[0] = x; - mMax[1] = y; - mMax[2] = z; - } - } - - public static class SplitPlane - { - public static bool computeSplitPlane(List vertices, List indices, ref float4 plane) - { - float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue }; - float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue }; - - for (int i = 0; i < vertices.Count; i++) - { - float3 p = vertices[i]; - - if (p[0] < bmin[0]) - bmin[0] = p[0]; - if (p[1] < bmin[1]) - bmin[1] = p[1]; - if (p[2] < bmin[2]) - bmin[2] = p[2]; - - if (p[0] > bmax[0]) - bmax[0] = p[0]; - if (p[1] > bmax[1]) - bmax[1] = p[1]; - if (p[2] > bmax[2]) - bmax[2] = p[2]; - } - - float dx = bmax[0] - bmin[0]; - float dy = bmax[1] - bmin[1]; - float dz = bmax[2] - bmin[2]; - - float laxis = dx; - - int axis = 0; - - if (dy > dx) - { - axis = 1; - laxis = dy; - } - - if (dz > dx && dz > dy) - { - axis = 2; - laxis = dz; - } - - float[] p1 = new float[3]; - float[] p2 = new float[3]; - float[] p3 = new float[3]; - - p3[0] = p2[0] = p1[0] = bmin[0] + dx * 0.5f; - p3[1] = p2[1] = p1[1] = bmin[1] + dy * 0.5f; - p3[2] = p2[2] = p1[2] = bmin[2] + dz * 0.5f; - - Rect3d b = new Rect3d(bmin, bmax); - - Rect3d b1 = new Rect3d(); - Rect3d b2 = new Rect3d(); - - splitRect(axis, b, b1, b2, p1); - - switch (axis) - { - case 0: - p2[1] = bmin[1]; - p2[2] = bmin[2]; - - if (dz > dy) - { - p3[1] = bmax[1]; - p3[2] = bmin[2]; - } - else - { - p3[1] = bmin[1]; - p3[2] = bmax[2]; - } - - break; - case 1: - p2[0] = bmin[0]; - p2[2] = bmin[2]; - - if (dx > dz) - { - p3[0] = bmax[0]; - p3[2] = bmin[2]; - } - else - { - p3[0] = bmin[0]; - p3[2] = bmax[2]; - } - - break; - case 2: - p2[0] = bmin[0]; - p2[1] = bmin[1]; - - if (dx > dy) - { - p3[0] = bmax[0]; - p3[1] = bmin[1]; - } - else - { - p3[0] = bmin[0]; - p3[1] = bmax[1]; - } - - break; - } - - computePlane(p1, p2, p3, plane); - - return true; - } - - internal static void computePlane(float[] A, float[] B, float[] C, float4 plane) - { - float vx = (B[0] - C[0]); - float vy = (B[1] - C[1]); - float vz = (B[2] - C[2]); - - float wx = (A[0] - B[0]); - float wy = (A[1] - B[1]); - float wz = (A[2] - B[2]); - - float vw_x = vy * wz - vz * wy; - float vw_y = vz * wx - vx * wz; - float vw_z = vx * wy - vy * wx; - - float mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z)); - - if (mag < 0.000001f) - { - mag = 0; - } - else - { - mag = 1.0f / mag; - } - - float x = vw_x * mag; - float y = vw_y * mag; - float z = vw_z * mag; - - float D = 0.0f - ((x * A[0]) + (y * A[1]) + (z * A[2])); - - plane.x = x; - plane.y = y; - plane.z = z; - plane.w = D; - } - - public static void splitRect(int axis, Rect3d source, Rect3d b1, Rect3d b2, float[] midpoint) - { - switch (axis) - { - case 0: - b1.SetMin(source.mMin); - b1.SetMax(midpoint[0], source.mMax[1], source.mMax[2]); - - b2.SetMin(midpoint[0], source.mMin[1], source.mMin[2]); - b2.SetMax(source.mMax); - break; - case 1: - b1.SetMin(source.mMin); - b1.SetMax(source.mMax[0], midpoint[1], source.mMax[2]); - - b2.SetMin(source.mMin[0], midpoint[1], source.mMin[2]); - b2.SetMax(source.mMax); - break; - case 2: - b1.SetMin(source.mMin); - b1.SetMax(source.mMax[0], source.mMax[1], midpoint[2]); - - b2.SetMin(source.mMin[0], source.mMin[1], midpoint[2]); - b2.SetMax(source.mMax); - break; - } - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs deleted file mode 100644 index 6f17c9f..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs +++ /dev/null @@ -1,70 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class VertexPool - { - private List mVertices = new List(); - private Dictionary mIndices = new Dictionary(); - - public int getIndex(float3 vtx) - { - int idx; - if (mIndices.TryGetValue(vtx, out idx)) - return idx; - - idx = mVertices.Count; - mVertices.Add(vtx); - mIndices.Add(vtx, idx); - return idx; - } - - public float3 Get(int idx) - { - return mVertices[idx]; - } - - public int GetSize() - { - return mVertices.Count; - } - - public List GetVertices() - { - return mVertices; - } - - public void Clear() - { - mVertices.Clear(); - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs deleted file mode 100644 index ce88fc8..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs +++ /dev/null @@ -1,70 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class float2 - { - public float x; - public float y; - - public float2() - { - } - - public float2(float _x, float _y) - { - x = _x; - y = _y; - } - - public float this[int i] - { - get - { - switch (i) - { - case 0: return x; - case 1: return y; - } - throw new ArgumentOutOfRangeException(); - } - } - - public static float2 operator -(float2 a, float2 b) - { - return new float2(a.x - b.x, a.y - b.y); - } - - public static float2 operator +(float2 a, float2 b) - { - return new float2(a.x + b.x, a.y + b.y); - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs deleted file mode 100644 index 4389114..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs +++ /dev/null @@ -1,444 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class float3 : IEquatable - { - public float x; - public float y; - public float z; - - public float3() - { - x = 0; - y = 0; - z = 0; - } - - public float3(float _x, float _y, float _z) - { - x = _x; - y = _y; - z = _z; - } - - public float3(float3 f) - { - x = f.x; - y = f.y; - z = f.z; - } - - public float this[int i] - { - get - { - switch (i) - { - case 0: return x; - case 1: return y; - case 2: return z; - } - throw new ArgumentOutOfRangeException(); - } - } - - public float Distance(float3 a) - { - float3 d = new float3(a.x - x, a.y - y, a.z - z); - return d.Length(); - } - - public float Distance2(float3 a) - { - float dx = a.x - x; - float dy = a.y - y; - float dz = a.z - z; - return dx * dx + dy * dy + dz * dz; - } - - public float Length() - { - return (float)Math.Sqrt(x * x + y * y + z * z); - } - - public float Area(float3 p1, float3 p2) - { - float A = Partial(p1); - A += p1.Partial(p2); - A += p2.Partial(this); - return A * 0.5f; - } - - public float Partial(float3 p) - { - return (x * p.y) - (p.x * y); - } - - // Given a point and a line (defined by two points), compute the closest point - // in the line. (The line is treated as infinitely long.) - public void NearestPointInLine(float3 point, float3 line0, float3 line1) - { - float3 nearestPoint = new float3(); - float3 lineDelta = line1 - line0; - - // Handle degenerate lines - if (lineDelta == float3.Zero) - { - nearestPoint = line0; - } - else - { - float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta); - nearestPoint = line0 + lineDelta * delta; - } - - this.x = nearestPoint.x; - this.y = nearestPoint.y; - this.z = nearestPoint.z; - } - - // Given a point and a line segment (defined by two points), compute the closest point - // in the line. Cap the point at the endpoints of the line segment. - public void NearestPointInLineSegment(float3 point, float3 line0, float3 line1) - { - float3 nearestPoint = new float3(); - float3 lineDelta = line1 - line0; - - // Handle degenerate lines - if (lineDelta == Zero) - { - nearestPoint = line0; - } - else - { - float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta); - - // Clamp the point to conform to the segment's endpoints - if (delta < 0) - delta = 0; - else if (delta > 1) - delta = 1; - - nearestPoint = line0 + lineDelta * delta; - } - - this.x = nearestPoint.x; - this.y = nearestPoint.y; - this.z = nearestPoint.z; - } - - // Given a point and a triangle (defined by three points), compute the closest point - // in the triangle. Clamp the point so it's confined to the area of the triangle. - public void NearestPointInTriangle(float3 point, float3 triangle0, float3 triangle1, float3 triangle2) - { - float3 nearestPoint = new float3(); - - float3 lineDelta0 = triangle1 - triangle0; - float3 lineDelta1 = triangle2 - triangle0; - - // Handle degenerate triangles - if ((lineDelta0 == Zero) || (lineDelta1 == Zero)) - { - nearestPoint.NearestPointInLineSegment(point, triangle1, triangle2); - } - else if (lineDelta0 == lineDelta1) - { - nearestPoint.NearestPointInLineSegment(point, triangle0, triangle1); - } - else - { - float3[] axis = new float3[3] { new float3(), new float3(), new float3() }; - axis[0].NearestPointInLine(triangle0, triangle1, triangle2); - axis[1].NearestPointInLine(triangle1, triangle0, triangle2); - axis[2].NearestPointInLine(triangle2, triangle0, triangle1); - - float3 axisDot = new float3(); - axisDot.x = dot(triangle0 - axis[0], point - axis[0]); - axisDot.y = dot(triangle1 - axis[1], point - axis[1]); - axisDot.z = dot(triangle2 - axis[2], point - axis[2]); - - bool bForce = true; - float bestMagnitude2 = 0; - float closeMagnitude2; - float3 closePoint = new float3(); - - if (axisDot.x < 0f) - { - closePoint.NearestPointInLineSegment(point, triangle1, triangle2); - closeMagnitude2 = point.Distance2(closePoint); - if (bForce || (bestMagnitude2 > closeMagnitude2)) - { - bForce = false; - bestMagnitude2 = closeMagnitude2; - nearestPoint = closePoint; - } - } - if (axisDot.y < 0f) - { - closePoint.NearestPointInLineSegment(point, triangle0, triangle2); - closeMagnitude2 = point.Distance2(closePoint); - if (bForce || (bestMagnitude2 > closeMagnitude2)) - { - bForce = false; - bestMagnitude2 = closeMagnitude2; - nearestPoint = closePoint; - } - } - if (axisDot.z < 0f) - { - closePoint.NearestPointInLineSegment(point, triangle0, triangle1); - closeMagnitude2 = point.Distance2(closePoint); - if (bForce || (bestMagnitude2 > closeMagnitude2)) - { - bForce = false; - bestMagnitude2 = closeMagnitude2; - nearestPoint = closePoint; - } - } - - // If bForce is true at this point, it means the nearest point lies - // inside the triangle; use the nearest-point-on-a-plane equation - if (bForce) - { - float3 normal; - - // Get the normal of the polygon (doesn't have to be a unit vector) - normal = float3.cross(lineDelta0, lineDelta1); - - float3 pointDelta = point - triangle0; - float delta = float3.dot(normal, pointDelta) / float3.dot(normal, normal); - - nearestPoint = point - normal * delta; - } - } - - this.x = nearestPoint.x; - this.y = nearestPoint.y; - this.z = nearestPoint.z; - } - - public static float3 operator +(float3 a, float3 b) - { - return new float3(a.x + b.x, a.y + b.y, a.z + b.z); - } - - public static float3 operator -(float3 a, float3 b) - { - return new float3(a.x - b.x, a.y - b.y, a.z - b.z); - } - - public static float3 operator -(float3 a, float s) - { - return new float3(a.x - s, a.y - s, a.z - s); - } - - public static float3 operator -(float3 v) - { - return new float3(-v.x, -v.y, -v.z); - } - - public static float3 operator *(float3 v, float s) - { - return new float3(v.x * s, v.y * s, v.z * s); - } - - public static float3 operator *(float s, float3 v) - { - return new float3(v.x * s, v.y * s, v.z * s); - } - - public static float3 operator *(float3 v, float3x3 m) - { - return new float3((m.x.x * v.x + m.y.x * v.y + m.z.x * v.z), (m.x.y * v.x + m.y.y * v.y + m.z.y * v.z), (m.x.z * v.x + m.y.z * v.y + m.z.z * v.z)); - } - - public static float3 operator *(float3x3 m, float3 v) - { - return new float3(dot(m.x, v), dot(m.y, v), dot(m.z, v)); - } - - public static float3 operator /(float3 v, float s) - { - float sinv = 1.0f / s; - return new float3(v.x * sinv, v.y * sinv, v.z * sinv); - } - - public bool Equals(float3 other) - { - return this == other; - } - - public override bool Equals(object obj) - { - float3 f = obj as float3; - if (f == null) - return false; - - return this == f; - } - - public override int GetHashCode() - { - return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); - } - - public static bool operator ==(float3 a, float3 b) - { - // If both are null, or both are same instance, return true. - if (System.Object.ReferenceEquals(a, b)) - return true; - // If one is null, but not both, return false. - if (((object)a == null) || ((object)b == null)) - return false; - - return (a.x == b.x && a.y == b.y && a.z == b.z); - } - - public static bool operator !=(float3 a, float3 b) - { - return (a.x != b.x || a.y != b.y || a.z != b.z); - } - - public static float dot(float3 a, float3 b) - { - return a.x * b.x + a.y * b.y + a.z * b.z; - } - - public static float3 cmul(float3 v1, float3 v2) - { - return new float3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z); - } - - public static float3 cross(float3 a, float3 b) - { - return new float3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); - } - - public static float3 Interpolate(float3 v0, float3 v1, float alpha) - { - return v0 * (1 - alpha) + v1 * alpha; - } - - public static float3 Round(float3 a, int digits) - { - return new float3((float)Math.Round(a.x, digits), (float)Math.Round(a.y, digits), (float)Math.Round(a.z, digits)); - } - - public static float3 VectorMax(float3 a, float3 b) - { - return new float3(Math.Max(a.x, b.x), Math.Max(a.y, b.y), Math.Max(a.z, b.z)); - } - - public static float3 VectorMin(float3 a, float3 b) - { - return new float3(Math.Min(a.x, b.x), Math.Min(a.y, b.y), Math.Min(a.z, b.z)); - } - - public static float3 vabs(float3 v) - { - return new float3(Math.Abs(v.x), Math.Abs(v.y), Math.Abs(v.z)); - } - - public static float magnitude(float3 v) - { - return (float)Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z); - } - - public static float3 normalize(float3 v) - { - float d = magnitude(v); - if (d == 0) - d = 0.1f; - d = 1 / d; - return new float3(v.x * d, v.y * d, v.z * d); - } - - public static float3 safenormalize(float3 v) - { - if (magnitude(v) <= 0.0f) - return new float3(1, 0, 0); - else - return normalize(v); - } - - public static float Yaw(float3 v) - { - return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f); - } - - public static float Pitch(float3 v) - { - return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f); - } - - public float ComputePlane(float3 A, float3 B, float3 C) - { - float vx, vy, vz, wx, wy, wz, vw_x, vw_y, vw_z, mag; - - vx = (B.x - C.x); - vy = (B.y - C.y); - vz = (B.z - C.z); - - wx = (A.x - B.x); - wy = (A.y - B.y); - wz = (A.z - B.z); - - vw_x = vy * wz - vz * wy; - vw_y = vz * wx - vx * wz; - vw_z = vx * wy - vy * wx; - - mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z)); - - if (mag < 0.000001f) - { - mag = 0; - } - else - { - mag = 1.0f / mag; - } - - x = vw_x * mag; - y = vw_y * mag; - z = vw_z * mag; - - float D = 0.0f - ((x * A.x) + (y * A.y) + (z * A.z)); - return D; - } - - public override string ToString() - { - return String.Format("<{0}, {1}, {2}>", x, y, z); - } - - public static readonly float3 Zero = new float3(); - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs deleted file mode 100644 index 76cf063..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs +++ /dev/null @@ -1,195 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class float3x3 - { - public float3 x = new float3(); - public float3 y = new float3(); - public float3 z = new float3(); - - public float3x3() - { - } - - public float3x3(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz) - { - x = new float3(xx, xy, xz); - y = new float3(yx, yy, yz); - z = new float3(zx, zy, zz); - } - - public float3x3(float3 _x, float3 _y, float3 _z) - { - x = new float3(_x); - y = new float3(_y); - z = new float3(_z); - } - - public float3 this[int i] - { - get - { - switch (i) - { - case 0: return x; - case 1: return y; - case 2: return z; - } - throw new ArgumentOutOfRangeException(); - } - } - - public float this[int i, int j] - { - get - { - switch (i) - { - case 0: - switch (j) - { - case 0: return x.x; - case 1: return x.y; - case 2: return x.z; - } - break; - case 1: - switch (j) - { - case 0: return y.x; - case 1: return y.y; - case 2: return y.z; - } - break; - case 2: - switch (j) - { - case 0: return z.x; - case 1: return z.y; - case 2: return z.z; - } - break; - } - throw new ArgumentOutOfRangeException(); - } - set - { - switch (i) - { - case 0: - switch (j) - { - case 0: x.x = value; return; - case 1: x.y = value; return; - case 2: x.z = value; return; - } - break; - case 1: - switch (j) - { - case 0: y.x = value; return; - case 1: y.y = value; return; - case 2: y.z = value; return; - } - break; - case 2: - switch (j) - { - case 0: z.x = value; return; - case 1: z.y = value; return; - case 2: z.z = value; return; - } - break; - } - throw new ArgumentOutOfRangeException(); - } - } - - public static float3x3 Transpose(float3x3 m) - { - return new float3x3(new float3(m.x.x, m.y.x, m.z.x), new float3(m.x.y, m.y.y, m.z.y), new float3(m.x.z, m.y.z, m.z.z)); - } - - public static float3x3 operator *(float3x3 a, float3x3 b) - { - return new float3x3(a.x * b, a.y * b, a.z * b); - } - - public static float3x3 operator *(float3x3 a, float s) - { - return new float3x3(a.x * s, a.y * s, a.z * s); - } - - public static float3x3 operator /(float3x3 a, float s) - { - float t = 1f / s; - return new float3x3(a.x * t, a.y * t, a.z * t); - } - - public static float3x3 operator +(float3x3 a, float3x3 b) - { - return new float3x3(a.x + b.x, a.y + b.y, a.z + b.z); - } - - public static float3x3 operator -(float3x3 a, float3x3 b) - { - return new float3x3(a.x - b.x, a.y - b.y, a.z - b.z); - } - - public static float Determinant(float3x3 m) - { - return m.x.x * m.y.y * m.z.z + m.y.x * m.z.y * m.x.z + m.z.x * m.x.y * m.y.z - m.x.x * m.z.y * m.y.z - m.y.x * m.x.y * m.z.z - m.z.x * m.y.y * m.x.z; - } - - public static float3x3 Inverse(float3x3 a) - { - float3x3 b = new float3x3(); - float d = Determinant(a); - Debug.Assert(d != 0); - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - { - int i1 = (i + 1) % 3; - int i2 = (i + 2) % 3; - int j1 = (j + 1) % 3; - int j2 = (j + 2) % 3; - - // reverse indexs i&j to take transpose - b[i, j] = (a[i1][j1] * a[i2][j2] - a[i1][j2] * a[i2][j1]) / d; - } - } - return b; - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs deleted file mode 100644 index fa60876..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs +++ /dev/null @@ -1,170 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class float4 - { - public float x; - public float y; - public float z; - public float w; - - public float4() - { - x = 0; - y = 0; - z = 0; - w = 0; - } - - public float4(float _x, float _y, float _z, float _w) - { - x = _x; - y = _y; - z = _z; - w = _w; - } - - public float4(float3 v, float _w) - { - x = v.x; - y = v.y; - z = v.z; - w = _w; - } - - public float4(float4 f) - { - x = f.x; - y = f.y; - z = f.z; - w = f.w; - } - - public float this[int i] - { - get - { - switch (i) - { - case 0: return x; - case 1: return y; - case 2: return z; - case 3: return w; - } - throw new ArgumentOutOfRangeException(); - } - } - - public float3 xyz() - { - return new float3(x, y, z); - } - - public void setxyz(float3 xyz) - { - x = xyz.x; - y = xyz.y; - z = xyz.z; - } - - public override int GetHashCode() - { - return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); - } - - public override bool Equals(object obj) - { - float4 f = obj as float4; - if (f == null) - return false; - - return this == f; - } - - public static float4 Homogenize(float3 v3) - { - return Homogenize(v3, 1.0f); - } - - //C++ TO C# CONVERTER NOTE: C# does not allow default values for parameters. Overloaded methods are inserted above. - //ORIGINAL LINE: float4 Homogenize(const float3 &v3, const float &w =1.0f) - public static float4 Homogenize(float3 v3, float w) - { - return new float4(v3.x, v3.y, v3.z, w); - } - - public static float4 cmul(float4 a, float4 b) - { - return new float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); - } - - public static float4 operator +(float4 a, float4 b) - { - return new float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); - } - public static float4 operator -(float4 a, float4 b) - { - return new float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); - } - - public static float4 operator *(float4 v, float4x4 m) - { - return v.x * m.x + v.y * m.y + v.z * m.z + v.w * m.w; // yes this actually works - } - - public static bool operator ==(float4 a, float4 b) - { - // If both are null, or both are same instance, return true. - if (System.Object.ReferenceEquals(a, b)) - return true; - // If one is null, but not both, return false. - if (((object)a == null) || ((object)b == null)) - return false; - - return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w); - } - - public static bool operator !=(float4 a, float4 b) - { - return !(a == b); - } - - public static float4 operator *(float4 v, float s) - { - return new float4(v.x * s, v.y * s, v.z * s, v.w * s); - } - - public static float4 operator *(float s, float4 v) - { - return new float4(v.x * s, v.y * s, v.z * s, v.w * s); - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs deleted file mode 100644 index 7d1592f..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs +++ /dev/null @@ -1,284 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class float4x4 - { - public float4 x = new float4(); - public float4 y = new float4(); - public float4 z = new float4(); - public float4 w = new float4(); - - public float4x4() - { - } - - public float4x4(float4 _x, float4 _y, float4 _z, float4 _w) - { - x = new float4(_x); - y = new float4(_y); - z = new float4(_z); - w = new float4(_w); - } - - public float4x4( - float m00, float m01, float m02, float m03, - float m10, float m11, float m12, float m13, - float m20, float m21, float m22, float m23, - float m30, float m31, float m32, float m33) - { - x = new float4(m00, m01, m02, m03); - y = new float4(m10, m11, m12, m13); - z = new float4(m20, m21, m22, m23); - w = new float4(m30, m31, m32, m33); - } - - public float4x4(float4x4 m) - { - x = new float4(m.x); - y = new float4(m.y); - z = new float4(m.z); - w = new float4(m.w); - } - - public float4 this[int i] - { - get - { - switch (i) - { - case 0: return x; - case 1: return y; - case 2: return z; - case 3: return w; - } - throw new ArgumentOutOfRangeException(); - } - set - { - switch (i) - { - case 0: x = value; return; - case 1: y = value; return; - case 2: z = value; return; - case 3: w = value; return; - } - throw new ArgumentOutOfRangeException(); - } - } - - public override int GetHashCode() - { - return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); - } - - public override bool Equals(object obj) - { - float4x4 m = obj as float4x4; - if (m == null) - return false; - - return this == m; - } - - public static float4x4 operator *(float4x4 a, float4x4 b) - { - return new float4x4(a.x * b, a.y * b, a.z * b, a.w * b); - } - - public static bool operator ==(float4x4 a, float4x4 b) - { - return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w); - } - - public static bool operator !=(float4x4 a, float4x4 b) - { - return !(a == b); - } - - public static float4x4 Inverse(float4x4 m) - { - float4x4 d = new float4x4(); - //float dst = d.x.x; - float[] tmp = new float[12]; // temp array for pairs - float[] src = new float[16]; // array of transpose source matrix - float det; // determinant - // transpose matrix - for (int i = 0; i < 4; i++) - { - src[i] = m[i].x; - src[i + 4] = m[i].y; - src[i + 8] = m[i].z; - src[i + 12] = m[i].w; - } - // calculate pairs for first 8 elements (cofactors) - tmp[0] = src[10] * src[15]; - tmp[1] = src[11] * src[14]; - tmp[2] = src[9] * src[15]; - tmp[3] = src[11] * src[13]; - tmp[4] = src[9] * src[14]; - tmp[5] = src[10] * src[13]; - tmp[6] = src[8] * src[15]; - tmp[7] = src[11] * src[12]; - tmp[8] = src[8] * src[14]; - tmp[9] = src[10] * src[12]; - tmp[10] = src[8] * src[13]; - tmp[11] = src[9] * src[12]; - // calculate first 8 elements (cofactors) - d.x.x = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7]; - d.x.x -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7]; - d.x.y = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7]; - d.x.y -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7]; - d.x.z = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7]; - d.x.z -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7]; - d.x.w = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6]; - d.x.w -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6]; - d.y.x = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3]; - d.y.x -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3]; - d.y.y = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3]; - d.y.y -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3]; - d.y.z = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3]; - d.y.z -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3]; - d.y.w = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2]; - d.y.w -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2]; - // calculate pairs for second 8 elements (cofactors) - tmp[0] = src[2]*src[7]; - tmp[1] = src[3]*src[6]; - tmp[2] = src[1]*src[7]; - tmp[3] = src[3]*src[5]; - tmp[4] = src[1]*src[6]; - tmp[5] = src[2]*src[5]; - tmp[6] = src[0]*src[7]; - tmp[7] = src[3]*src[4]; - tmp[8] = src[0]*src[6]; - tmp[9] = src[2]*src[4]; - tmp[10] = src[0]*src[5]; - tmp[11] = src[1]*src[4]; - // calculate second 8 elements (cofactors) - d.z.x = tmp[0]*src[13] + tmp[3]*src[14] + tmp[4]*src[15]; - d.z.x -= tmp[1]*src[13] + tmp[2]*src[14] + tmp[5]*src[15]; - d.z.y = tmp[1]*src[12] + tmp[6]*src[14] + tmp[9]*src[15]; - d.z.y -= tmp[0]*src[12] + tmp[7]*src[14] + tmp[8]*src[15]; - d.z.z = tmp[2]*src[12] + tmp[7]*src[13] + tmp[10]*src[15]; - d.z.z -= tmp[3]*src[12] + tmp[6]*src[13] + tmp[11]*src[15]; - d.z.w = tmp[5]*src[12] + tmp[8]*src[13] + tmp[11]*src[14]; - d.z.w-= tmp[4]*src[12] + tmp[9]*src[13] + tmp[10]*src[14]; - d.w.x = tmp[2]*src[10] + tmp[5]*src[11] + tmp[1]*src[9]; - d.w.x-= tmp[4]*src[11] + tmp[0]*src[9] + tmp[3]*src[10]; - d.w.y = tmp[8]*src[11] + tmp[0]*src[8] + tmp[7]*src[10]; - d.w.y-= tmp[6]*src[10] + tmp[9]*src[11] + tmp[1]*src[8]; - d.w.z = tmp[6]*src[9] + tmp[11]*src[11] + tmp[3]*src[8]; - d.w.z-= tmp[10]*src[11] + tmp[2]*src[8] + tmp[7]*src[9]; - d.w.w = tmp[10]*src[10] + tmp[4]*src[8] + tmp[9]*src[9]; - d.w.w-= tmp[8]*src[9] + tmp[11]*src[10] + tmp[5]*src[8]; - // calculate determinant - det = src[0] * d.x.x + src[1] * d.x.y + src[2] * d.x.z + src[3] * d.x.w; - // calculate matrix inverse - det = 1/det; - for (int j = 0; j < 4; j++) - d[j] *= det; - return d; - } - - public static float4x4 MatrixRigidInverse(float4x4 m) - { - float4x4 trans_inverse = MatrixTranslation(-m.w.xyz()); - float4x4 rot = new float4x4(m); - rot.w = new float4(0f, 0f, 0f, 1f); - return trans_inverse * MatrixTranspose(rot); - } - public static float4x4 MatrixTranspose(float4x4 m) - { - return new float4x4(m.x.x, m.y.x, m.z.x, m.w.x, m.x.y, m.y.y, m.z.y, m.w.y, m.x.z, m.y.z, m.z.z, m.w.z, m.x.w, m.y.w, m.z.w, m.w.w); - } - public static float4x4 MatrixPerspectiveFov(float fovy, float aspect, float zn, float zf) - { - float h = 1.0f / (float)Math.Tan(fovy / 2.0f); // view space height - float w = h / aspect; // view space width - return new float4x4(w, 0, 0, 0, 0, h, 0, 0, 0, 0, zf / (zn - zf), -1, 0, 0, zn * zf / (zn - zf), 0); - } - public static float4x4 MatrixTranslation(float3 t) - { - return new float4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, t.x, t.y, t.z, 1); - } - public static float4x4 MatrixRotationZ(float angle_radians) - { - float s = (float)Math.Sin(angle_radians); - float c = (float)Math.Cos(angle_radians); - return new float4x4(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - } - public static float4x4 MatrixLookAt(float3 eye, float3 at, float3 up) - { - float4x4 m = new float4x4(); - m.w.w = 1.0f; - m.w.setxyz(eye); - m.z.setxyz(float3.normalize(eye - at)); - m.x.setxyz(float3.normalize(float3.cross(up, m.z.xyz()))); - m.y.setxyz(float3.cross(m.z.xyz(), m.x.xyz())); - return MatrixRigidInverse(m); - } - - public static float4x4 MatrixFromQuatVec(Quaternion q, float3 v) - { - // builds a 4x4 transformation matrix based on orientation q and translation v - float qx2 = q.x * q.x; - float qy2 = q.y * q.y; - float qz2 = q.z * q.z; - - float qxqy = q.x * q.y; - float qxqz = q.x * q.z; - float qxqw = q.x * q.w; - float qyqz = q.y * q.z; - float qyqw = q.y * q.w; - float qzqw = q.z * q.w; - - return new float4x4( - 1 - 2 * (qy2 + qz2), - 2 * (qxqy + qzqw), - 2 * (qxqz - qyqw), - 0, - 2 * (qxqy - qzqw), - 1 - 2 * (qx2 + qz2), - 2 * (qyqz + qxqw), - 0, - 2 * (qxqz + qyqw), - 2 * (qyqz - qxqw), - 1 - 2 * (qx2 + qy2), - 0, - v.x, - v.y, - v.z, - 1.0f); - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs deleted file mode 100644 index 9c5760d..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs +++ /dev/null @@ -1,128 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class int3 - { - public int x; - public int y; - public int z; - - public int3() - { - } - - public int3(int _x, int _y, int _z) - { - x = _x; - y = _y; - z = _z; - } - - public int this[int i] - { - get - { - switch (i) - { - case 0: return x; - case 1: return y; - case 2: return z; - } - throw new ArgumentOutOfRangeException(); - } - set - { - switch (i) - { - case 0: x = value; return; - case 1: y = value; return; - case 2: z = value; return; - } - throw new ArgumentOutOfRangeException(); - } - } - - public override int GetHashCode() - { - return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); - } - - public override bool Equals(object obj) - { - int3 i = obj as int3; - if (i == null) - return false; - - return this == i; - } - - public static bool operator ==(int3 a, int3 b) - { - // If both are null, or both are same instance, return true. - if (System.Object.ReferenceEquals(a, b)) - return true; - // If one is null, but not both, return false. - if (((object)a == null) || ((object)b == null)) - return false; - - for (int i = 0; i < 3; i++) - { - if (a[i] != b[i]) - return false; - } - return true; - } - - public static bool operator !=(int3 a, int3 b) - { - return !(a == b); - } - - public static int3 roll3(int3 a) - { - int tmp = a[0]; - a[0] = a[1]; - a[1] = a[2]; - a[2] = tmp; - return a; - } - - public static bool isa(int3 a, int3 b) - { - return (a == b || roll3(a) == b || a == roll3(b)); - } - - public static bool b2b(int3 a, int3 b) - { - return isa(a, new int3(b[2], b[1], b[0])); - } - } -} diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs deleted file mode 100644 index c2b32e5..0000000 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs +++ /dev/null @@ -1,66 +0,0 @@ -/* The MIT License - * - * Copyright (c) 2010 Intel Corporation. - * All rights reserved. - * - * Based on the convexdecomposition library from - * by John W. Ratcliff and Stan Melax. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -using System; - -namespace OpenSim.Region.Physics.ConvexDecompositionDotNet -{ - public class int4 - { - public int x; - public int y; - public int z; - public int w; - - public int4() - { - } - - public int4(int _x, int _y, int _z, int _w) - { - x = _x; - y = _y; - z = _z; - w = _w; - } - - public int this[int i] - { - get - { - switch (i) - { - case 0: return x; - case 1: return y; - case 2: return z; - case 3: return w; - } - throw new ArgumentOutOfRangeException(); - } - } - } -} diff --git a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs b/OpenSim/Region/Physics/Manager/AssemblyInfo.cs deleted file mode 100644 index 36b4235..0000000 --- a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Reflection; -using System.Runtime.InteropServices; - -// Information about this assembly is defined by the following -// attributes. -// -// change them to the information which is associated with the assembly -// you compile. - -[assembly : AssemblyTitle("PhysicsManager")] -[assembly : AssemblyDescription("")] -[assembly : AssemblyConfiguration("")] -[assembly : AssemblyCompany("http://opensimulator.org")] -[assembly : AssemblyProduct("PhysicsManager")] -[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] -[assembly : AssemblyTrademark("")] -[assembly : AssemblyCulture("")] - -// This sets the default COM visibility of types in the assembly to invisible. -// If you need to expose a type to COM, use [ComVisible(true)] on that type. - -[assembly : ComVisible(false)] - -// The assembly version has following format : -// -// Major.Minor.Build.Revision -// -// You can specify all values by your own or you can build default build and revision -// numbers with the '*' character (the default): - -[assembly : AssemblyVersion("0.7.5.*")] diff --git a/OpenSim/Region/Physics/Manager/CollisionLocker.cs b/OpenSim/Region/Physics/Manager/CollisionLocker.cs deleted file mode 100644 index cace4e4..0000000 --- a/OpenSim/Region/Physics/Manager/CollisionLocker.cs +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; - -namespace OpenSim.Region.Physics.Manager -{ - public class CollisionLocker - { - private List worldlock = new List(); - - public CollisionLocker() - { - - } - - public void dlock(IntPtr world) - { - lock (worldlock) - { - worldlock.Add(world); - } - - } - - public void dunlock(IntPtr world) - { - lock (worldlock) - { - worldlock.Remove(world); - } - } - - public bool lockquery() - { - return (worldlock.Count > 0); - } - - public void drelease(IntPtr world) - { - lock (worldlock) - { - if (worldlock.Contains(world)) - worldlock.Remove(world); - } - } - } -} diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs deleted file mode 100644 index 10c4bd3..0000000 --- a/OpenSim/Region/Physics/Manager/IMesher.cs +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using OpenSim.Framework; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.Manager -{ - public interface IMesher - { - IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); - IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); - IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache); - } - - // Values for level of detail to be passed to the mesher. - // Values origionally chosen for the LOD of sculpties (the sqrt(width*heigth) of sculpt texture) - // Lower level of detail reduces the number of vertices used to represent the meshed shape. - public enum LevelOfDetail - { - High = 32, - Medium = 16, - Low = 8, - VeryLow = 4 - } - - public interface IVertex - { - } - - public interface IMesh - { - List getVertexList(); - int[] getIndexListAsInt(); - int[] getIndexListAsIntLocked(); - float[] getVertexListAsFloatLocked(); - void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount); - void getVertexListAsPtrToFloatArray(out IntPtr vertexList, out int vertexStride, out int vertexCount); - void releaseSourceMeshData(); - void releasePinned(); - void Append(IMesh newMesh); - void TransformLinear(float[,] matrix, float[] offset); - } -} diff --git a/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs deleted file mode 100755 index b8676ba..0000000 --- a/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using OpenSim.Framework; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.Manager -{ - public struct PhysParameterEntry - { - // flags to say to apply to all or no instances (I wish one could put consts into interfaces) - public const uint APPLY_TO_ALL = 0xfffffff3; - public const uint APPLY_TO_NONE = 0xfffffff4; - - // values that denote true and false values - public const float NUMERIC_TRUE = 1f; - public const float NUMERIC_FALSE = 0f; - - public string name; - public string desc; - - public PhysParameterEntry(string n, string d) - { - name = n; - desc = d; - } - } - - // Interface for a physics scene that implements the runtime setting and getting of physics parameters - public interface IPhysicsParameters - { - // Get the list of parameters this physics engine supports - PhysParameterEntry[] GetParameterList(); - - // Set parameter on a specific or all instances. - // Return 'false' if not able to set the parameter. - bool SetPhysicsParameter(string parm, float value, uint localID); - - // Get parameter. - // Return 'false' if not able to get the parameter. - bool GetPhysicsParameter(string parm, out float value); - - // Get parameter from a particular object - // TODO: - // bool GetPhysicsParameter(string parm, out float value, uint localID); - } -} diff --git a/OpenSim/Region/Physics/Manager/NullPhysicsScene.cs b/OpenSim/Region/Physics/Manager/NullPhysicsScene.cs deleted file mode 100644 index 1ccf46d..0000000 --- a/OpenSim/Region/Physics/Manager/NullPhysicsScene.cs +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Collections.Generic; -using System.Reflection; -using log4net; -using Nini.Config; -using OpenSim.Framework; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.Manager -{ - class NullPhysicsScene : PhysicsScene - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private static int m_workIndicator; - - public override void Initialise(IMesher meshmerizer, IConfigSource config) - { - // Does nothing right now - } - - public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) - { - m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : AddAvatar({0})", position); - return PhysicsActor.Null; - } - - public override void RemoveAvatar(PhysicsActor actor) - { - } - - public override void RemovePrim(PhysicsActor prim) - { - } - public override void SetWaterLevel(float baseheight) - { - - } - -/* - public override PhysicsActor AddPrim(Vector3 position, Vector3 size, Quaternion rotation) - { - m_log.InfoFormat("NullPhysicsScene : AddPrim({0},{1})", position, size); - return PhysicsActor.Null; - } -*/ - - public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, - Vector3 size, Quaternion rotation, bool isPhysical, uint localid) - { - m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : AddPrim({0},{1})", position, size); - return PhysicsActor.Null; - } - - public override void AddPhysicsActorTaint(PhysicsActor prim) - { - } - - public override float Simulate(float timeStep) - { - m_workIndicator = (m_workIndicator + 1) % 10; - - return 0f; - } - - public override void GetResults() - { - m_log.Info("[PHYSICS]: NullPhysicsScene : GetResults()"); - } - - public override void SetTerrain(float[] heightMap) - { - m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : SetTerrain({0} items)", heightMap.Length); - } - - public override void DeleteTerrain() - { - } - - public override bool IsThreaded - { - get { return false; } - } - - public override void Dispose() - { - } - - public override Dictionary GetTopColliders() - { - Dictionary returncolliders = new Dictionary(); - return returncolliders; - } - } -} \ No newline at end of file diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs deleted file mode 100644 index d119791..0000000 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ /dev/null @@ -1,567 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using log4net; -using System; -using System.Collections.Generic; -using System.Reflection; -using OpenSim.Framework; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.Manager -{ - public delegate void PositionUpdate(Vector3 position); - public delegate void VelocityUpdate(Vector3 velocity); - public delegate void OrientationUpdate(Quaternion orientation); - - public enum ActorTypes : int - { - Unknown = 0, - Agent = 1, - Prim = 2, - Ground = 3 - } - - public enum PIDHoverType - { - Ground, - GroundAndWater, - Water, - Absolute - } - - public struct ContactPoint - { - public Vector3 Position; - public Vector3 SurfaceNormal; - public float PenetrationDepth; - - public ContactPoint(Vector3 position, Vector3 surfaceNormal, float penetrationDepth) - { - Position = position; - SurfaceNormal = surfaceNormal; - PenetrationDepth = penetrationDepth; - } - } - - /// - /// Used to pass collision information to OnCollisionUpdate listeners. - /// - public class CollisionEventUpdate : EventArgs - { - /// - /// Number of collision events in this update. - /// - public int Count { get { return m_objCollisionList.Count; } } - - public bool CollisionsOnPreviousFrame { get; private set; } - - public Dictionary m_objCollisionList; - - public CollisionEventUpdate(Dictionary objCollisionList) - { - m_objCollisionList = objCollisionList; - } - - public CollisionEventUpdate() - { - m_objCollisionList = new Dictionary(); - } - - public void AddCollider(uint localID, ContactPoint contact) - { - if (!m_objCollisionList.ContainsKey(localID)) - { - m_objCollisionList.Add(localID, contact); - } - else - { - if (m_objCollisionList[localID].PenetrationDepth < contact.PenetrationDepth) - m_objCollisionList[localID] = contact; - } - } - - /// - /// Clear added collision events. - /// - public void Clear() - { - m_objCollisionList.Clear(); - } - } - - public abstract class PhysicsActor - { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - public delegate void RequestTerseUpdate(); - public delegate void CollisionUpdate(EventArgs e); - public delegate void OutOfBounds(Vector3 pos); - -// disable warning: public events -#pragma warning disable 67 - public event PositionUpdate OnPositionUpdate; - public event VelocityUpdate OnVelocityUpdate; - public event OrientationUpdate OnOrientationUpdate; - public event RequestTerseUpdate OnRequestTerseUpdate; - - /// - /// Subscribers to this event must synchronously handle the dictionary of collisions received, since the event - /// object is reused in subsequent physics frames. - /// - public event CollisionUpdate OnCollisionUpdate; - - public event OutOfBounds OnOutOfBounds; -#pragma warning restore 67 - - public static PhysicsActor Null - { - get { return new NullPhysicsActor(); } - } - - public abstract bool Stopped { get; } - - public abstract Vector3 Size { get; set; } - - public abstract PrimitiveBaseShape Shape { set; } - - uint m_baseLocalID; - public virtual uint LocalID - { - set { m_baseLocalID = value; } - get { return m_baseLocalID; } - } - - public abstract bool Grabbed { set; } - - public abstract bool Selected { set; } - - /// - /// Name of this actor. - /// - /// - /// XXX: Bizarrely, this cannot be "Terrain" or "Water" right now unless it really is simulating terrain or - /// water. This is not a problem due to the formatting of names given by prims and avatars. - /// - public string Name { get; protected set; } - - /// - /// This is being used by ODE joint code. - /// - public string SOPName; - - public abstract void CrossingFailure(); - - public abstract void link(PhysicsActor obj); - - public abstract void delink(); - - public abstract void LockAngularMotion(Vector3 axis); - - public virtual void RequestPhysicsterseUpdate() - { - // Make a temporary copy of the event to avoid possibility of - // a race condition if the last subscriber unsubscribes - // immediately after the null check and before the event is raised. - RequestTerseUpdate handler = OnRequestTerseUpdate; - - if (handler != null) - { - handler(); - } - } - - public virtual void RaiseOutOfBounds(Vector3 pos) - { - // Make a temporary copy of the event to avoid possibility of - // a race condition if the last subscriber unsubscribes - // immediately after the null check and before the event is raised. - OutOfBounds handler = OnOutOfBounds; - - if (handler != null) - { - handler(pos); - } - } - - public virtual void SendCollisionUpdate(EventArgs e) - { - CollisionUpdate handler = OnCollisionUpdate; - -// m_log.DebugFormat("[PHYSICS ACTOR]: Sending collision for {0}", LocalID); - - if (handler != null) - handler(e); - } - - public virtual void SetMaterial (int material) - { - } - - /// - /// Position of this actor. - /// - /// - /// Setting this directly moves the actor to a given position. - /// Getting this retrieves the position calculated by physics scene updates, using factors such as velocity and - /// collisions. - /// - public abstract Vector3 Position { get; set; } - - public abstract float Mass { get; } - public abstract Vector3 Force { get; set; } - - public abstract int VehicleType { get; set; } - public abstract void VehicleFloatParam(int param, float value); - public abstract void VehicleVectorParam(int param, Vector3 value); - public abstract void VehicleRotationParam(int param, Quaternion rotation); - public abstract void VehicleFlags(int param, bool remove); - - /// - /// Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more - /// - public abstract void SetVolumeDetect(int param); - - public abstract Vector3 GeometricCenter { get; } - public abstract Vector3 CenterOfMass { get; } - - /// - /// The desired velocity of this actor. - /// - /// - /// Setting this provides a target velocity for physics scene updates. - /// Getting this returns the last set target. Fetch Velocity to get the current velocity. - /// - protected Vector3 m_targetVelocity; - public virtual Vector3 TargetVelocity - { - get { return m_targetVelocity; } - set { - m_targetVelocity = value; - Velocity = m_targetVelocity; - } - } - - public abstract Vector3 Velocity { get; set; } - - public abstract Vector3 Torque { get; set; } - public abstract float CollisionScore { get; set;} - public abstract Vector3 Acceleration { get; set; } - public abstract Quaternion Orientation { get; set; } - public abstract int PhysicsActorType { get; set; } - public abstract bool IsPhysical { get; set; } - public abstract bool Flying { get; set; } - public abstract bool SetAlwaysRun { get; set; } - public abstract bool ThrottleUpdates { get; set; } - public abstract bool IsColliding { get; set; } - public abstract bool CollidingGround { get; set; } - public abstract bool CollidingObj { get; set; } - public abstract bool FloatOnWater { set; } - public abstract Vector3 RotationalVelocity { get; set; } - public abstract bool Kinematic { get; set; } - public abstract float Buoyancy { get; set; } - - // Used for MoveTo - public abstract Vector3 PIDTarget { set; } - public abstract bool PIDActive { set;} - public abstract float PIDTau { set; } - - // Used for llSetHoverHeight and maybe vehicle height - // Hover Height will override MoveTo target's Z - public abstract bool PIDHoverActive { set;} - public abstract float PIDHoverHeight { set;} - public abstract PIDHoverType PIDHoverType { set;} - public abstract float PIDHoverTau { set;} - - // For RotLookAt - public abstract Quaternion APIDTarget { set;} - public abstract bool APIDActive { set;} - public abstract float APIDStrength { set;} - public abstract float APIDDamping { set;} - - public abstract void AddForce(Vector3 force, bool pushforce); - public abstract void AddAngularForce(Vector3 force, bool pushforce); - public abstract void SetMomentum(Vector3 momentum); - public abstract void SubscribeEvents(int ms); - public abstract void UnSubscribeEvents(); - public abstract bool SubscribedEvents(); - } - - public class NullPhysicsActor : PhysicsActor - { - public override bool Stopped - { - get{ return false; } - } - - public override Vector3 Position - { - get { return Vector3.Zero; } - set { return; } - } - - public override bool SetAlwaysRun - { - get { return false; } - set { return; } - } - - public override uint LocalID - { - set { return; } - } - - public override bool Grabbed - { - set { return; } - } - - public override bool Selected - { - set { return; } - } - - public override float Buoyancy - { - get { return 0f; } - set { return; } - } - - public override bool FloatOnWater - { - set { return; } - } - - public override bool CollidingGround - { - get { return false; } - set { return; } - } - - public override bool CollidingObj - { - get { return false; } - set { return; } - } - - public override Vector3 Size - { - get { return Vector3.Zero; } - set { return; } - } - - public override float Mass - { - get { return 0f; } - } - - public override Vector3 Force - { - get { return Vector3.Zero; } - set { return; } - } - - public override int VehicleType - { - get { return 0; } - set { return; } - } - - public override void VehicleFloatParam(int param, float value) - { - - } - - public override void VehicleVectorParam(int param, Vector3 value) - { - - } - - public override void VehicleRotationParam(int param, Quaternion rotation) - { - - } - - public override void VehicleFlags(int param, bool remove) - { - - } - - public override void SetVolumeDetect(int param) - { - - } - - public override void SetMaterial(int material) - { - - } - - public override Vector3 CenterOfMass - { - get { return Vector3.Zero; } - } - - public override Vector3 GeometricCenter - { - get { return Vector3.Zero; } - } - - public override PrimitiveBaseShape Shape - { - set { return; } - } - - public override Vector3 Velocity - { - get { return Vector3.Zero; } - set { return; } - } - - public override Vector3 Torque - { - get { return Vector3.Zero; } - set { return; } - } - - public override float CollisionScore - { - get { return 0f; } - set { } - } - - public override void CrossingFailure() - { - } - - public override Quaternion Orientation - { - get { return Quaternion.Identity; } - set { } - } - - public override Vector3 Acceleration - { - get { return Vector3.Zero; } - set { } - } - - public override bool IsPhysical - { - get { return false; } - set { return; } - } - - public override bool Flying - { - get { return false; } - set { return; } - } - - public override bool ThrottleUpdates - { - get { return false; } - set { return; } - } - - public override bool IsColliding - { - get { return false; } - set { return; } - } - - public override int PhysicsActorType - { - get { return (int) ActorTypes.Unknown; } - set { return; } - } - - public override bool Kinematic - { - get { return true; } - set { return; } - } - - public override void link(PhysicsActor obj) - { - } - - public override void delink() - { - } - - public override void LockAngularMotion(Vector3 axis) - { - } - - public override void AddForce(Vector3 force, bool pushforce) - { - } - - public override void AddAngularForce(Vector3 force, bool pushforce) - { - - } - - public override Vector3 RotationalVelocity - { - get { return Vector3.Zero; } - set { return; } - } - - public override Vector3 PIDTarget { set { return; } } - public override bool PIDActive { set { return; } } - public override float PIDTau { set { return; } } - - public override float PIDHoverHeight { set { return; } } - public override bool PIDHoverActive { set { return; } } - public override PIDHoverType PIDHoverType { set { return; } } - public override float PIDHoverTau { set { return; } } - - public override Quaternion APIDTarget { set { return; } } - public override bool APIDActive { set { return; } } - public override float APIDStrength { set { return; } } - public override float APIDDamping { set { return; } } - - public override void SetMomentum(Vector3 momentum) - { - } - - public override void SubscribeEvents(int ms) - { - - } - public override void UnSubscribeEvents() - { - - } - public override bool SubscribedEvents() - { - return false; - } - } -} diff --git a/OpenSim/Region/Physics/Manager/PhysicsJoint.cs b/OpenSim/Region/Physics/Manager/PhysicsJoint.cs deleted file mode 100644 index b685d04..0000000 --- a/OpenSim/Region/Physics/Manager/PhysicsJoint.cs +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using OpenSim.Framework; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.Manager -{ - public enum PhysicsJointType : int - { - Ball = 0, - Hinge = 1 - } - - public class PhysicsJoint - { - public virtual bool IsInPhysicsEngine { get { return false; } } // set internally to indicate if this joint has already been passed to the physics engine or is still pending - public PhysicsJointType Type; - public string RawParams; - public List BodyNames = new List(); - public Vector3 Position; // global coords - public Quaternion Rotation; // global coords - public string ObjectNameInScene; // proxy object in scene that represents the joint position/orientation - public string TrackedBodyName; // body name that this joint is attached to (ObjectNameInScene will follow TrackedBodyName) - public Quaternion LocalRotation; // joint orientation relative to one of the involved bodies, the tracked body - public int ErrorMessageCount; // total # of error messages printed for this joint since its creation. if too many, further error messages are suppressed to prevent flooding. - public const int maxErrorMessages = 100; // no more than this # of error messages will be printed for each joint - } -} diff --git a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs deleted file mode 100644 index 8ccfda5..0000000 --- a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using Nini.Config; -using log4net; -using OpenSim.Framework; - -namespace OpenSim.Region.Physics.Manager -{ - /// - /// Description of MyClass. - /// - public class PhysicsPluginManager - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private Dictionary _PhysPlugins = new Dictionary(); - private Dictionary _MeshPlugins = new Dictionary(); - - /// - /// Constructor. - /// - public PhysicsPluginManager() - { - // Load "plugins", that are hard coded and not existing in form of an external lib, and hence always - // available - IMeshingPlugin plugHard; - plugHard = new ZeroMesherPlugin(); - _MeshPlugins.Add(plugHard.GetName(), plugHard); - - m_log.Info("[PHYSICS]: Added meshing engine: " + plugHard.GetName()); - } - - /// - /// Get a physics scene for the given physics engine and mesher. - /// - /// - /// - /// - /// - public PhysicsScene GetPhysicsScene(string physEngineName, string meshEngineName, IConfigSource config, string regionName) - { - if (String.IsNullOrEmpty(physEngineName)) - { - return PhysicsScene.Null; - } - - if (String.IsNullOrEmpty(meshEngineName)) - { - return PhysicsScene.Null; - } - - IMesher meshEngine = null; - if (_MeshPlugins.ContainsKey(meshEngineName)) - { - m_log.Info("[PHYSICS]: creating meshing engine " + meshEngineName); - meshEngine = _MeshPlugins[meshEngineName].GetMesher(config); - } - else - { - m_log.WarnFormat("[PHYSICS]: couldn't find meshingEngine: {0}", meshEngineName); - throw new ArgumentException(String.Format("couldn't find meshingEngine: {0}", meshEngineName)); - } - - if (_PhysPlugins.ContainsKey(physEngineName)) - { - m_log.Info("[PHYSICS]: creating " + physEngineName); - PhysicsScene result = _PhysPlugins[physEngineName].GetScene(regionName); - result.Initialise(meshEngine, config); - return result; - } - else - { - m_log.WarnFormat("[PHYSICS]: couldn't find physicsEngine: {0}", physEngineName); - throw new ArgumentException(String.Format("couldn't find physicsEngine: {0}", physEngineName)); - } - } - - /// - /// Load all plugins in assemblies at the given path - /// - /// - public void LoadPluginsFromAssemblies(string assembliesPath) - { - // Walk all assemblies (DLLs effectively) and see if they are home - // of a plugin that is of interest for us - string[] pluginFiles = Directory.GetFiles(assembliesPath, "*.dll"); - - for (int i = 0; i < pluginFiles.Length; i++) - { - LoadPluginsFromAssembly(pluginFiles[i]); - } - } - - /// - /// Load plugins from an assembly at the given path - /// - /// - public void LoadPluginsFromAssembly(string assemblyPath) - { - // TODO / NOTE - // The assembly named 'OpenSim.Region.Physics.BasicPhysicsPlugin' was loaded from - // 'file:///C:/OpenSim/trunk2/bin/Physics/OpenSim.Region.Physics.BasicPhysicsPlugin.dll' - // using the LoadFrom context. The use of this context can result in unexpected behavior - // for serialization, casting and dependency resolution. In almost all cases, it is recommended - // that the LoadFrom context be avoided. This can be done by installing assemblies in the - // Global Assembly Cache or in the ApplicationBase directory and using Assembly. - // Load when explicitly loading assemblies. - Assembly pluginAssembly = null; - Type[] types = null; - - try - { - pluginAssembly = Assembly.LoadFrom(assemblyPath); - } - catch (Exception ex) - { - m_log.Error("[PHYSICS]: Failed to load plugin from " + assemblyPath, ex); - } - - if (pluginAssembly != null) - { - try - { - types = pluginAssembly.GetTypes(); - } - catch (ReflectionTypeLoadException ex) - { - m_log.Error("[PHYSICS]: Failed to enumerate types in plugin from " + assemblyPath + ": " + - ex.LoaderExceptions[0].Message, ex); - } - catch (Exception ex) - { - m_log.Error("[PHYSICS]: Failed to enumerate types in plugin from " + assemblyPath, ex); - } - - if (types != null) - { - foreach (Type pluginType in types) - { - if (pluginType.IsPublic) - { - if (!pluginType.IsAbstract) - { - Type physTypeInterface = pluginType.GetInterface("IPhysicsPlugin", true); - - if (physTypeInterface != null) - { - IPhysicsPlugin plug = - (IPhysicsPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString())); - plug.Init(); - if (!_PhysPlugins.ContainsKey(plug.GetName())) - { - _PhysPlugins.Add(plug.GetName(), plug); - m_log.Info("[PHYSICS]: Added physics engine: " + plug.GetName()); - } - } - - Type meshTypeInterface = pluginType.GetInterface("IMeshingPlugin", true); - - if (meshTypeInterface != null) - { - IMeshingPlugin plug = - (IMeshingPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString())); - if (!_MeshPlugins.ContainsKey(plug.GetName())) - { - _MeshPlugins.Add(plug.GetName(), plug); - m_log.Info("[PHYSICS]: Added meshing engine: " + plug.GetName()); - } - } - - physTypeInterface = null; - meshTypeInterface = null; - } - } - } - } - } - - pluginAssembly = null; - } - - //--- - public static void PhysicsPluginMessage(string message, bool isWarning) - { - if (isWarning) - { - m_log.Warn("[PHYSICS]: " + message); - } - else - { - m_log.Info("[PHYSICS]: " + message); - } - } - - //--- - } - - public interface IPhysicsPlugin - { - bool Init(); - PhysicsScene GetScene(String sceneIdentifier); - string GetName(); - void Dispose(); - } - - public interface IMeshingPlugin - { - string GetName(); - IMesher GetMesher(IConfigSource config); - } -} diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs deleted file mode 100644 index 488900e..0000000 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Collections.Generic; -using System.Reflection; -using log4net; -using Nini.Config; -using OpenSim.Framework; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.Manager -{ - public delegate void physicsCrash(); - - public delegate void RaycastCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal); - public delegate void RayCallback(List list); - - public delegate void JointMoved(PhysicsJoint joint); - public delegate void JointDeactivated(PhysicsJoint joint); - public delegate void JointErrorMessage(PhysicsJoint joint, string message); // this refers to an "error message due to a problem", not "amount of joint constraint violation" - - public delegate void RequestAssetDelegate(UUID assetID, AssetReceivedDelegate callback); - public delegate void AssetReceivedDelegate(AssetBase asset); - - /// - /// Contact result from a raycast. - /// - public struct ContactResult - { - public Vector3 Pos; - public float Depth; - public uint ConsumerID; - public Vector3 Normal; - } - - public abstract class PhysicsScene - { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// Name of this scene. Useful in debug messages to distinguish one OdeScene instance from another. - /// - public string Name { get; protected set; } - - // The only thing that should register for this event is the SceneGraph - // Anything else could cause problems. - - public event physicsCrash OnPhysicsCrash; - - public static PhysicsScene Null - { - get { return new NullPhysicsScene(); } - } - - public RequestAssetDelegate RequestAssetMethod { get; set; } - - public virtual void TriggerPhysicsBasedRestart() - { - physicsCrash handler = OnPhysicsCrash; - if (handler != null) - { - OnPhysicsCrash(); - } - } - - public abstract void Initialise(IMesher meshmerizer, IConfigSource config); - - /// - /// Add an avatar - /// - /// - /// - /// - /// - /// - public abstract PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying); - - /// - /// Add an avatar - /// - /// - /// - /// - /// - /// - /// - public virtual PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying) - { - PhysicsActor ret = AddAvatar(avName, position, size, isFlying); - if (ret != null) ret.LocalID = localID; - return ret; - } - - /// - /// Remove an avatar. - /// - /// - public abstract void RemoveAvatar(PhysicsActor actor); - - /// - /// Remove a prim. - /// - /// - public abstract void RemovePrim(PhysicsActor prim); - - public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, - Vector3 size, Quaternion rotation, bool isPhysical, uint localid); - - public virtual float TimeDilation - { - get { return 1.0f; } - } - - public virtual bool SupportsNINJAJoints - { - get { return false; } - } - - public virtual PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position, - Quaternion rotation, string parms, List bodyNames, string trackedBodyName, Quaternion localRotation) - { return null; } - - public virtual void RequestJointDeletion(string objectNameInScene) - { return; } - - public virtual void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor) - { return; } - - public virtual void DumpJointInfo() - { return; } - - public event JointMoved OnJointMoved; - - protected virtual void DoJointMoved(PhysicsJoint joint) - { - // We need this to allow subclasses (but not other classes) to invoke the event; C# does - // not allow subclasses to invoke the parent class event. - if (OnJointMoved != null) - { - OnJointMoved(joint); - } - } - - public event JointDeactivated OnJointDeactivated; - - protected virtual void DoJointDeactivated(PhysicsJoint joint) - { - // We need this to allow subclasses (but not other classes) to invoke the event; C# does - // not allow subclasses to invoke the parent class event. - if (OnJointDeactivated != null) - { - OnJointDeactivated(joint); - } - } - - public event JointErrorMessage OnJointErrorMessage; - - protected virtual void DoJointErrorMessage(PhysicsJoint joint, string message) - { - // We need this to allow subclasses (but not other classes) to invoke the event; C# does - // not allow subclasses to invoke the parent class event. - if (OnJointErrorMessage != null) - { - OnJointErrorMessage(joint, message); - } - } - - public virtual Vector3 GetJointAnchor(PhysicsJoint joint) - { return Vector3.Zero; } - - public virtual Vector3 GetJointAxis(PhysicsJoint joint) - { return Vector3.Zero; } - - public abstract void AddPhysicsActorTaint(PhysicsActor prim); - - /// - /// Perform a simulation of the current physics scene over the given timestep. - /// - /// - /// The number of frames simulated over that period. - public abstract float Simulate(float timeStep); - - /// - /// Get statistics about this scene. - /// - /// This facility is currently experimental and subject to change. - /// - /// A dictionary where the key is the statistic name. If no statistics are supplied then returns null. - /// - public virtual Dictionary GetStats() { return null; } - - public abstract void GetResults(); - - public abstract void SetTerrain(float[] heightMap); - - public abstract void SetWaterLevel(float baseheight); - - public abstract void DeleteTerrain(); - - public abstract void Dispose(); - - public abstract Dictionary GetTopColliders(); - - public abstract bool IsThreaded { get; } - - /// - /// True if the physics plugin supports raycasting against the physics scene - /// - public virtual bool SupportsRayCast() - { - return false; - } - - public virtual bool SupportsCombining() - { - return false; - } - - public virtual void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) {} - - public virtual void UnCombine(PhysicsScene pScene) {} - - /// - /// Queue a raycast against the physics scene. - /// The provided callback method will be called when the raycast is complete - /// - /// Many physics engines don't support collision testing at the same time as - /// manipulating the physics scene, so we queue the request up and callback - /// a custom method when the raycast is complete. - /// This allows physics engines that give an immediate result to callback immediately - /// and ones that don't, to callback when it gets a result back. - /// - /// ODE for example will not allow you to change the scene while collision testing or - /// it asserts, 'opteration not valid for locked space'. This includes adding a ray to the scene. - /// - /// This is named RayCastWorld to not conflict with modrex's Raycast method. - /// - /// Origin of the ray - /// Direction of the ray - /// Length of ray in meters - /// Method to call when the raycast is complete - public virtual void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod) - { - if (retMethod != null) - retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero); - } - - public virtual void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod) - { - if (retMethod != null) - retMethod(new List()); - } - - public virtual List RaycastWorld(Vector3 position, Vector3 direction, float length, int Count) - { - return new List(); - } - } -} diff --git a/OpenSim/Region/Physics/Manager/PhysicsSensor.cs b/OpenSim/Region/Physics/Manager/PhysicsSensor.cs deleted file mode 100644 index f480d71..0000000 --- a/OpenSim/Region/Physics/Manager/PhysicsSensor.cs +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Timers; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.Manager -{ - [Flags] - public enum SenseType : uint - { - NONE = 0, - AGENT = 1, - ACTIVE = 2, - PASSIVE = 3, - SCRIPTED = 4 - } - - public abstract class PhysicsSensor - { - public static PhysicsSensor Null - { - get { return new NullPhysicsSensor(); } - } - public abstract Vector3 Position { get; set; } - public abstract void TimerCallback (object obj, ElapsedEventArgs eea); - public abstract float radianarc {get; set;} - public abstract string targetname {get; set;} - public abstract Guid targetKey{get;set;} - public abstract SenseType sensetype { get;set;} - public abstract float range { get;set;} - public abstract float rateSeconds { get;set;} - } - - public class NullPhysicsSensor : PhysicsSensor - { - public override Vector3 Position - { - get { return Vector3.Zero; } - set { return; } - } - public override void TimerCallback(object obj, ElapsedEventArgs eea) - { - // don't do squat - } - public override float radianarc { get { return 0f; } set { } } - public override string targetname { get { return ""; } set { } } - public override Guid targetKey { get { return Guid.Empty; } set { } } - public override SenseType sensetype { get { return SenseType.NONE; } set { } } - public override float range { get { return 0; } set { } } - public override float rateSeconds { get { return 0; } set { } } - } -} diff --git a/OpenSim/Region/Physics/Manager/PhysicsVector.cs b/OpenSim/Region/Physics/Manager/PhysicsVector.cs deleted file mode 100644 index f60a636..0000000 --- a/OpenSim/Region/Physics/Manager/PhysicsVector.cs +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; - -namespace OpenSim.Region.Physics.Manager -{ - /*public class PhysicsVector - { - public float X; - public float Y; - public float Z; - - public Vector3() - { - } - - public Vector3(float x, float y, float z) - { - X = x; - Y = y; - Z = z; - } - - public Vector3(Vector3 pv) : this(pv.X, pv.Y, pv.Z) - { - } - - public void setValues(float x, float y, float z) - { - X = x; - Y = y; - Z = z; - } - - public static readonly PhysicsVector Zero = new PhysicsVector(0f, 0f, 0f); - - public override string ToString() - { - return "<" + X + "," + Y + "," + Z + ">"; - } - - /// - /// These routines are the easiest way to store XYZ values in an Vector3 without requiring 3 calls. - /// - /// - public byte[] GetBytes() - { - byte[] byteArray = new byte[12]; - - Buffer.BlockCopy(BitConverter.GetBytes(X), 0, byteArray, 0, 4); - Buffer.BlockCopy(BitConverter.GetBytes(Y), 0, byteArray, 4, 4); - Buffer.BlockCopy(BitConverter.GetBytes(Z), 0, byteArray, 8, 4); - - if (!BitConverter.IsLittleEndian) - { - Array.Reverse(byteArray, 0, 4); - Array.Reverse(byteArray, 4, 4); - Array.Reverse(byteArray, 8, 4); - } - - return byteArray; - } - - public void FromBytes(byte[] byteArray, int pos) - { - byte[] conversionBuffer = null; - if (!BitConverter.IsLittleEndian) - { - // Big endian architecture - if (conversionBuffer == null) - conversionBuffer = new byte[12]; - - Buffer.BlockCopy(byteArray, pos, conversionBuffer, 0, 12); - - Array.Reverse(conversionBuffer, 0, 4); - Array.Reverse(conversionBuffer, 4, 4); - Array.Reverse(conversionBuffer, 8, 4); - - X = BitConverter.ToSingle(conversionBuffer, 0); - Y = BitConverter.ToSingle(conversionBuffer, 4); - Z = BitConverter.ToSingle(conversionBuffer, 8); - } - else - { - // Little endian architecture - X = BitConverter.ToSingle(byteArray, pos); - Y = BitConverter.ToSingle(byteArray, pos + 4); - Z = BitConverter.ToSingle(byteArray, pos + 8); - } - } - - // Operations - public static PhysicsVector operator +(Vector3 a, Vector3 b) - { - return new PhysicsVector(a.X + b.X, a.Y + b.Y, a.Z + b.Z); - } - - public static PhysicsVector operator -(Vector3 a, Vector3 b) - { - return new PhysicsVector(a.X - b.X, a.Y - b.Y, a.Z - b.Z); - } - - public static PhysicsVector cross(Vector3 a, Vector3 b) - { - return new PhysicsVector(a.Y*b.Z - a.Z*b.Y, a.Z*b.X - a.X*b.Z, a.X*b.Y - a.Y*b.X); - } - - public float length() - { - return (float) Math.Sqrt(X*X + Y*Y + Z*Z); - } - - public static float GetDistanceTo(Vector3 a, Vector3 b) - { - float dx = a.X - b.X; - float dy = a.Y - b.Y; - float dz = a.Z - b.Z; - return (float) Math.Sqrt(dx * dx + dy * dy + dz * dz); - } - - public static PhysicsVector operator /(Vector3 v, float f) - { - return new PhysicsVector(v.X/f, v.Y/f, v.Z/f); - } - - public static PhysicsVector operator *(Vector3 v, float f) - { - return new PhysicsVector(v.X*f, v.Y*f, v.Z*f); - } - - public static PhysicsVector operator *(float f, Vector3 v) - { - return v*f; - } - - public static bool isFinite(Vector3 v) - { - if (v == null) - return false; - if (Single.IsInfinity(v.X) || Single.IsNaN(v.X)) - return false; - if (Single.IsInfinity(v.Y) || Single.IsNaN(v.Y)) - return false; - if (Single.IsInfinity(v.Z) || Single.IsNaN(v.Z)) - return false; - - return true; - } - - public virtual bool IsIdentical(Vector3 v, float tolerance) - { - PhysicsVector diff = this - v; - float d = diff.length(); - if (d <= tolerance) - return true; - - return false; - } - - }*/ -} diff --git a/OpenSim/Region/Physics/Manager/VehicleConstants.cs b/OpenSim/Region/Physics/Manager/VehicleConstants.cs deleted file mode 100644 index f0775c1..0000000 --- a/OpenSim/Region/Physics/Manager/VehicleConstants.cs +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; - -namespace OpenSim.Region.Physics.Manager -{ - public enum Vehicle : int - { - /// - /// Turns off Vehicle Support - /// - TYPE_NONE = 0, - - /// - /// No Angular motor, High Left right friction, No Hover, Linear Deflection 1, no angular deflection - /// no vertical attractor, No banking, Identity rotation frame - /// - TYPE_SLED = 1, - - /// - /// Needs Motors to be driven by timer or control events High left/right friction, No angular friction - /// Linear Motor wins in a second, decays in 60 seconds. Angular motor wins in a second, decays in 8/10ths of a second - /// linear deflection 2 seconds - /// Vertical Attractor locked UP - /// - TYPE_CAR = 2, - TYPE_BOAT = 3, - TYPE_AIRPLANE = 4, - TYPE_BALLOON = 5, - LINEAR_FRICTION_TIMESCALE = 16, - /// - /// vector of timescales for exponential decay of angular velocity about three axis - /// - ANGULAR_FRICTION_TIMESCALE = 17, - /// - /// linear velocity vehicle will try for - /// - LINEAR_MOTOR_DIRECTION = 18, - - /// - /// Offset from center of mass where linear motor forces are added - /// - LINEAR_MOTOR_OFFSET = 20, - /// - /// angular velocity that vehicle will try for - /// - ANGULAR_MOTOR_DIRECTION = 19, - HOVER_HEIGHT = 24, - HOVER_EFFICIENCY = 25, - HOVER_TIMESCALE = 26, - BUOYANCY = 27, - LINEAR_DEFLECTION_EFFICIENCY = 28, - LINEAR_DEFLECTION_TIMESCALE = 29, - LINEAR_MOTOR_TIMESCALE = 30, - LINEAR_MOTOR_DECAY_TIMESCALE = 31, - - /// - /// slide between 0 and 1 - /// - ANGULAR_DEFLECTION_EFFICIENCY = 32, - ANGULAR_DEFLECTION_TIMESCALE = 33, - ANGULAR_MOTOR_TIMESCALE = 34, - ANGULAR_MOTOR_DECAY_TIMESCALE = 35, - VERTICAL_ATTRACTION_EFFICIENCY = 36, - VERTICAL_ATTRACTION_TIMESCALE = 37, - BANKING_EFFICIENCY = 38, - BANKING_MIX = 39, - BANKING_TIMESCALE = 40, - REFERENCE_FRAME = 44, - BLOCK_EXIT = 45, - ROLL_FRAME = 46 - - } - - [Flags] - public enum VehicleFlag - { - NO_DEFLECTION_UP = 1, - LIMIT_ROLL_ONLY = 2, - HOVER_WATER_ONLY = 4, - HOVER_TERRAIN_ONLY = 8, - HOVER_GLOBAL_HEIGHT = 16, - HOVER_UP_ONLY = 32, - LIMIT_MOTOR_UP = 64, - MOUSELOOK_STEER = 128, - MOUSELOOK_BANK = 256, - CAMERA_DECOUPLED = 512, - NO_X = 1024, - NO_Y = 2048, - NO_Z = 4096, - LOCK_HOVER_HEIGHT = 8192, - NO_DEFLECTION = 16392, - LOCK_ROTATION = 32784 - } - -} diff --git a/OpenSim/Region/Physics/Manager/ZeroMesher.cs b/OpenSim/Region/Physics/Manager/ZeroMesher.cs deleted file mode 100644 index 270d2ec..0000000 --- a/OpenSim/Region/Physics/Manager/ZeroMesher.cs +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using OpenSim.Framework; -using OpenMetaverse; -using Nini.Config; - -/* - * This is the zero mesher. - * Whatever you want him to mesh, he can't, telling you that by responding with a null pointer. - * Effectivly this is for switching off meshing and for testing as each physics machine should deal - * with the null pointer situation. - * But it's also a convenience thing, as physics machines can rely on having a mesher in any situation, even - * if it's a dump one like this. - * Note, that this mesher is *not* living in a module but in the manager itself, so - * it's always availabe and thus the default in case of configuration errors -*/ - -namespace OpenSim.Region.Physics.Manager -{ - public class ZeroMesherPlugin : IMeshingPlugin - { - public ZeroMesherPlugin() - { - } - - public string GetName() - { - return "ZeroMesher"; - } - - public IMesher GetMesher(IConfigSource config) - { - return new ZeroMesher(); - } - } - - public class ZeroMesher : IMesher - { - public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) - { - return CreateMesh(primName, primShape, size, lod, false, false); - } - - public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) - { - return CreateMesh(primName, primShape, size, lod, false, false); - } - - public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) - { - // Remove the reference to the encoded JPEG2000 data so it can be GCed - primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; - - return null; - } - } -} diff --git a/OpenSim/Region/Physics/Meshing/HelperTypes.cs b/OpenSim/Region/Physics/Meshing/HelperTypes.cs deleted file mode 100644 index 8cd8dcf..0000000 --- a/OpenSim/Region/Physics/Meshing/HelperTypes.cs +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using OpenMetaverse; -using OpenSim.Region.Physics.Manager; -using OpenSim.Region.Physics.Meshing; - -public class Vertex : IComparable -{ - Vector3 vector; - - public float X - { - get { return vector.X; } - set { vector.X = value; } - } - - public float Y - { - get { return vector.Y; } - set { vector.Y = value; } - } - - public float Z - { - get { return vector.Z; } - set { vector.Z = value; } - } - - public Vertex(float x, float y, float z) - { - vector.X = x; - vector.Y = y; - vector.Z = z; - } - - public Vertex normalize() - { - float tlength = vector.Length(); - if (tlength != 0f) - { - float mul = 1.0f / tlength; - return new Vertex(vector.X * mul, vector.Y * mul, vector.Z * mul); - } - else - { - return new Vertex(0f, 0f, 0f); - } - } - - public Vertex cross(Vertex v) - { - return new Vertex(vector.Y * v.Z - vector.Z * v.Y, vector.Z * v.X - vector.X * v.Z, vector.X * v.Y - vector.Y * v.X); - } - - // disable warning: mono compiler moans about overloading - // operators hiding base operator but should not according to C# - // language spec -#pragma warning disable 0108 - public static Vertex operator *(Vertex v, Quaternion q) - { - // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/ - - Vertex v2 = new Vertex(0f, 0f, 0f); - - v2.X = q.W * q.W * v.X + - 2f * q.Y * q.W * v.Z - - 2f * q.Z * q.W * v.Y + - q.X * q.X * v.X + - 2f * q.Y * q.X * v.Y + - 2f * q.Z * q.X * v.Z - - q.Z * q.Z * v.X - - q.Y * q.Y * v.X; - - v2.Y = - 2f * q.X * q.Y * v.X + - q.Y * q.Y * v.Y + - 2f * q.Z * q.Y * v.Z + - 2f * q.W * q.Z * v.X - - q.Z * q.Z * v.Y + - q.W * q.W * v.Y - - 2f * q.X * q.W * v.Z - - q.X * q.X * v.Y; - - v2.Z = - 2f * q.X * q.Z * v.X + - 2f * q.Y * q.Z * v.Y + - q.Z * q.Z * v.Z - - 2f * q.W * q.Y * v.X - - q.Y * q.Y * v.Z + - 2f * q.W * q.X * v.Y - - q.X * q.X * v.Z + - q.W * q.W * v.Z; - - return v2; - } - - public static Vertex operator +(Vertex v1, Vertex v2) - { - return new Vertex(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z); - } - - public static Vertex operator -(Vertex v1, Vertex v2) - { - return new Vertex(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z); - } - - public static Vertex operator *(Vertex v1, Vertex v2) - { - return new Vertex(v1.X * v2.X, v1.Y * v2.Y, v1.Z * v2.Z); - } - - public static Vertex operator +(Vertex v1, float am) - { - v1.X += am; - v1.Y += am; - v1.Z += am; - return v1; - } - - public static Vertex operator -(Vertex v1, float am) - { - v1.X -= am; - v1.Y -= am; - v1.Z -= am; - return v1; - } - - public static Vertex operator *(Vertex v1, float am) - { - v1.X *= am; - v1.Y *= am; - v1.Z *= am; - return v1; - } - - public static Vertex operator /(Vertex v1, float am) - { - if (am == 0f) - { - return new Vertex(0f,0f,0f); - } - float mul = 1.0f / am; - v1.X *= mul; - v1.Y *= mul; - v1.Z *= mul; - return v1; - } -#pragma warning restore 0108 - - - public float dot(Vertex v) - { - return X * v.X + Y * v.Y + Z * v.Z; - } - - public Vertex(Vector3 v) - { - vector = v; - } - - public Vertex Clone() - { - return new Vertex(X, Y, Z); - } - - public static Vertex FromAngle(double angle) - { - return new Vertex((float) Math.Cos(angle), (float) Math.Sin(angle), 0.0f); - } - - public float Length() - { - return vector.Length(); - } - - public virtual bool Equals(Vertex v, float tolerance) - { - Vertex diff = this - v; - float d = diff.Length(); - if (d < tolerance) - return true; - - return false; - } - - - public int CompareTo(Vertex other) - { - if (X < other.X) - return -1; - - if (X > other.X) - return 1; - - if (Y < other.Y) - return -1; - - if (Y > other.Y) - return 1; - - if (Z < other.Z) - return -1; - - if (Z > other.Z) - return 1; - - return 0; - } - - public static bool operator >(Vertex me, Vertex other) - { - return me.CompareTo(other) > 0; - } - - public static bool operator <(Vertex me, Vertex other) - { - return me.CompareTo(other) < 0; - } - - public String ToRaw() - { - // Why this stuff with the number formatter? - // Well, the raw format uses the english/US notation of numbers - // where the "," separates groups of 1000 while the "." marks the border between 1 and 10E-1. - // The german notation uses these characters exactly vice versa! - // The Float.ToString() routine is a localized one, giving different results depending on the country - // settings your machine works with. Unusable for a machine readable file format :-( - NumberFormatInfo nfi = new NumberFormatInfo(); - nfi.NumberDecimalSeparator = "."; - nfi.NumberDecimalDigits = 3; - - String s1 = X.ToString("N2", nfi) + " " + Y.ToString("N2", nfi) + " " + Z.ToString("N2", nfi); - - return s1; - } -} - -public class Triangle -{ - public Vertex v1; - public Vertex v2; - public Vertex v3; - - private float radius_square; - private float cx; - private float cy; - - public Triangle(Vertex _v1, Vertex _v2, Vertex _v3) - { - v1 = _v1; - v2 = _v2; - v3 = _v3; - - CalcCircle(); - } - - public bool isInCircle(float x, float y) - { - float dx, dy; - float dd; - - dx = x - cx; - dy = y - cy; - - dd = dx*dx + dy*dy; - if (dd < radius_square) - return true; - else - return false; - } - - public bool isDegraded() - { - // This means, the vertices of this triangle are somewhat strange. - // They either line up or at least two of them are identical - return (radius_square == 0.0); - } - - private void CalcCircle() - { - // Calculate the center and the radius of a circle given by three points p1, p2, p3 - // It is assumed, that the triangles vertices are already set correctly - double p1x, p2x, p1y, p2y, p3x, p3y; - - // Deviation of this routine: - // A circle has the general equation (M-p)^2=r^2, where M and p are vectors - // this gives us three equations f(p)=r^2, each for one point p1, p2, p3 - // putting respectively two equations together gives two equations - // f(p1)=f(p2) and f(p1)=f(p3) - // bringing all constant terms to one side brings them to the form - // M*v1=c1 resp.M*v2=c2 where v1=(p1-p2) and v2=(p1-p3) (still vectors) - // and c1, c2 are scalars (Naming conventions like the variables below) - // Now using the equations that are formed by the components of the vectors - // and isolate Mx lets you make one equation that only holds My - // The rest is straight forward and eaasy :-) - // - - /* helping variables for temporary results */ - double c1, c2; - double v1x, v1y, v2x, v2y; - - double z, n; - - double rx, ry; - - // Readout the three points, the triangle consists of - p1x = v1.X; - p1y = v1.Y; - - p2x = v2.X; - p2y = v2.Y; - - p3x = v3.X; - p3y = v3.Y; - - /* calc helping values first */ - c1 = (p1x*p1x + p1y*p1y - p2x*p2x - p2y*p2y)/2; - c2 = (p1x*p1x + p1y*p1y - p3x*p3x - p3y*p3y)/2; - - v1x = p1x - p2x; - v1y = p1y - p2y; - - v2x = p1x - p3x; - v2y = p1y - p3y; - - z = (c1*v2x - c2*v1x); - n = (v1y*v2x - v2y*v1x); - - if (n == 0.0) // This is no triangle, i.e there are (at least) two points at the same location - { - radius_square = 0.0f; - return; - } - - cy = (float) (z/n); - - if (v2x != 0.0) - { - cx = (float) ((c2 - v2y*cy)/v2x); - } - else if (v1x != 0.0) - { - cx = (float) ((c1 - v1y*cy)/v1x); - } - else - { - Debug.Assert(false, "Malformed triangle"); /* Both terms zero means nothing good */ - } - - rx = (p1x - cx); - ry = (p1y - cy); - - radius_square = (float) (rx*rx + ry*ry); - } - - public override String ToString() - { - NumberFormatInfo nfi = new NumberFormatInfo(); - nfi.CurrencyDecimalDigits = 2; - nfi.CurrencyDecimalSeparator = "."; - - String s1 = "<" + v1.X.ToString(nfi) + "," + v1.Y.ToString(nfi) + "," + v1.Z.ToString(nfi) + ">"; - String s2 = "<" + v2.X.ToString(nfi) + "," + v2.Y.ToString(nfi) + "," + v2.Z.ToString(nfi) + ">"; - String s3 = "<" + v3.X.ToString(nfi) + "," + v3.Y.ToString(nfi) + "," + v3.Z.ToString(nfi) + ">"; - - return s1 + ";" + s2 + ";" + s3; - } - - public Vector3 getNormal() - { - // Vertices - - // Vectors for edges - Vector3 e1; - Vector3 e2; - - e1 = new Vector3(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z); - e2 = new Vector3(v1.X - v3.X, v1.Y - v3.Y, v1.Z - v3.Z); - - // Cross product for normal - Vector3 n = Vector3.Cross(e1, e2); - - // Length - float l = n.Length(); - - // Normalized "normal" - n = n/l; - - return n; - } - - public void invertNormal() - { - Vertex vt; - vt = v1; - v1 = v2; - v2 = vt; - } - - // Dumps a triangle in the "raw faces" format, blender can import. This is for visualisation and - // debugging purposes - public String ToStringRaw() - { - String output = v1.ToRaw() + " " + v2.ToRaw() + " " + v3.ToRaw(); - return output; - } -} diff --git a/OpenSim/Region/Physics/Meshing/Mesh.cs b/OpenSim/Region/Physics/Meshing/Mesh.cs deleted file mode 100644 index f781ff9..0000000 --- a/OpenSim/Region/Physics/Meshing/Mesh.cs +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; -using OpenSim.Region.Physics.Manager; -using PrimMesher; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.Meshing -{ - public class Mesh : IMesh - { - private Dictionary m_vertices; - private List m_triangles; - GCHandle m_pinnedVertexes; - GCHandle m_pinnedIndex; - IntPtr m_verticesPtr = IntPtr.Zero; - int m_vertexCount = 0; - IntPtr m_indicesPtr = IntPtr.Zero; - int m_indexCount = 0; - public float[] m_normals; - - public Mesh() - { - m_vertices = new Dictionary(); - m_triangles = new List(); - } - - public Mesh Clone() - { - Mesh result = new Mesh(); - - foreach (Triangle t in m_triangles) - { - result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone())); - } - - return result; - } - - public void Add(Triangle triangle) - { - if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) - throw new NotSupportedException("Attempt to Add to a pinned Mesh"); - // If a vertex of the triangle is not yet in the vertices list, - // add it and set its index to the current index count - if (!m_vertices.ContainsKey(triangle.v1)) - m_vertices[triangle.v1] = m_vertices.Count; - if (!m_vertices.ContainsKey(triangle.v2)) - m_vertices[triangle.v2] = m_vertices.Count; - if (!m_vertices.ContainsKey(triangle.v3)) - m_vertices[triangle.v3] = m_vertices.Count; - m_triangles.Add(triangle); - } - - public void CalcNormals() - { - int iTriangles = m_triangles.Count; - - this.m_normals = new float[iTriangles * 3]; - - int i = 0; - foreach (Triangle t in m_triangles) - { - float ux, uy, uz; - float vx, vy, vz; - float wx, wy, wz; - - ux = t.v1.X; - uy = t.v1.Y; - uz = t.v1.Z; - - vx = t.v2.X; - vy = t.v2.Y; - vz = t.v2.Z; - - wx = t.v3.X; - wy = t.v3.Y; - wz = t.v3.Z; - - - // Vectors for edges - float e1x, e1y, e1z; - float e2x, e2y, e2z; - - e1x = ux - vx; - e1y = uy - vy; - e1z = uz - vz; - - e2x = ux - wx; - e2y = uy - wy; - e2z = uz - wz; - - - // Cross product for normal - float nx, ny, nz; - nx = e1y * e2z - e1z * e2y; - ny = e1z * e2x - e1x * e2z; - nz = e1x * e2y - e1y * e2x; - - // Length - float l = (float)Math.Sqrt(nx * nx + ny * ny + nz * nz); - float lReciprocal = 1.0f / l; - - // Normalized "normal" - //nx /= l; - //ny /= l; - //nz /= l; - - m_normals[i] = nx * lReciprocal; - m_normals[i + 1] = ny * lReciprocal; - m_normals[i + 2] = nz * lReciprocal; - - i += 3; - } - } - - public List getVertexList() - { - List result = new List(); - foreach (Vertex v in m_vertices.Keys) - { - result.Add(new Vector3(v.X, v.Y, v.Z)); - } - return result; - } - - private float[] getVertexListAsFloat() - { - if (m_vertices == null) - throw new NotSupportedException(); - float[] result = new float[m_vertices.Count * 3]; - foreach (KeyValuePair kvp in m_vertices) - { - Vertex v = kvp.Key; - int i = kvp.Value; - result[3 * i + 0] = v.X; - result[3 * i + 1] = v.Y; - result[3 * i + 2] = v.Z; - } - return result; - } - - public float[] getVertexListAsFloatLocked() - { - if (m_pinnedVertexes.IsAllocated) - return (float[])(m_pinnedVertexes.Target); - - float[] result = getVertexListAsFloat(); - m_pinnedVertexes = GCHandle.Alloc(result, GCHandleType.Pinned); - // Inform the garbage collector of this unmanaged allocation so it can schedule - // the next GC round more intelligently - GC.AddMemoryPressure(Buffer.ByteLength(result)); - - return result; - } - - public void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount) - { - // A vertex is 3 floats - vertexStride = 3 * sizeof(float); - - // If there isn't an unmanaged array allocated yet, do it now - if (m_verticesPtr == IntPtr.Zero) - { - float[] vertexList = getVertexListAsFloat(); - // Each vertex is 3 elements (floats) - m_vertexCount = vertexList.Length / 3; - int byteCount = m_vertexCount * vertexStride; - m_verticesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); - System.Runtime.InteropServices.Marshal.Copy(vertexList, 0, m_verticesPtr, m_vertexCount * 3); - } - vertices = m_verticesPtr; - vertexCount = m_vertexCount; - } - - public int[] getIndexListAsInt() - { - if (m_triangles == null) - throw new NotSupportedException(); - int[] result = new int[m_triangles.Count * 3]; - for (int i = 0; i < m_triangles.Count; i++) - { - Triangle t = m_triangles[i]; - result[3 * i + 0] = m_vertices[t.v1]; - result[3 * i + 1] = m_vertices[t.v2]; - result[3 * i + 2] = m_vertices[t.v3]; - } - return result; - } - - /// - /// creates a list of index values that defines triangle faces. THIS METHOD FREES ALL NON-PINNED MESH DATA - /// - /// - public int[] getIndexListAsIntLocked() - { - if (m_pinnedIndex.IsAllocated) - return (int[])(m_pinnedIndex.Target); - - int[] result = getIndexListAsInt(); - m_pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); - // Inform the garbage collector of this unmanaged allocation so it can schedule - // the next GC round more intelligently - GC.AddMemoryPressure(Buffer.ByteLength(result)); - - return result; - } - - public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount) - { - // If there isn't an unmanaged array allocated yet, do it now - if (m_indicesPtr == IntPtr.Zero) - { - int[] indexList = getIndexListAsInt(); - m_indexCount = indexList.Length; - int byteCount = m_indexCount * sizeof(int); - m_indicesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); - System.Runtime.InteropServices.Marshal.Copy(indexList, 0, m_indicesPtr, m_indexCount); - } - // A triangle is 3 ints (indices) - triStride = 3 * sizeof(int); - indices = m_indicesPtr; - indexCount = m_indexCount; - } - - public void releasePinned() - { - if (m_pinnedVertexes.IsAllocated) - m_pinnedVertexes.Free(); - if (m_pinnedIndex.IsAllocated) - m_pinnedIndex.Free(); - if (m_verticesPtr != IntPtr.Zero) - { - System.Runtime.InteropServices.Marshal.FreeHGlobal(m_verticesPtr); - m_verticesPtr = IntPtr.Zero; - } - if (m_indicesPtr != IntPtr.Zero) - { - System.Runtime.InteropServices.Marshal.FreeHGlobal(m_indicesPtr); - m_indicesPtr = IntPtr.Zero; - } - } - - /// - /// frees up the source mesh data to minimize memory - call this method after calling get*Locked() functions - /// - public void releaseSourceMeshData() - { - m_triangles = null; - m_vertices = null; - } - - public void Append(IMesh newMesh) - { - if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) - throw new NotSupportedException("Attempt to Append to a pinned Mesh"); - - if (!(newMesh is Mesh)) - return; - - foreach (Triangle t in ((Mesh)newMesh).m_triangles) - Add(t); - } - - // Do a linear transformation of mesh. - public void TransformLinear(float[,] matrix, float[] offset) - { - if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) - throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); - - foreach (Vertex v in m_vertices.Keys) - { - if (v == null) - continue; - float x, y, z; - x = v.X*matrix[0, 0] + v.Y*matrix[1, 0] + v.Z*matrix[2, 0]; - y = v.X*matrix[0, 1] + v.Y*matrix[1, 1] + v.Z*matrix[2, 1]; - z = v.X*matrix[0, 2] + v.Y*matrix[1, 2] + v.Z*matrix[2, 2]; - v.X = x + offset[0]; - v.Y = y + offset[1]; - v.Z = z + offset[2]; - } - } - - public void DumpRaw(String path, String name, String title) - { - if (path == null) - return; - String fileName = name + "_" + title + ".raw"; - String completePath = System.IO.Path.Combine(path, fileName); - StreamWriter sw = new StreamWriter(completePath); - foreach (Triangle t in m_triangles) - { - String s = t.ToStringRaw(); - sw.WriteLine(s); - } - sw.Close(); - } - - public void TrimExcess() - { - m_triangles.TrimExcess(); - } - } -} diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs deleted file mode 100644 index 8145d61..0000000 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ /dev/null @@ -1,761 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -//#define SPAM - -using System; -using System.Collections.Generic; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; -using OpenMetaverse; -using OpenMetaverse.StructuredData; -using System.Drawing; -using System.Drawing.Imaging; -using System.IO.Compression; -using PrimMesher; -using log4net; -using Nini.Config; -using System.Reflection; -using System.IO; -using ComponentAce.Compression.Libs.zlib; - -namespace OpenSim.Region.Physics.Meshing -{ - public class MeshmerizerPlugin : IMeshingPlugin - { - public MeshmerizerPlugin() - { - } - - public string GetName() - { - return "Meshmerizer"; - } - - public IMesher GetMesher(IConfigSource config) - { - return new Meshmerizer(config); - } - } - - public class Meshmerizer : IMesher - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - // Setting baseDir to a path will enable the dumping of raw files - // raw files can be imported by blender so a visual inspection of the results can be done -#if SPAM - const string baseDir = "rawFiles"; -#else - private const string baseDir = null; //"rawFiles"; -#endif - - private bool cacheSculptMaps = true; - private string decodedSculptMapPath = null; - private bool useMeshiesPhysicsMesh = false; - - private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh - - private Dictionary m_uniqueMeshes = new Dictionary(); - - public Meshmerizer(IConfigSource config) - { - IConfig start_config = config.Configs["Startup"]; - IConfig mesh_config = config.Configs["Mesh"]; - - decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); - cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); - if(mesh_config != null) - useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); - - try - { - if (!Directory.Exists(decodedSculptMapPath)) - Directory.CreateDirectory(decodedSculptMapPath); - } - catch (Exception e) - { - m_log.WarnFormat("[SCULPT]: Unable to create {0} directory: ", decodedSculptMapPath, e.Message); - } - } - - /// - /// creates a simple box mesh of the specified size. This mesh is of very low vertex count and may - /// be useful as a backup proxy when level of detail is not needed or when more complex meshes fail - /// for some reason - /// - /// - /// - /// - /// - /// - /// - /// - private static Mesh CreateSimpleBoxMesh(float minX, float maxX, float minY, float maxY, float minZ, float maxZ) - { - Mesh box = new Mesh(); - List vertices = new List(); - // bottom - - vertices.Add(new Vertex(minX, maxY, minZ)); - vertices.Add(new Vertex(maxX, maxY, minZ)); - vertices.Add(new Vertex(maxX, minY, minZ)); - vertices.Add(new Vertex(minX, minY, minZ)); - - box.Add(new Triangle(vertices[0], vertices[1], vertices[2])); - box.Add(new Triangle(vertices[0], vertices[2], vertices[3])); - - // top - - vertices.Add(new Vertex(maxX, maxY, maxZ)); - vertices.Add(new Vertex(minX, maxY, maxZ)); - vertices.Add(new Vertex(minX, minY, maxZ)); - vertices.Add(new Vertex(maxX, minY, maxZ)); - - box.Add(new Triangle(vertices[4], vertices[5], vertices[6])); - box.Add(new Triangle(vertices[4], vertices[6], vertices[7])); - - // sides - - box.Add(new Triangle(vertices[5], vertices[0], vertices[3])); - box.Add(new Triangle(vertices[5], vertices[3], vertices[6])); - - box.Add(new Triangle(vertices[1], vertices[0], vertices[5])); - box.Add(new Triangle(vertices[1], vertices[5], vertices[4])); - - box.Add(new Triangle(vertices[7], vertices[1], vertices[4])); - box.Add(new Triangle(vertices[7], vertices[2], vertices[1])); - - box.Add(new Triangle(vertices[3], vertices[2], vertices[7])); - box.Add(new Triangle(vertices[3], vertices[7], vertices[6])); - - return box; - } - - /// - /// Creates a simple bounding box mesh for a complex input mesh - /// - /// - /// - private static Mesh CreateBoundingBoxMesh(Mesh meshIn) - { - float minX = float.MaxValue; - float maxX = float.MinValue; - float minY = float.MaxValue; - float maxY = float.MinValue; - float minZ = float.MaxValue; - float maxZ = float.MinValue; - - foreach (Vector3 v in meshIn.getVertexList()) - { - if (v.X < minX) minX = v.X; - if (v.Y < minY) minY = v.Y; - if (v.Z < minZ) minZ = v.Z; - - if (v.X > maxX) maxX = v.X; - if (v.Y > maxY) maxY = v.Y; - if (v.Z > maxZ) maxZ = v.Z; - } - - return CreateSimpleBoxMesh(minX, maxX, minY, maxY, minZ, maxZ); - } - - private void ReportPrimError(string message, string primName, PrimMesh primMesh) - { - m_log.Error(message); - m_log.Error("\nPrim Name: " + primName); - m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString()); - } - - /// - /// Add a submesh to an existing list of coords and faces. - /// - /// - /// Size of entire object - /// - /// - private void AddSubMesh(OSDMap subMeshData, Vector3 size, List coords, List faces) - { - // Console.WriteLine("subMeshMap for {0} - {1}", primName, Util.GetFormattedXml((OSD)subMeshMap)); - - // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level - // of Detail Blocks (maps) contain just a NoGeometry key to signal there is no - // geometry for this submesh. - if (subMeshData.ContainsKey("NoGeometry") && ((OSDBoolean)subMeshData["NoGeometry"])) - return; - - OpenMetaverse.Vector3 posMax = ((OSDMap)subMeshData["PositionDomain"])["Max"].AsVector3(); - OpenMetaverse.Vector3 posMin = ((OSDMap)subMeshData["PositionDomain"])["Min"].AsVector3(); - ushort faceIndexOffset = (ushort)coords.Count; - - byte[] posBytes = subMeshData["Position"].AsBinary(); - for (int i = 0; i < posBytes.Length; i += 6) - { - ushort uX = Utils.BytesToUInt16(posBytes, i); - ushort uY = Utils.BytesToUInt16(posBytes, i + 2); - ushort uZ = Utils.BytesToUInt16(posBytes, i + 4); - - Coord c = new Coord( - Utils.UInt16ToFloat(uX, posMin.X, posMax.X) * size.X, - Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y) * size.Y, - Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z) * size.Z); - - coords.Add(c); - } - - byte[] triangleBytes = subMeshData["TriangleList"].AsBinary(); - for (int i = 0; i < triangleBytes.Length; i += 6) - { - ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i) + faceIndexOffset); - ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2) + faceIndexOffset); - ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4) + faceIndexOffset); - Face f = new Face(v1, v2, v3); - faces.Add(f); - } - } - - /// - /// Create a physics mesh from data that comes with the prim. The actual data used depends on the prim type. - /// - /// - /// - /// - /// - /// - private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod) - { -// m_log.DebugFormat( -// "[MESH]: Creating physics proxy for {0}, shape {1}", -// primName, (OpenMetaverse.SculptType)primShape.SculptType); - - List coords; - List faces; - - if (primShape.SculptEntry) - { - if (((OpenMetaverse.SculptType)primShape.SculptType) == SculptType.Mesh) - { - if (!useMeshiesPhysicsMesh) - return null; - - if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, size, out coords, out faces)) - return null; - } - else - { - if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces)) - return null; - } - } - else - { - if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces)) - return null; - } - - // Remove the reference to any JPEG2000 sculpt data so it can be GCed - primShape.SculptData = Utils.EmptyBytes; - - int numCoords = coords.Count; - int numFaces = faces.Count; - - // Create the list of vertices - List vertices = new List(); - for (int i = 0; i < numCoords; i++) - { - Coord c = coords[i]; - vertices.Add(new Vertex(c.X, c.Y, c.Z)); - } - - Mesh mesh = new Mesh(); - // Add the corresponding triangles to the mesh - for (int i = 0; i < numFaces; i++) - { - Face f = faces[i]; - mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); - } - - return mesh; - } - - /// - /// Generate the co-ords and faces necessary to construct a mesh from the mesh data the accompanies a prim. - /// - /// - /// - /// - /// Coords are added to this list by the method. - /// Faces are added to this list by the method. - /// true if coords and faces were successfully generated, false if not - private bool GenerateCoordsAndFacesFromPrimMeshData( - string primName, PrimitiveBaseShape primShape, Vector3 size, out List coords, out List faces) - { -// m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName); - - coords = new List(); - faces = new List(); - OSD meshOsd = null; - - if (primShape.SculptData.Length <= 0) - { - // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this - // method twice - once before it has loaded sculpt data from the asset service and once afterwards. - // The first time will always call with unloaded SculptData if this needs to be uploaded. -// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); - return false; - } - - long start = 0; - using (MemoryStream data = new MemoryStream(primShape.SculptData)) - { - try - { - OSD osd = OSDParser.DeserializeLLSDBinary(data); - if (osd is OSDMap) - meshOsd = (OSDMap)osd; - else - { - m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap"); - return false; - } - } - catch (Exception e) - { - m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString()); - } - - start = data.Position; - } - - if (meshOsd is OSDMap) - { - OSDMap physicsParms = null; - OSDMap map = (OSDMap)meshOsd; - if (map.ContainsKey("physics_shape")) - physicsParms = (OSDMap)map["physics_shape"]; // old asset format - else if (map.ContainsKey("physics_mesh")) - physicsParms = (OSDMap)map["physics_mesh"]; // new asset format - - if (physicsParms == null) - { - m_log.WarnFormat("[MESH]: No recognized physics mesh found in mesh asset for {0}", primName); - return false; - } - - int physOffset = physicsParms["offset"].AsInteger() + (int)start; - int physSize = physicsParms["size"].AsInteger(); - - if (physOffset < 0 || physSize == 0) - return false; // no mesh data in asset - - OSD decodedMeshOsd = new OSD(); - byte[] meshBytes = new byte[physSize]; - System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); -// byte[] decompressed = new byte[physSize * 5]; - try - { - using (MemoryStream inMs = new MemoryStream(meshBytes)) - { - using (MemoryStream outMs = new MemoryStream()) - { - using (ZOutputStream zOut = new ZOutputStream(outMs)) - { - byte[] readBuffer = new byte[2048]; - int readLen = 0; - while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) - { - zOut.Write(readBuffer, 0, readLen); - } - zOut.Flush(); - outMs.Seek(0, SeekOrigin.Begin); - - byte[] decompressedBuf = outMs.GetBuffer(); - - decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); - } - } - } - } - catch (Exception e) - { - m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); - return false; - } - - OSDArray decodedMeshOsdArray = null; - - // physics_shape is an array of OSDMaps, one for each submesh - if (decodedMeshOsd is OSDArray) - { -// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); - - decodedMeshOsdArray = (OSDArray)decodedMeshOsd; - foreach (OSD subMeshOsd in decodedMeshOsdArray) - { - if (subMeshOsd is OSDMap) - AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); - } - } - } - - return true; - } - - /// - /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim. - /// - /// - /// - /// - /// - /// Coords are added to this list by the method. - /// Faces are added to this list by the method. - /// true if coords and faces were successfully generated, false if not - private bool GenerateCoordsAndFacesFromPrimSculptData( - string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List coords, out List faces) - { - coords = new List(); - faces = new List(); - PrimMesher.SculptMesh sculptMesh; - Image idata = null; - string decodedSculptFileName = ""; - - if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero) - { - decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString()); - try - { - if (File.Exists(decodedSculptFileName)) - { - idata = Image.FromFile(decodedSculptFileName); - } - } - catch (Exception e) - { - m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message); - - } - //if (idata != null) - // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString()); - } - - if (idata == null) - { - if (primShape.SculptData == null || primShape.SculptData.Length == 0) - return false; - - try - { - OpenMetaverse.Imaging.ManagedImage unusedData; - OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata); - - if (idata == null) - { - // In some cases it seems that the decode can return a null bitmap without throwing - // an exception - m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName); - - return false; - } - - unusedData = null; - - //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData); - - if (cacheSculptMaps) - { - try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); } - catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); } - } - } - catch (DllNotFoundException) - { - m_log.Error("[PHYSICS]: OpenJpeg is not installed correctly on this system. Physics Proxy generation failed. Often times this is because of an old version of GLIBC. You must have version 2.4 or above!"); - return false; - } - catch (IndexOutOfRangeException) - { - m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed"); - return false; - } - catch (Exception ex) - { - m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message); - return false; - } - } - - PrimMesher.SculptMesh.SculptType sculptType; - switch ((OpenMetaverse.SculptType)primShape.SculptType) - { - case OpenMetaverse.SculptType.Cylinder: - sculptType = PrimMesher.SculptMesh.SculptType.cylinder; - break; - case OpenMetaverse.SculptType.Plane: - sculptType = PrimMesher.SculptMesh.SculptType.plane; - break; - case OpenMetaverse.SculptType.Torus: - sculptType = PrimMesher.SculptMesh.SculptType.torus; - break; - case OpenMetaverse.SculptType.Sphere: - sculptType = PrimMesher.SculptMesh.SculptType.sphere; - break; - default: - sculptType = PrimMesher.SculptMesh.SculptType.plane; - break; - } - - bool mirror = ((primShape.SculptType & 128) != 0); - bool invert = ((primShape.SculptType & 64) != 0); - - sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert); - - idata.Dispose(); - - sculptMesh.DumpRaw(baseDir, primName, "primMesh"); - - sculptMesh.Scale(size.X, size.Y, size.Z); - - coords = sculptMesh.coords; - faces = sculptMesh.faces; - - return true; - } - - /// - /// Generate the co-ords and faces necessary to construct a mesh from the shape data the accompanies a prim. - /// - /// - /// - /// - /// Coords are added to this list by the method. - /// Faces are added to this list by the method. - /// true if coords and faces were successfully generated, false if not - private bool GenerateCoordsAndFacesFromPrimShapeData( - string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List coords, out List faces) - { - PrimMesh primMesh; - coords = new List(); - faces = new List(); - - float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f; - float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f; - float pathBegin = (float)primShape.PathBegin * 2.0e-5f; - float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f; - float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f; - float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f; - - float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f; - float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f; - float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f; - if (profileHollow > 0.95f) - profileHollow = 0.95f; - - int sides = 4; - LevelOfDetail iLOD = (LevelOfDetail)lod; - if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) - sides = 3; - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) - { - switch (iLOD) - { - case LevelOfDetail.High: sides = 24; break; - case LevelOfDetail.Medium: sides = 12; break; - case LevelOfDetail.Low: sides = 6; break; - case LevelOfDetail.VeryLow: sides = 3; break; - default: sides = 24; break; - } - } - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) - { // half circle, prim is a sphere - switch (iLOD) - { - case LevelOfDetail.High: sides = 24; break; - case LevelOfDetail.Medium: sides = 12; break; - case LevelOfDetail.Low: sides = 6; break; - case LevelOfDetail.VeryLow: sides = 3; break; - default: sides = 24; break; - } - - profileBegin = 0.5f * profileBegin + 0.5f; - profileEnd = 0.5f * profileEnd + 0.5f; - } - - int hollowSides = sides; - if (primShape.HollowShape == HollowShape.Circle) - { - switch (iLOD) - { - case LevelOfDetail.High: hollowSides = 24; break; - case LevelOfDetail.Medium: hollowSides = 12; break; - case LevelOfDetail.Low: hollowSides = 6; break; - case LevelOfDetail.VeryLow: hollowSides = 3; break; - default: hollowSides = 24; break; - } - } - else if (primShape.HollowShape == HollowShape.Square) - hollowSides = 4; - else if (primShape.HollowShape == HollowShape.Triangle) - hollowSides = 3; - - primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides); - - if (primMesh.errorMessage != null) - if (primMesh.errorMessage.Length > 0) - m_log.Error("[ERROR] " + primMesh.errorMessage); - - primMesh.topShearX = pathShearX; - primMesh.topShearY = pathShearY; - primMesh.pathCutBegin = pathBegin; - primMesh.pathCutEnd = pathEnd; - - if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible) - { - primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10; - primMesh.twistEnd = primShape.PathTwist * 18 / 10; - primMesh.taperX = pathScaleX; - primMesh.taperY = pathScaleY; - - if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) - { - ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); - if (profileBegin < 0.0f) profileBegin = 0.0f; - if (profileEnd > 1.0f) profileEnd = 1.0f; - } -#if SPAM - m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString()); -#endif - try - { - primMesh.ExtrudeLinear(); - } - catch (Exception ex) - { - ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); - return false; - } - } - else - { - primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f; - primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f; - primMesh.radius = 0.01f * primShape.PathRadiusOffset; - primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions; - primMesh.skew = 0.01f * primShape.PathSkew; - primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10; - primMesh.twistEnd = primShape.PathTwist * 36 / 10; - primMesh.taperX = primShape.PathTaperX * 0.01f; - primMesh.taperY = primShape.PathTaperY * 0.01f; - - if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) - { - ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); - if (profileBegin < 0.0f) profileBegin = 0.0f; - if (profileEnd > 1.0f) profileEnd = 1.0f; - } -#if SPAM - m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString()); -#endif - try - { - primMesh.ExtrudeCircular(); - } - catch (Exception ex) - { - ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); - return false; - } - } - - primMesh.DumpRaw(baseDir, primName, "primMesh"); - - primMesh.Scale(size.X, size.Y, size.Z); - - coords = primMesh.coords; - faces = primMesh.faces; - - return true; - } - - public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) - { - return CreateMesh(primName, primShape, size, lod, false, true); - } - - public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) - { - return CreateMesh(primName, primShape, size, lod, isPhysical, true); - } - - public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) - { -#if SPAM - m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); -#endif - - Mesh mesh = null; - ulong key = 0; - - // If this mesh has been created already, return it instead of creating another copy - // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory - if (shouldCache) - { - key = primShape.GetMeshKey(size, lod); - if (m_uniqueMeshes.TryGetValue(key, out mesh)) - return mesh; - } - - if (size.X < 0.01f) size.X = 0.01f; - if (size.Y < 0.01f) size.Y = 0.01f; - if (size.Z < 0.01f) size.Z = 0.01f; - - mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod); - - if (mesh != null) - { - if ((!isPhysical) && size.X < minSizeForComplexMesh && size.Y < minSizeForComplexMesh && size.Z < minSizeForComplexMesh) - { -#if SPAM - m_log.Debug("Meshmerizer: prim " + primName + " has a size of " + size.ToString() + " which is below threshold of " + - minSizeForComplexMesh.ToString() + " - creating simple bounding box"); -#endif - mesh = CreateBoundingBoxMesh(mesh); - mesh.DumpRaw(baseDir, primName, "Z extruded"); - } - - // trim the vertex and triangle lists to free up memory - mesh.TrimExcess(); - - if (shouldCache) - { - m_uniqueMeshes.Add(key, mesh); - } - } - - return mesh; - } - } -} diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs deleted file mode 100644 index 4049ee1..0000000 --- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs +++ /dev/null @@ -1,2324 +0,0 @@ -/* - * Copyright (c) Contributors - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; - -namespace PrimMesher -{ - public struct Quat - { - /// X value - public float X; - /// Y value - public float Y; - /// Z value - public float Z; - /// W value - public float W; - - public Quat(float x, float y, float z, float w) - { - X = x; - Y = y; - Z = z; - W = w; - } - - public Quat(Coord axis, float angle) - { - axis = axis.Normalize(); - - angle *= 0.5f; - float c = (float)Math.Cos(angle); - float s = (float)Math.Sin(angle); - - X = axis.X * s; - Y = axis.Y * s; - Z = axis.Z * s; - W = c; - - Normalize(); - } - - public float Length() - { - return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); - } - - public Quat Normalize() - { - const float MAG_THRESHOLD = 0.0000001f; - float mag = Length(); - - // Catch very small rounding errors when normalizing - if (mag > MAG_THRESHOLD) - { - float oomag = 1f / mag; - X *= oomag; - Y *= oomag; - Z *= oomag; - W *= oomag; - } - else - { - X = 0f; - Y = 0f; - Z = 0f; - W = 1f; - } - - return this; - } - - public static Quat operator *(Quat q1, Quat q2) - { - float x = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y; - float y = q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X; - float z = q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W; - float w = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z; - return new Quat(x, y, z, w); - } - - public override string ToString() - { - return "< X: " + this.X.ToString() + ", Y: " + this.Y.ToString() + ", Z: " + this.Z.ToString() + ", W: " + this.W.ToString() + ">"; - } - } - - public struct Coord - { - public float X; - public float Y; - public float Z; - - public Coord(float x, float y, float z) - { - this.X = x; - this.Y = y; - this.Z = z; - } - - public float Length() - { - return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z); - } - - public Coord Invert() - { - this.X = -this.X; - this.Y = -this.Y; - this.Z = -this.Z; - - return this; - } - - public Coord Normalize() - { - const float MAG_THRESHOLD = 0.0000001f; - float mag = Length(); - - // Catch very small rounding errors when normalizing - if (mag > MAG_THRESHOLD) - { - float oomag = 1.0f / mag; - this.X *= oomag; - this.Y *= oomag; - this.Z *= oomag; - } - else - { - this.X = 0.0f; - this.Y = 0.0f; - this.Z = 0.0f; - } - - return this; - } - - public override string ToString() - { - return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString(); - } - - public static Coord Cross(Coord c1, Coord c2) - { - return new Coord( - c1.Y * c2.Z - c2.Y * c1.Z, - c1.Z * c2.X - c2.Z * c1.X, - c1.X * c2.Y - c2.X * c1.Y - ); - } - - public static Coord operator +(Coord v, Coord a) - { - return new Coord(v.X + a.X, v.Y + a.Y, v.Z + a.Z); - } - - public static Coord operator *(Coord v, Coord m) - { - return new Coord(v.X * m.X, v.Y * m.Y, v.Z * m.Z); - } - - public static Coord operator *(Coord v, Quat q) - { - // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/ - - Coord c2 = new Coord(0.0f, 0.0f, 0.0f); - - c2.X = q.W * q.W * v.X + - 2f * q.Y * q.W * v.Z - - 2f * q.Z * q.W * v.Y + - q.X * q.X * v.X + - 2f * q.Y * q.X * v.Y + - 2f * q.Z * q.X * v.Z - - q.Z * q.Z * v.X - - q.Y * q.Y * v.X; - - c2.Y = - 2f * q.X * q.Y * v.X + - q.Y * q.Y * v.Y + - 2f * q.Z * q.Y * v.Z + - 2f * q.W * q.Z * v.X - - q.Z * q.Z * v.Y + - q.W * q.W * v.Y - - 2f * q.X * q.W * v.Z - - q.X * q.X * v.Y; - - c2.Z = - 2f * q.X * q.Z * v.X + - 2f * q.Y * q.Z * v.Y + - q.Z * q.Z * v.Z - - 2f * q.W * q.Y * v.X - - q.Y * q.Y * v.Z + - 2f * q.W * q.X * v.Y - - q.X * q.X * v.Z + - q.W * q.W * v.Z; - - return c2; - } - } - - public struct UVCoord - { - public float U; - public float V; - - - public UVCoord(float u, float v) - { - this.U = u; - this.V = v; - } - - public UVCoord Flip() - { - this.U = 1.0f - this.U; - this.V = 1.0f - this.V; - return this; - } - } - - public struct Face - { - public int primFace; - - // vertices - public int v1; - public int v2; - public int v3; - - //normals - public int n1; - public int n2; - public int n3; - - // uvs - public int uv1; - public int uv2; - public int uv3; - - public Face(int v1, int v2, int v3) - { - primFace = 0; - - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - - this.n1 = 0; - this.n2 = 0; - this.n3 = 0; - - this.uv1 = 0; - this.uv2 = 0; - this.uv3 = 0; - - } - - public Face(int v1, int v2, int v3, int n1, int n2, int n3) - { - primFace = 0; - - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - - this.n1 = n1; - this.n2 = n2; - this.n3 = n3; - - this.uv1 = 0; - this.uv2 = 0; - this.uv3 = 0; - } - - public Coord SurfaceNormal(List coordList) - { - Coord c1 = coordList[this.v1]; - Coord c2 = coordList[this.v2]; - Coord c3 = coordList[this.v3]; - - Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); - Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); - - return Coord.Cross(edge1, edge2).Normalize(); - } - } - - public struct ViewerFace - { - public int primFaceNumber; - - public Coord v1; - public Coord v2; - public Coord v3; - - public int coordIndex1; - public int coordIndex2; - public int coordIndex3; - - public Coord n1; - public Coord n2; - public Coord n3; - - public UVCoord uv1; - public UVCoord uv2; - public UVCoord uv3; - - public ViewerFace(int primFaceNumber) - { - this.primFaceNumber = primFaceNumber; - - this.v1 = new Coord(); - this.v2 = new Coord(); - this.v3 = new Coord(); - - this.coordIndex1 = this.coordIndex2 = this.coordIndex3 = -1; // -1 means not assigned yet - - this.n1 = new Coord(); - this.n2 = new Coord(); - this.n3 = new Coord(); - - this.uv1 = new UVCoord(); - this.uv2 = new UVCoord(); - this.uv3 = new UVCoord(); - } - - public void Scale(float x, float y, float z) - { - this.v1.X *= x; - this.v1.Y *= y; - this.v1.Z *= z; - - this.v2.X *= x; - this.v2.Y *= y; - this.v2.Z *= z; - - this.v3.X *= x; - this.v3.Y *= y; - this.v3.Z *= z; - } - - public void AddPos(float x, float y, float z) - { - this.v1.X += x; - this.v2.X += x; - this.v3.X += x; - - this.v1.Y += y; - this.v2.Y += y; - this.v3.Y += y; - - this.v1.Z += z; - this.v2.Z += z; - this.v3.Z += z; - } - - public void AddRot(Quat q) - { - this.v1 *= q; - this.v2 *= q; - this.v3 *= q; - - this.n1 *= q; - this.n2 *= q; - this.n3 *= q; - } - - public void CalcSurfaceNormal() - { - - Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z); - Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z); - - this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize(); - } - } - - internal struct Angle - { - internal float angle; - internal float X; - internal float Y; - - internal Angle(float angle, float x, float y) - { - this.angle = angle; - this.X = x; - this.Y = y; - } - } - - internal class AngleList - { - private float iX, iY; // intersection point - - private static Angle[] angles3 = - { - new Angle(0.0f, 1.0f, 0.0f), - new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), - new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), - new Angle(1.0f, 1.0f, 0.0f) - }; - - private static Coord[] normals3 = - { - new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(), - new Coord(-0.5f, 0.0f, 0.0f).Normalize(), - new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(), - new Coord(0.25f, 0.4330127019f, 0.0f).Normalize() - }; - - private static Angle[] angles4 = - { - new Angle(0.0f, 1.0f, 0.0f), - new Angle(0.25f, 0.0f, 1.0f), - new Angle(0.5f, -1.0f, 0.0f), - new Angle(0.75f, 0.0f, -1.0f), - new Angle(1.0f, 1.0f, 0.0f) - }; - - private static Coord[] normals4 = - { - new Coord(0.5f, 0.5f, 0.0f).Normalize(), - new Coord(-0.5f, 0.5f, 0.0f).Normalize(), - new Coord(-0.5f, -0.5f, 0.0f).Normalize(), - new Coord(0.5f, -0.5f, 0.0f).Normalize(), - new Coord(0.5f, 0.5f, 0.0f).Normalize() - }; - - private static Angle[] angles24 = - { - new Angle(0.0f, 1.0f, 0.0f), - new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f), - new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f), - new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f), - new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f), - new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f), - new Angle(0.25f, 0.0f, 1.0f), - new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f), - new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), - new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f), - new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f), - new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f), - new Angle(0.5f, -1.0f, 0.0f), - new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f), - new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f), - new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f), - new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), - new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f), - new Angle(0.75f, 0.0f, -1.0f), - new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f), - new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f), - new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f), - new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f), - new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f), - new Angle(1.0f, 1.0f, 0.0f) - }; - - private Angle interpolatePoints(float newPoint, Angle p1, Angle p2) - { - float m = (newPoint - p1.angle) / (p2.angle - p1.angle); - return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y)); - } - - private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) - { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ - double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); - double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); - - if (denom != 0.0) - { - double ua = uaNumerator / denom; - iX = (float)(x1 + ua * (x2 - x1)); - iY = (float)(y1 + ua * (y2 - y1)); - } - } - - internal List angles; - internal List normals; - - internal void makeAngles(int sides, float startAngle, float stopAngle) - { - angles = new List(); - normals = new List(); - - double twoPi = System.Math.PI * 2.0; - float twoPiInv = 1.0f / (float)twoPi; - - if (sides < 1) - throw new Exception("number of sides not greater than zero"); - if (stopAngle <= startAngle) - throw new Exception("stopAngle not greater than startAngle"); - - if ((sides == 3 || sides == 4 || sides == 24)) - { - startAngle *= twoPiInv; - stopAngle *= twoPiInv; - - Angle[] sourceAngles; - if (sides == 3) - sourceAngles = angles3; - else if (sides == 4) - sourceAngles = angles4; - else sourceAngles = angles24; - - int startAngleIndex = (int)(startAngle * sides); - int endAngleIndex = sourceAngles.Length - 1; - if (stopAngle < 1.0f) - endAngleIndex = (int)(stopAngle * sides) + 1; - if (endAngleIndex == startAngleIndex) - endAngleIndex++; - - for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++) - { - angles.Add(sourceAngles[angleIndex]); - if (sides == 3) - normals.Add(normals3[angleIndex]); - else if (sides == 4) - normals.Add(normals4[angleIndex]); - } - - if (startAngle > 0.0f) - angles[0] = interpolatePoints(startAngle, angles[0], angles[1]); - - if (stopAngle < 1.0f) - { - int lastAngleIndex = angles.Count - 1; - angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]); - } - } - else - { - double stepSize = twoPi / sides; - - int startStep = (int)(startAngle / stepSize); - double angle = stepSize * startStep; - int step = startStep; - double stopAngleTest = stopAngle; - if (stopAngle < twoPi) - { - stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1); - if (stopAngleTest < stopAngle) - stopAngleTest += stepSize; - if (stopAngleTest > twoPi) - stopAngleTest = twoPi; - } - - while (angle <= stopAngleTest) - { - Angle newAngle; - newAngle.angle = (float)angle; - newAngle.X = (float)System.Math.Cos(angle); - newAngle.Y = (float)System.Math.Sin(angle); - angles.Add(newAngle); - step += 1; - angle = stepSize * step; - } - - if (startAngle > angles[0].angle) - { - Angle newAngle; - intersection(angles[0].X, angles[0].Y, angles[1].X, angles[1].Y, 0.0f, 0.0f, (float)Math.Cos(startAngle), (float)Math.Sin(startAngle)); - newAngle.angle = startAngle; - newAngle.X = iX; - newAngle.Y = iY; - angles[0] = newAngle; - } - - int index = angles.Count - 1; - if (stopAngle < angles[index].angle) - { - Angle newAngle; - intersection(angles[index - 1].X, angles[index - 1].Y, angles[index].X, angles[index].Y, 0.0f, 0.0f, (float)Math.Cos(stopAngle), (float)Math.Sin(stopAngle)); - newAngle.angle = stopAngle; - newAngle.X = iX; - newAngle.Y = iY; - angles[index] = newAngle; - } - } - } - } - - /// - /// generates a profile for extrusion - /// - public class Profile - { - private const float twoPi = 2.0f * (float)Math.PI; - - public string errorMessage = null; - - public List coords; - public List faces; - public List vertexNormals; - public List us; - public List faceUVs; - public List faceNumbers; - - // use these for making individual meshes for each prim face - public List outerCoordIndices = null; - public List hollowCoordIndices = null; - public List cut1CoordIndices = null; - public List cut2CoordIndices = null; - - public Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); - public Coord cutNormal1 = new Coord(); - public Coord cutNormal2 = new Coord(); - - public int numOuterVerts = 0; - public int numHollowVerts = 0; - - public int outerFaceNumber = -1; - public int hollowFaceNumber = -1; - - public bool calcVertexNormals = false; - public int bottomFaceNumber = 0; - public int numPrimFaces = 0; - - public Profile() - { - this.coords = new List(); - this.faces = new List(); - this.vertexNormals = new List(); - this.us = new List(); - this.faceUVs = new List(); - this.faceNumbers = new List(); - } - - public Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) - { - this.calcVertexNormals = calcVertexNormals; - this.coords = new List(); - this.faces = new List(); - this.vertexNormals = new List(); - this.us = new List(); - this.faceUVs = new List(); - this.faceNumbers = new List(); - - Coord center = new Coord(0.0f, 0.0f, 0.0f); - - List hollowCoords = new List(); - List hollowNormals = new List(); - List hollowUs = new List(); - - if (calcVertexNormals) - { - this.outerCoordIndices = new List(); - this.hollowCoordIndices = new List(); - this.cut1CoordIndices = new List(); - this.cut2CoordIndices = new List(); - } - - bool hasHollow = (hollow > 0.0f); - - bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f); - - AngleList angles = new AngleList(); - AngleList hollowAngles = new AngleList(); - - float xScale = 0.5f; - float yScale = 0.5f; - if (sides == 4) // corners of a square are sqrt(2) from center - { - xScale = 0.707107f; - yScale = 0.707107f; - } - - float startAngle = profileStart * twoPi; - float stopAngle = profileEnd * twoPi; - - try { angles.makeAngles(sides, startAngle, stopAngle); } - catch (Exception ex) - { - - errorMessage = "makeAngles failed: Exception: " + ex.ToString() - + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); - - return; - } - - this.numOuterVerts = angles.angles.Count; - - // flag to create as few triangles as possible for 3 or 4 side profile - bool simpleFace = (sides < 5 && !hasHollow && !hasProfileCut); - - if (hasHollow) - { - if (sides == hollowSides) - hollowAngles = angles; - else - { - try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); } - catch (Exception ex) - { - errorMessage = "makeAngles failed: Exception: " + ex.ToString() - + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); - - return; - } - } - this.numHollowVerts = hollowAngles.angles.Count; - } - else if (!simpleFace) - { - this.coords.Add(center); - if (this.calcVertexNormals) - this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); - this.us.Add(0.0f); - } - - float z = 0.0f; - - Angle angle; - Coord newVert = new Coord(); - if (hasHollow && hollowSides != sides) - { - int numHollowAngles = hollowAngles.angles.Count; - for (int i = 0; i < numHollowAngles; i++) - { - angle = hollowAngles.angles[i]; - newVert.X = hollow * xScale * angle.X; - newVert.Y = hollow * yScale * angle.Y; - newVert.Z = z; - - hollowCoords.Add(newVert); - if (this.calcVertexNormals) - { - if (hollowSides < 5) - hollowNormals.Add(hollowAngles.normals[i].Invert()); - else - hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); - - if (hollowSides == 4) - hollowUs.Add(angle.angle * hollow * 0.707107f); - else - hollowUs.Add(angle.angle * hollow); - } - } - } - - int index = 0; - int numAngles = angles.angles.Count; - - for (int i = 0; i < numAngles; i++) - { - angle = angles.angles[i]; - newVert.X = angle.X * xScale; - newVert.Y = angle.Y * yScale; - newVert.Z = z; - this.coords.Add(newVert); - if (this.calcVertexNormals) - { - this.outerCoordIndices.Add(this.coords.Count - 1); - - if (sides < 5) - { - this.vertexNormals.Add(angles.normals[i]); - float u = angle.angle; - this.us.Add(u); - } - else - { - this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f)); - this.us.Add(angle.angle); - } - } - - if (hasHollow) - { - if (hollowSides == sides) - { - newVert.X *= hollow; - newVert.Y *= hollow; - newVert.Z = z; - hollowCoords.Add(newVert); - if (this.calcVertexNormals) - { - if (sides < 5) - { - hollowNormals.Add(angles.normals[i].Invert()); - } - - else - hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); - - hollowUs.Add(angle.angle * hollow); - } - } - } - else if (!simpleFace && createFaces && angle.angle > 0.0001f) - { - Face newFace = new Face(); - newFace.v1 = 0; - newFace.v2 = index; - newFace.v3 = index + 1; - - this.faces.Add(newFace); - } - index += 1; - } - - if (hasHollow) - { - hollowCoords.Reverse(); - if (this.calcVertexNormals) - { - hollowNormals.Reverse(); - hollowUs.Reverse(); - } - - if (createFaces) - { - int numTotalVerts = this.numOuterVerts + this.numHollowVerts; - - if (this.numOuterVerts == this.numHollowVerts) - { - Face newFace = new Face(); - - for (int coordIndex = 0; coordIndex < this.numOuterVerts - 1; coordIndex++) - { - newFace.v1 = coordIndex; - newFace.v2 = coordIndex + 1; - newFace.v3 = numTotalVerts - coordIndex - 1; - this.faces.Add(newFace); - - newFace.v1 = coordIndex + 1; - newFace.v2 = numTotalVerts - coordIndex - 2; - newFace.v3 = numTotalVerts - coordIndex - 1; - this.faces.Add(newFace); - } - } - else - { - if (this.numOuterVerts < this.numHollowVerts) - { - Face newFace = new Face(); - int j = 0; // j is the index for outer vertices - int maxJ = this.numOuterVerts - 1; - for (int i = 0; i < this.numHollowVerts; i++) // i is the index for inner vertices - { - if (j < maxJ) - if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle < hollowAngles.angles[i].angle - angles.angles[j].angle + 0.000001f) - { - newFace.v1 = numTotalVerts - i - 1; - newFace.v2 = j; - newFace.v3 = j + 1; - - this.faces.Add(newFace); - j += 1; - } - - newFace.v1 = j; - newFace.v2 = numTotalVerts - i - 2; - newFace.v3 = numTotalVerts - i - 1; - - this.faces.Add(newFace); - } - } - else // numHollowVerts < numOuterVerts - { - Face newFace = new Face(); - int j = 0; // j is the index for inner vertices - int maxJ = this.numHollowVerts - 1; - for (int i = 0; i < this.numOuterVerts; i++) - { - if (j < maxJ) - if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle < angles.angles[i].angle - hollowAngles.angles[j].angle + 0.000001f) - { - newFace.v1 = i; - newFace.v2 = numTotalVerts - j - 2; - newFace.v3 = numTotalVerts - j - 1; - - this.faces.Add(newFace); - j += 1; - } - - newFace.v1 = numTotalVerts - j - 1; - newFace.v2 = i; - newFace.v3 = i + 1; - - this.faces.Add(newFace); - } - } - } - } - - if (calcVertexNormals) - { - foreach (Coord hc in hollowCoords) - { - this.coords.Add(hc); - hollowCoordIndices.Add(this.coords.Count - 1); - } - } - else - this.coords.AddRange(hollowCoords); - - if (this.calcVertexNormals) - { - this.vertexNormals.AddRange(hollowNormals); - this.us.AddRange(hollowUs); - - } - } - - if (simpleFace && createFaces) - { - if (sides == 3) - this.faces.Add(new Face(0, 1, 2)); - else if (sides == 4) - { - this.faces.Add(new Face(0, 1, 2)); - this.faces.Add(new Face(0, 2, 3)); - } - } - - if (calcVertexNormals && hasProfileCut) - { - int lastOuterVertIndex = this.numOuterVerts - 1; - - if (hasHollow) - { - this.cut1CoordIndices.Add(0); - this.cut1CoordIndices.Add(this.coords.Count - 1); - - this.cut2CoordIndices.Add(lastOuterVertIndex + 1); - this.cut2CoordIndices.Add(lastOuterVertIndex); - - this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y; - this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X); - - this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y; - this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X); - } - - else - { - this.cut1CoordIndices.Add(0); - this.cut1CoordIndices.Add(1); - - this.cut2CoordIndices.Add(lastOuterVertIndex); - this.cut2CoordIndices.Add(0); - - this.cutNormal1.X = this.vertexNormals[1].Y; - this.cutNormal1.Y = -this.vertexNormals[1].X; - - this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y; - this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X; - - } - this.cutNormal1.Normalize(); - this.cutNormal2.Normalize(); - } - - this.MakeFaceUVs(); - - hollowCoords = null; - hollowNormals = null; - hollowUs = null; - - if (calcVertexNormals) - { // calculate prim face numbers - - // face number order is top, outer, hollow, bottom, start cut, end cut - // I know it's ugly but so is the whole concept of prim face numbers - - int faceNum = 1; // start with outer faces - this.outerFaceNumber = faceNum; - - int startVert = hasProfileCut && !hasHollow ? 1 : 0; - if (startVert > 0) - this.faceNumbers.Add(-1); - for (int i = 0; i < this.numOuterVerts - 1; i++) - this.faceNumbers.Add(sides < 5 && i <= sides ? faceNum++ : faceNum); - - this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++); - - if (sides > 4 && (hasHollow || hasProfileCut)) - faceNum++; - - if (sides < 5 && (hasHollow || hasProfileCut) && this.numOuterVerts < sides) - faceNum++; - - if (hasHollow) - { - for (int i = 0; i < this.numHollowVerts; i++) - this.faceNumbers.Add(faceNum); - - this.hollowFaceNumber = faceNum++; - } - - this.bottomFaceNumber = faceNum++; - - if (hasHollow && hasProfileCut) - this.faceNumbers.Add(faceNum++); - - for (int i = 0; i < this.faceNumbers.Count; i++) - if (this.faceNumbers[i] == -1) - this.faceNumbers[i] = faceNum++; - - this.numPrimFaces = faceNum; - } - - } - - public void MakeFaceUVs() - { - this.faceUVs = new List(); - foreach (Coord c in this.coords) - this.faceUVs.Add(new UVCoord(1.0f - (0.5f + c.X), 1.0f - (0.5f - c.Y))); - } - - public Profile Copy() - { - return this.Copy(true); - } - - public Profile Copy(bool needFaces) - { - Profile copy = new Profile(); - - copy.coords.AddRange(this.coords); - copy.faceUVs.AddRange(this.faceUVs); - - if (needFaces) - copy.faces.AddRange(this.faces); - if ((copy.calcVertexNormals = this.calcVertexNormals) == true) - { - copy.vertexNormals.AddRange(this.vertexNormals); - copy.faceNormal = this.faceNormal; - copy.cutNormal1 = this.cutNormal1; - copy.cutNormal2 = this.cutNormal2; - copy.us.AddRange(this.us); - copy.faceNumbers.AddRange(this.faceNumbers); - - copy.cut1CoordIndices = new List(this.cut1CoordIndices); - copy.cut2CoordIndices = new List(this.cut2CoordIndices); - copy.hollowCoordIndices = new List(this.hollowCoordIndices); - copy.outerCoordIndices = new List(this.outerCoordIndices); - } - copy.numOuterVerts = this.numOuterVerts; - copy.numHollowVerts = this.numHollowVerts; - - return copy; - } - - public void AddPos(Coord v) - { - this.AddPos(v.X, v.Y, v.Z); - } - - public void AddPos(float x, float y, float z) - { - int i; - int numVerts = this.coords.Count; - Coord vert; - - for (i = 0; i < numVerts; i++) - { - vert = this.coords[i]; - vert.X += x; - vert.Y += y; - vert.Z += z; - this.coords[i] = vert; - } - } - - public void AddRot(Quat q) - { - int i; - int numVerts = this.coords.Count; - - for (i = 0; i < numVerts; i++) - this.coords[i] *= q; - - if (this.calcVertexNormals) - { - int numNormals = this.vertexNormals.Count; - for (i = 0; i < numNormals; i++) - this.vertexNormals[i] *= q; - - this.faceNormal *= q; - this.cutNormal1 *= q; - this.cutNormal2 *= q; - - } - } - - public void Scale(float x, float y) - { - int i; - int numVerts = this.coords.Count; - Coord vert; - - for (i = 0; i < numVerts; i++) - { - vert = this.coords[i]; - vert.X *= x; - vert.Y *= y; - this.coords[i] = vert; - } - } - - /// - /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices - /// - public void FlipNormals() - { - int i; - int numFaces = this.faces.Count; - Face tmpFace; - int tmp; - - for (i = 0; i < numFaces; i++) - { - tmpFace = this.faces[i]; - tmp = tmpFace.v3; - tmpFace.v3 = tmpFace.v1; - tmpFace.v1 = tmp; - this.faces[i] = tmpFace; - } - - if (this.calcVertexNormals) - { - int normalCount = this.vertexNormals.Count; - if (normalCount > 0) - { - Coord n = this.vertexNormals[normalCount - 1]; - n.Z = -n.Z; - this.vertexNormals[normalCount - 1] = n; - } - } - - this.faceNormal.X = -this.faceNormal.X; - this.faceNormal.Y = -this.faceNormal.Y; - this.faceNormal.Z = -this.faceNormal.Z; - - int numfaceUVs = this.faceUVs.Count; - for (i = 0; i < numfaceUVs; i++) - { - UVCoord uv = this.faceUVs[i]; - uv.V = 1.0f - uv.V; - this.faceUVs[i] = uv; - } - } - - public void AddValue2FaceVertexIndices(int num) - { - int numFaces = this.faces.Count; - Face tmpFace; - for (int i = 0; i < numFaces; i++) - { - tmpFace = this.faces[i]; - tmpFace.v1 += num; - tmpFace.v2 += num; - tmpFace.v3 += num; - - this.faces[i] = tmpFace; - } - } - - public void AddValue2FaceNormalIndices(int num) - { - if (this.calcVertexNormals) - { - int numFaces = this.faces.Count; - Face tmpFace; - for (int i = 0; i < numFaces; i++) - { - tmpFace = this.faces[i]; - tmpFace.n1 += num; - tmpFace.n2 += num; - tmpFace.n3 += num; - - this.faces[i] = tmpFace; - } - } - } - - public void DumpRaw(String path, String name, String title) - { - if (path == null) - return; - String fileName = name + "_" + title + ".raw"; - String completePath = System.IO.Path.Combine(path, fileName); - StreamWriter sw = new StreamWriter(completePath); - - for (int i = 0; i < this.faces.Count; i++) - { - string s = this.coords[this.faces[i].v1].ToString(); - s += " " + this.coords[this.faces[i].v2].ToString(); - s += " " + this.coords[this.faces[i].v3].ToString(); - - sw.WriteLine(s); - } - - sw.Close(); - } - } - - public struct PathNode - { - public Coord position; - public Quat rotation; - public float xScale; - public float yScale; - public float percentOfPath; - } - - public enum PathType { Linear = 0, Circular = 1, Flexible = 2 } - - public class Path - { - public List pathNodes = new List(); - - public float twistBegin = 0.0f; - public float twistEnd = 0.0f; - public float topShearX = 0.0f; - public float topShearY = 0.0f; - public float pathCutBegin = 0.0f; - public float pathCutEnd = 1.0f; - public float dimpleBegin = 0.0f; - public float dimpleEnd = 1.0f; - public float skew = 0.0f; - public float holeSizeX = 1.0f; // called pathScaleX in pbs - public float holeSizeY = 0.25f; - public float taperX = 0.0f; - public float taperY = 0.0f; - public float radius = 0.0f; - public float revolutions = 1.0f; - public int stepsPerRevolution = 24; - - private const float twoPi = 2.0f * (float)Math.PI; - - public void Create(PathType pathType, int steps) - { - if (this.taperX > 0.999f) - this.taperX = 0.999f; - if (this.taperX < -0.999f) - this.taperX = -0.999f; - if (this.taperY > 0.999f) - this.taperY = 0.999f; - if (this.taperY < -0.999f) - this.taperY = -0.999f; - - if (pathType == PathType.Linear || pathType == PathType.Flexible) - { - int step = 0; - - float length = this.pathCutEnd - this.pathCutBegin; - float twistTotal = twistEnd - twistBegin; - float twistTotalAbs = Math.Abs(twistTotal); - if (twistTotalAbs > 0.01f) - steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number - - float start = -0.5f; - float stepSize = length / (float)steps; - float percentOfPathMultiplier = stepSize * 0.999999f; - float xOffset = this.topShearX * this.pathCutBegin; - float yOffset = this.topShearY * this.pathCutBegin; - float zOffset = start; - float xOffsetStepIncrement = this.topShearX * length / steps; - float yOffsetStepIncrement = this.topShearY * length / steps; - - float percentOfPath = this.pathCutBegin; - zOffset += percentOfPath; - - // sanity checks - - bool done = false; - - while (!done) - { - PathNode newNode = new PathNode(); - - newNode.xScale = 1.0f; - if (this.taperX == 0.0f) - newNode.xScale = 1.0f; - else if (this.taperX > 0.0f) - newNode.xScale = 1.0f - percentOfPath * this.taperX; - else newNode.xScale = 1.0f + (1.0f - percentOfPath) * this.taperX; - - newNode.yScale = 1.0f; - if (this.taperY == 0.0f) - newNode.yScale = 1.0f; - else if (this.taperY > 0.0f) - newNode.yScale = 1.0f - percentOfPath * this.taperY; - else newNode.yScale = 1.0f + (1.0f - percentOfPath) * this.taperY; - - float twist = twistBegin + twistTotal * percentOfPath; - - newNode.rotation = new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); - newNode.position = new Coord(xOffset, yOffset, zOffset); - newNode.percentOfPath = percentOfPath; - - pathNodes.Add(newNode); - - if (step < steps) - { - step += 1; - percentOfPath += percentOfPathMultiplier; - xOffset += xOffsetStepIncrement; - yOffset += yOffsetStepIncrement; - zOffset += stepSize; - if (percentOfPath > this.pathCutEnd) - done = true; - } - else done = true; - } - } // end of linear path code - - else // pathType == Circular - { - float twistTotal = twistEnd - twistBegin; - - // if the profile has a lot of twist, add more layers otherwise the layers may overlap - // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't - // accurately match the viewer - float twistTotalAbs = Math.Abs(twistTotal); - if (twistTotalAbs > 0.01f) - { - if (twistTotalAbs > Math.PI * 1.5f) - steps *= 2; - if (twistTotalAbs > Math.PI * 3.0f) - steps *= 2; - } - - float yPathScale = this.holeSizeY * 0.5f; - float pathLength = this.pathCutEnd - this.pathCutBegin; - float totalSkew = this.skew * 2.0f * pathLength; - float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew; - float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY)); - float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f; - - // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end - // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used - // to calculate the sine for generating the path radius appears to approximate it's effects there - // too, but there are some subtle differences in the radius which are noticeable as the prim size - // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on - // the meshes generated with this technique appear nearly identical in shape to the same prims when - // displayed by the viewer. - - float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f; - float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f; - float stepSize = twoPi / this.stepsPerRevolution; - - int step = (int)(startAngle / stepSize); - float angle = startAngle; - - bool done = false; - while (!done) // loop through the length of the path and add the layers - { - PathNode newNode = new PathNode(); - - float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX; - float yProfileScale = this.holeSizeY; - - float percentOfPath = angle / (twoPi * this.revolutions); - float percentOfAngles = (angle - startAngle) / (endAngle - startAngle); - - if (this.taperX > 0.01f) - xProfileScale *= 1.0f - percentOfPath * this.taperX; - else if (this.taperX < -0.01f) - xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX; - - if (this.taperY > 0.01f) - yProfileScale *= 1.0f - percentOfPath * this.taperY; - else if (this.taperY < -0.01f) - yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY; - - newNode.xScale = xProfileScale; - newNode.yScale = yProfileScale; - - float radiusScale = 1.0f; - if (this.radius > 0.001f) - radiusScale = 1.0f - this.radius * percentOfPath; - else if (this.radius < 0.001f) - radiusScale = 1.0f + this.radius * (1.0f - percentOfPath); - - float twist = twistBegin + twistTotal * percentOfPath; - - float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles); - xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor; - - float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale; - - float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale; - - newNode.position = new Coord(xOffset, yOffset, zOffset); - - // now orient the rotation of the profile layer relative to it's position on the path - // adding taperY to the angle used to generate the quat appears to approximate the viewer - - newNode.rotation = new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY); - - // next apply twist rotation to the profile layer - if (twistTotal != 0.0f || twistBegin != 0.0f) - newNode.rotation *= new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); - - newNode.percentOfPath = percentOfPath; - - pathNodes.Add(newNode); - - // calculate terms for next iteration - // calculate the angle for the next iteration of the loop - - if (angle >= endAngle - 0.01) - done = true; - else - { - step += 1; - angle = stepSize * step; - if (angle > endAngle) - angle = endAngle; - } - } - } - } - } - - public class PrimMesh - { - public string errorMessage = ""; - private const float twoPi = 2.0f * (float)Math.PI; - - public List coords; - public List normals; - public List faces; - - public List viewerFaces; - - private int sides = 4; - private int hollowSides = 4; - private float profileStart = 0.0f; - private float profileEnd = 1.0f; - private float hollow = 0.0f; - public int twistBegin = 0; - public int twistEnd = 0; - public float topShearX = 0.0f; - public float topShearY = 0.0f; - public float pathCutBegin = 0.0f; - public float pathCutEnd = 1.0f; - public float dimpleBegin = 0.0f; - public float dimpleEnd = 1.0f; - public float skew = 0.0f; - public float holeSizeX = 1.0f; // called pathScaleX in pbs - public float holeSizeY = 0.25f; - public float taperX = 0.0f; - public float taperY = 0.0f; - public float radius = 0.0f; - public float revolutions = 1.0f; - public int stepsPerRevolution = 24; - - private int profileOuterFaceNumber = -1; - private int profileHollowFaceNumber = -1; - - private bool hasProfileCut = false; - private bool hasHollow = false; - public bool calcVertexNormals = false; - private bool normalsProcessed = false; - public bool viewerMode = false; - public bool sphereMode = false; - - public int numPrimFaces = 0; - - /// - /// Human readable string representation of the parameters used to create a mesh. - /// - /// - public string ParamsToDisplayString() - { - string s = ""; - s += "sides..................: " + this.sides.ToString(); - s += "\nhollowSides..........: " + this.hollowSides.ToString(); - s += "\nprofileStart.........: " + this.profileStart.ToString(); - s += "\nprofileEnd...........: " + this.profileEnd.ToString(); - s += "\nhollow...............: " + this.hollow.ToString(); - s += "\ntwistBegin...........: " + this.twistBegin.ToString(); - s += "\ntwistEnd.............: " + this.twistEnd.ToString(); - s += "\ntopShearX............: " + this.topShearX.ToString(); - s += "\ntopShearY............: " + this.topShearY.ToString(); - s += "\npathCutBegin.........: " + this.pathCutBegin.ToString(); - s += "\npathCutEnd...........: " + this.pathCutEnd.ToString(); - s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString(); - s += "\ndimpleEnd............: " + this.dimpleEnd.ToString(); - s += "\nskew.................: " + this.skew.ToString(); - s += "\nholeSizeX............: " + this.holeSizeX.ToString(); - s += "\nholeSizeY............: " + this.holeSizeY.ToString(); - s += "\ntaperX...............: " + this.taperX.ToString(); - s += "\ntaperY...............: " + this.taperY.ToString(); - s += "\nradius...............: " + this.radius.ToString(); - s += "\nrevolutions..........: " + this.revolutions.ToString(); - s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString(); - s += "\nsphereMode...........: " + this.sphereMode.ToString(); - s += "\nhasProfileCut........: " + this.hasProfileCut.ToString(); - s += "\nhasHollow............: " + this.hasHollow.ToString(); - s += "\nviewerMode...........: " + this.viewerMode.ToString(); - - return s; - } - - public int ProfileOuterFaceNumber - { - get { return profileOuterFaceNumber; } - } - - public int ProfileHollowFaceNumber - { - get { return profileHollowFaceNumber; } - } - - public bool HasProfileCut - { - get { return hasProfileCut; } - } - - public bool HasHollow - { - get { return hasHollow; } - } - - - /// - /// Constructs a PrimMesh object and creates the profile for extrusion. - /// - /// - /// - /// - /// - /// - public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) - { - this.coords = new List(); - this.faces = new List(); - - this.sides = sides; - this.profileStart = profileStart; - this.profileEnd = profileEnd; - this.hollow = hollow; - this.hollowSides = hollowSides; - - if (sides < 3) - this.sides = 3; - if (hollowSides < 3) - this.hollowSides = 3; - if (profileStart < 0.0f) - this.profileStart = 0.0f; - if (profileEnd > 1.0f) - this.profileEnd = 1.0f; - if (profileEnd < 0.02f) - this.profileEnd = 0.02f; - if (profileStart >= profileEnd) - this.profileStart = profileEnd - 0.02f; - if (hollow > 0.99f) - this.hollow = 0.99f; - if (hollow < 0.0f) - this.hollow = 0.0f; - } - - /// - /// Extrudes a profile along a path. - /// - public void Extrude(PathType pathType) - { - bool needEndFaces = false; - - this.coords = new List(); - this.faces = new List(); - - if (this.viewerMode) - { - this.viewerFaces = new List(); - this.calcVertexNormals = true; - } - - if (this.calcVertexNormals) - this.normals = new List(); - - int steps = 1; - - float length = this.pathCutEnd - this.pathCutBegin; - normalsProcessed = false; - - if (this.viewerMode && this.sides == 3) - { - // prisms don't taper well so add some vertical resolution - // other prims may benefit from this but just do prisms for now - if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01) - steps = (int)(steps * 4.5 * length); - } - - if (this.sphereMode) - this.hasProfileCut = this.profileEnd - this.profileStart < 0.4999f; - else - this.hasProfileCut = this.profileEnd - this.profileStart < 0.9999f; - this.hasHollow = (this.hollow > 0.001f); - - float twistBegin = this.twistBegin / 360.0f * twoPi; - float twistEnd = this.twistEnd / 360.0f * twoPi; - float twistTotal = twistEnd - twistBegin; - float twistTotalAbs = Math.Abs(twistTotal); - if (twistTotalAbs > 0.01f) - steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number - - float hollow = this.hollow; - - if (pathType == PathType.Circular) - { - needEndFaces = false; - if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) - needEndFaces = true; - else if (this.taperX != 0.0f || this.taperY != 0.0f) - needEndFaces = true; - else if (this.skew != 0.0f) - needEndFaces = true; - else if (twistTotal != 0.0f) - needEndFaces = true; - else if (this.radius != 0.0f) - needEndFaces = true; - } - else needEndFaces = true; - - // sanity checks - float initialProfileRot = 0.0f; - if (pathType == PathType.Circular) - { - if (this.sides == 3) - { - initialProfileRot = (float)Math.PI; - if (this.hollowSides == 4) - { - if (hollow > 0.7f) - hollow = 0.7f; - hollow *= 0.707f; - } - else hollow *= 0.5f; - } - else if (this.sides == 4) - { - initialProfileRot = 0.25f * (float)Math.PI; - if (this.hollowSides != 4) - hollow *= 0.707f; - } - else if (this.sides > 4) - { - initialProfileRot = (float)Math.PI; - if (this.hollowSides == 4) - { - if (hollow > 0.7f) - hollow = 0.7f; - hollow /= 0.7f; - } - } - } - else - { - if (this.sides == 3) - { - if (this.hollowSides == 4) - { - if (hollow > 0.7f) - hollow = 0.7f; - hollow *= 0.707f; - } - else hollow *= 0.5f; - } - else if (this.sides == 4) - { - initialProfileRot = 1.25f * (float)Math.PI; - if (this.hollowSides != 4) - hollow *= 0.707f; - } - else if (this.sides == 24 && this.hollowSides == 4) - hollow *= 1.414f; - } - - Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals); - this.errorMessage = profile.errorMessage; - - this.numPrimFaces = profile.numPrimFaces; - - int cut1FaceNumber = profile.bottomFaceNumber + 1; - int cut2FaceNumber = cut1FaceNumber + 1; - if (!needEndFaces) - { - cut1FaceNumber -= 2; - cut2FaceNumber -= 2; - } - - profileOuterFaceNumber = profile.outerFaceNumber; - if (!needEndFaces) - profileOuterFaceNumber--; - - if (hasHollow) - { - profileHollowFaceNumber = profile.hollowFaceNumber; - if (!needEndFaces) - profileHollowFaceNumber--; - } - - int cut1Vert = -1; - int cut2Vert = -1; - if (hasProfileCut) - { - cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; - cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; - } - - if (initialProfileRot != 0.0f) - { - profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); - if (viewerMode) - profile.MakeFaceUVs(); - } - - Coord lastCutNormal1 = new Coord(); - Coord lastCutNormal2 = new Coord(); - float thisV = 0.0f; - float lastV = 0.0f; - - Path path = new Path(); - path.twistBegin = twistBegin; - path.twistEnd = twistEnd; - path.topShearX = topShearX; - path.topShearY = topShearY; - path.pathCutBegin = pathCutBegin; - path.pathCutEnd = pathCutEnd; - path.dimpleBegin = dimpleBegin; - path.dimpleEnd = dimpleEnd; - path.skew = skew; - path.holeSizeX = holeSizeX; - path.holeSizeY = holeSizeY; - path.taperX = taperX; - path.taperY = taperY; - path.radius = radius; - path.revolutions = revolutions; - path.stepsPerRevolution = stepsPerRevolution; - - path.Create(pathType, steps); - - for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) - { - PathNode node = path.pathNodes[nodeIndex]; - Profile newLayer = profile.Copy(); - newLayer.Scale(node.xScale, node.yScale); - - newLayer.AddRot(node.rotation); - newLayer.AddPos(node.position); - - if (needEndFaces && nodeIndex == 0) - { - newLayer.FlipNormals(); - - // add the bottom faces to the viewerFaces list - if (this.viewerMode) - { - Coord faceNormal = newLayer.faceNormal; - ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber); - int numFaces = newLayer.faces.Count; - List faces = newLayer.faces; - - for (int i = 0; i < numFaces; i++) - { - Face face = faces[i]; - newViewerFace.v1 = newLayer.coords[face.v1]; - newViewerFace.v2 = newLayer.coords[face.v2]; - newViewerFace.v3 = newLayer.coords[face.v3]; - - newViewerFace.coordIndex1 = face.v1; - newViewerFace.coordIndex2 = face.v2; - newViewerFace.coordIndex3 = face.v3; - - newViewerFace.n1 = faceNormal; - newViewerFace.n2 = faceNormal; - newViewerFace.n3 = faceNormal; - - newViewerFace.uv1 = newLayer.faceUVs[face.v1]; - newViewerFace.uv2 = newLayer.faceUVs[face.v2]; - newViewerFace.uv3 = newLayer.faceUVs[face.v3]; - - if (pathType == PathType.Linear) - { - newViewerFace.uv1.Flip(); - newViewerFace.uv2.Flip(); - newViewerFace.uv3.Flip(); - } - - this.viewerFaces.Add(newViewerFace); - } - } - } // if (nodeIndex == 0) - - // append this layer - - int coordsLen = this.coords.Count; - newLayer.AddValue2FaceVertexIndices(coordsLen); - - this.coords.AddRange(newLayer.coords); - - if (this.calcVertexNormals) - { - newLayer.AddValue2FaceNormalIndices(this.normals.Count); - this.normals.AddRange(newLayer.vertexNormals); - } - - if (node.percentOfPath < this.pathCutBegin + 0.01f || node.percentOfPath > this.pathCutEnd - 0.01f) - this.faces.AddRange(newLayer.faces); - - // fill faces between layers - - int numVerts = newLayer.coords.Count; - Face newFace1 = new Face(); - Face newFace2 = new Face(); - - thisV = 1.0f - node.percentOfPath; - - if (nodeIndex > 0) - { - int startVert = coordsLen + 1; - int endVert = this.coords.Count; - - if (sides < 5 || this.hasProfileCut || this.hasHollow) - startVert--; - - for (int i = startVert; i < endVert; i++) - { - int iNext = i + 1; - if (i == endVert - 1) - iNext = startVert; - - int whichVert = i - startVert; - - newFace1.v1 = i; - newFace1.v2 = i - numVerts; - newFace1.v3 = iNext; - - newFace1.n1 = newFace1.v1; - newFace1.n2 = newFace1.v2; - newFace1.n3 = newFace1.v3; - this.faces.Add(newFace1); - - newFace2.v1 = iNext; - newFace2.v2 = i - numVerts; - newFace2.v3 = iNext - numVerts; - - newFace2.n1 = newFace2.v1; - newFace2.n2 = newFace2.v2; - newFace2.n3 = newFace2.v3; - this.faces.Add(newFace2); - - if (this.viewerMode) - { - // add the side faces to the list of viewerFaces here - - int primFaceNum = profile.faceNumbers[whichVert]; - if (!needEndFaces) - primFaceNum -= 1; - - ViewerFace newViewerFace1 = new ViewerFace(primFaceNum); - ViewerFace newViewerFace2 = new ViewerFace(primFaceNum); - - int uIndex = whichVert; - if (!hasHollow && sides > 4 && uIndex < newLayer.us.Count - 1) - { - uIndex++; - } - - float u1 = newLayer.us[uIndex]; - float u2 = 1.0f; - if (uIndex < (int)newLayer.us.Count - 1) - u2 = newLayer.us[uIndex + 1]; - - if (whichVert == cut1Vert || whichVert == cut2Vert) - { - u1 = 0.0f; - u2 = 1.0f; - } - else if (sides < 5) - { - if (whichVert < profile.numOuterVerts) - { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled - // to reflect the entire texture width - u1 *= sides; - u2 *= sides; - u2 -= (int)u1; - u1 -= (int)u1; - if (u2 < 0.1f) - u2 = 1.0f; - } - } - - if (this.sphereMode) - { - if (whichVert != cut1Vert && whichVert != cut2Vert) - { - u1 = u1 * 2.0f - 1.0f; - u2 = u2 * 2.0f - 1.0f; - - if (whichVert >= newLayer.numOuterVerts) - { - u1 -= hollow; - u2 -= hollow; - } - - } - } - - newViewerFace1.uv1.U = u1; - newViewerFace1.uv2.U = u1; - newViewerFace1.uv3.U = u2; - - newViewerFace1.uv1.V = thisV; - newViewerFace1.uv2.V = lastV; - newViewerFace1.uv3.V = thisV; - - newViewerFace2.uv1.U = u2; - newViewerFace2.uv2.U = u1; - newViewerFace2.uv3.U = u2; - - newViewerFace2.uv1.V = thisV; - newViewerFace2.uv2.V = lastV; - newViewerFace2.uv3.V = lastV; - - newViewerFace1.v1 = this.coords[newFace1.v1]; - newViewerFace1.v2 = this.coords[newFace1.v2]; - newViewerFace1.v3 = this.coords[newFace1.v3]; - - newViewerFace2.v1 = this.coords[newFace2.v1]; - newViewerFace2.v2 = this.coords[newFace2.v2]; - newViewerFace2.v3 = this.coords[newFace2.v3]; - - newViewerFace1.coordIndex1 = newFace1.v1; - newViewerFace1.coordIndex2 = newFace1.v2; - newViewerFace1.coordIndex3 = newFace1.v3; - - newViewerFace2.coordIndex1 = newFace2.v1; - newViewerFace2.coordIndex2 = newFace2.v2; - newViewerFace2.coordIndex3 = newFace2.v3; - - // profile cut faces - if (whichVert == cut1Vert) - { - newViewerFace1.primFaceNumber = cut1FaceNumber; - newViewerFace2.primFaceNumber = cut1FaceNumber; - newViewerFace1.n1 = newLayer.cutNormal1; - newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; - - newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; - newViewerFace2.n2 = lastCutNormal1; - } - else if (whichVert == cut2Vert) - { - newViewerFace1.primFaceNumber = cut2FaceNumber; - newViewerFace2.primFaceNumber = cut2FaceNumber; - newViewerFace1.n1 = newLayer.cutNormal2; - newViewerFace1.n2 = lastCutNormal2; - newViewerFace1.n3 = lastCutNormal2; - - newViewerFace2.n1 = newLayer.cutNormal2; - newViewerFace2.n3 = newLayer.cutNormal2; - newViewerFace2.n2 = lastCutNormal2; - } - - else // outer and hollow faces - { - if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts)) - { // looks terrible when path is twisted... need vertex normals here - newViewerFace1.CalcSurfaceNormal(); - newViewerFace2.CalcSurfaceNormal(); - } - else - { - newViewerFace1.n1 = this.normals[newFace1.n1]; - newViewerFace1.n2 = this.normals[newFace1.n2]; - newViewerFace1.n3 = this.normals[newFace1.n3]; - - newViewerFace2.n1 = this.normals[newFace2.n1]; - newViewerFace2.n2 = this.normals[newFace2.n2]; - newViewerFace2.n3 = this.normals[newFace2.n3]; - } - } - - this.viewerFaces.Add(newViewerFace1); - this.viewerFaces.Add(newViewerFace2); - - } - } - } - - lastCutNormal1 = newLayer.cutNormal1; - lastCutNormal2 = newLayer.cutNormal2; - lastV = thisV; - - if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode) - { - // add the top faces to the viewerFaces list here - Coord faceNormal = newLayer.faceNormal; - ViewerFace newViewerFace = new ViewerFace(0); - int numFaces = newLayer.faces.Count; - List faces = newLayer.faces; - - for (int i = 0; i < numFaces; i++) - { - Face face = faces[i]; - newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; - newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; - newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; - - newViewerFace.coordIndex1 = face.v1 - coordsLen; - newViewerFace.coordIndex2 = face.v2 - coordsLen; - newViewerFace.coordIndex3 = face.v3 - coordsLen; - - newViewerFace.n1 = faceNormal; - newViewerFace.n2 = faceNormal; - newViewerFace.n3 = faceNormal; - - newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; - newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; - newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; - - if (pathType == PathType.Linear) - { - newViewerFace.uv1.Flip(); - newViewerFace.uv2.Flip(); - newViewerFace.uv3.Flip(); - } - - this.viewerFaces.Add(newViewerFace); - } - } - - - } // for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) - - } - - - /// - /// DEPRICATED - use Extrude(PathType.Linear) instead - /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. - /// - /// - public void ExtrudeLinear() - { - this.Extrude(PathType.Linear); - } - - - /// - /// DEPRICATED - use Extrude(PathType.Circular) instead - /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. - /// - /// - public void ExtrudeCircular() - { - this.Extrude(PathType.Circular); - } - - - private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) - { - Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); - Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); - - Coord normal = Coord.Cross(edge1, edge2); - - normal.Normalize(); - - return normal; - } - - private Coord SurfaceNormal(Face face) - { - return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]); - } - - /// - /// Calculate the surface normal for a face in the list of faces - /// - /// - /// - public Coord SurfaceNormal(int faceIndex) - { - int numFaces = this.faces.Count; - if (faceIndex < 0 || faceIndex >= numFaces) - throw new Exception("faceIndex out of range"); - - return SurfaceNormal(this.faces[faceIndex]); - } - - /// - /// Duplicates a PrimMesh object. All object properties are copied by value, including lists. - /// - /// - public PrimMesh Copy() - { - PrimMesh copy = new PrimMesh(this.sides, this.profileStart, this.profileEnd, this.hollow, this.hollowSides); - copy.twistBegin = this.twistBegin; - copy.twistEnd = this.twistEnd; - copy.topShearX = this.topShearX; - copy.topShearY = this.topShearY; - copy.pathCutBegin = this.pathCutBegin; - copy.pathCutEnd = this.pathCutEnd; - copy.dimpleBegin = this.dimpleBegin; - copy.dimpleEnd = this.dimpleEnd; - copy.skew = this.skew; - copy.holeSizeX = this.holeSizeX; - copy.holeSizeY = this.holeSizeY; - copy.taperX = this.taperX; - copy.taperY = this.taperY; - copy.radius = this.radius; - copy.revolutions = this.revolutions; - copy.stepsPerRevolution = this.stepsPerRevolution; - copy.calcVertexNormals = this.calcVertexNormals; - copy.normalsProcessed = this.normalsProcessed; - copy.viewerMode = this.viewerMode; - copy.numPrimFaces = this.numPrimFaces; - copy.errorMessage = this.errorMessage; - - copy.coords = new List(this.coords); - copy.faces = new List(this.faces); - copy.viewerFaces = new List(this.viewerFaces); - copy.normals = new List(this.normals); - - return copy; - } - - /// - /// Calculate surface normals for all of the faces in the list of faces in this mesh - /// - public void CalcNormals() - { - if (normalsProcessed) - return; - - normalsProcessed = true; - - int numFaces = faces.Count; - - if (!this.calcVertexNormals) - this.normals = new List(); - - for (int i = 0; i < numFaces; i++) - { - Face face = faces[i]; - - this.normals.Add(SurfaceNormal(i).Normalize()); - - int normIndex = normals.Count - 1; - face.n1 = normIndex; - face.n2 = normIndex; - face.n3 = normIndex; - - this.faces[i] = face; - } - } - - /// - /// Adds a value to each XYZ vertex coordinate in the mesh - /// - /// - /// - /// - public void AddPos(float x, float y, float z) - { - int i; - int numVerts = this.coords.Count; - Coord vert; - - for (i = 0; i < numVerts; i++) - { - vert = this.coords[i]; - vert.X += x; - vert.Y += y; - vert.Z += z; - this.coords[i] = vert; - } - - if (this.viewerFaces != null) - { - int numViewerFaces = this.viewerFaces.Count; - - for (i = 0; i < numViewerFaces; i++) - { - ViewerFace v = this.viewerFaces[i]; - v.AddPos(x, y, z); - this.viewerFaces[i] = v; - } - } - } - - /// - /// Rotates the mesh - /// - /// - public void AddRot(Quat q) - { - int i; - int numVerts = this.coords.Count; - - for (i = 0; i < numVerts; i++) - this.coords[i] *= q; - - if (this.normals != null) - { - int numNormals = this.normals.Count; - for (i = 0; i < numNormals; i++) - this.normals[i] *= q; - } - - if (this.viewerFaces != null) - { - int numViewerFaces = this.viewerFaces.Count; - - for (i = 0; i < numViewerFaces; i++) - { - ViewerFace v = this.viewerFaces[i]; - v.v1 *= q; - v.v2 *= q; - v.v3 *= q; - - v.n1 *= q; - v.n2 *= q; - v.n3 *= q; - this.viewerFaces[i] = v; - } - } - } - -#if VERTEX_INDEXER - public VertexIndexer GetVertexIndexer() - { - if (this.viewerMode && this.viewerFaces.Count > 0) - return new VertexIndexer(this); - return null; - } -#endif - - /// - /// Scales the mesh - /// - /// - /// - /// - public void Scale(float x, float y, float z) - { - int i; - int numVerts = this.coords.Count; - //Coord vert; - - Coord m = new Coord(x, y, z); - for (i = 0; i < numVerts; i++) - this.coords[i] *= m; - - if (this.viewerFaces != null) - { - int numViewerFaces = this.viewerFaces.Count; - for (i = 0; i < numViewerFaces; i++) - { - ViewerFace v = this.viewerFaces[i]; - v.v1 *= m; - v.v2 *= m; - v.v3 *= m; - this.viewerFaces[i] = v; - } - - } - - } - - /// - /// Dumps the mesh to a Blender compatible "Raw" format file - /// - /// - /// - /// - public void DumpRaw(String path, String name, String title) - { - if (path == null) - return; - String fileName = name + "_" + title + ".raw"; - String completePath = System.IO.Path.Combine(path, fileName); - StreamWriter sw = new StreamWriter(completePath); - - for (int i = 0; i < this.faces.Count; i++) - { - string s = this.coords[this.faces[i].v1].ToString(); - s += " " + this.coords[this.faces[i].v2].ToString(); - s += " " + this.coords[this.faces[i].v3].ToString(); - - sw.WriteLine(s); - } - - sw.Close(); - } - } -} diff --git a/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs deleted file mode 100644 index 4cc1731..0000000 --- a/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenSim.Region.Physics.Meshing")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("http://opensimulator.org")] -[assembly: AssemblyProduct("OpenSim")] -[assembly: AssemblyCopyright("OpenSimulator developers")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("4b7e35c2-a9dd-4b10-b778-eb417f4f6884")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Region/Physics/Meshing/SculptMap.cs b/OpenSim/Region/Physics/Meshing/SculptMap.cs deleted file mode 100644 index 740424e..0000000 --- a/OpenSim/Region/Physics/Meshing/SculptMap.cs +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) Contributors - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// to build without references to System.Drawing, comment this out -#define SYSTEM_DRAWING - -using System; -using System.Collections.Generic; -using System.Text; - -#if SYSTEM_DRAWING -using System.Drawing; -using System.Drawing.Imaging; - -namespace PrimMesher -{ - public class SculptMap - { - public int width; - public int height; - public byte[] redBytes; - public byte[] greenBytes; - public byte[] blueBytes; - - public SculptMap() - { - } - - public SculptMap(Bitmap bm, int lod) - { - int bmW = bm.Width; - int bmH = bm.Height; - - if (bmW == 0 || bmH == 0) - throw new Exception("SculptMap: bitmap has no data"); - - int numLodPixels = lod * 2 * lod * 2; // (32 * 2)^2 = 64^2 pixels for default sculpt map image - - bool needsScaling = false; - - bool smallMap = bmW * bmH <= lod * lod; - - width = bmW; - height = bmH; - while (width * height > numLodPixels) - { - width >>= 1; - height >>= 1; - needsScaling = true; - } - - - - try - { - if (needsScaling) - bm = ScaleImage(bm, width, height, - System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor); - } - - catch (Exception e) - { - throw new Exception("Exception in ScaleImage(): e: " + e.ToString()); - } - - if (width * height > lod * lod) - { - width >>= 1; - height >>= 1; - } - - int numBytes = (width + 1) * (height + 1); - redBytes = new byte[numBytes]; - greenBytes = new byte[numBytes]; - blueBytes = new byte[numBytes]; - - int byteNdx = 0; - - try - { - for (int y = 0; y <= height; y++) - { - for (int x = 0; x <= width; x++) - { - Color c; - - if (smallMap) - c = bm.GetPixel(x < width ? x : x - 1, - y < height ? y : y - 1); - else - c = bm.GetPixel(x < width ? x * 2 : x * 2 - 1, - y < height ? y * 2 : y * 2 - 1); - - redBytes[byteNdx] = c.R; - greenBytes[byteNdx] = c.G; - blueBytes[byteNdx] = c.B; - - ++byteNdx; - } - } - } - catch (Exception e) - { - throw new Exception("Caught exception processing byte arrays in SculptMap(): e: " + e.ToString()); - } - - width++; - height++; - } - - public List> ToRows(bool mirror) - { - int numRows = height; - int numCols = width; - - List> rows = new List>(numRows); - - float pixScale = 1.0f / 255; - - int rowNdx, colNdx; - int smNdx = 0; - - for (rowNdx = 0; rowNdx < numRows; rowNdx++) - { - List row = new List(numCols); - for (colNdx = 0; colNdx < numCols; colNdx++) - { - if (mirror) - row.Add(new Coord(-(redBytes[smNdx] * pixScale - 0.5f), (greenBytes[smNdx] * pixScale - 0.5f), blueBytes[smNdx] * pixScale - 0.5f)); - else - row.Add(new Coord(redBytes[smNdx] * pixScale - 0.5f, greenBytes[smNdx] * pixScale - 0.5f, blueBytes[smNdx] * pixScale - 0.5f)); - - ++smNdx; - } - rows.Add(row); - } - return rows; - } - - private Bitmap ScaleImage(Bitmap srcImage, int destWidth, int destHeight, - System.Drawing.Drawing2D.InterpolationMode interpMode) - { - Bitmap scaledImage = new Bitmap(srcImage, destWidth, destHeight); - scaledImage.SetResolution(96.0f, 96.0f); - - Graphics grPhoto = Graphics.FromImage(scaledImage); - grPhoto.InterpolationMode = interpMode; - - grPhoto.DrawImage(srcImage, - new Rectangle(0, 0, destWidth, destHeight), - new Rectangle(0, 0, srcImage.Width, srcImage.Height), - GraphicsUnit.Pixel); - - grPhoto.Dispose(); - return scaledImage; - } - } -} -#endif diff --git a/OpenSim/Region/Physics/Meshing/SculptMesh.cs b/OpenSim/Region/Physics/Meshing/SculptMesh.cs deleted file mode 100644 index 4a7f3ad..0000000 --- a/OpenSim/Region/Physics/Meshing/SculptMesh.cs +++ /dev/null @@ -1,646 +0,0 @@ -/* - * Copyright (c) Contributors - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// to build without references to System.Drawing, comment this out -#define SYSTEM_DRAWING - -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; - -#if SYSTEM_DRAWING -using System.Drawing; -using System.Drawing.Imaging; -#endif - -namespace PrimMesher -{ - - public class SculptMesh - { - public List coords; - public List faces; - - public List viewerFaces; - public List normals; - public List uvs; - - public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 }; - -#if SYSTEM_DRAWING - - public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) - { - Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); - SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); - bitmap.Dispose(); - return sculptMesh; - } - - - public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert) - { - Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); - _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0); - bitmap.Dispose(); - } -#endif - - /// - /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications - /// Construct a sculpt mesh from a 2D array of floats - /// - /// - /// - /// - /// - /// - /// - public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode) - { - float xStep, yStep; - float uStep, vStep; - - int numYElements = zMap.GetLength(0); - int numXElements = zMap.GetLength(1); - - try - { - xStep = (xEnd - xBegin) / (float)(numXElements - 1); - yStep = (yEnd - yBegin) / (float)(numYElements - 1); - - uStep = 1.0f / (numXElements - 1); - vStep = 1.0f / (numYElements - 1); - } - catch (DivideByZeroException) - { - return; - } - - coords = new List(); - faces = new List(); - normals = new List(); - uvs = new List(); - - viewerFaces = new List(); - - int p1, p2, p3, p4; - - int x, y; - int xStart = 0, yStart = 0; - - for (y = yStart; y < numYElements; y++) - { - int rowOffset = y * numXElements; - - for (x = xStart; x < numXElements; x++) - { - /* - * p1-----p2 - * | \ f2 | - * | \ | - * | f1 \| - * p3-----p4 - */ - - p4 = rowOffset + x; - p3 = p4 - 1; - - p2 = p4 - numXElements; - p1 = p3 - numXElements; - - Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]); - this.coords.Add(c); - if (viewerMode) - { - this.normals.Add(new Coord()); - this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y)); - } - - if (y > 0 && x > 0) - { - Face f1, f2; - - if (viewerMode) - { - f1 = new Face(p1, p4, p3, p1, p4, p3); - f1.uv1 = p1; - f1.uv2 = p4; - f1.uv3 = p3; - - f2 = new Face(p1, p2, p4, p1, p2, p4); - f2.uv1 = p1; - f2.uv2 = p2; - f2.uv3 = p4; - } - else - { - f1 = new Face(p1, p4, p3); - f2 = new Face(p1, p2, p4); - } - - this.faces.Add(f1); - this.faces.Add(f2); - } - } - } - - if (viewerMode) - calcVertexNormals(SculptType.plane, numXElements, numYElements); - } - -#if SYSTEM_DRAWING - public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) - { - _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false); - } - - public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) - { - _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert); - } -#endif - - public SculptMesh(List> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) - { - _SculptMesh(rows, sculptType, viewerMode, mirror, invert); - } - -#if SYSTEM_DRAWING - /// - /// converts a bitmap to a list of lists of coords, while scaling the image. - /// the scaling is done in floating point so as to allow for reduced vertex position - /// quantization as the position will be averaged between pixel values. this routine will - /// likely fail if the bitmap width and height are not powers of 2. - /// - /// - /// - /// - /// - private List> bitmap2Coords(Bitmap bitmap, int scale, bool mirror) - { - int numRows = bitmap.Height / scale; - int numCols = bitmap.Width / scale; - List> rows = new List>(numRows); - - float pixScale = 1.0f / (scale * scale); - pixScale /= 255; - - int imageX, imageY = 0; - - int rowNdx, colNdx; - - for (rowNdx = 0; rowNdx < numRows; rowNdx++) - { - List row = new List(numCols); - for (colNdx = 0; colNdx < numCols; colNdx++) - { - imageX = colNdx * scale; - int imageYStart = rowNdx * scale; - int imageYEnd = imageYStart + scale; - int imageXEnd = imageX + scale; - float rSum = 0.0f; - float gSum = 0.0f; - float bSum = 0.0f; - for (; imageX < imageXEnd; imageX++) - { - for (imageY = imageYStart; imageY < imageYEnd; imageY++) - { - Color c = bitmap.GetPixel(imageX, imageY); - if (c.A != 255) - { - bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B)); - c = bitmap.GetPixel(imageX, imageY); - } - rSum += c.R; - gSum += c.G; - bSum += c.B; - } - } - if (mirror) - row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); - else - row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); - - } - rows.Add(row); - } - return rows; - } - - private List> bitmap2CoordsSampled(Bitmap bitmap, int scale, bool mirror) - { - int numRows = bitmap.Height / scale; - int numCols = bitmap.Width / scale; - List> rows = new List>(numRows); - - float pixScale = 1.0f / 256.0f; - - int imageX, imageY = 0; - - int rowNdx, colNdx; - - for (rowNdx = 0; rowNdx <= numRows; rowNdx++) - { - List row = new List(numCols); - imageY = rowNdx * scale; - if (rowNdx == numRows) imageY--; - for (colNdx = 0; colNdx <= numCols; colNdx++) - { - imageX = colNdx * scale; - if (colNdx == numCols) imageX--; - - Color c = bitmap.GetPixel(imageX, imageY); - if (c.A != 255) - { - bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B)); - c = bitmap.GetPixel(imageX, imageY); - } - - if (mirror) - row.Add(new Coord(-(c.R * pixScale - 0.5f), c.G * pixScale - 0.5f, c.B * pixScale - 0.5f)); - else - row.Add(new Coord(c.R * pixScale - 0.5f, c.G * pixScale - 0.5f, c.B * pixScale - 0.5f)); - - } - rows.Add(row); - } - return rows; - } - - - void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) - { - _SculptMesh(new SculptMap(sculptBitmap, lod).ToRows(mirror), sculptType, viewerMode, mirror, invert); - } -#endif - - void _SculptMesh(List> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) - { - coords = new List(); - faces = new List(); - normals = new List(); - uvs = new List(); - - sculptType = (SculptType)(((int)sculptType) & 0x07); - - if (mirror) - invert = !invert; - - viewerFaces = new List(); - - int width = rows[0].Count; - - int p1, p2, p3, p4; - - int imageX, imageY; - - if (sculptType != SculptType.plane) - { - if (rows.Count % 2 == 0) - { - for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++) - rows[rowNdx].Add(rows[rowNdx][0]); - } - else - { - int lastIndex = rows[0].Count - 1; - - for (int i = 0; i < rows.Count; i++) - rows[i][0] = rows[i][lastIndex]; - } - } - - Coord topPole = rows[0][width / 2]; - Coord bottomPole = rows[rows.Count - 1][width / 2]; - - if (sculptType == SculptType.sphere) - { - if (rows.Count % 2 == 0) - { - int count = rows[0].Count; - List topPoleRow = new List(count); - List bottomPoleRow = new List(count); - - for (int i = 0; i < count; i++) - { - topPoleRow.Add(topPole); - bottomPoleRow.Add(bottomPole); - } - rows.Insert(0, topPoleRow); - rows.Add(bottomPoleRow); - } - else - { - int count = rows[0].Count; - - List topPoleRow = rows[0]; - List bottomPoleRow = rows[rows.Count - 1]; - - for (int i = 0; i < count; i++) - { - topPoleRow[i] = topPole; - bottomPoleRow[i] = bottomPole; - } - } - } - - if (sculptType == SculptType.torus) - rows.Add(rows[0]); - - int coordsDown = rows.Count; - int coordsAcross = rows[0].Count; -// int lastColumn = coordsAcross - 1; - - float widthUnit = 1.0f / (coordsAcross - 1); - float heightUnit = 1.0f / (coordsDown - 1); - - for (imageY = 0; imageY < coordsDown; imageY++) - { - int rowOffset = imageY * coordsAcross; - - for (imageX = 0; imageX < coordsAcross; imageX++) - { - /* - * p1-----p2 - * | \ f2 | - * | \ | - * | f1 \| - * p3-----p4 - */ - - p4 = rowOffset + imageX; - p3 = p4 - 1; - - p2 = p4 - coordsAcross; - p1 = p3 - coordsAcross; - - this.coords.Add(rows[imageY][imageX]); - if (viewerMode) - { - this.normals.Add(new Coord()); - this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); - } - - if (imageY > 0 && imageX > 0) - { - Face f1, f2; - - if (viewerMode) - { - if (invert) - { - f1 = new Face(p1, p4, p3, p1, p4, p3); - f1.uv1 = p1; - f1.uv2 = p4; - f1.uv3 = p3; - - f2 = new Face(p1, p2, p4, p1, p2, p4); - f2.uv1 = p1; - f2.uv2 = p2; - f2.uv3 = p4; - } - else - { - f1 = new Face(p1, p3, p4, p1, p3, p4); - f1.uv1 = p1; - f1.uv2 = p3; - f1.uv3 = p4; - - f2 = new Face(p1, p4, p2, p1, p4, p2); - f2.uv1 = p1; - f2.uv2 = p4; - f2.uv3 = p2; - } - } - else - { - if (invert) - { - f1 = new Face(p1, p4, p3); - f2 = new Face(p1, p2, p4); - } - else - { - f1 = new Face(p1, p3, p4); - f2 = new Face(p1, p4, p2); - } - } - - this.faces.Add(f1); - this.faces.Add(f2); - } - } - } - - if (viewerMode) - calcVertexNormals(sculptType, coordsAcross, coordsDown); - } - - /// - /// Duplicates a SculptMesh object. All object properties are copied by value, including lists. - /// - /// - public SculptMesh Copy() - { - return new SculptMesh(this); - } - - public SculptMesh(SculptMesh sm) - { - coords = new List(sm.coords); - faces = new List(sm.faces); - viewerFaces = new List(sm.viewerFaces); - normals = new List(sm.normals); - uvs = new List(sm.uvs); - } - - private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) - { // compute vertex normals by summing all the surface normals of all the triangles sharing - // each vertex and then normalizing - int numFaces = this.faces.Count; - for (int i = 0; i < numFaces; i++) - { - Face face = this.faces[i]; - Coord surfaceNormal = face.SurfaceNormal(this.coords); - this.normals[face.n1] += surfaceNormal; - this.normals[face.n2] += surfaceNormal; - this.normals[face.n3] += surfaceNormal; - } - - int numNormals = this.normals.Count; - for (int i = 0; i < numNormals; i++) - this.normals[i] = this.normals[i].Normalize(); - - if (sculptType != SculptType.plane) - { // blend the vertex normals at the cylinder seam - for (int y = 0; y < ySize; y++) - { - int rowOffset = y * xSize; - - this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize(); - } - } - - foreach (Face face in this.faces) - { - ViewerFace vf = new ViewerFace(0); - vf.v1 = this.coords[face.v1]; - vf.v2 = this.coords[face.v2]; - vf.v3 = this.coords[face.v3]; - - vf.coordIndex1 = face.v1; - vf.coordIndex2 = face.v2; - vf.coordIndex3 = face.v3; - - vf.n1 = this.normals[face.n1]; - vf.n2 = this.normals[face.n2]; - vf.n3 = this.normals[face.n3]; - - vf.uv1 = this.uvs[face.uv1]; - vf.uv2 = this.uvs[face.uv2]; - vf.uv3 = this.uvs[face.uv3]; - - this.viewerFaces.Add(vf); - } - } - - /// - /// Adds a value to each XYZ vertex coordinate in the mesh - /// - /// - /// - /// - public void AddPos(float x, float y, float z) - { - int i; - int numVerts = this.coords.Count; - Coord vert; - - for (i = 0; i < numVerts; i++) - { - vert = this.coords[i]; - vert.X += x; - vert.Y += y; - vert.Z += z; - this.coords[i] = vert; - } - - if (this.viewerFaces != null) - { - int numViewerFaces = this.viewerFaces.Count; - - for (i = 0; i < numViewerFaces; i++) - { - ViewerFace v = this.viewerFaces[i]; - v.AddPos(x, y, z); - this.viewerFaces[i] = v; - } - } - } - - /// - /// Rotates the mesh - /// - /// - public void AddRot(Quat q) - { - int i; - int numVerts = this.coords.Count; - - for (i = 0; i < numVerts; i++) - this.coords[i] *= q; - - int numNormals = this.normals.Count; - for (i = 0; i < numNormals; i++) - this.normals[i] *= q; - - if (this.viewerFaces != null) - { - int numViewerFaces = this.viewerFaces.Count; - - for (i = 0; i < numViewerFaces; i++) - { - ViewerFace v = this.viewerFaces[i]; - v.v1 *= q; - v.v2 *= q; - v.v3 *= q; - - v.n1 *= q; - v.n2 *= q; - v.n3 *= q; - - this.viewerFaces[i] = v; - } - } - } - - public void Scale(float x, float y, float z) - { - int i; - int numVerts = this.coords.Count; - - Coord m = new Coord(x, y, z); - for (i = 0; i < numVerts; i++) - this.coords[i] *= m; - - if (this.viewerFaces != null) - { - int numViewerFaces = this.viewerFaces.Count; - for (i = 0; i < numViewerFaces; i++) - { - ViewerFace v = this.viewerFaces[i]; - v.v1 *= m; - v.v2 *= m; - v.v3 *= m; - this.viewerFaces[i] = v; - } - } - } - - public void DumpRaw(String path, String name, String title) - { - if (path == null) - return; - String fileName = name + "_" + title + ".raw"; - String completePath = System.IO.Path.Combine(path, fileName); - StreamWriter sw = new StreamWriter(completePath); - - for (int i = 0; i < this.faces.Count; i++) - { - string s = this.coords[this.faces[i].v1].ToString(); - s += " " + this.coords[this.faces[i].v2].ToString(); - s += " " + this.coords[this.faces[i].v3].ToString(); - - sw.WriteLine(s); - } - - sw.Close(); - } - } -} diff --git a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs deleted file mode 100644 index 3c4f06a..0000000 --- a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Reflection; -using System.Runtime.InteropServices; - -// Information about this assembly is defined by the following -// attributes. -// -// change them to the information which is associated with the assembly -// you compile. - -[assembly : AssemblyTitle("OdePlugin")] -[assembly : AssemblyDescription("")] -[assembly : AssemblyConfiguration("")] -[assembly : AssemblyCompany("http://opensimulator.org")] -[assembly : AssemblyProduct("OdePlugin")] -[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] -[assembly : AssemblyTrademark("")] -[assembly : AssemblyCulture("")] - -// This sets the default COM visibility of types in the assembly to invisible. -// If you need to expose a type to COM, use [ComVisible(true)] on that type. - -[assembly : ComVisible(false)] - -// The assembly version has following format : -// -// Major.Minor.Build.Revision -// -// You can specify all values by your own or you can build default build and revision -// numbers with the '*' character (the default): - -[assembly : AssemblyVersion("0.7.5.*")] diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs deleted file mode 100644 index 319f6ab..0000000 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ /dev/null @@ -1,1411 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using OpenMetaverse; -using Ode.NET; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; -using log4net; - -namespace OpenSim.Region.Physics.OdePlugin -{ - /// - /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves. - /// - public enum dParam : int - { - LowStop = 0, - HiStop = 1, - Vel = 2, - FMax = 3, - FudgeFactor = 4, - Bounce = 5, - CFM = 6, - StopERP = 7, - StopCFM = 8, - LoStop2 = 256, - HiStop2 = 257, - Vel2 = 258, - FMax2 = 259, - StopERP2 = 7 + 256, - StopCFM2 = 8 + 256, - LoStop3 = 512, - HiStop3 = 513, - Vel3 = 514, - FMax3 = 515, - StopERP3 = 7 + 512, - StopCFM3 = 8 + 512 - } - - public class OdeCharacter : PhysicsActor - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private Vector3 _position; - private d.Vector3 _zeroPosition; - private bool _zeroFlag = false; - private bool m_lastUpdateSent = false; - private Vector3 _velocity; - private Vector3 m_taintTargetVelocity; - private Vector3 _target_velocity; - private Vector3 _acceleration; - private Vector3 m_rotationalVelocity; - private float m_mass = 80f; - private float m_density = 60f; - private bool m_pidControllerActive = true; - private float PID_D = 800.0f; - private float PID_P = 900.0f; - //private static float POSTURE_SERVO = 10000.0f; - private float CAPSULE_RADIUS = 0.37f; - private float CAPSULE_LENGTH = 2.140599f; - private float m_tensor = 3800000f; -// private float heightFudgeFactor = 0.52f; - private float walkDivisor = 1.3f; - private float runDivisor = 0.8f; - private bool flying = false; - private bool m_iscolliding = false; - private bool m_iscollidingGround = false; - private bool m_wascolliding = false; - private bool m_wascollidingGround = false; - private bool m_iscollidingObj = false; - private bool m_alwaysRun = false; - private bool m_hackSentFall = false; - private bool m_hackSentFly = false; - private int m_requestedUpdateFrequency = 0; - private Vector3 m_taintPosition; - internal bool m_avatarplanted = false; - /// - /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force - /// while calculatios are going on - /// - private Vector3 m_taintForce; - - // taints and their non-tainted counterparts - private bool m_isPhysical = false; // the current physical status - private bool m_tainted_isPhysical = false; // set when the physical status is tainted (false=not existing in physics engine, true=existing) - internal float MinimumGroundFlightOffset = 3f; - - private float m_tainted_CAPSULE_LENGTH; // set when the capsule length changes. - - /// - /// Base movement for calculating tilt. - /// - private float m_tiltBaseMovement = (float)Math.Sqrt(2); - - /// - /// Used to introduce a fixed tilt because a straight-up capsule falls through terrain, probably a bug in terrain collider - /// - private float m_tiltMagnitudeWhenProjectedOnXYPlane = 0.1131371f; - - private float m_buoyancy = 0f; - - // private CollisionLocker ode; - private bool[] m_colliderarr = new bool[11]; - private bool[] m_colliderGroundarr = new bool[11]; - - // Default we're a Character - private CollisionCategories m_collisionCategories = (CollisionCategories.Character); - - // Default, Collide with Other Geometries, spaces, bodies and characters. - private CollisionCategories m_collisionFlags = (CollisionCategories.Geom - | CollisionCategories.Space - | CollisionCategories.Body - | CollisionCategories.Character - | CollisionCategories.Land); - /// - /// Body for dynamics simulation - /// - internal IntPtr Body { get; private set; } - - private OdeScene _parent_scene; - - /// - /// Collision geometry - /// - internal IntPtr Shell { get; private set; } - - private IntPtr Amotor = IntPtr.Zero; - private d.Mass ShellMass; - - private int m_eventsubscription = 0; - private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate(); - - // unique UUID of this character object - internal UUID m_uuid { get; private set; } - internal bool bad = false; - - /// - /// ODE Avatar. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// Only used right now to return information to LSL. Not actually used to set mass in ODE! - /// - /// - /// - public OdeCharacter( - String avName, OdeScene parent_scene, Vector3 pos, Vector3 size, float pid_d, float pid_p, - float capsule_radius, float tensor, float density, - float walk_divisor, float rundivisor) - { - m_uuid = UUID.Random(); - - if (pos.IsFinite()) - { - if (pos.Z > 9999999f) - { - pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5; - } - if (pos.Z < -90000f) - { - pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5; - } - - _position = pos; - m_taintPosition = pos; - } - else - { - _position - = new Vector3( - (float)_parent_scene.WorldExtents.X * 0.5f, - (float)_parent_scene.WorldExtents.Y * 0.5f, - parent_scene.GetTerrainHeightAtXY(128f, 128f) + 10f); - m_taintPosition = _position; - - m_log.WarnFormat("[ODE CHARACTER]: Got NaN Position on Character Create for {0}", avName); - } - - _parent_scene = parent_scene; - - PID_D = pid_d; - PID_P = pid_p; - CAPSULE_RADIUS = capsule_radius; - m_tensor = tensor; - m_density = density; -// heightFudgeFactor = height_fudge_factor; - walkDivisor = walk_divisor; - runDivisor = rundivisor; - - // m_StandUpRotation = - // new d.Matrix3(0.5f, 0.7071068f, 0.5f, -0.7071068f, 0f, 0.7071068f, 0.5f, -0.7071068f, - // 0.5f); - - // We can set taint and actual to be the same here, since the entire character will be set up when the - // m_tainted_isPhysical is processed. - SetTaintedCapsuleLength(size); - CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH; - - m_isPhysical = false; // current status: no ODE information exists - m_tainted_isPhysical = true; // new tainted status: need to create ODE information - - _parent_scene.AddPhysicsActorTaint(this); - - Name = avName; - } - - public override int PhysicsActorType - { - get { return (int) ActorTypes.Agent; } - set { return; } - } - - /// - /// If this is set, the avatar will move faster - /// - public override bool SetAlwaysRun - { - get { return m_alwaysRun; } - set { m_alwaysRun = value; } - } - - public override bool Grabbed - { - set { return; } - } - - public override bool Selected - { - set { return; } - } - - public override float Buoyancy - { - get { return m_buoyancy; } - set { m_buoyancy = value; } - } - - public override bool FloatOnWater - { - set { return; } - } - - public override bool IsPhysical - { - get { return false; } - set { return; } - } - - public override bool ThrottleUpdates - { - get { return false; } - set { return; } - } - - public override bool Flying - { - get { return flying; } - set - { - flying = value; -// m_log.DebugFormat("[ODE CHARACTER]: Set OdeCharacter Flying to {0}", flying); - } - } - - /// - /// Returns if the avatar is colliding in general. - /// This includes the ground and objects and avatar. - /// - public override bool IsColliding - { - get { return m_iscolliding; } - set - { - int i; - int truecount = 0; - int falsecount = 0; - - if (m_colliderarr.Length >= 10) - { - for (i = 0; i < 10; i++) - { - m_colliderarr[i] = m_colliderarr[i + 1]; - } - } - m_colliderarr[10] = value; - - for (i = 0; i < 11; i++) - { - if (m_colliderarr[i]) - { - truecount++; - } - else - { - falsecount++; - } - } - - // Equal truecounts and false counts means we're colliding with something. - - if (falsecount > 1.2*truecount) - { - m_iscolliding = false; - } - else - { - m_iscolliding = true; - } - - if (m_wascolliding != m_iscolliding) - { - //base.SendCollisionUpdate(new CollisionEventUpdate()); - } - - m_wascolliding = m_iscolliding; - } - } - - /// - /// Returns if an avatar is colliding with the ground - /// - public override bool CollidingGround - { - get { return m_iscollidingGround; } - set - { - // Collisions against the ground are not really reliable - // So, to get a consistant value we have to average the current result over time - // Currently we use 1 second = 10 calls to this. - int i; - int truecount = 0; - int falsecount = 0; - - if (m_colliderGroundarr.Length >= 10) - { - for (i = 0; i < 10; i++) - { - m_colliderGroundarr[i] = m_colliderGroundarr[i + 1]; - } - } - m_colliderGroundarr[10] = value; - - for (i = 0; i < 11; i++) - { - if (m_colliderGroundarr[i]) - { - truecount++; - } - else - { - falsecount++; - } - } - - // Equal truecounts and false counts means we're colliding with something. - - if (falsecount > 1.2*truecount) - { - m_iscollidingGround = false; - } - else - { - m_iscollidingGround = true; - } - if (m_wascollidingGround != m_iscollidingGround) - { - //base.SendCollisionUpdate(new CollisionEventUpdate()); - } - m_wascollidingGround = m_iscollidingGround; - } - } - - /// - /// Returns if the avatar is colliding with an object - /// - public override bool CollidingObj - { - get { return m_iscollidingObj; } - set - { - m_iscollidingObj = value; - if (value && !m_avatarplanted) - m_pidControllerActive = false; - else - m_pidControllerActive = true; - } - } - - /// - /// turn the PID controller on or off. - /// The PID Controller will turn on all by itself in many situations - /// - /// - public void SetPidStatus(bool status) - { - m_pidControllerActive = status; - } - - public override bool Stopped - { - get { return _zeroFlag; } - } - - /// - /// This 'puts' an avatar somewhere in the physics space. - /// Not really a good choice unless you 'know' it's a good - /// spot otherwise you're likely to orbit the avatar. - /// - public override Vector3 Position - { - get { return _position; } - set - { - if (Body == IntPtr.Zero || Shell == IntPtr.Zero) - { - if (value.IsFinite()) - { - if (value.Z > 9999999f) - { - value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5; - } - if (value.Z < -90000f) - { - value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5; - } - - m_taintPosition = value; - _parent_scene.AddPhysicsActorTaint(this); - } - else - { - m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Position from Scene on character {0}", Name); - } - } - } - } - - public override Vector3 RotationalVelocity - { - get { return m_rotationalVelocity; } - set { m_rotationalVelocity = value; } - } - - /// - /// This property sets the height of the avatar only. We use the height to make sure the avatar stands up straight - /// and use it to offset landings properly - /// - public override Vector3 Size - { - get { return new Vector3(CAPSULE_RADIUS * 2, CAPSULE_RADIUS * 2, CAPSULE_LENGTH); } - set - { - SetTaintedCapsuleLength(value); - - // If we reset velocity here, then an avatar stalls when it crosses a border for the first time - // (as the height of the new root agent is set). -// Velocity = Vector3.Zero; - - _parent_scene.AddPhysicsActorTaint(this); - } - } - - private void SetTaintedCapsuleLength(Vector3 size) - { - if (size.IsFinite()) - { - m_pidControllerActive = true; - - m_tainted_CAPSULE_LENGTH = (size.Z * 1.15f) - CAPSULE_RADIUS * 2.0f; -// m_log.Info("[ODE CHARACTER]: " + CAPSULE_LENGTH); - } - else - { - m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Size for {0} in {1}", Name, _parent_scene.Name); - } - } - - private void AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3 movementVector) - { - movementVector.Z = 0f; - float magnitude = (float)Math.Sqrt((double)(movementVector.X * movementVector.X + movementVector.Y * movementVector.Y)); - if (magnitude < 0.1f) return; - - // normalize the velocity vector - float invMagnitude = 1.0f / magnitude; - movementVector.X *= invMagnitude; - movementVector.Y *= invMagnitude; - - // if we change the capsule heading too often, the capsule can fall down - // therefore we snap movement vector to just 1 of 4 predefined directions (ne, nw, se, sw), - // meaning only 4 possible capsule tilt orientations - if (movementVector.X > 0) - { - // east - if (movementVector.Y > 0) - { - // northeast - movementVector.X = m_tiltBaseMovement; - movementVector.Y = m_tiltBaseMovement; - } - else - { - // southeast - movementVector.X = m_tiltBaseMovement; - movementVector.Y = -m_tiltBaseMovement; - } - } - else - { - // west - if (movementVector.Y > 0) - { - // northwest - movementVector.X = -m_tiltBaseMovement; - movementVector.Y = m_tiltBaseMovement; - } - else - { - // southwest - movementVector.X = -m_tiltBaseMovement; - movementVector.Y = -m_tiltBaseMovement; - } - } - - // movementVector.Z is zero - - // calculate tilt components based on desired amount of tilt and current (snapped) heading. - // the "-" sign is to force the tilt to be OPPOSITE the direction of movement. - float xTiltComponent = -movementVector.X * m_tiltMagnitudeWhenProjectedOnXYPlane; - float yTiltComponent = -movementVector.Y * m_tiltMagnitudeWhenProjectedOnXYPlane; - - //m_log.Debug("[ODE CHARACTER]: changing avatar tilt"); - d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, xTiltComponent); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, xTiltComponent); // must be same as lowstop, else a different, spurious tilt is introduced - d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, yTiltComponent); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, yTiltComponent); // same as lowstop - d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop - } - - /// - /// Uses the capped cyllinder volume formula to calculate the avatar's mass. - /// This may be used in calculations in the scene/scenepresence - /// - public override float Mass - { - get - { - float AVvolume = (float)(Math.PI * Math.Pow(CAPSULE_RADIUS, 2) * CAPSULE_LENGTH); - return m_density * AVvolume; - } - } - - public override void link(PhysicsActor obj) {} - - public override void delink() {} - - public override void LockAngularMotion(Vector3 axis) {} - -// This code is very useful. Written by DanX0r. We're just not using it right now. -// Commented out to prevent a warning. -// -// private void standupStraight() -// { -// // The purpose of this routine here is to quickly stabilize the Body while it's popped up in the air. -// // The amotor needs a few seconds to stabilize so without it, the avatar shoots up sky high when you -// // change appearance and when you enter the simulator -// // After this routine is done, the amotor stabilizes much quicker -// d.Vector3 feet; -// d.Vector3 head; -// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet); -// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head); -// float posture = head.Z - feet.Z; - -// // restoring force proportional to lack of posture: -// float servo = (2.5f - posture) * POSTURE_SERVO; -// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f); -// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f); -// //d.Matrix3 bodyrotation = d.BodyGetRotation(Body); -// //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyFArotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22); -// } - - public override Vector3 Force - { - get { return _target_velocity; } - set { return; } - } - - public override int VehicleType - { - get { return 0; } - set { return; } - } - - public override void VehicleFloatParam(int param, float value) - { - } - - public override void VehicleVectorParam(int param, Vector3 value) - { - } - - public override void VehicleRotationParam(int param, Quaternion rotation) - { - } - - public override void VehicleFlags(int param, bool remove) - { - } - - public override void SetVolumeDetect(int param) - { - } - - public override Vector3 CenterOfMass - { - get { return Vector3.Zero; } - } - - public override Vector3 GeometricCenter - { - get { return Vector3.Zero; } - } - - public override PrimitiveBaseShape Shape - { - set { return; } - } - - public override Vector3 TargetVelocity - { - get - { - return m_taintTargetVelocity; - } - - set - { - Velocity = value; - } - } - - - public override Vector3 Velocity - { - get - { - // There's a problem with Vector3.Zero! Don't Use it Here! - if (_zeroFlag) - return Vector3.Zero; - m_lastUpdateSent = false; - return _velocity; - } - - set - { - if (value.IsFinite()) - { - m_pidControllerActive = true; - m_taintTargetVelocity = value; - _parent_scene.AddPhysicsActorTaint(this); - } - else - { - m_log.WarnFormat("[ODE CHARACTER]: Got a NaN velocity from Scene for {0}", Name); - } - -// m_log.DebugFormat("[PHYSICS]: Set target velocity of {0}", m_taintTargetVelocity); - } - } - - public override Vector3 Torque - { - get { return Vector3.Zero; } - set { return; } - } - - public override float CollisionScore - { - get { return 0f; } - set { } - } - - public override bool Kinematic - { - get { return false; } - set { } - } - - public override Quaternion Orientation - { - get { return Quaternion.Identity; } - set { - //Matrix3 or = Orientation.ToRotationMatrix(); - //d.Matrix3 ord = new d.Matrix3(or.m00, or.m10, or.m20, or.m01, or.m11, or.m21, or.m02, or.m12, or.m22); - //d.BodySetRotation(Body, ref ord); - } - } - - public override Vector3 Acceleration - { - get { return _acceleration; } - set { _acceleration = value; } - } - - /// - /// Adds the force supplied to the Target Velocity - /// The PID controller takes this target velocity and tries to make it a reality - /// - /// - public override void AddForce(Vector3 force, bool pushforce) - { - if (force.IsFinite()) - { - if (pushforce) - { - m_pidControllerActive = false; - force *= 100f; - m_taintForce += force; - _parent_scene.AddPhysicsActorTaint(this); - - // If uncommented, things get pushed off world - // - // m_log.Debug("Push!"); - // m_taintTargetVelocity.X += force.X; - // m_taintTargetVelocity.Y += force.Y; - // m_taintTargetVelocity.Z += force.Z; - } - else - { - m_pidControllerActive = true; - m_taintTargetVelocity += force; - } - } - else - { - m_log.WarnFormat("[ODE CHARACTER]: Got a NaN force applied to {0}", Name); - } - //m_lastUpdateSent = false; - } - - public override void AddAngularForce(Vector3 force, bool pushforce) - { - } - - public override void SetMomentum(Vector3 momentum) - { - } - - /// - /// Called from Simulate - /// This is the avatar's movement control + PID Controller - /// - /// The character will be added to this list if there is something wrong (non-finite - /// position or velocity). - /// - internal void Move(List defects) - { - // no lock; for now it's only called from within Simulate() - - // If the PID Controller isn't active then we set our force - // calculating base velocity to the current position - - if (Body == IntPtr.Zero) - return; - - if (m_pidControllerActive == false) - { - _zeroPosition = d.BodyGetPosition(Body); - } - //PidStatus = true; - - d.Vector3 localpos = d.BodyGetPosition(Body); - Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z); - - if (!localPos.IsFinite()) - { - m_log.WarnFormat( - "[ODE CHARACTER]: Avatar position of {0} for {1} is non-finite! Removing from physics scene.", - localPos, Name); - - defects.Add(this); - - return; - } - - Vector3 vec = Vector3.Zero; - d.Vector3 vel = d.BodyGetLinearVel(Body); - -// m_log.DebugFormat( -// "[ODE CHARACTER]: Current velocity in Move() is <{0},{1},{2}>, target {3} for {4}", -// vel.X, vel.Y, vel.Z, _target_velocity, Name); - - float movementdivisor = 1f; - - if (!m_alwaysRun) - { - movementdivisor = walkDivisor; - } - else - { - movementdivisor = runDivisor; - } - - // if velocity is zero, use position control; otherwise, velocity control - if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding) - { - // keep track of where we stopped. No more slippin' & slidin' - if (!_zeroFlag) - { - _zeroFlag = true; - _zeroPosition = d.BodyGetPosition(Body); - } - - if (m_pidControllerActive) - { - // We only want to deactivate the PID Controller if we think we want to have our surrogate - // react to the physics scene by moving it's position. - // Avatar to Avatar collisions - // Prim to avatar collisions - - d.Vector3 pos = d.BodyGetPosition(Body); - vec.X = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2); - vec.Y = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y)* (PID_P * 2); - if (flying) - { - vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P; - } - } - //PidStatus = true; - } - else - { - m_pidControllerActive = true; - _zeroFlag = false; - if (m_iscolliding && !flying) - { - // We're standing on something - vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D); - vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D); - } - else if (m_iscolliding && flying) - { - // We're flying and colliding with something - vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 16); - vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 16); - } - else if (!m_iscolliding && flying) - { - // we're in mid air suspended - vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 6); - vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 6); - -// m_log.DebugFormat( -// "[ODE CHARACTER]: !m_iscolliding && flying, vec {0}, _target_velocity {1}, movementdivisor {2}, vel {3}", -// vec, _target_velocity, movementdivisor, vel); - } - - if (m_iscolliding && !flying && _target_velocity.Z > 0.0f) - { - // We're colliding with something and we're not flying but we're moving - // This means we're walking or running. - d.Vector3 pos = d.BodyGetPosition(Body); - vec.Z = (_target_velocity.Z - vel.Z)*PID_D + (_zeroPosition.Z - pos.Z)*PID_P; - if (_target_velocity.X > 0) - { - vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D; - } - if (_target_velocity.Y > 0) - { - vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; - } - } - else if (!m_iscolliding && !flying) - { - // we're not colliding and we're not flying so that means we're falling! - // m_iscolliding includes collisions with the ground. - - // d.Vector3 pos = d.BodyGetPosition(Body); - if (_target_velocity.X > 0) - { - vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D; - } - if (_target_velocity.Y > 0) - { - vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; - } - } - - if (flying) - { - // This also acts as anti-gravity so that we hover when flying rather than fall. - vec.Z = (_target_velocity.Z - vel.Z) * (PID_D); - } - } - - if (flying) - { - // Anti-gravity so that we hover when flying rather than fall. - vec.Z += ((-1 * _parent_scene.gravityz) * m_mass); - - //Added for auto fly height. Kitto Flora - //d.Vector3 pos = d.BodyGetPosition(Body); - float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset; - - if (_position.Z < target_altitude) - { - vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f; - } - // end add Kitto Flora - } - - if (vec.IsFinite()) - { - // Apply the total force acting on this avatar - d.BodyAddForce(Body, vec.X, vec.Y, vec.Z); - - if (!_zeroFlag) - AlignAvatarTiltWithCurrentDirectionOfMovement(vec); - } - else - { - m_log.WarnFormat( - "[ODE CHARACTER]: Got a NaN force vector {0} in Move() for {1}. Removing character from physics scene.", - vec, Name); - - defects.Add(this); - - return; - } - - d.Vector3 newVel = d.BodyGetLinearVel(Body); - if (newVel.X >= 256 || newVel.X <= 256 || newVel.Y >= 256 || newVel.Y <= 256 || newVel.Z >= 256 || newVel.Z <= 256) - { -// m_log.DebugFormat( -// "[ODE CHARACTER]: Limiting falling velocity from {0} to {1} for {2}", newVel.Z, -9.8, Name); - - newVel.X = Util.Clamp(newVel.X, -255f, 255f); - newVel.Y = Util.Clamp(newVel.Y, -255f, 255f); - - if (!flying) - newVel.Z - = Util.Clamp( - newVel.Z, -_parent_scene.AvatarTerminalVelocity, _parent_scene.AvatarTerminalVelocity); - else - newVel.Z = Util.Clamp(newVel.Z, -255f, 255f); - - d.BodySetLinearVel(Body, newVel.X, newVel.Y, newVel.Z); - } - } - - /// - /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. - /// - /// The character will be added to this list if there is something wrong (non-finite - /// position or velocity). - /// - internal void UpdatePositionAndVelocity(List defects) - { - // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! - d.Vector3 newPos; - try - { - newPos = d.BodyGetPosition(Body); - } - catch (NullReferenceException) - { - bad = true; - defects.Add(this); - newPos = new d.Vector3(_position.X, _position.Y, _position.Z); - base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! - m_log.WarnFormat("[ODE CHARACTER]: Avatar Null reference for Avatar {0}, physical actor {1}", Name, m_uuid); - - return; - } - - // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) - if (newPos.X < 0.0f) newPos.X = 0.0f; - if (newPos.Y < 0.0f) newPos.Y = 0.0f; - if (newPos.X > (int)_parent_scene.WorldExtents.X - 0.05f) newPos.X = (int)_parent_scene.WorldExtents.X - 0.05f; - if (newPos.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) newPos.Y = (int)_parent_scene.WorldExtents.Y - 0.05f; - - _position.X = newPos.X; - _position.Y = newPos.Y; - _position.Z = newPos.Z; - - // I think we need to update the taintPosition too -- Diva 12/24/10 - m_taintPosition = _position; - - // Did we move last? = zeroflag - // This helps keep us from sliding all over - - if (_zeroFlag) - { - _velocity = Vector3.Zero; - - // Did we send out the 'stopped' message? - if (!m_lastUpdateSent) - { - m_lastUpdateSent = true; - //base.RequestPhysicsterseUpdate(); - } - } - else - { - m_lastUpdateSent = false; - d.Vector3 newVelocity; - - try - { - newVelocity = d.BodyGetLinearVel(Body); - } - catch (NullReferenceException) - { - newVelocity.X = _velocity.X; - newVelocity.Y = _velocity.Y; - newVelocity.Z = _velocity.Z; - } - - _velocity.X = newVelocity.X; - _velocity.Y = newVelocity.Y; - _velocity.Z = newVelocity.Z; - - if (_velocity.Z < -6 && !m_hackSentFall) - { - m_hackSentFall = true; - m_pidControllerActive = false; - } - else if (flying && !m_hackSentFly) - { - //m_hackSentFly = true; - //base.SendCollisionUpdate(new CollisionEventUpdate()); - } - else - { - m_hackSentFly = false; - m_hackSentFall = false; - } - } - } - - /// - /// This creates the Avatar's physical Surrogate in ODE at the position supplied - /// - /// - /// WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access - /// to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only - /// place that is safe to call this routine AvatarGeomAndBodyCreation. - /// - /// - /// - /// - /// - private void CreateOdeStructures(float npositionX, float npositionY, float npositionZ, float tensor) - { - if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero)) - { - m_log.ErrorFormat( - "[ODE CHARACTER]: Creating ODE structures for {0} even though some already exist. Shell = {1}, Body = {2}, Amotor = {3}", - Name, Shell, Body, Amotor); - } - - int dAMotorEuler = 1; -// _parent_scene.waitForSpaceUnlock(_parent_scene.space); - if (CAPSULE_LENGTH <= 0) - { - m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); - CAPSULE_LENGTH = 0.01f; - } - - if (CAPSULE_RADIUS <= 0) - { - m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); - CAPSULE_RADIUS = 0.01f; - } - -// lock (OdeScene.UniversalColliderSyncObject) - Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH); - - d.GeomSetCategoryBits(Shell, (int)m_collisionCategories); - d.GeomSetCollideBits(Shell, (int)m_collisionFlags); - - d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH); - Body = d.BodyCreate(_parent_scene.world); - d.BodySetPosition(Body, npositionX, npositionY, npositionZ); - - _position.X = npositionX; - _position.Y = npositionY; - _position.Z = npositionZ; - - m_taintPosition = _position; - - d.BodySetMass(Body, ref ShellMass); - d.Matrix3 m_caprot; - // 90 Stand up on the cap of the capped cyllinder - if (_parent_scene.IsAvCapsuleTilted) - { - d.RFromAxisAndAngle(out m_caprot, 1, 0, 1, (float)(Math.PI / 2)); - } - else - { - d.RFromAxisAndAngle(out m_caprot, 0, 0, 1, (float)(Math.PI / 2)); - } - - d.GeomSetRotation(Shell, ref m_caprot); - d.BodySetRotation(Body, ref m_caprot); - - d.GeomSetBody(Shell, Body); - - // The purpose of the AMotor here is to keep the avatar's physical - // surrogate from rotating while moving - Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero); - d.JointAttach(Amotor, Body, IntPtr.Zero); - d.JointSetAMotorMode(Amotor, dAMotorEuler); - d.JointSetAMotorNumAxes(Amotor, 3); - d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0); - d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0); - d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1); - d.JointSetAMotorAngle(Amotor, 0, 0); - d.JointSetAMotorAngle(Amotor, 1, 0); - d.JointSetAMotorAngle(Amotor, 2, 0); - - // These lowstops and high stops are effectively (no wiggle room) - if (_parent_scene.IsAvCapsuleTilted) - { - d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f); - d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f); - d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f); - } - else - { - #region Documentation of capsule motor LowStop and HighStop parameters - // Intentionally introduce some tilt into the capsule by setting - // the motor stops to small epsilon values. This small tilt prevents - // the capsule from falling into the terrain; a straight-up capsule - // (with -0..0 motor stops) falls into the terrain for reasons yet - // to be comprehended in their entirety. - #endregion - AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3.Zero); - d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0.08f); - d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f); - d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0.08f); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.08f); // must be same as lowstop, else a different, spurious tilt is introduced - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.08f); // same as lowstop - } - - // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the - // capped cyllinder will fall over - d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f); - d.JointSetAMotorParam(Amotor, (int)dParam.FMax, tensor); - - //d.Matrix3 bodyrotation = d.BodyGetRotation(Body); - //d.QfromR( - //d.Matrix3 checkrotation = new d.Matrix3(0.7071068,0.5, -0.7071068, - // - //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22); - //standupStraight(); - - _parent_scene.geom_name_map[Shell] = Name; - _parent_scene.actor_name_map[Shell] = this; - } - - /// - /// Cleanup the things we use in the scene. - /// - internal void Destroy() - { - m_tainted_isPhysical = false; - _parent_scene.AddPhysicsActorTaint(this); - } - - /// - /// Used internally to destroy the ODE structures associated with this character. - /// - internal void DestroyOdeStructures() - { - // Create avatar capsule and related ODE data - if (Shell == IntPtr.Zero || Body == IntPtr.Zero || Amotor == IntPtr.Zero) - { - m_log.ErrorFormat( - "[ODE CHARACTER]: Destroying ODE structures for {0} even though some are already null. Shell = {1}, Body = {2}, Amotor = {3}", - Name, Shell, Body, Amotor); - } - - // destroy avatar capsule and related ODE data - if (Amotor != IntPtr.Zero) - { - // Kill the Amotor - d.JointDestroy(Amotor); - Amotor = IntPtr.Zero; - } - - //kill the Geometry -// _parent_scene.waitForSpaceUnlock(_parent_scene.space); - - if (Body != IntPtr.Zero) - { - //kill the body - d.BodyDestroy(Body); - Body = IntPtr.Zero; - } - - if (Shell != IntPtr.Zero) - { -// lock (OdeScene.UniversalColliderSyncObject) - d.GeomDestroy(Shell); - - _parent_scene.geom_name_map.Remove(Shell); - _parent_scene.actor_name_map.Remove(Shell); - - Shell = IntPtr.Zero; - } - } - - public override void CrossingFailure() - { - } - - public override Vector3 PIDTarget { set { return; } } - public override bool PIDActive { set { return; } } - public override float PIDTau { set { return; } } - - public override float PIDHoverHeight { set { return; } } - public override bool PIDHoverActive { set { return; } } - public override PIDHoverType PIDHoverType { set { return; } } - public override float PIDHoverTau { set { return; } } - - public override Quaternion APIDTarget{ set { return; } } - - public override bool APIDActive{ set { return; } } - - public override float APIDStrength{ set { return; } } - - public override float APIDDamping{ set { return; } } - - public override void SubscribeEvents(int ms) - { - m_requestedUpdateFrequency = ms; - m_eventsubscription = ms; - - // Don't clear collision event reporting here. This is called directly from scene code and so can lead - // to a race condition with the simulate loop - - _parent_scene.AddCollisionEventReporting(this); - } - - public override void UnSubscribeEvents() - { - _parent_scene.RemoveCollisionEventReporting(this); - - // Don't clear collision event reporting here. This is called directly from scene code and so can lead - // to a race condition with the simulate loop - - m_requestedUpdateFrequency = 0; - m_eventsubscription = 0; - } - - internal void AddCollisionEvent(uint CollidedWith, ContactPoint contact) - { - if (m_eventsubscription > 0) - { -// m_log.DebugFormat( -// "[PHYSICS]: Adding collision event for {0}, collidedWith {1}, contact {2}", "", CollidedWith, contact); - - CollisionEventsThisFrame.AddCollider(CollidedWith, contact); - } - } - - internal void SendCollisions() - { - if (m_eventsubscription > m_requestedUpdateFrequency) - { - base.SendCollisionUpdate(CollisionEventsThisFrame); - - CollisionEventsThisFrame.Clear(); - m_eventsubscription = 0; - } - } - - public override bool SubscribedEvents() - { - if (m_eventsubscription > 0) - return true; - return false; - } - - internal void ProcessTaints() - { - if (m_taintPosition != _position) - { - if (Body != IntPtr.Zero) - { - d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z); - _position = m_taintPosition; - } - } - - if (m_taintForce != Vector3.Zero) - { - if (Body != IntPtr.Zero) - { - // FIXME: This is not a good solution since it's subject to a race condition if a force is another - // thread sets a new force while we're in this loop (since it could be obliterated by - // m_taintForce = Vector3.Zero. Need to lock ProcessTaints() when we set a new tainted force. - d.BodyAddForce(Body, m_taintForce.X, m_taintForce.Y, m_taintForce.Z); - } - - m_taintForce = Vector3.Zero; - } - - if (m_taintTargetVelocity != _target_velocity) - _target_velocity = m_taintTargetVelocity; - - if (m_tainted_isPhysical != m_isPhysical) - { - if (m_tainted_isPhysical) - { - CreateOdeStructures(_position.X, _position.Y, _position.Z, m_tensor); - _parent_scene.AddCharacter(this); - } - else - { - _parent_scene.RemoveCharacter(this); - DestroyOdeStructures(); - } - - m_isPhysical = m_tainted_isPhysical; - } - - if (m_tainted_CAPSULE_LENGTH != CAPSULE_LENGTH) - { - if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero) - { -// m_log.DebugFormat( -// "[ODE CHARACTER]: Changing capsule size from {0} to {1} for {2}", -// CAPSULE_LENGTH, m_tainted_CAPSULE_LENGTH, Name); - - m_pidControllerActive = true; - - // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate() - DestroyOdeStructures(); - - float prevCapsule = CAPSULE_LENGTH; - CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH; - - CreateOdeStructures( - _position.X, - _position.Y, - _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor); - - // As with Size, we reset velocity. However, this isn't strictly necessary since it doesn't - // appear to stall initial region crossings when done here. Being done for consistency. -// Velocity = Vector3.Zero; - } - else - { - m_log.Warn("[ODE CHARACTER]: trying to change capsule size for " + Name + ", but the following ODE data is missing - " - + (Shell==IntPtr.Zero ? "Shell ":"") - + (Body==IntPtr.Zero ? "Body ":"") - + (Amotor==IntPtr.Zero ? "Amotor ":"")); - } - } - } - - internal void AddCollisionFrameTime(int p) - { - // protect it from overflow crashing - if (m_eventsubscription + p >= int.MaxValue) - m_eventsubscription = 0; - m_eventsubscription += p; - } - } -} diff --git a/OpenSim/Region/Physics/OdePlugin/ODEDynamics.c_comments b/OpenSim/Region/Physics/OdePlugin/ODEDynamics.c_comments deleted file mode 100644 index 1060aa6..0000000 --- a/OpenSim/Region/Physics/OdePlugin/ODEDynamics.c_comments +++ /dev/null @@ -1,630 +0,0 @@ -/* - * Revised August 26 2009 by Kitto Flora. ODEDynamics.cs replaces - * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: - * ODEPrim.cs contains methods dealing with Prim editing, Prim - * characteristics and Kinetic motion. - * ODEDynamics.cs contains methods dealing with Prim Physical motion - * (dynamics) and the associated settings. Old Linear and angular - * motors for dynamic motion have been replace with MoveLinear() - * and MoveAngular(); 'Physical' is used only to switch ODE dynamic - * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_ is to - * switch between 'VEHICLE' parameter use and general dynamics - * settings use. - * - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using log4net; -using OpenMetaverse; -using Ode.NET; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.OdePlugin -{ - public class ODEDynamics - { - public Vehicle Type - { - get { return m_type; } - } - - public IntPtr Body - { - get { return m_body; } - } - - private int frcount = 0; // Used to limit dynamics debug output to - // every 100th frame - - // private OdeScene m_parentScene = null; - private IntPtr m_body = IntPtr.Zero; - private IntPtr m_jointGroup = IntPtr.Zero; - private IntPtr m_aMotor = IntPtr.Zero; - - - // Vehicle properties - private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind - // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier - private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: - // HOVER_TERRAIN_ONLY - // HOVER_GLOBAL_HEIGHT - // NO_DEFLECTION_UP - // HOVER_WATER_ONLY - // HOVER_UP_ONLY - // LIMIT_MOTOR_UP - // LIMIT_ROLL_ONLY - - // Linear properties - private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time - private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL - private Vector3 m_dir = Vector3.Zero; // velocity applied to body - private Vector3 m_linearFrictionTimescale = Vector3.Zero; - private float m_linearMotorDecayTimescale = 0; - private float m_linearMotorTimescale = 0; - private Vector3 m_lastLinearVelocityVector = Vector3.Zero; - // private bool m_LinearMotorSetLastFrame = false; - // private Vector3 m_linearMotorOffset = Vector3.Zero; - - //Angular properties - private Vector3 m_angularMotorDirection = Vector3.Zero; - private Vector3 m_angularMotorDirectionLASTSET = Vector3.Zero; - private Vector3 m_angularFrictionTimescale = Vector3.Zero; - private float m_angularMotorDecayTimescale = 0; - private float m_angularMotorTimescale = 0; - private Vector3 m_lastAngularVelocityVector = Vector3.Zero; - - //Deflection properties - // private float m_angularDeflectionEfficiency = 0; - // private float m_angularDeflectionTimescale = 0; - // private float m_linearDeflectionEfficiency = 0; - // private float m_linearDeflectionTimescale = 0; - - //Banking properties - // private float m_bankingEfficiency = 0; - // private float m_bankingMix = 0; - // private float m_bankingTimescale = 0; - - //Hover and Buoyancy properties - private float m_VhoverHeight = 0f; - private float m_VhoverEfficiency = 0f; - private float m_VhoverTimescale = 0f; - private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height - private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. - // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) - // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. - // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. - - //Attractor properties - private float m_verticalAttractionEfficiency = 0; - private float m_verticalAttractionTimescale = 0; - - - - - - internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) - { - switch (pParam) - { - case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: - if (pValue < 0.01f) pValue = 0.01f; - // m_angularDeflectionEfficiency = pValue; - break; - case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - // m_angularDeflectionTimescale = pValue; - break; - case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_angularMotorDecayTimescale = pValue; - break; - case Vehicle.ANGULAR_MOTOR_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_angularMotorTimescale = pValue; - break; - case Vehicle.BANKING_EFFICIENCY: - if (pValue < 0.01f) pValue = 0.01f; - // m_bankingEfficiency = pValue; - break; - case Vehicle.BANKING_MIX: - if (pValue < 0.01f) pValue = 0.01f; - // m_bankingMix = pValue; - break; - case Vehicle.BANKING_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - // m_bankingTimescale = pValue; - break; - case Vehicle.BUOYANCY: - if (pValue < -1f) pValue = -1f; - if (pValue > 1f) pValue = 1f; - m_VehicleBuoyancy = pValue; - break; - case Vehicle.HOVER_EFFICIENCY: - if (pValue < 0f) pValue = 0f; - if (pValue > 1f) pValue = 1f; - m_VhoverEfficiency = pValue; - break; - case Vehicle.HOVER_HEIGHT: - m_VhoverHeight = pValue; - break; - case Vehicle.HOVER_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_VhoverTimescale = pValue; - break; - case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: - if (pValue < 0.01f) pValue = 0.01f; - // m_linearDeflectionEfficiency = pValue; - break; - case Vehicle.LINEAR_DEFLECTION_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - // m_linearDeflectionTimescale = pValue; - break; - case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_linearMotorDecayTimescale = pValue; - break; - case Vehicle.LINEAR_MOTOR_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_linearMotorTimescale = pValue; - break; - case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: - if (pValue < 0.0f) pValue = 0.0f; - if (pValue > 1.0f) pValue = 1.0f; - m_verticalAttractionEfficiency = pValue; - break; - case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_verticalAttractionTimescale = pValue; - break; - - // These are vector properties but the engine lets you use a single float value to - // set all of the components to the same value - case Vehicle.ANGULAR_FRICTION_TIMESCALE: - m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); - break; - case Vehicle.ANGULAR_MOTOR_DIRECTION: - m_angularMotorDirection = new Vector3(pValue, pValue, pValue); - m_angularMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); - break; - case Vehicle.LINEAR_FRICTION_TIMESCALE: - m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); - break; - case Vehicle.LINEAR_MOTOR_DIRECTION: - m_linearMotorDirection = new Vector3(pValue, pValue, pValue); - m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); - break; - case Vehicle.LINEAR_MOTOR_OFFSET: - // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); - break; - - } - - }//end ProcessFloatVehicleParam - - internal void ProcessVectorVehicleParam(Vehicle pParam, PhysicsVector pValue) - { - switch (pParam) - { - case Vehicle.ANGULAR_FRICTION_TIMESCALE: - m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - case Vehicle.ANGULAR_MOTOR_DIRECTION: - m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_angularMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - case Vehicle.LINEAR_FRICTION_TIMESCALE: - m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - case Vehicle.LINEAR_MOTOR_DIRECTION: - m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - case Vehicle.LINEAR_MOTOR_OFFSET: - // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - } - - }//end ProcessVectorVehicleParam - - internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) - { - switch (pParam) - { - case Vehicle.REFERENCE_FRAME: - // m_referenceFrame = pValue; - break; - } - - }//end ProcessRotationVehicleParam - - internal void ProcessTypeChange(Vehicle pType) - { -Console.WriteLine("ProcessTypeChange to " + pType); - - // Set Defaults For Type - m_type = pType; - switch (pType) - { - case Vehicle.TYPE_SLED: - m_linearFrictionTimescale = new Vector3(30, 1, 1000); - m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 1000; - m_linearMotorDecayTimescale = 120; - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 1000; - m_angularMotorDecayTimescale = 120; - m_VhoverHeight = 0; - m_VhoverEfficiency = 1; - m_VhoverTimescale = 10; - m_VehicleBuoyancy = 0; - // m_linearDeflectionEfficiency = 1; - // m_linearDeflectionTimescale = 1; - // m_angularDeflectionEfficiency = 1; - // m_angularDeflectionTimescale = 1000; - // m_bankingEfficiency = 0; - // m_bankingMix = 1; - // m_bankingTimescale = 10; - // m_referenceFrame = Quaternion.Identity; - m_flags &= - ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | - VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); - m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); - break; - case Vehicle.TYPE_CAR: - m_linearFrictionTimescale = new Vector3(100, 2, 1000); - m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 1; - m_linearMotorDecayTimescale = 60; - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 1; - m_angularMotorDecayTimescale = 0.8f; - m_VhoverHeight = 0; - m_VhoverEfficiency = 0; - m_VhoverTimescale = 1000; - m_VehicleBuoyancy = 0; - // // m_linearDeflectionEfficiency = 1; - // // m_linearDeflectionTimescale = 2; - // // m_angularDeflectionEfficiency = 0; - // m_angularDeflectionTimescale = 10; - m_verticalAttractionEfficiency = 1; - m_verticalAttractionTimescale = 10; - // m_bankingEfficiency = -0.2f; - // m_bankingMix = 1; - // m_bankingTimescale = 1; - // m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); - m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_UP_ONLY | - VehicleFlag.LIMIT_MOTOR_UP); - break; - case Vehicle.TYPE_BOAT: - m_linearFrictionTimescale = new Vector3(10, 3, 2); - m_angularFrictionTimescale = new Vector3(10,10,10); - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 5; - m_linearMotorDecayTimescale = 60; - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 4; - m_angularMotorDecayTimescale = 4; - m_VhoverHeight = 0; - m_VhoverEfficiency = 0.5f; - m_VhoverTimescale = 2; - m_VehicleBuoyancy = 1; - // m_linearDeflectionEfficiency = 0.5f; - // m_linearDeflectionTimescale = 3; - // m_angularDeflectionEfficiency = 0.5f; - // m_angularDeflectionTimescale = 5; - m_verticalAttractionEfficiency = 0.5f; - m_verticalAttractionTimescale = 5; - // m_bankingEfficiency = -0.3f; - // m_bankingMix = 0.8f; - // m_bankingTimescale = 1; - // m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.LIMIT_ROLL_ONLY | - VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); - m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | - VehicleFlag.LIMIT_MOTOR_UP); - break; - case Vehicle.TYPE_AIRPLANE: - m_linearFrictionTimescale = new Vector3(200, 10, 5); - m_angularFrictionTimescale = new Vector3(20, 20, 20); - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 2; - m_linearMotorDecayTimescale = 60; - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 4; - m_angularMotorDecayTimescale = 4; - m_VhoverHeight = 0; - m_VhoverEfficiency = 0.5f; - m_VhoverTimescale = 1000; - m_VehicleBuoyancy = 0; - // m_linearDeflectionEfficiency = 0.5f; - // m_linearDeflectionTimescale = 3; - // m_angularDeflectionEfficiency = 1; - // m_angularDeflectionTimescale = 2; - m_verticalAttractionEfficiency = 0.9f; - m_verticalAttractionTimescale = 2; - // m_bankingEfficiency = 1; - // m_bankingMix = 0.7f; - // m_bankingTimescale = 2; - // m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | - VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP); - m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); - break; - case Vehicle.TYPE_BALLOON: - m_linearFrictionTimescale = new Vector3(5, 5, 5); - m_angularFrictionTimescale = new Vector3(10, 10, 10); - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 5; - m_linearMotorDecayTimescale = 60; - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 6; - m_angularMotorDecayTimescale = 10; - m_VhoverHeight = 5; - m_VhoverEfficiency = 0.8f; - m_VhoverTimescale = 10; - m_VehicleBuoyancy = 1; - // m_linearDeflectionEfficiency = 0; - // m_linearDeflectionTimescale = 5; - // m_angularDeflectionEfficiency = 0; - // m_angularDeflectionTimescale = 5; - m_verticalAttractionEfficiency = 1; - m_verticalAttractionTimescale = 1000; - // m_bankingEfficiency = 0; - // m_bankingMix = 0.7f; - // m_bankingTimescale = 5; - // m_referenceFrame = Quaternion.Identity; - m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | - VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP); - m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); - break; - - } - }//end SetDefaultsForType - - internal void Enable(IntPtr pBody, OdeScene pParentScene) - { -//Console.WriteLine("Enable m_type=" + m_type + " m_VehicleBuoyancy=" + m_VehicleBuoyancy); - if (m_type == Vehicle.TYPE_NONE) - return; - - m_body = pBody; - //KF: This used to set up the linear and angular joints - } - - internal void Step(float pTimestep, OdeScene pParentScene) - { - if (m_body == IntPtr.Zero || m_type == Vehicle.TYPE_NONE) - return; - frcount++; // used to limit debug comment output - if (frcount > 100) - frcount = 0; - - MoveLinear(pTimestep, pParentScene); - MoveAngular(pTimestep); - }// end Step - - private void MoveLinear(float pTimestep, OdeScene _pParentScene) - { - if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant - { - if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); - - // add drive to body - Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); - m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector? - - // This will work temporarily, but we really need to compare speed on an axis - // KF: Limit body velocity to applied velocity? - if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) - m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; - if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) - m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; - if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) - m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; - - // decay applied velocity - Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); - //Console.WriteLine("decay: " + decayfraction); - m_linearMotorDirection -= m_linearMotorDirection * decayfraction; - //Console.WriteLine("actual: " + m_linearMotorDirection); - } - else - { // requested is not significant - // if what remains of applied is small, zero it. - if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) - m_lastLinearVelocityVector = Vector3.Zero; - } - - - // convert requested object velocity to world-referenced vector - m_dir = m_lastLinearVelocityVector; - d.Quaternion rot = d.BodyGetQuaternion(Body); - Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object - m_dir *= rotq; // apply obj rotation to velocity vector - - // add Gravity andBuoyancy - // KF: So far I have found no good method to combine a script-requested - // .Z velocity and gravity. Therefore only 0g will used script-requested - // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. - Vector3 grav = Vector3.Zero; - if(m_VehicleBuoyancy < 1.0f) - { - // There is some gravity, make a gravity force vector - // that is applied after object velocity. - d.Mass objMass; - d.BodyGetMass(Body, out objMass); - // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; - grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); - // Preserve the current Z velocity - d.Vector3 vel_now = d.BodyGetLinearVel(Body); - m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity - } // else its 1.0, no gravity. - - // Check if hovering - if( (m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) - { - // We should hover, get the target height - d.Vector3 pos = d.BodyGetPosition(Body); - if((m_flags & VehicleFlag.HOVER_WATER_ONLY) == VehicleFlag.HOVER_WATER_ONLY) - { - m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; - } - else if((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) == VehicleFlag.HOVER_TERRAIN_ONLY) - { - m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; - } - else if((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) == VehicleFlag.HOVER_GLOBAL_HEIGHT) - { - m_VhoverTargetHeight = m_VhoverHeight; - } - - if((m_flags & VehicleFlag.HOVER_UP_ONLY) == VehicleFlag.HOVER_UP_ONLY) - { - // If body is aready heigher, use its height as target height - if(pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; - } - -// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped -// m_VhoverTimescale = 0f; // time to acheive height -// pTimestep is time since last frame,in secs - float herr0 = pos.Z - m_VhoverTargetHeight; -//if(frcount == 0) Console.WriteLine("herr0=" + herr0); - // Replace Vertical speed with correction figure if significant - if(Math.Abs(herr0) > 0.01f ) - { - d.Mass objMass; - d.BodyGetMass(Body, out objMass); - m_dir.Z = - ( (herr0 * pTimestep * 50.0f) / m_VhoverTimescale); - // m_VhoverEfficiency is not yet implemented - } - else - { - m_dir.Z = 0f; - } - } - - // Apply velocity - d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z); -//if(frcount == 0) Console.WriteLine("Move " + Body + ":"+ m_dir.X + " " + m_dir.Y + " " + m_dir.Z); - // apply gravity force - d.BodyAddForce(Body, grav.X, grav.Y, grav.Z); -//if(frcount == 0) Console.WriteLine("Force " + Body + ":" + grav.X + " " + grav.Y + " " + grav.Z); - - - // apply friction - Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); - m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; - } // end MoveLinear() - - private void MoveAngular(float pTimestep) - { - - // m_angularMotorDirection is the latest value from the script, and is decayed here - // m_angularMotorDirectionLASTSET is the latest value from the script - // m_lastAngularVelocityVector is what is being applied to the Body, varied up and down here - - if (!m_angularMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) - { - if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); - // ramp up to new value - Vector3 addAmount = m_angularMotorDirection / (m_angularMotorTimescale / pTimestep); - m_lastAngularVelocityVector += (addAmount * 10f); -//if(frcount == 0) Console.WriteLine("add: " + addAmount); - - // limit applied value to what was set by script - // This will work temporarily, but we really need to compare speed on an axis - if (Math.Abs(m_lastAngularVelocityVector.X) > Math.Abs(m_angularMotorDirectionLASTSET.X)) - m_lastAngularVelocityVector.X = m_angularMotorDirectionLASTSET.X; - if (Math.Abs(m_lastAngularVelocityVector.Y) > Math.Abs(m_angularMotorDirectionLASTSET.Y)) - m_lastAngularVelocityVector.Y = m_angularMotorDirectionLASTSET.Y; - if (Math.Abs(m_lastAngularVelocityVector.Z) > Math.Abs(m_angularMotorDirectionLASTSET.Z)) - m_lastAngularVelocityVector.Z = m_angularMotorDirectionLASTSET.Z; - - // decay the requested value - Vector3 decayfraction = ((Vector3.One / (m_angularMotorDecayTimescale / pTimestep))); - //Console.WriteLine("decay: " + decayfraction); - m_angularMotorDirection -= m_angularMotorDirection * decayfraction; - //Console.WriteLine("actual: " + m_linearMotorDirection); - } - // KF: m_lastAngularVelocityVector is rotational speed in rad/sec ? - - // Vertical attractor section - -// d.Mass objMass; -// d.BodyGetMass(Body, out objMass); -// float servo = 100f * objMass.mass * m_verticalAttractionEfficiency / (m_verticalAttractionTimescale * pTimestep); - float servo = 0.1f * m_verticalAttractionEfficiency / (m_verticalAttractionTimescale * pTimestep); - // get present body rotation - d.Quaternion rot = d.BodyGetQuaternion(Body); - Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); - // make a vector pointing up - Vector3 verterr = Vector3.Zero; - verterr.Z = 1.0f; - // rotate it to Body Angle - verterr = verterr * rotq; - // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. - // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go - // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. - if (verterr.Z < 0.0f) - { - verterr.X = 2.0f - verterr.X; - verterr.Y = 2.0f - verterr.Y; - } - // Error is 0 (no error) to +/- 2 (max error) - // scale it by servo - verterr = verterr * servo; - - // rotate to object frame - // verterr = verterr * rotq; - - // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so - // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. - m_lastAngularVelocityVector.X += verterr.Y; - m_lastAngularVelocityVector.Y -= verterr.X; -/* -if(frcount == 0) - { -// Console.WriteLine("AngleMotor " + m_lastAngularVelocityVector); - Console.WriteLine(String.Format("VA Body:{0} servo:{1} err:<{2},{3},{4}> VAE:{5}", - Body, servo, verterr.X, verterr.Y, verterr.Z, m_verticalAttractionEfficiency)); - } - */ - d.BodySetAngularVel (Body, m_lastAngularVelocityVector.X, m_lastAngularVelocityVector.Y, m_lastAngularVelocityVector.Z); - // apply friction - Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep); - m_lastAngularVelocityVector -= m_lastAngularVelocityVector * decayamount; - - } //end MoveAngular - } -} diff --git a/OpenSim/Region/Physics/OdePlugin/ODEDynamics.cs b/OpenSim/Region/Physics/OdePlugin/ODEDynamics.cs deleted file mode 100644 index 2342bfa..0000000 --- a/OpenSim/Region/Physics/OdePlugin/ODEDynamics.cs +++ /dev/null @@ -1,974 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces - * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: - * ODEPrim.cs contains methods dealing with Prim editing, Prim - * characteristics and Kinetic motion. - * ODEDynamics.cs contains methods dealing with Prim Physical motion - * (dynamics) and the associated settings. Old Linear and angular - * motors for dynamic motion have been replace with MoveLinear() - * and MoveAngular(); 'Physical' is used only to switch ODE dynamic - * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_ is to - * switch between 'VEHICLE' parameter use and general dynamics - * settings use. - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using log4net; -using OpenMetaverse; -using Ode.NET; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.OdePlugin -{ - public class ODEDynamics - { - public Vehicle Type - { - get { return m_type; } - } - - public IntPtr Body - { - get { return m_body; } - } - - private int frcount = 0; // Used to limit dynamics debug output to - // every 100th frame - - // private OdeScene m_parentScene = null; - private IntPtr m_body = IntPtr.Zero; -// private IntPtr m_jointGroup = IntPtr.Zero; -// private IntPtr m_aMotor = IntPtr.Zero; - - - // Vehicle properties - private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind - // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier - private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: - // HOVER_TERRAIN_ONLY - // HOVER_GLOBAL_HEIGHT - // NO_DEFLECTION_UP - // HOVER_WATER_ONLY - // HOVER_UP_ONLY - // LIMIT_MOTOR_UP - // LIMIT_ROLL_ONLY - private VehicleFlag m_Hoverflags = (VehicleFlag)0; - private Vector3 m_BlockingEndPoint = Vector3.Zero; - private Quaternion m_RollreferenceFrame = Quaternion.Identity; - // Linear properties - private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time - private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL - private Vector3 m_dir = Vector3.Zero; // velocity applied to body - private Vector3 m_linearFrictionTimescale = Vector3.Zero; - private float m_linearMotorDecayTimescale = 0; - private float m_linearMotorTimescale = 0; - private Vector3 m_lastLinearVelocityVector = Vector3.Zero; - private d.Vector3 m_lastPositionVector = new d.Vector3(); - // private bool m_LinearMotorSetLastFrame = false; - // private Vector3 m_linearMotorOffset = Vector3.Zero; - - //Angular properties - private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor - private int m_angularMotorApply = 0; // application frame counter - private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity - private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate - private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate - private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate - private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body - // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body - - //Deflection properties - // private float m_angularDeflectionEfficiency = 0; - // private float m_angularDeflectionTimescale = 0; - // private float m_linearDeflectionEfficiency = 0; - // private float m_linearDeflectionTimescale = 0; - - //Banking properties - // private float m_bankingEfficiency = 0; - // private float m_bankingMix = 0; - // private float m_bankingTimescale = 0; - - //Hover and Buoyancy properties - private float m_VhoverHeight = 0f; -// private float m_VhoverEfficiency = 0f; - private float m_VhoverTimescale = 0f; - private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height - private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. - // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) - // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. - // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. - - //Attractor properties - private float m_verticalAttractionEfficiency = 1.0f; // damped - private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. - - internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) - { - switch (pParam) - { - case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: - if (pValue < 0.01f) pValue = 0.01f; - // m_angularDeflectionEfficiency = pValue; - break; - case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - // m_angularDeflectionTimescale = pValue; - break; - case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_angularMotorDecayTimescale = pValue; - break; - case Vehicle.ANGULAR_MOTOR_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_angularMotorTimescale = pValue; - break; - case Vehicle.BANKING_EFFICIENCY: - if (pValue < 0.01f) pValue = 0.01f; - // m_bankingEfficiency = pValue; - break; - case Vehicle.BANKING_MIX: - if (pValue < 0.01f) pValue = 0.01f; - // m_bankingMix = pValue; - break; - case Vehicle.BANKING_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - // m_bankingTimescale = pValue; - break; - case Vehicle.BUOYANCY: - if (pValue < -1f) pValue = -1f; - if (pValue > 1f) pValue = 1f; - m_VehicleBuoyancy = pValue; - break; -// case Vehicle.HOVER_EFFICIENCY: -// if (pValue < 0f) pValue = 0f; -// if (pValue > 1f) pValue = 1f; -// m_VhoverEfficiency = pValue; -// break; - case Vehicle.HOVER_HEIGHT: - m_VhoverHeight = pValue; - break; - case Vehicle.HOVER_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_VhoverTimescale = pValue; - break; - case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: - if (pValue < 0.01f) pValue = 0.01f; - // m_linearDeflectionEfficiency = pValue; - break; - case Vehicle.LINEAR_DEFLECTION_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - // m_linearDeflectionTimescale = pValue; - break; - case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_linearMotorDecayTimescale = pValue; - break; - case Vehicle.LINEAR_MOTOR_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_linearMotorTimescale = pValue; - break; - case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: - if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable - if (pValue > 1.0f) pValue = 1.0f; - m_verticalAttractionEfficiency = pValue; - break; - case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: - if (pValue < 0.01f) pValue = 0.01f; - m_verticalAttractionTimescale = pValue; - break; - - // These are vector properties but the engine lets you use a single float value to - // set all of the components to the same value - case Vehicle.ANGULAR_FRICTION_TIMESCALE: - m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); - break; - case Vehicle.ANGULAR_MOTOR_DIRECTION: - m_angularMotorDirection = new Vector3(pValue, pValue, pValue); - m_angularMotorApply = 10; - break; - case Vehicle.LINEAR_FRICTION_TIMESCALE: - m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); - break; - case Vehicle.LINEAR_MOTOR_DIRECTION: - m_linearMotorDirection = new Vector3(pValue, pValue, pValue); - m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); - break; - case Vehicle.LINEAR_MOTOR_OFFSET: - // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); - break; - - } - }//end ProcessFloatVehicleParam - - internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) - { - switch (pParam) - { - case Vehicle.ANGULAR_FRICTION_TIMESCALE: - m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - case Vehicle.ANGULAR_MOTOR_DIRECTION: - m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); - // Limit requested angular speed to 2 rps= 4 pi rads/sec - if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f; - if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f; - if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f; - if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f; - if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f; - if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f; - m_angularMotorApply = 10; - break; - case Vehicle.LINEAR_FRICTION_TIMESCALE: - m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - case Vehicle.LINEAR_MOTOR_DIRECTION: - m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - case Vehicle.LINEAR_MOTOR_OFFSET: - // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - case Vehicle.BLOCK_EXIT: - m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); - break; - } - }//end ProcessVectorVehicleParam - - internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) - { - switch (pParam) - { - case Vehicle.REFERENCE_FRAME: - // m_referenceFrame = pValue; - break; - case Vehicle.ROLL_FRAME: - m_RollreferenceFrame = pValue; - break; - } - }//end ProcessRotationVehicleParam - - internal void ProcessVehicleFlags(int pParam, bool remove) - { - if (remove) - { - if (pParam == -1) - { - m_flags = (VehicleFlag)0; - m_Hoverflags = (VehicleFlag)0; - return; - } - if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) - { - if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != (VehicleFlag)0) - m_Hoverflags &= ~(VehicleFlag.HOVER_GLOBAL_HEIGHT); - } - if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY) - { - if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != (VehicleFlag)0) - m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY); - } - if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY) - { - if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != (VehicleFlag)0) - m_Hoverflags &= ~(VehicleFlag.HOVER_UP_ONLY); - } - if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY) - { - if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != (VehicleFlag)0) - m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY); - } - if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP) - { - if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != (VehicleFlag)0) - m_flags &= ~(VehicleFlag.LIMIT_MOTOR_UP); - } - if ((pParam & (int)VehicleFlag.LIMIT_ROLL_ONLY) == (int)VehicleFlag.LIMIT_ROLL_ONLY) - { - if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != (VehicleFlag)0) - m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); - } - if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK) - { - if ((m_flags & VehicleFlag.MOUSELOOK_BANK) != (VehicleFlag)0) - m_flags &= ~(VehicleFlag.MOUSELOOK_BANK); - } - if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER) - { - if ((m_flags & VehicleFlag.MOUSELOOK_STEER) != (VehicleFlag)0) - m_flags &= ~(VehicleFlag.MOUSELOOK_STEER); - } - if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP) - { - if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) != (VehicleFlag)0) - m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP); - } - if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED) - { - if ((m_flags & VehicleFlag.CAMERA_DECOUPLED) != (VehicleFlag)0) - m_flags &= ~(VehicleFlag.CAMERA_DECOUPLED); - } - if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X) - { - if ((m_flags & VehicleFlag.NO_X) != (VehicleFlag)0) - m_flags &= ~(VehicleFlag.NO_X); - } - if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y) - { - if ((m_flags & VehicleFlag.NO_Y) != (VehicleFlag)0) - m_flags &= ~(VehicleFlag.NO_Y); - } - if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z) - { - if ((m_flags & VehicleFlag.NO_Z) != (VehicleFlag)0) - m_flags &= ~(VehicleFlag.NO_Z); - } - if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT) - { - if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != (VehicleFlag)0) - m_Hoverflags &= ~(VehicleFlag.LOCK_HOVER_HEIGHT); - } - if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION) - { - if ((m_flags & VehicleFlag.NO_DEFLECTION) != (VehicleFlag)0) - m_flags &= ~(VehicleFlag.NO_DEFLECTION); - } - if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION) - { - if ((m_flags & VehicleFlag.LOCK_ROTATION) != (VehicleFlag)0) - m_flags &= ~(VehicleFlag.LOCK_ROTATION); - } - } - else - { - if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) - { - m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT | m_flags); - } - if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY) - { - m_Hoverflags |= (VehicleFlag.HOVER_TERRAIN_ONLY | m_flags); - } - if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY) - { - m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY | m_flags); - } - if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY) - { - m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY | m_flags); - } - if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP) - { - m_flags |= (VehicleFlag.LIMIT_MOTOR_UP | m_flags); - } - if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK) - { - m_flags |= (VehicleFlag.MOUSELOOK_BANK | m_flags); - } - if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER) - { - m_flags |= (VehicleFlag.MOUSELOOK_STEER | m_flags); - } - if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP) - { - m_flags |= (VehicleFlag.NO_DEFLECTION_UP | m_flags); - } - if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED) - { - m_flags |= (VehicleFlag.CAMERA_DECOUPLED | m_flags); - } - if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X) - { - m_flags |= (VehicleFlag.NO_X); - } - if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y) - { - m_flags |= (VehicleFlag.NO_Y); - } - if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z) - { - m_flags |= (VehicleFlag.NO_Z); - } - if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT) - { - m_Hoverflags |= (VehicleFlag.LOCK_HOVER_HEIGHT); - } - if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION) - { - m_flags |= (VehicleFlag.NO_DEFLECTION); - } - if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION) - { - m_flags |= (VehicleFlag.LOCK_ROTATION); - } - } - }//end ProcessVehicleFlags - - internal void ProcessTypeChange(Vehicle pType) - { - // Set Defaults For Type - m_type = pType; - switch (pType) - { - case Vehicle.TYPE_NONE: - m_linearFrictionTimescale = new Vector3(0, 0, 0); - m_angularFrictionTimescale = new Vector3(0, 0, 0); - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 0; - m_linearMotorDecayTimescale = 0; - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 0; - m_angularMotorDecayTimescale = 0; - m_VhoverHeight = 0; - m_VhoverTimescale = 0; - m_VehicleBuoyancy = 0; - m_flags = (VehicleFlag)0; - break; - - case Vehicle.TYPE_SLED: - m_linearFrictionTimescale = new Vector3(30, 1, 1000); - m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 1000; - m_linearMotorDecayTimescale = 120; - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 1000; - m_angularMotorDecayTimescale = 120; - m_VhoverHeight = 0; -// m_VhoverEfficiency = 1; - m_VhoverTimescale = 10; - m_VehicleBuoyancy = 0; - // m_linearDeflectionEfficiency = 1; - // m_linearDeflectionTimescale = 1; - // m_angularDeflectionEfficiency = 1; - // m_angularDeflectionTimescale = 1000; - // m_bankingEfficiency = 0; - // m_bankingMix = 1; - // m_bankingTimescale = 10; - // m_referenceFrame = Quaternion.Identity; - m_Hoverflags &= - ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | - VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); - m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); - break; - case Vehicle.TYPE_CAR: - m_linearFrictionTimescale = new Vector3(100, 2, 1000); - m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 1; - m_linearMotorDecayTimescale = 60; - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 1; - m_angularMotorDecayTimescale = 0.8f; - m_VhoverHeight = 0; -// m_VhoverEfficiency = 0; - m_VhoverTimescale = 1000; - m_VehicleBuoyancy = 0; - // // m_linearDeflectionEfficiency = 1; - // // m_linearDeflectionTimescale = 2; - // // m_angularDeflectionEfficiency = 0; - // m_angularDeflectionTimescale = 10; - m_verticalAttractionEfficiency = 1f; - m_verticalAttractionTimescale = 10f; - // m_bankingEfficiency = -0.2f; - // m_bankingMix = 1; - // m_bankingTimescale = 1; - // m_referenceFrame = Quaternion.Identity; - m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); - m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | - VehicleFlag.LIMIT_MOTOR_UP); - m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY); - break; - case Vehicle.TYPE_BOAT: - m_linearFrictionTimescale = new Vector3(10, 3, 2); - m_angularFrictionTimescale = new Vector3(10,10,10); - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 5; - m_linearMotorDecayTimescale = 60; - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 4; - m_angularMotorDecayTimescale = 4; - m_VhoverHeight = 0; -// m_VhoverEfficiency = 0.5f; - m_VhoverTimescale = 2; - m_VehicleBuoyancy = 1; - // m_linearDeflectionEfficiency = 0.5f; - // m_linearDeflectionTimescale = 3; - // m_angularDeflectionEfficiency = 0.5f; - // m_angularDeflectionTimescale = 5; - m_verticalAttractionEfficiency = 0.5f; - m_verticalAttractionTimescale = 5f; - // m_bankingEfficiency = -0.3f; - // m_bankingMix = 0.8f; - // m_bankingTimescale = 1; - // m_referenceFrame = Quaternion.Identity; - m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | - VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); - m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); - m_flags |= (VehicleFlag.NO_DEFLECTION_UP | - VehicleFlag.LIMIT_MOTOR_UP); - m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY); - break; - case Vehicle.TYPE_AIRPLANE: - m_linearFrictionTimescale = new Vector3(200, 10, 5); - m_angularFrictionTimescale = new Vector3(20, 20, 20); - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 2; - m_linearMotorDecayTimescale = 60; - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 4; - m_angularMotorDecayTimescale = 4; - m_VhoverHeight = 0; -// m_VhoverEfficiency = 0.5f; - m_VhoverTimescale = 1000; - m_VehicleBuoyancy = 0; - // m_linearDeflectionEfficiency = 0.5f; - // m_linearDeflectionTimescale = 3; - // m_angularDeflectionEfficiency = 1; - // m_angularDeflectionTimescale = 2; - m_verticalAttractionEfficiency = 0.9f; - m_verticalAttractionTimescale = 2f; - // m_bankingEfficiency = 1; - // m_bankingMix = 0.7f; - // m_bankingTimescale = 2; - // m_referenceFrame = Quaternion.Identity; - m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | - VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); - m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); - m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); - break; - case Vehicle.TYPE_BALLOON: - m_linearFrictionTimescale = new Vector3(5, 5, 5); - m_angularFrictionTimescale = new Vector3(10, 10, 10); - m_linearMotorDirection = Vector3.Zero; - m_linearMotorTimescale = 5; - m_linearMotorDecayTimescale = 60; - m_angularMotorDirection = Vector3.Zero; - m_angularMotorTimescale = 6; - m_angularMotorDecayTimescale = 10; - m_VhoverHeight = 5; -// m_VhoverEfficiency = 0.8f; - m_VhoverTimescale = 10; - m_VehicleBuoyancy = 1; - // m_linearDeflectionEfficiency = 0; - // m_linearDeflectionTimescale = 5; - // m_angularDeflectionEfficiency = 0; - // m_angularDeflectionTimescale = 5; - m_verticalAttractionEfficiency = 1f; - m_verticalAttractionTimescale = 100f; - // m_bankingEfficiency = 0; - // m_bankingMix = 0.7f; - // m_bankingTimescale = 5; - // m_referenceFrame = Quaternion.Identity; - m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | - VehicleFlag.HOVER_UP_ONLY); - m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); - m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); - m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT); - break; - - } - }//end SetDefaultsForType - - internal void Enable(IntPtr pBody, OdeScene pParentScene) - { - if (m_type == Vehicle.TYPE_NONE) - return; - - m_body = pBody; - } - - internal void Step(float pTimestep, OdeScene pParentScene) - { - if (m_body == IntPtr.Zero || m_type == Vehicle.TYPE_NONE) - return; - frcount++; // used to limit debug comment output - if (frcount > 100) - frcount = 0; - - MoveLinear(pTimestep, pParentScene); - MoveAngular(pTimestep); - LimitRotation(pTimestep); - }// end Step - - private void MoveLinear(float pTimestep, OdeScene _pParentScene) - { - if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant - { - if (!d.BodyIsEnabled(Body)) - d.BodyEnable(Body); - - // add drive to body - Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); - m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector? - - // This will work temporarily, but we really need to compare speed on an axis - // KF: Limit body velocity to applied velocity? - if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) - m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; - if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) - m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; - if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) - m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; - - // decay applied velocity - Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); - //Console.WriteLine("decay: " + decayfraction); - m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; - //Console.WriteLine("actual: " + m_linearMotorDirection); - } - else - { // requested is not significant - // if what remains of applied is small, zero it. - if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) - m_lastLinearVelocityVector = Vector3.Zero; - } - - // convert requested object velocity to world-referenced vector - m_dir = m_lastLinearVelocityVector; - d.Quaternion rot = d.BodyGetQuaternion(Body); - Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object - m_dir *= rotq; // apply obj rotation to velocity vector - - // add Gravity andBuoyancy - // KF: So far I have found no good method to combine a script-requested - // .Z velocity and gravity. Therefore only 0g will used script-requested - // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. - Vector3 grav = Vector3.Zero; - // There is some gravity, make a gravity force vector - // that is applied after object velocity. - d.Mass objMass; - d.BodyGetMass(Body, out objMass); - // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; - grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); - // Preserve the current Z velocity - d.Vector3 vel_now = d.BodyGetLinearVel(Body); - m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity - - d.Vector3 pos = d.BodyGetPosition(Body); -// 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); - Vector3 posChange = new Vector3(); - posChange.X = pos.X - m_lastPositionVector.X; - posChange.Y = pos.Y - m_lastPositionVector.Y; - posChange.Z = pos.Z - m_lastPositionVector.Z; - double Zchange = Math.Abs(posChange.Z); - if (m_BlockingEndPoint != Vector3.Zero) - { - if (pos.X >= (m_BlockingEndPoint.X - (float)1)) - { - pos.X -= posChange.X + 1; - d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); - } - if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) - { - pos.Y -= posChange.Y + 1; - d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); - } - if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) - { - pos.Z -= posChange.Z + 1; - d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); - } - if (pos.X <= 0) - { - pos.X += posChange.X + 1; - d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); - } - if (pos.Y <= 0) - { - pos.Y += posChange.Y + 1; - d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); - } - } - if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y)) - { - pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2; - d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); - } - - // Check if hovering - if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) - { - // We should hover, get the target height - if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) - { - m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; - } - if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) - { - m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; - } - if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) - { - m_VhoverTargetHeight = m_VhoverHeight; - } - - if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0) - { - // If body is aready heigher, use its height as target height - if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; - } - if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) - { - if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) - { - d.BodySetPosition(Body, pos.X, pos.Y, m_VhoverTargetHeight); - } - } - else - { - float herr0 = pos.Z - m_VhoverTargetHeight; - // Replace Vertical speed with correction figure if significant - if (Math.Abs(herr0) > 0.01f) - { - m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); - //KF: m_VhoverEfficiency is not yet implemented - } - else - { - m_dir.Z = 0f; - } - } - -// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped -// m_VhoverTimescale = 0f; // time to acheive height -// pTimestep is time since last frame,in secs - } - - if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) - { - //Start Experimental Values - if (Zchange > .3) - { - grav.Z = (float)(grav.Z * 3); - } - if (Zchange > .15) - { - grav.Z = (float)(grav.Z * 2); - } - if (Zchange > .75) - { - grav.Z = (float)(grav.Z * 1.5); - } - if (Zchange > .05) - { - grav.Z = (float)(grav.Z * 1.25); - } - if (Zchange > .025) - { - grav.Z = (float)(grav.Z * 1.125); - } - float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y); - float postemp = (pos.Z - terraintemp); - if (postemp > 2.5f) - { - grav.Z = (float)(grav.Z * 1.037125); - } - //End Experimental Values - } - if ((m_flags & (VehicleFlag.NO_X)) != 0) - { - m_dir.X = 0; - } - if ((m_flags & (VehicleFlag.NO_Y)) != 0) - { - m_dir.Y = 0; - } - if ((m_flags & (VehicleFlag.NO_Z)) != 0) - { - m_dir.Z = 0; - } - - m_lastPositionVector = d.BodyGetPosition(Body); - - // Apply velocity - d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z); - // apply gravity force - d.BodyAddForce(Body, grav.X, grav.Y, grav.Z); - - - // apply friction - Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); - m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; - } // end MoveLinear() - - private void MoveAngular(float pTimestep) - { - /* - private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor - private int m_angularMotorApply = 0; // application frame counter - private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down) - private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate - private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate - private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate - private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body - */ - - // Get what the body is doing, this includes 'external' influences - d.Vector3 angularVelocity = d.BodyGetAngularVel(Body); - // Vector3 angularVelocity = Vector3.Zero; - - if (m_angularMotorApply > 0) - { - // ramp up to new value - // current velocity += error / (time to get there / step interval) - // requested speed - last motor speed - m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); - m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); - m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); - - m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected - // velocity may still be acheived. - } - else - { - // no motor recently applied, keep the body velocity - /* m_angularMotorVelocity.X = angularVelocity.X; - m_angularMotorVelocity.Y = angularVelocity.Y; - m_angularMotorVelocity.Z = angularVelocity.Z; */ - - // and decay the velocity - m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); - } // end motor section - - // Vertical attractor section - Vector3 vertattr = Vector3.Zero; - - if (m_verticalAttractionTimescale < 300) - { - float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); - // get present body rotation - d.Quaternion rot = d.BodyGetQuaternion(Body); - Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); - // make a vector pointing up - Vector3 verterr = Vector3.Zero; - verterr.Z = 1.0f; - // rotate it to Body Angle - verterr = verterr * rotq; - // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. - // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go - // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. - if (verterr.Z < 0.0f) - { - verterr.X = 2.0f - verterr.X; - verterr.Y = 2.0f - verterr.Y; - } - // Error is 0 (no error) to +/- 2 (max error) - // scale it by VAservo - verterr = verterr * VAservo; -//if (frcount == 0) Console.WriteLine("VAerr=" + verterr); - - // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so - // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. - vertattr.X = verterr.Y; - vertattr.Y = - verterr.X; - vertattr.Z = 0f; - - // scaling appears better usingsquare-law - float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); - vertattr.X += bounce * angularVelocity.X; - vertattr.Y += bounce * angularVelocity.Y; - - } // else vertical attractor is off - - // m_lastVertAttractor = vertattr; - - // Bank section tba - // Deflection section tba - - // Sum velocities - m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection - - if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) - { - m_lastAngularVelocity.X = 0; - m_lastAngularVelocity.Y = 0; - } - - if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) - { - if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); - } - else - { - m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. - } - - // apply friction - Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep); - m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; - - // Apply to the body - d.BodySetAngularVel (Body, m_lastAngularVelocity.X, m_lastAngularVelocity.Y, m_lastAngularVelocity.Z); - - } //end MoveAngular - internal void LimitRotation(float timestep) - { - d.Quaternion rot = d.BodyGetQuaternion(Body); - Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object - d.Quaternion m_rot = new d.Quaternion(); - bool changed = false; - m_rot.X = rotq.X; - m_rot.Y = rotq.Y; - m_rot.Z = rotq.Z; - m_rot.W = rotq.W; - if (m_RollreferenceFrame != Quaternion.Identity) - { - if (rotq.X >= m_RollreferenceFrame.X) - { - m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); - } - if (rotq.Y >= m_RollreferenceFrame.Y) - { - m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); - } - if (rotq.X <= -m_RollreferenceFrame.X) - { - m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); - } - if (rotq.Y <= -m_RollreferenceFrame.Y) - { - m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); - } - changed = true; - } - if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) - { - m_rot.X = 0; - m_rot.Y = 0; - changed = true; - } - if (changed) - d.BodySetQuaternion(Body, ref m_rot); - } - } -} diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs deleted file mode 100644 index 0d66496..0000000 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ /dev/null @@ -1,3380 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Revised August 26 2009 by Kitto Flora. ODEDynamics.cs replaces - * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: - * ODEPrim.cs contains methods dealing with Prim editing, Prim - * characteristics and Kinetic motion. - * ODEDynamics.cs contains methods dealing with Prim Physical motion - * (dynamics) and the associated settings. Old Linear and angular - * motors for dynamic motion have been replace with MoveLinear() - * and MoveAngular(); 'Physical' is used only to switch ODE dynamic - * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_ is to - * switch between 'VEHICLE' parameter use and general dynamics - * settings use. - */ - -//#define SPAM - -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Threading; -using log4net; -using OpenMetaverse; -using Ode.NET; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.OdePlugin -{ - /// - /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves. - /// - public class OdePrim : PhysicsActor - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private bool m_isphysical; - - public int ExpectedCollisionContacts { get { return m_expectedCollisionContacts; } } - private int m_expectedCollisionContacts = 0; - - /// - /// Gets collide bits so that we can still perform land collisions if a mesh fails to load. - /// - private int BadMeshAssetCollideBits - { - get { return m_isphysical ? (int)CollisionCategories.Land : 0; } - } - - /// - /// Is this prim subject to physics? Even if not, it's still solid for collision purposes. - /// - public override bool IsPhysical - { - get { return m_isphysical; } - set - { - m_isphysical = value; - if (!m_isphysical) // Zero the remembered last velocity - m_lastVelocity = Vector3.Zero; - } - } - - private Vector3 _position; - private Vector3 _velocity; - private Vector3 _torque; - private Vector3 m_lastVelocity; - private Vector3 m_lastposition; - private Quaternion m_lastorientation = new Quaternion(); - private Vector3 m_rotationalVelocity; - private Vector3 _size; - private Vector3 _acceleration; - // private d.Vector3 _zeroPosition = new d.Vector3(0.0f, 0.0f, 0.0f); - private Quaternion _orientation; - private Vector3 m_taintposition; - private Vector3 m_taintsize; - private Vector3 m_taintVelocity; - private Vector3 m_taintTorque; - private Quaternion m_taintrot; - private Vector3 m_angularlock = Vector3.One; - private Vector3 m_taintAngularLock = Vector3.One; - private IntPtr Amotor = IntPtr.Zero; - - private object m_assetsLock = new object(); - private bool m_assetFailed = false; - - private Vector3 m_PIDTarget; - private float m_PIDTau; - private float PID_D = 35f; - private float PID_G = 25f; - private bool m_usePID; - - // KF: These next 7 params apply to llSetHoverHeight(float height, integer water, float tau), - // and are for non-VEHICLES only. - - private float m_PIDHoverHeight; - private float m_PIDHoverTau; - private bool m_useHoverPID; - private PIDHoverType m_PIDHoverType = PIDHoverType.Ground; - private float m_targetHoverHeight; - private float m_groundHeight; - private float m_waterHeight; - private float m_buoyancy; //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle. - - // private float m_tensor = 5f; - private int body_autodisable_frames = 20; - - - private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom - | CollisionCategories.Space - | CollisionCategories.Body - | CollisionCategories.Character - ); - private bool m_taintshape; - private bool m_taintPhysics; - private bool m_collidesLand = true; - private bool m_collidesWater; - - // Default we're a Geometry - private CollisionCategories m_collisionCategories = (CollisionCategories.Geom); - - // Default, Collide with Other Geometries, spaces and Bodies - private CollisionCategories m_collisionFlags = m_default_collisionFlags; - - public bool m_taintremove { get; private set; } - public bool m_taintdisable { get; private set; } - internal bool m_disabled; - public bool m_taintadd { get; private set; } - public bool m_taintselected { get; private set; } - public bool m_taintCollidesWater { get; private set; } - - private bool m_taintforce = false; - private bool m_taintaddangularforce = false; - private Vector3 m_force; - private List m_forcelist = new List(); - private List m_angularforcelist = new List(); - - private PrimitiveBaseShape _pbs; - private OdeScene _parent_scene; - - /// - /// The physics space which contains prim geometries - /// - public IntPtr m_targetSpace = IntPtr.Zero; - - /// - /// The prim geometry, used for collision detection. - /// - /// - /// This is never null except for a brief period when the geometry needs to be replaced (due to resizing or - /// mesh change) or when the physical prim is being removed from the scene. - /// - public IntPtr prim_geom { get; private set; } - - public IntPtr _triMeshData { get; private set; } - - private IntPtr _linkJointGroup = IntPtr.Zero; - private PhysicsActor _parent; - private PhysicsActor m_taintparent; - - private List childrenPrim = new List(); - - private bool iscolliding; - private bool m_isSelected; - - internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively - - private bool m_throttleUpdates; - private int throttleCounter; - public int m_interpenetrationcount { get; private set; } - internal float m_collisionscore; - public int m_roundsUnderMotionThreshold { get; private set; } - private int m_crossingfailures; - - public bool outofBounds { get; private set; } - private float m_density = 10.000006836f; // Aluminum g/cm3; - - public bool _zeroFlag { get; private set; } - private bool m_lastUpdateSent; - - public IntPtr Body = IntPtr.Zero; - private Vector3 _target_velocity; - private d.Mass pMass; - - private int m_eventsubscription; - private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate(); - - /// - /// Signal whether there were collisions on the previous frame, so we know if we need to send the - /// empty CollisionEventsThisFrame to the prim so that it can detect the end of a collision. - /// - /// - /// This is probably a temporary measure, pending storing this information consistently in CollisionEventUpdate itself. - /// - private bool m_collisionsOnPreviousFrame; - - private IntPtr m_linkJoint = IntPtr.Zero; - - internal volatile bool childPrim; - - private ODEDynamics m_vehicle; - - internal int m_material = (int)Material.Wood; - - public OdePrim( - String primName, OdeScene parent_scene, Vector3 pos, Vector3 size, - Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) - { - Name = primName; - m_vehicle = new ODEDynamics(); - //gc = GCHandle.Alloc(prim_geom, GCHandleType.Pinned); - - if (!pos.IsFinite()) - { - pos = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), - parent_scene.GetTerrainHeightAtXY(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f)) + 0.5f); - m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Position for {0}", Name); - } - _position = pos; - m_taintposition = pos; - PID_D = parent_scene.bodyPIDD; - PID_G = parent_scene.bodyPIDG; - m_density = parent_scene.geomDefaultDensity; - // m_tensor = parent_scene.bodyMotorJointMaxforceTensor; - body_autodisable_frames = parent_scene.bodyFramesAutoDisable; - - prim_geom = IntPtr.Zero; - - if (!pos.IsFinite()) - { - size = new Vector3(0.5f, 0.5f, 0.5f); - m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Size for {0}", Name); - } - - if (size.X <= 0) size.X = 0.01f; - if (size.Y <= 0) size.Y = 0.01f; - if (size.Z <= 0) size.Z = 0.01f; - - _size = size; - m_taintsize = _size; - - if (!QuaternionIsFinite(rotation)) - { - rotation = Quaternion.Identity; - m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Rotation for {0}", Name); - } - - _orientation = rotation; - m_taintrot = _orientation; - _pbs = pbs; - - _parent_scene = parent_scene; - m_targetSpace = (IntPtr)0; - - if (pos.Z < 0) - { - IsPhysical = false; - } - else - { - IsPhysical = pisPhysical; - // If we're physical, we need to be in the master space for now. - // linksets *should* be in a space together.. but are not currently - if (IsPhysical) - m_targetSpace = _parent_scene.space; - } - - m_taintadd = true; - m_assetFailed = false; - _parent_scene.AddPhysicsActorTaint(this); - } - - public override int PhysicsActorType - { - get { return (int) ActorTypes.Prim; } - set { return; } - } - - public override bool SetAlwaysRun - { - get { return false; } - set { return; } - } - - public override bool Grabbed - { - set { return; } - } - - public override bool Selected - { - set - { - // This only makes the object not collidable if the object - // is physical or the object is modified somehow *IN THE FUTURE* - // without this, if an avatar selects prim, they can walk right - // through it while it's selected - m_collisionscore = 0; - - if ((IsPhysical && !_zeroFlag) || !value) - { - m_taintselected = value; - _parent_scene.AddPhysicsActorTaint(this); - } - else - { - m_taintselected = value; - m_isSelected = value; - } - - if (m_isSelected) - disableBodySoft(); - } - } - - /// - /// Set a new geometry for this prim. - /// - /// - private void SetGeom(IntPtr geom) - { - prim_geom = geom; -//Console.WriteLine("SetGeom to " + prim_geom + " for " + Name); - - if (m_assetFailed) - { - d.GeomSetCategoryBits(prim_geom, 0); - d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits); - } - else - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } - - _parent_scene.geom_name_map[prim_geom] = Name; - _parent_scene.actor_name_map[prim_geom] = this; - - if (childPrim) - { - if (_parent != null && _parent is OdePrim) - { - OdePrim parent = (OdePrim)_parent; -//Console.WriteLine("SetGeom calls ChildSetGeom"); - parent.ChildSetGeom(this); - } - } - //m_log.Warn("Setting Geom to: " + prim_geom); - } - - private void enableBodySoft() - { - if (!childPrim) - { - if (IsPhysical && Body != IntPtr.Zero) - { - d.BodyEnable(Body); - if (m_vehicle.Type != Vehicle.TYPE_NONE) - m_vehicle.Enable(Body, _parent_scene); - } - - m_disabled = false; - } - } - - private void disableBodySoft() - { - m_disabled = true; - - if (IsPhysical && Body != IntPtr.Zero) - { - d.BodyDisable(Body); - } - } - - /// - /// Make a prim subject to physics. - /// - private void enableBody() - { - // Don't enable this body if we're a child prim - // this should be taken care of in the parent function not here - if (!childPrim) - { - // Sets the geom to a body - Body = d.BodyCreate(_parent_scene.world); - - setMass(); - d.BodySetPosition(Body, _position.X, _position.Y, _position.Z); - d.Quaternion myrot = new d.Quaternion(); - myrot.X = _orientation.X; - myrot.Y = _orientation.Y; - myrot.Z = _orientation.Z; - myrot.W = _orientation.W; - d.BodySetQuaternion(Body, ref myrot); - d.GeomSetBody(prim_geom, Body); - - if (m_assetFailed) - { - d.GeomSetCategoryBits(prim_geom, 0); - d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits); - } - else - { - m_collisionCategories |= CollisionCategories.Body; - m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); - } - - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - - d.BodySetAutoDisableFlag(Body, true); - d.BodySetAutoDisableSteps(Body, body_autodisable_frames); - - // disconnect from world gravity so we can apply buoyancy - d.BodySetGravityMode (Body, false); - - m_interpenetrationcount = 0; - m_collisionscore = 0; - m_disabled = false; - - // The body doesn't already have a finite rotation mode set here - if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0.0f)) && _parent == null) - { - createAMotor(m_angularlock); - } - if (m_vehicle.Type != Vehicle.TYPE_NONE) - { - m_vehicle.Enable(Body, _parent_scene); - } - - _parent_scene.ActivatePrim(this); - } - } - - #region Mass Calculation - - private float CalculateMass() - { - float volume = _size.X * _size.Y * _size.Z; // default - float tmp; - - float returnMass = 0; - float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; - float hollowVolume = hollowAmount * hollowAmount; - - switch (_pbs.ProfileShape) - { - case ProfileShape.Square: - // default box - - if (_pbs.PathCurve == (byte)Extrusion.Straight) - { - if (hollowAmount > 0.0) - { - switch (_pbs.HollowShape) - { - case HollowShape.Square: - case HollowShape.Same: - break; - - case HollowShape.Circle: - - hollowVolume *= 0.78539816339f; - break; - - case HollowShape.Triangle: - - hollowVolume *= (0.5f * .5f); - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - - else if (_pbs.PathCurve == (byte)Extrusion.Curve1) - { - //a tube - - volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); - tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); - volume -= volume*tmp*tmp; - - if (hollowAmount > 0.0) - { - hollowVolume *= hollowAmount; - - switch (_pbs.HollowShape) - { - case HollowShape.Square: - case HollowShape.Same: - break; - - case HollowShape.Circle: - hollowVolume *= 0.78539816339f;; - break; - - case HollowShape.Triangle: - hollowVolume *= 0.5f * 0.5f; - break; - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - - break; - - case ProfileShape.Circle: - - if (_pbs.PathCurve == (byte)Extrusion.Straight) - { - volume *= 0.78539816339f; // elipse base - - if (hollowAmount > 0.0) - { - switch (_pbs.HollowShape) - { - case HollowShape.Same: - case HollowShape.Circle: - break; - - case HollowShape.Square: - hollowVolume *= 0.5f * 2.5984480504799f; - break; - - case HollowShape.Triangle: - hollowVolume *= .5f * 1.27323954473516f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - - else if (_pbs.PathCurve == (byte)Extrusion.Curve1) - { - volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); - tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); - volume *= (1.0f - tmp * tmp); - - if (hollowAmount > 0.0) - { - - // calculate the hollow volume by it's shape compared to the prim shape - hollowVolume *= hollowAmount; - - switch (_pbs.HollowShape) - { - case HollowShape.Same: - case HollowShape.Circle: - break; - - case HollowShape.Square: - hollowVolume *= 0.5f * 2.5984480504799f; - break; - - case HollowShape.Triangle: - hollowVolume *= .5f * 1.27323954473516f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - break; - - case ProfileShape.HalfCircle: - if (_pbs.PathCurve == (byte)Extrusion.Curve1) - { - volume *= 0.52359877559829887307710723054658f; - } - break; - - case ProfileShape.EquilateralTriangle: - - if (_pbs.PathCurve == (byte)Extrusion.Straight) - { - volume *= 0.32475953f; - - if (hollowAmount > 0.0) - { - - // calculate the hollow volume by it's shape compared to the prim shape - switch (_pbs.HollowShape) - { - case HollowShape.Same: - case HollowShape.Triangle: - hollowVolume *= .25f; - break; - - case HollowShape.Square: - hollowVolume *= 0.499849f * 3.07920140172638f; - break; - - case HollowShape.Circle: - // Hollow shape is a perfect cyllinder in respect to the cube's scale - // Cyllinder hollow volume calculation - - hollowVolume *= 0.1963495f * 3.07920140172638f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - else if (_pbs.PathCurve == (byte)Extrusion.Curve1) - { - volume *= 0.32475953f; - volume *= 0.01f * (float)(200 - _pbs.PathScaleX); - tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); - volume *= (1.0f - tmp * tmp); - - if (hollowAmount > 0.0) - { - - hollowVolume *= hollowAmount; - - switch (_pbs.HollowShape) - { - case HollowShape.Same: - case HollowShape.Triangle: - hollowVolume *= .25f; - break; - - case HollowShape.Square: - hollowVolume *= 0.499849f * 3.07920140172638f; - break; - - case HollowShape.Circle: - - hollowVolume *= 0.1963495f * 3.07920140172638f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - break; - - default: - break; - } - - float taperX1; - float taperY1; - float taperX; - float taperY; - float pathBegin; - float pathEnd; - float profileBegin; - float profileEnd; - - if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) - { - taperX1 = _pbs.PathScaleX * 0.01f; - if (taperX1 > 1.0f) - taperX1 = 2.0f - taperX1; - taperX = 1.0f - taperX1; - - taperY1 = _pbs.PathScaleY * 0.01f; - if (taperY1 > 1.0f) - taperY1 = 2.0f - taperY1; - taperY = 1.0f - taperY1; - } - else - { - taperX = _pbs.PathTaperX * 0.01f; - if (taperX < 0.0f) - taperX = -taperX; - taperX1 = 1.0f - taperX; - - taperY = _pbs.PathTaperY * 0.01f; - if (taperY < 0.0f) - taperY = -taperY; - taperY1 = 1.0f - taperY; - } - - volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); - - pathBegin = (float)_pbs.PathBegin * 2.0e-5f; - pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f; - volume *= (pathEnd - pathBegin); - -// this is crude aproximation - profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f; - profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f; - volume *= (profileEnd - profileBegin); - - returnMass = m_density * volume; - - if (returnMass <= 0) - returnMass = 0.0001f;//ckrinke: Mass must be greater then zero. -// else if (returnMass > _parent_scene.maximumMassObject) -// returnMass = _parent_scene.maximumMassObject; - - // Recursively calculate mass - bool HasChildPrim = false; - lock (childrenPrim) - { - if (childrenPrim.Count > 0) - { - HasChildPrim = true; - } - } - - if (HasChildPrim) - { - OdePrim[] childPrimArr = new OdePrim[0]; - - lock (childrenPrim) - childPrimArr = childrenPrim.ToArray(); - - for (int i = 0; i < childPrimArr.Length; i++) - { - if (childPrimArr[i] != null && !childPrimArr[i].m_taintremove) - returnMass += childPrimArr[i].CalculateMass(); - // failsafe, this shouldn't happen but with OpenSim, you never know :) - if (i > 256) - break; - } - } - - if (returnMass > _parent_scene.maximumMassObject) - returnMass = _parent_scene.maximumMassObject; - - return returnMass; - } - - #endregion - - private void setMass() - { - if (Body != (IntPtr) 0) - { - float newmass = CalculateMass(); - - //m_log.Info("[PHYSICS]: New Mass: " + newmass.ToString()); - - d.MassSetBoxTotal(out pMass, newmass, _size.X, _size.Y, _size.Z); - d.BodySetMass(Body, ref pMass); - } - } - - /// - /// Stop a prim from being subject to physics. - /// - internal void disableBody() - { - //this kills the body so things like 'mesh' can re-create it. - lock (this) - { - if (!childPrim) - { - if (Body != IntPtr.Zero) - { - _parent_scene.DeactivatePrim(this); - m_collisionCategories &= ~CollisionCategories.Body; - m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); - - if (m_assetFailed) - { - d.GeomSetCategoryBits(prim_geom, 0); - d.GeomSetCollideBits(prim_geom, 0); - } - else - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } - - d.BodyDestroy(Body); - lock (childrenPrim) - { - if (childrenPrim.Count > 0) - { - foreach (OdePrim prm in childrenPrim) - { - _parent_scene.DeactivatePrim(prm); - prm.Body = IntPtr.Zero; - } - } - } - Body = IntPtr.Zero; - } - } - else - { - _parent_scene.DeactivatePrim(this); - - m_collisionCategories &= ~CollisionCategories.Body; - m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); - - if (m_assetFailed) - { - d.GeomSetCategoryBits(prim_geom, 0); - d.GeomSetCollideBits(prim_geom, 0); - } - else - { - - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } - - Body = IntPtr.Zero; - } - } - - m_disabled = true; - m_collisionscore = 0; - } - - private static Dictionary m_MeshToTriMeshMap = new Dictionary(); - - private void setMesh(OdeScene parent_scene, IMesh mesh) - { -// m_log.DebugFormat("[ODE PRIM]: Setting mesh on {0} to {1}", Name, mesh); - - // This sleeper is there to moderate how long it takes between - // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object - - //Thread.Sleep(10); - - //Kill Body so that mesh can re-make the geom - if (IsPhysical && Body != IntPtr.Zero) - { - if (childPrim) - { - if (_parent != null) - { - OdePrim parent = (OdePrim)_parent; - parent.ChildDelink(this); - } - } - else - { - disableBody(); - } - } - - IntPtr vertices, indices; - int vertexCount, indexCount; - int vertexStride, triStride; - mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap - mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage - m_expectedCollisionContacts = indexCount; - mesh.releaseSourceMeshData(); // free up the original mesh data to save memory - - // We must lock here since m_MeshToTriMeshMap is static and multiple scene threads may call this method at - // the same time. - lock (m_MeshToTriMeshMap) - { - if (m_MeshToTriMeshMap.ContainsKey(mesh)) - { - _triMeshData = m_MeshToTriMeshMap[mesh]; - } - else - { - _triMeshData = d.GeomTriMeshDataCreate(); - - d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride); - d.GeomTriMeshDataPreprocess(_triMeshData); - m_MeshToTriMeshMap[mesh] = _triMeshData; - } - } - -// _parent_scene.waitForSpaceUnlock(m_targetSpace); - try - { - SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null)); - } - catch (AccessViolationException) - { - m_log.ErrorFormat("[PHYSICS]: MESH LOCKED FOR {0}", Name); - return; - } - - // if (IsPhysical && Body == (IntPtr) 0) - // { - // Recreate the body - // m_interpenetrationcount = 0; - // m_collisionscore = 0; - - // enableBody(); - // } - } - - internal void ProcessTaints() - { -#if SPAM -Console.WriteLine("ZProcessTaints for " + Name); -#endif - - // This must be processed as the very first taint so that later operations have a prim_geom to work with - // if this is a new prim. - if (m_taintadd) - changeadd(); - - if (!_position.ApproxEquals(m_taintposition, 0f)) - changemove(); - - if (m_taintrot != _orientation) - { - if (childPrim && IsPhysical) // For physical child prim... - { - rotate(); - // KF: ODE will also rotate the parent prim! - // so rotate the root back to where it was - OdePrim parent = (OdePrim)_parent; - parent.rotate(); - } - else - { - //Just rotate the prim - rotate(); - } - } - - if (m_taintPhysics != IsPhysical && !(m_taintparent != _parent)) - changePhysicsStatus(); - - if (!_size.ApproxEquals(m_taintsize, 0f)) - changesize(); - - if (m_taintshape) - changeshape(); - - if (m_taintforce) - changeAddForce(); - - if (m_taintaddangularforce) - changeAddAngularForce(); - - if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f)) - changeSetTorque(); - - if (m_taintdisable) - changedisable(); - - if (m_taintselected != m_isSelected) - changeSelectedStatus(); - - if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f)) - changevelocity(); - - if (m_taintparent != _parent) - changelink(); - - if (m_taintCollidesWater != m_collidesWater) - changefloatonwater(); - - if (!m_angularlock.ApproxEquals(m_taintAngularLock,0f)) - changeAngularLock(); - } - - /// - /// Change prim in response to an angular lock taint. - /// - private void changeAngularLock() - { - // do we have a Physical object? - if (Body != IntPtr.Zero) - { - //Check that we have a Parent - //If we have a parent then we're not authorative here - if (_parent == null) - { - if (!m_taintAngularLock.ApproxEquals(Vector3.One, 0f)) - { - //d.BodySetFiniteRotationMode(Body, 0); - //d.BodySetFiniteRotationAxis(Body,m_taintAngularLock.X,m_taintAngularLock.Y,m_taintAngularLock.Z); - createAMotor(m_taintAngularLock); - } - else - { - if (Amotor != IntPtr.Zero) - { - d.JointDestroy(Amotor); - Amotor = IntPtr.Zero; - } - } - } - } - - // Store this for later in case we get turned into a separate body - m_angularlock = m_taintAngularLock; - } - - /// - /// Change prim in response to a link taint. - /// - private void changelink() - { - // If the newly set parent is not null - // create link - if (_parent == null && m_taintparent != null) - { - if (m_taintparent.PhysicsActorType == (int)ActorTypes.Prim) - { - OdePrim obj = (OdePrim)m_taintparent; - //obj.disableBody(); -//Console.WriteLine("changelink calls ParentPrim"); - obj.AddChildPrim(this); - - /* - if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body) - { - _linkJointGroup = d.JointGroupCreate(0); - m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup); - d.JointAttach(m_linkJoint, obj.Body, Body); - d.JointSetFixed(m_linkJoint); - } - */ - } - } - // If the newly set parent is null - // destroy link - else if (_parent != null && m_taintparent == null) - { -//Console.WriteLine(" changelink B"); - - if (_parent is OdePrim) - { - OdePrim obj = (OdePrim)_parent; - obj.ChildDelink(this); - childPrim = false; - //_parent = null; - } - - /* - if (Body != (IntPtr)0 && _linkJointGroup != (IntPtr)0) - d.JointGroupDestroy(_linkJointGroup); - - _linkJointGroup = (IntPtr)0; - m_linkJoint = (IntPtr)0; - */ - } - - _parent = m_taintparent; - m_taintPhysics = IsPhysical; - } - - /// - /// Add a child prim to this parent prim. - /// - /// Child prim - private void AddChildPrim(OdePrim prim) - { - if (LocalID == prim.LocalID) - return; - - if (Body == IntPtr.Zero) - { - Body = d.BodyCreate(_parent_scene.world); - setMass(); - } - - lock (childrenPrim) - { - if (childrenPrim.Contains(prim)) - return; - -// m_log.DebugFormat( -// "[ODE PRIM]: Linking prim {0} {1} to {2} {3}", prim.Name, prim.LocalID, Name, LocalID); - - childrenPrim.Add(prim); - - foreach (OdePrim prm in childrenPrim) - { - d.Mass m2; - d.MassSetZero(out m2); - d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z); - - d.Quaternion quat = new d.Quaternion(); - quat.W = prm._orientation.W; - quat.X = prm._orientation.X; - quat.Y = prm._orientation.Y; - quat.Z = prm._orientation.Z; - - d.Matrix3 mat = new d.Matrix3(); - d.RfromQ(out mat, ref quat); - d.MassRotate(ref m2, ref mat); - d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z); - d.MassAdd(ref pMass, ref m2); - } - - foreach (OdePrim prm in childrenPrim) - { - prm.m_collisionCategories |= CollisionCategories.Body; - prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); - -//Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + Name); - if (prm.m_assetFailed) - { - d.GeomSetCategoryBits(prm.prim_geom, 0); - d.GeomSetCollideBits(prm.prim_geom, prm.BadMeshAssetCollideBits); - } - else - { - d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories); - d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags); - } - - d.Quaternion quat = new d.Quaternion(); - quat.W = prm._orientation.W; - quat.X = prm._orientation.X; - quat.Y = prm._orientation.Y; - quat.Z = prm._orientation.Z; - - d.Matrix3 mat = new d.Matrix3(); - d.RfromQ(out mat, ref quat); - if (Body != IntPtr.Zero) - { - d.GeomSetBody(prm.prim_geom, Body); - prm.childPrim = true; - d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z); - //d.GeomSetOffsetPosition(prim.prim_geom, - // (Position.X - prm.Position.X) - pMass.c.X, - // (Position.Y - prm.Position.Y) - pMass.c.Y, - // (Position.Z - prm.Position.Z) - pMass.c.Z); - d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat); - //d.GeomSetOffsetRotation(prm.prim_geom, ref mat); - d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); - d.BodySetMass(Body, ref pMass); - } - else - { - m_log.DebugFormat("[PHYSICS]: {0} ain't got no boooooooooddy, no body", Name); - } - - prm.m_interpenetrationcount = 0; - prm.m_collisionscore = 0; - prm.m_disabled = false; - - // The body doesn't already have a finite rotation mode set here - if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null) - { - prm.createAMotor(m_angularlock); - } - prm.Body = Body; - _parent_scene.ActivatePrim(prm); - } - - m_collisionCategories |= CollisionCategories.Body; - m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); - - if (m_assetFailed) - { - d.GeomSetCategoryBits(prim_geom, 0); - d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits); - } - else - { - //Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + Name); - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - //Console.WriteLine(" Post GeomSetCategoryBits 2"); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } - - d.Quaternion quat2 = new d.Quaternion(); - quat2.W = _orientation.W; - quat2.X = _orientation.X; - quat2.Y = _orientation.Y; - quat2.Z = _orientation.Z; - - d.Matrix3 mat2 = new d.Matrix3(); - d.RfromQ(out mat2, ref quat2); - d.GeomSetBody(prim_geom, Body); - d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z); - //d.GeomSetOffsetPosition(prim.prim_geom, - // (Position.X - prm.Position.X) - pMass.c.X, - // (Position.Y - prm.Position.Y) - pMass.c.Y, - // (Position.Z - prm.Position.Z) - pMass.c.Z); - //d.GeomSetOffsetRotation(prim_geom, ref mat2); - d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); - d.BodySetMass(Body, ref pMass); - - d.BodySetAutoDisableFlag(Body, true); - d.BodySetAutoDisableSteps(Body, body_autodisable_frames); - - m_interpenetrationcount = 0; - m_collisionscore = 0; - m_disabled = false; - - // The body doesn't already have a finite rotation mode set here - if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null) - { - createAMotor(m_angularlock); - } - - d.BodySetPosition(Body, Position.X, Position.Y, Position.Z); - - if (m_vehicle.Type != Vehicle.TYPE_NONE) - m_vehicle.Enable(Body, _parent_scene); - - _parent_scene.ActivatePrim(this); - } - } - - private void ChildSetGeom(OdePrim odePrim) - { -// m_log.DebugFormat( -// "[ODE PRIM]: ChildSetGeom {0} {1} for {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID); - - //if (IsPhysical && Body != IntPtr.Zero) - lock (childrenPrim) - { - foreach (OdePrim prm in childrenPrim) - { - //prm.childPrim = true; - prm.disableBody(); - //prm.m_taintparent = null; - //prm._parent = null; - //prm.m_taintPhysics = false; - //prm.m_disabled = true; - //prm.childPrim = false; - } - } - - disableBody(); - - // Spurious - Body == IntPtr.Zero after disableBody() -// if (Body != IntPtr.Zero) -// { -// _parent_scene.DeactivatePrim(this); -// } - - lock (childrenPrim) - { - foreach (OdePrim prm in childrenPrim) - { -//Console.WriteLine("ChildSetGeom calls ParentPrim"); - AddChildPrim(prm); - } - } - } - - private void ChildDelink(OdePrim odePrim) - { -// m_log.DebugFormat( -// "[ODE PRIM]: Delinking prim {0} {1} from {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID); - - // Okay, we have a delinked child.. need to rebuild the body. - lock (childrenPrim) - { - foreach (OdePrim prm in childrenPrim) - { - prm.childPrim = true; - prm.disableBody(); - //prm.m_taintparent = null; - //prm._parent = null; - //prm.m_taintPhysics = false; - //prm.m_disabled = true; - //prm.childPrim = false; - } - } - - disableBody(); - - lock (childrenPrim) - { - //Console.WriteLine("childrenPrim.Remove " + odePrim); - childrenPrim.Remove(odePrim); - } - - // Spurious - Body == IntPtr.Zero after disableBody() -// if (Body != IntPtr.Zero) -// { -// _parent_scene.DeactivatePrim(this); -// } - - lock (childrenPrim) - { - foreach (OdePrim prm in childrenPrim) - { -//Console.WriteLine("ChildDelink calls ParentPrim"); - AddChildPrim(prm); - } - } - } - - /// - /// Change prim in response to a selection taint. - /// - private void changeSelectedStatus() - { - if (m_taintselected) - { - m_collisionCategories = CollisionCategories.Selected; - m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space); - - // We do the body disable soft twice because 'in theory' a collision could have happened - // in between the disabling and the collision properties setting - // which would wake the physical body up from a soft disabling and potentially cause it to fall - // through the ground. - - // NOTE FOR JOINTS: this doesn't always work for jointed assemblies because if you select - // just one part of the assembly, the rest of the assembly is non-selected and still simulating, - // so that causes the selected part to wake up and continue moving. - - // even if you select all parts of a jointed assembly, it is not guaranteed that the entire - // assembly will stop simulating during the selection, because of the lack of atomicity - // of select operations (their processing could be interrupted by a thread switch, causing - // simulation to continue before all of the selected object notifications trickle down to - // the physics engine). - - // e.g. we select 100 prims that are connected by joints. non-atomically, the first 50 are - // selected and disabled. then, due to a thread switch, the selection processing is - // interrupted and the physics engine continues to simulate, so the last 50 items, whose - // selection was not yet processed, continues to simulate. this wakes up ALL of the - // first 50 again. then the last 50 are disabled. then the first 50, which were just woken - // up, start simulating again, which in turn wakes up the last 50. - - if (IsPhysical) - { - disableBodySoft(); - } - - if (m_assetFailed) - { - d.GeomSetCategoryBits(prim_geom, 0); - d.GeomSetCollideBits(prim_geom, 0); - } - else - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } - - if (IsPhysical) - { - disableBodySoft(); - } - } - else - { - m_collisionCategories = CollisionCategories.Geom; - - if (IsPhysical) - m_collisionCategories |= CollisionCategories.Body; - - m_collisionFlags = m_default_collisionFlags; - - if (m_collidesLand) - m_collisionFlags |= CollisionCategories.Land; - if (m_collidesWater) - m_collisionFlags |= CollisionCategories.Water; - - if (m_assetFailed) - { - d.GeomSetCategoryBits(prim_geom, 0); - d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits); - } - else - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } - - if (IsPhysical) - { - if (Body != IntPtr.Zero) - { - d.BodySetLinearVel(Body, 0f, 0f, 0f); - d.BodySetForce(Body, 0, 0, 0); - enableBodySoft(); - } - } - } - - resetCollisionAccounting(); - m_isSelected = m_taintselected; - }//end changeSelectedStatus - - internal void ResetTaints() - { - m_taintposition = _position; - m_taintrot = _orientation; - m_taintPhysics = IsPhysical; - m_taintselected = m_isSelected; - m_taintsize = _size; - m_taintshape = false; - m_taintforce = false; - m_taintdisable = false; - m_taintVelocity = Vector3.Zero; - } - - /// - /// Create a geometry for the given mesh in the given target space. - /// - /// - /// If null, then a mesh is used that is based on the profile shape data. - private void CreateGeom(IntPtr m_targetSpace, IMesh mesh) - { -#if SPAM -Console.WriteLine("CreateGeom:"); -#endif - if (mesh != null) - { - setMesh(_parent_scene, mesh); - } - else - { - if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) - { - if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) - { - if (((_size.X / 2f) > 0f)) - { -// _parent_scene.waitForSpaceUnlock(m_targetSpace); - try - { -//Console.WriteLine(" CreateGeom 1"); - SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2)); - m_expectedCollisionContacts = 3; - } - catch (AccessViolationException) - { - m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name); - return; - } - } - else - { -// _parent_scene.waitForSpaceUnlock(m_targetSpace); - try - { -//Console.WriteLine(" CreateGeom 2"); - SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); - m_expectedCollisionContacts = 4; - } - catch (AccessViolationException) - { - m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name); - return; - } - } - } - else - { -// _parent_scene.waitForSpaceUnlock(m_targetSpace); - try - { -//Console.WriteLine(" CreateGeom 3"); - SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); - m_expectedCollisionContacts = 4; - } - catch (AccessViolationException) - { - m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name); - return; - } - } - } - else - { -// _parent_scene.waitForSpaceUnlock(m_targetSpace); - try - { -//Console.WriteLine(" CreateGeom 4"); - SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); - m_expectedCollisionContacts = 4; - } - catch (AccessViolationException) - { - m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name); - return; - } - } - } - } - - /// - /// Remove the existing geom from this prim. - /// - /// - /// If null, then a mesh is used that is based on the profile shape data. - /// true if the geom was successfully removed, false if it was already gone or the remove failed. - internal bool RemoveGeom() - { - if (prim_geom != IntPtr.Zero) - { - try - { - _parent_scene.geom_name_map.Remove(prim_geom); - _parent_scene.actor_name_map.Remove(prim_geom); - d.GeomDestroy(prim_geom); - m_expectedCollisionContacts = 0; - prim_geom = IntPtr.Zero; - } - catch (System.AccessViolationException) - { - prim_geom = IntPtr.Zero; - m_expectedCollisionContacts = 0; - m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name); - - return false; - } - - return true; - } - else - { - m_log.WarnFormat( - "[ODE PRIM]: Called RemoveGeom() on {0} {1} where geometry was already null.", Name, LocalID); - - return false; - } - } - /// - /// Add prim in response to an add taint. - /// - private void changeadd() - { -// m_log.DebugFormat("[ODE PRIM]: Adding prim {0}", Name); - - int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position); - IntPtr targetspace = _parent_scene.calculateSpaceForGeom(_position); - - if (targetspace == IntPtr.Zero) - targetspace = _parent_scene.createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]); - - m_targetSpace = targetspace; - - IMesh mesh = null; - - if (_parent_scene.needsMeshing(_pbs)) - { - // Don't need to re-enable body.. it's done in SetMesh - mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical); - // createmesh returns null when it's a shape that isn't a cube. - // m_log.Debug(m_localID); - if (mesh == null) - CheckMeshAsset(); - else - m_assetFailed = false; - } - -#if SPAM -Console.WriteLine("changeadd 1"); -#endif - CreateGeom(m_targetSpace, mesh); - - d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); - d.Quaternion myrot = new d.Quaternion(); - myrot.X = _orientation.X; - myrot.Y = _orientation.Y; - myrot.Z = _orientation.Z; - myrot.W = _orientation.W; - d.GeomSetQuaternion(prim_geom, ref myrot); - - if (IsPhysical && Body == IntPtr.Zero) - enableBody(); - - changeSelectedStatus(); - - m_taintadd = false; - } - - /// - /// Move prim in response to a move taint. - /// - private void changemove() - { - if (IsPhysical) - { - if (!m_disabled && !m_taintremove && !childPrim) - { - if (Body == IntPtr.Zero) - enableBody(); - - //Prim auto disable after 20 frames, - //if you move it, re-enable the prim manually. - if (_parent != null) - { - if (m_linkJoint != IntPtr.Zero) - { - d.JointDestroy(m_linkJoint); - m_linkJoint = IntPtr.Zero; - } - } - - if (Body != IntPtr.Zero) - { - d.BodySetPosition(Body, _position.X, _position.Y, _position.Z); - - if (_parent != null) - { - OdePrim odParent = (OdePrim)_parent; - if (Body != (IntPtr)0 && odParent.Body != (IntPtr)0 && Body != odParent.Body) - { -// KF: Fixed Joints were removed? Anyway - this Console.WriteLine does not show up, so routine is not used?? -Console.WriteLine(" JointCreateFixed"); - m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup); - d.JointAttach(m_linkJoint, Body, odParent.Body); - d.JointSetFixed(m_linkJoint); - } - } - d.BodyEnable(Body); - if (m_vehicle.Type != Vehicle.TYPE_NONE) - { - m_vehicle.Enable(Body, _parent_scene); - } - } - else - { - m_log.WarnFormat("[PHYSICS]: Body for {0} still null after enableBody(). This is a crash scenario.", Name); - } - } - //else - // { - //m_log.Debug("[BUG]: race!"); - //} - } - - // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position); - // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position); -// _parent_scene.waitForSpaceUnlock(m_targetSpace); - - IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace); - m_targetSpace = tempspace; - -// _parent_scene.waitForSpaceUnlock(m_targetSpace); - - d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); - -// _parent_scene.waitForSpaceUnlock(m_targetSpace); - d.SpaceAdd(m_targetSpace, prim_geom); - - changeSelectedStatus(); - - resetCollisionAccounting(); - m_taintposition = _position; - } - - internal void Move(float timestep) - { - float fx = 0; - float fy = 0; - float fz = 0; - - if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // KF: Only move root prims. - { - if (m_vehicle.Type != Vehicle.TYPE_NONE) - { - // 'VEHICLES' are dealt with in ODEDynamics.cs - m_vehicle.Step(timestep, _parent_scene); - } - else - { -//Console.WriteLine("Move " + Name); - if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009 - // NON-'VEHICLES' are dealt with here -// if (d.BodyIsEnabled(Body) && !m_angularlock.ApproxEquals(Vector3.Zero, 0.003f)) -// { -// d.Vector3 avel2 = d.BodyGetAngularVel(Body); -// /* -// if (m_angularlock.X == 1) -// avel2.X = 0; -// if (m_angularlock.Y == 1) -// avel2.Y = 0; -// if (m_angularlock.Z == 1) -// avel2.Z = 0; -// d.BodySetAngularVel(Body, avel2.X, avel2.Y, avel2.Z); -// */ -// } - //float PID_P = 900.0f; - - float m_mass = CalculateMass(); - -// fz = 0f; - //m_log.Info(m_collisionFlags.ToString()); - - - //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle. - // would come from SceneObjectPart.cs, public void SetBuoyancy(float fvalue) , PhysActor.Buoyancy = fvalue; ?? - // m_buoyancy: (unlimited value) <0=Falls fast; 0=1g; 1=0g; >1 = floats up - // gravityz multiplier = 1 - m_buoyancy - fz = _parent_scene.gravityz * (1.0f - m_buoyancy) * m_mass; - - if (m_usePID) - { -//Console.WriteLine("PID " + Name); - // KF - this is for object move? eg. llSetPos() ? - //if (!d.BodyIsEnabled(Body)) - //d.BodySetForce(Body, 0f, 0f, 0f); - // If we're using the PID controller, then we have no gravity - //fz = (-1 * _parent_scene.gravityz) * m_mass; //KF: ?? Prims have no global gravity,so simply... - fz = 0f; - - // no lock; for now it's only called from within Simulate() - - // If the PID Controller isn't active then we set our force - // calculating base velocity to the current position - - if ((m_PIDTau < 1) && (m_PIDTau != 0)) - { - //PID_G = PID_G / m_PIDTau; - m_PIDTau = 1; - } - - if ((PID_G - m_PIDTau) <= 0) - { - PID_G = m_PIDTau + 1; - } - //PidStatus = true; - - // PhysicsVector vec = new PhysicsVector(); - d.Vector3 vel = d.BodyGetLinearVel(Body); - - d.Vector3 pos = d.BodyGetPosition(Body); - _target_velocity = - new Vector3( - (m_PIDTarget.X - pos.X) * ((PID_G - m_PIDTau) * timestep), - (m_PIDTarget.Y - pos.Y) * ((PID_G - m_PIDTau) * timestep), - (m_PIDTarget.Z - pos.Z) * ((PID_G - m_PIDTau) * timestep) - ); - - // if velocity is zero, use position control; otherwise, velocity control - - if (_target_velocity.ApproxEquals(Vector3.Zero,0.1f)) - { - // keep track of where we stopped. No more slippin' & slidin' - - // We only want to deactivate the PID Controller if we think we want to have our surrogate - // react to the physics scene by moving it's position. - // Avatar to Avatar collisions - // Prim to avatar collisions - - //fx = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2); - //fy = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2); - //fz = fz + (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P; - d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z); - d.BodySetLinearVel(Body, 0, 0, 0); - d.BodyAddForce(Body, 0, 0, fz); - return; - } - else - { - _zeroFlag = false; - - // We're flying and colliding with something - fx = ((_target_velocity.X) - vel.X) * (PID_D); - fy = ((_target_velocity.Y) - vel.Y) * (PID_D); - - // vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P; - - fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass); - } - } // end if (m_usePID) - - // Hover PID Controller needs to be mutually exlusive to MoveTo PID controller - if (m_useHoverPID && !m_usePID) - { -//Console.WriteLine("Hover " + Name); - - // If we're using the PID controller, then we have no gravity - fz = (-1 * _parent_scene.gravityz) * m_mass; - - // no lock; for now it's only called from within Simulate() - - // If the PID Controller isn't active then we set our force - // calculating base velocity to the current position - - if ((m_PIDTau < 1)) - { - PID_G = PID_G / m_PIDTau; - } - - if ((PID_G - m_PIDTau) <= 0) - { - PID_G = m_PIDTau + 1; - } - - // Where are we, and where are we headed? - d.Vector3 pos = d.BodyGetPosition(Body); - d.Vector3 vel = d.BodyGetLinearVel(Body); - - // Non-Vehicles have a limited set of Hover options. - // determine what our target height really is based on HoverType - switch (m_PIDHoverType) - { - case PIDHoverType.Ground: - m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y); - m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight; - break; - case PIDHoverType.GroundAndWater: - m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y); - m_waterHeight = _parent_scene.GetWaterLevel(); - if (m_groundHeight > m_waterHeight) - { - m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight; - } - else - { - m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight; - } - break; - - } // end switch (m_PIDHoverType) - - - _target_velocity = - new Vector3(0.0f, 0.0f, - (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep) - ); - - // if velocity is zero, use position control; otherwise, velocity control - - if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f)) - { - // keep track of where we stopped. No more slippin' & slidin' - - // We only want to deactivate the PID Controller if we think we want to have our surrogate - // react to the physics scene by moving it's position. - // Avatar to Avatar collisions - // Prim to avatar collisions - - d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight); - d.BodySetLinearVel(Body, vel.X, vel.Y, 0); - d.BodyAddForce(Body, 0, 0, fz); - return; - } - else - { - _zeroFlag = false; - - // We're flying and colliding with something - fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass); - } - } - - fx *= m_mass; - fy *= m_mass; - //fz *= m_mass; - - fx += m_force.X; - fy += m_force.Y; - fz += m_force.Z; - - //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString()); - if (fx != 0 || fy != 0 || fz != 0) - { - //m_taintdisable = true; - //base.RaiseOutOfBounds(Position); - //d.BodySetLinearVel(Body, fx, fy, 0f); - if (!d.BodyIsEnabled(Body)) - { - // A physical body at rest on a surface will auto-disable after a while, - // this appears to re-enable it incase the surface it is upon vanishes, - // and the body should fall again. - d.BodySetLinearVel(Body, 0f, 0f, 0f); - d.BodySetForce(Body, 0, 0, 0); - enableBodySoft(); - } - - // 35x10 = 350n times the mass per second applied maximum. - float nmax = 35f * m_mass; - float nmin = -35f * m_mass; - - if (fx > nmax) - fx = nmax; - if (fx < nmin) - fx = nmin; - if (fy > nmax) - fy = nmax; - if (fy < nmin) - fy = nmin; - d.BodyAddForce(Body, fx, fy, fz); -//Console.WriteLine("AddForce " + fx + "," + fy + "," + fz); - } - } - } - else - { // is not physical, or is not a body or is selected - // _zeroPosition = d.BodyGetPosition(Body); - return; -//Console.WriteLine("Nothing " + Name); - - } - } - - private void rotate() - { - d.Quaternion myrot = new d.Quaternion(); - myrot.X = _orientation.X; - myrot.Y = _orientation.Y; - myrot.Z = _orientation.Z; - myrot.W = _orientation.W; - if (Body != IntPtr.Zero) - { - // KF: If this is a root prim do BodySet - d.BodySetQuaternion(Body, ref myrot); - if (IsPhysical) - { - if (!m_angularlock.ApproxEquals(Vector3.One, 0f)) - createAMotor(m_angularlock); - } - } - else - { - // daughter prim, do Geom set - d.GeomSetQuaternion(prim_geom, ref myrot); - } - - resetCollisionAccounting(); - m_taintrot = _orientation; - } - - private void resetCollisionAccounting() - { - m_collisionscore = 0; - m_interpenetrationcount = 0; - m_disabled = false; - } - - /// - /// Change prim in response to a disable taint. - /// - private void changedisable() - { - m_disabled = true; - if (Body != IntPtr.Zero) - { - d.BodyDisable(Body); - Body = IntPtr.Zero; - } - - m_taintdisable = false; - } - - /// - /// Change prim in response to a physics status taint - /// - private void changePhysicsStatus() - { - if (IsPhysical) - { - if (Body == IntPtr.Zero) - { - if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim) - { - changeshape(); - } - else - { - enableBody(); - } - } - } - else - { - if (Body != IntPtr.Zero) - { - if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim) - { - RemoveGeom(); - -//Console.WriteLine("changePhysicsStatus for " + Name); - changeadd(); - } - - if (childPrim) - { - if (_parent != null) - { - OdePrim parent = (OdePrim)_parent; - parent.ChildDelink(this); - } - } - else - { - disableBody(); - } - } - } - - changeSelectedStatus(); - - resetCollisionAccounting(); - m_taintPhysics = IsPhysical; - } - - /// - /// Change prim in response to a size taint. - /// - private void changesize() - { -#if SPAM - m_log.DebugFormat("[ODE PRIM]: Called changesize"); -#endif - - if (_size.X <= 0) _size.X = 0.01f; - if (_size.Y <= 0) _size.Y = 0.01f; - if (_size.Z <= 0) _size.Z = 0.01f; - - //kill body to rebuild - if (IsPhysical && Body != IntPtr.Zero) - { - if (childPrim) - { - if (_parent != null) - { - OdePrim parent = (OdePrim)_parent; - parent.ChildDelink(this); - } - } - else - { - disableBody(); - } - } - - if (d.SpaceQuery(m_targetSpace, prim_geom)) - { -// _parent_scene.waitForSpaceUnlock(m_targetSpace); - d.SpaceRemove(m_targetSpace, prim_geom); - } - - RemoveGeom(); - - // we don't need to do space calculation because the client sends a position update also. - - IMesh mesh = null; - - // Construction of new prim - if (_parent_scene.needsMeshing(_pbs)) - { - float meshlod = _parent_scene.meshSculptLOD; - - if (IsPhysical) - meshlod = _parent_scene.MeshSculptphysicalLOD; - // Don't need to re-enable body.. it's done in SetMesh - - if (_parent_scene.needsMeshing(_pbs)) - { - mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical); - if (mesh == null) - CheckMeshAsset(); - else - m_assetFailed = false; - } - - } - - CreateGeom(m_targetSpace, mesh); - d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); - d.Quaternion myrot = new d.Quaternion(); - myrot.X = _orientation.X; - myrot.Y = _orientation.Y; - myrot.Z = _orientation.Z; - myrot.W = _orientation.W; - d.GeomSetQuaternion(prim_geom, ref myrot); - - //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z); - if (IsPhysical && Body == IntPtr.Zero && !childPrim) - { - // Re creates body on size. - // EnableBody also does setMass() - enableBody(); - d.BodyEnable(Body); - } - - changeSelectedStatus(); - - if (childPrim) - { - if (_parent is OdePrim) - { - OdePrim parent = (OdePrim)_parent; - parent.ChildSetGeom(this); - } - } - resetCollisionAccounting(); - m_taintsize = _size; - } - - /// - /// Change prim in response to a float on water taint. - /// - /// - private void changefloatonwater() - { - m_collidesWater = m_taintCollidesWater; - - if (m_collidesWater) - { - m_collisionFlags |= CollisionCategories.Water; - } - else - { - m_collisionFlags &= ~CollisionCategories.Water; - } - - if (m_assetFailed) - d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits); - else - - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } - /// - /// Change prim in response to a shape taint. - /// - private void changeshape() - { - m_taintshape = false; - - // Cleanup of old prim geometry and Bodies - if (IsPhysical && Body != IntPtr.Zero) - { - if (childPrim) - { - if (_parent != null) - { - OdePrim parent = (OdePrim)_parent; - parent.ChildDelink(this); - } - } - else - { - disableBody(); - } - } - - RemoveGeom(); - - // we don't need to do space calculation because the client sends a position update also. - if (_size.X <= 0) _size.X = 0.01f; - if (_size.Y <= 0) _size.Y = 0.01f; - if (_size.Z <= 0) _size.Z = 0.01f; - // Construction of new prim - - IMesh mesh = null; - - - if (_parent_scene.needsMeshing(_pbs)) - { - // Don't need to re-enable body.. it's done in CreateMesh - float meshlod = _parent_scene.meshSculptLOD; - - if (IsPhysical) - meshlod = _parent_scene.MeshSculptphysicalLOD; - - // createmesh returns null when it doesn't mesh. - mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical); - if (mesh == null) - CheckMeshAsset(); - else - m_assetFailed = false; - } - - CreateGeom(m_targetSpace, mesh); - d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); - d.Quaternion myrot = new d.Quaternion(); - //myrot.W = _orientation.w; - myrot.W = _orientation.W; - myrot.X = _orientation.X; - myrot.Y = _orientation.Y; - myrot.Z = _orientation.Z; - d.GeomSetQuaternion(prim_geom, ref myrot); - - //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z); - if (IsPhysical && Body == IntPtr.Zero) - { - // Re creates body on size. - // EnableBody also does setMass() - enableBody(); - if (Body != IntPtr.Zero) - { - d.BodyEnable(Body); - } - } - - changeSelectedStatus(); - - if (childPrim) - { - if (_parent is OdePrim) - { - OdePrim parent = (OdePrim)_parent; - parent.ChildSetGeom(this); - } - } - - resetCollisionAccounting(); -// m_taintshape = false; - } - - /// - /// Change prim in response to an add force taint. - /// - private void changeAddForce() - { - if (!m_isSelected) - { - lock (m_forcelist) - { - //m_log.Info("[PHYSICS]: dequeing forcelist"); - if (IsPhysical) - { - Vector3 iforce = Vector3.Zero; - int i = 0; - try - { - for (i = 0; i < m_forcelist.Count; i++) - { - - iforce = iforce + (m_forcelist[i] * 100); - } - } - catch (IndexOutOfRangeException) - { - m_forcelist = new List(); - m_collisionscore = 0; - m_interpenetrationcount = 0; - m_taintforce = false; - return; - } - catch (ArgumentOutOfRangeException) - { - m_forcelist = new List(); - m_collisionscore = 0; - m_interpenetrationcount = 0; - m_taintforce = false; - return; - } - d.BodyEnable(Body); - d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z); - } - m_forcelist.Clear(); - } - - m_collisionscore = 0; - m_interpenetrationcount = 0; - } - - m_taintforce = false; - } - - /// - /// Change prim in response to a torque taint. - /// - private void changeSetTorque() - { - if (!m_isSelected) - { - if (IsPhysical && Body != IntPtr.Zero) - { - d.BodySetTorque(Body, m_taintTorque.X, m_taintTorque.Y, m_taintTorque.Z); - } - } - - m_taintTorque = Vector3.Zero; - } - - /// - /// Change prim in response to an angular force taint. - /// - private void changeAddAngularForce() - { - if (!m_isSelected) - { - lock (m_angularforcelist) - { - //m_log.Info("[PHYSICS]: dequeing forcelist"); - if (IsPhysical) - { - Vector3 iforce = Vector3.Zero; - for (int i = 0; i < m_angularforcelist.Count; i++) - { - iforce = iforce + (m_angularforcelist[i] * 100); - } - d.BodyEnable(Body); - d.BodyAddTorque(Body, iforce.X, iforce.Y, iforce.Z); - - } - m_angularforcelist.Clear(); - } - - m_collisionscore = 0; - m_interpenetrationcount = 0; - } - - m_taintaddangularforce = false; - } - - /// - /// Change prim in response to a velocity taint. - /// - private void changevelocity() - { - if (!m_isSelected) - { - // Not sure exactly why this sleep is here, but from experimentation it appears to stop an avatar - // walking through a default rez size prim if it keeps kicking it around - justincc. - Thread.Sleep(20); - - if (IsPhysical) - { - if (Body != IntPtr.Zero) - { - d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z); - } - } - - //resetCollisionAccounting(); - } - - m_taintVelocity = Vector3.Zero; - } - - internal void setPrimForRemoval() - { - m_taintremove = true; - } - - public override bool Flying - { - // no flying prims for you - get { return false; } - set { } - } - - public override bool IsColliding - { - get { return iscolliding; } - set { iscolliding = value; } - } - - public override bool CollidingGround - { - get { return false; } - set { return; } - } - - public override bool CollidingObj - { - get { return false; } - set { return; } - } - - public override bool ThrottleUpdates - { - get { return m_throttleUpdates; } - set { m_throttleUpdates = value; } - } - - public override bool Stopped - { - get { return _zeroFlag; } - } - - public override Vector3 Position - { - get { return _position; } - - set { _position = value; - //m_log.Info("[PHYSICS]: " + _position.ToString()); - } - } - - public override Vector3 Size - { - get { return _size; } - set - { - if (value.IsFinite()) - { - _size = value; -// m_log.DebugFormat("[PHYSICS]: Set size on {0} to {1}", Name, value); - } - else - { - m_log.WarnFormat("[PHYSICS]: Got NaN Size on object {0}", Name); - } - } - } - - public override float Mass - { - get { return CalculateMass(); } - } - - public override Vector3 Force - { - //get { return Vector3.Zero; } - get { return m_force; } - set - { - if (value.IsFinite()) - { - m_force = value; - } - else - { - m_log.WarnFormat("[PHYSICS]: NaN in Force Applied to an Object {0}", Name); - } - } - } - - public override int VehicleType - { - get { return (int)m_vehicle.Type; } - set { m_vehicle.ProcessTypeChange((Vehicle)value); } - } - - public override void VehicleFloatParam(int param, float value) - { - m_vehicle.ProcessFloatVehicleParam((Vehicle) param, value); - } - - public override void VehicleVectorParam(int param, Vector3 value) - { - m_vehicle.ProcessVectorVehicleParam((Vehicle) param, value); - } - - public override void VehicleRotationParam(int param, Quaternion rotation) - { - m_vehicle.ProcessRotationVehicleParam((Vehicle) param, rotation); - } - - public override void VehicleFlags(int param, bool remove) - { - m_vehicle.ProcessVehicleFlags(param, remove); - } - - public override void SetVolumeDetect(int param) - { - // We have to lock the scene here so that an entire simulate loop either uses volume detect for all - // possible collisions with this prim or for none of them. - lock (_parent_scene.OdeLock) - { - m_isVolumeDetect = (param != 0); - } - } - - public override Vector3 CenterOfMass - { - get { return Vector3.Zero; } - } - - public override Vector3 GeometricCenter - { - get { return Vector3.Zero; } - } - - public override PrimitiveBaseShape Shape - { - set - { - _pbs = value; - m_assetFailed = false; - m_taintshape = true; - } - } - - public override Vector3 Velocity - { - get - { - // Average previous velocity with the new one so - // client object interpolation works a 'little' better - if (_zeroFlag) - return Vector3.Zero; - - Vector3 returnVelocity = Vector3.Zero; - returnVelocity.X = (m_lastVelocity.X + _velocity.X) * 0.5f; // 0.5f is mathematically equiv to '/ 2' - returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y) * 0.5f; - returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z) * 0.5f; - return returnVelocity; - } - set - { - if (value.IsFinite()) - { - _velocity = value; - - m_taintVelocity = value; - _parent_scene.AddPhysicsActorTaint(this); - } - else - { - m_log.WarnFormat("[PHYSICS]: Got NaN Velocity in Object {0}", Name); - } - - } - } - - public override Vector3 Torque - { - get - { - if (!IsPhysical || Body == IntPtr.Zero) - return Vector3.Zero; - - return _torque; - } - - set - { - if (value.IsFinite()) - { - m_taintTorque = value; - _parent_scene.AddPhysicsActorTaint(this); - } - else - { - m_log.WarnFormat("[PHYSICS]: Got NaN Torque in Object {0}", Name); - } - } - } - - public override float CollisionScore - { - get { return m_collisionscore; } - set { m_collisionscore = value; } - } - - public override bool Kinematic - { - get { return false; } - set { } - } - - public override Quaternion Orientation - { - get { return _orientation; } - set - { - if (QuaternionIsFinite(value)) - _orientation = value; - else - m_log.WarnFormat("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object {0}", Name); - } - } - - private static bool QuaternionIsFinite(Quaternion q) - { - if (Single.IsNaN(q.X) || Single.IsInfinity(q.X)) - return false; - if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y)) - return false; - if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z)) - return false; - if (Single.IsNaN(q.W) || Single.IsInfinity(q.W)) - return false; - return true; - } - - public override Vector3 Acceleration - { - get { return _acceleration; } - set { _acceleration = value; } - } - - public override void AddForce(Vector3 force, bool pushforce) - { - if (force.IsFinite()) - { - lock (m_forcelist) - m_forcelist.Add(force); - - m_taintforce = true; - } - else - { - m_log.WarnFormat("[PHYSICS]: Got Invalid linear force vector from Scene in Object {0}", Name); - } - //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString()); - } - - public override void AddAngularForce(Vector3 force, bool pushforce) - { - if (force.IsFinite()) - { - m_angularforcelist.Add(force); - m_taintaddangularforce = true; - } - else - { - m_log.WarnFormat("[PHYSICS]: Got Invalid Angular force vector from Scene in Object {0}", Name); - } - } - - public override Vector3 RotationalVelocity - { - get - { - Vector3 pv = Vector3.Zero; - if (_zeroFlag) - return pv; - m_lastUpdateSent = false; - - if (m_rotationalVelocity.ApproxEquals(pv, 0.2f)) - return pv; - - return m_rotationalVelocity; - } - set - { - if (value.IsFinite()) - { - m_rotationalVelocity = value; - } - else - { - m_log.WarnFormat("[PHYSICS]: Got NaN RotationalVelocity in Object {0}", Name); - } - } - } - - public override void CrossingFailure() - { - m_crossingfailures++; - if (m_crossingfailures > _parent_scene.geomCrossingFailuresBeforeOutofbounds) - { - base.RaiseOutOfBounds(_position); - return; - } - else if (m_crossingfailures == _parent_scene.geomCrossingFailuresBeforeOutofbounds) - { - m_log.Warn("[PHYSICS]: Too many crossing failures for: " + Name); - } - } - - public override float Buoyancy - { - get { return m_buoyancy; } - set { m_buoyancy = value; } - } - - public override void link(PhysicsActor obj) - { - m_taintparent = obj; - } - - public override void delink() - { - m_taintparent = null; - } - - public override void LockAngularMotion(Vector3 axis) - { - // reverse the zero/non zero values for ODE. - if (axis.IsFinite()) - { - axis.X = (axis.X > 0) ? 1f : 0f; - axis.Y = (axis.Y > 0) ? 1f : 0f; - axis.Z = (axis.Z > 0) ? 1f : 0f; - m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z); - m_taintAngularLock = axis; - } - else - { - m_log.WarnFormat("[PHYSICS]: Got NaN locking axis from Scene on Object {0}", Name); - } - } - - internal void UpdatePositionAndVelocity() - { - // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! - if (_parent == null) - { - Vector3 pv = Vector3.Zero; - bool lastZeroFlag = _zeroFlag; - float m_minvelocity = 0; - if (Body != (IntPtr)0) // FIXME -> or if it is a joint - { - d.Vector3 vec = d.BodyGetPosition(Body); - d.Quaternion ori = d.BodyGetQuaternion(Body); - d.Vector3 vel = d.BodyGetLinearVel(Body); - d.Vector3 rotvel = d.BodyGetAngularVel(Body); - d.Vector3 torque = d.BodyGetTorque(Body); - _torque = new Vector3(torque.X, torque.Y, torque.Z); - Vector3 l_position = Vector3.Zero; - Quaternion l_orientation = Quaternion.Identity; - - // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) - //if (vec.X < 0.0f) { vec.X = 0.0f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); } - //if (vec.Y < 0.0f) { vec.Y = 0.0f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); } - //if (vec.X > 255.95f) { vec.X = 255.95f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); } - //if (vec.Y > 255.95f) { vec.Y = 255.95f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); } - - m_lastposition = _position; - m_lastorientation = _orientation; - - l_position.X = vec.X; - l_position.Y = vec.Y; - l_position.Z = vec.Z; - l_orientation.X = ori.X; - l_orientation.Y = ori.Y; - l_orientation.Z = ori.Z; - l_orientation.W = ori.W; - - if (l_position.X > ((int)_parent_scene.WorldExtents.X - 0.05f) || l_position.X < 0f || l_position.Y > ((int)_parent_scene.WorldExtents.Y - 0.05f) || l_position.Y < 0f) - { - //base.RaiseOutOfBounds(l_position); - - if (m_crossingfailures < _parent_scene.geomCrossingFailuresBeforeOutofbounds) - { - _position = l_position; - //_parent_scene.remActivePrim(this); - if (_parent == null) - base.RequestPhysicsterseUpdate(); - return; - } - else - { - if (_parent == null) - base.RaiseOutOfBounds(l_position); - return; - } - } - - if (l_position.Z < 0) - { - // This is so prim that get lost underground don't fall forever and suck up - // - // Sim resources and memory. - // Disables the prim's movement physics.... - // It's a hack and will generate a console message if it fails. - - //IsPhysical = false; - if (_parent == null) - base.RaiseOutOfBounds(_position); - - _acceleration.X = 0; - _acceleration.Y = 0; - _acceleration.Z = 0; - - _velocity.X = 0; - _velocity.Y = 0; - _velocity.Z = 0; - m_rotationalVelocity.X = 0; - m_rotationalVelocity.Y = 0; - m_rotationalVelocity.Z = 0; - - if (_parent == null) - base.RequestPhysicsterseUpdate(); - - m_throttleUpdates = false; - throttleCounter = 0; - _zeroFlag = true; - //outofBounds = true; - } - - //float Adiff = 1.0f - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)); -//Console.WriteLine("Adiff " + Name + " = " + Adiff); - if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02) - && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02) - && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02) -// && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.01)) - && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.0001)) // KF 0.01 is far to large - { - _zeroFlag = true; -//Console.WriteLine("ZFT 2"); - m_throttleUpdates = false; - } - else - { - //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString()); - _zeroFlag = false; - m_lastUpdateSent = false; - //m_throttleUpdates = false; - } - - if (_zeroFlag) - { - _velocity.X = 0.0f; - _velocity.Y = 0.0f; - _velocity.Z = 0.0f; - - _acceleration.X = 0; - _acceleration.Y = 0; - _acceleration.Z = 0; - - //_orientation.w = 0f; - //_orientation.X = 0f; - //_orientation.Y = 0f; - //_orientation.Z = 0f; - m_rotationalVelocity.X = 0; - m_rotationalVelocity.Y = 0; - m_rotationalVelocity.Z = 0; - if (!m_lastUpdateSent) - { - m_throttleUpdates = false; - throttleCounter = 0; - m_rotationalVelocity = pv; - - if (_parent == null) - { - base.RequestPhysicsterseUpdate(); - } - - m_lastUpdateSent = true; - } - } - else - { - if (lastZeroFlag != _zeroFlag) - { - if (_parent == null) - { - base.RequestPhysicsterseUpdate(); - } - } - - m_lastVelocity = _velocity; - - _position = l_position; - - _velocity.X = vel.X; - _velocity.Y = vel.Y; - _velocity.Z = vel.Z; - - _acceleration = ((_velocity - m_lastVelocity) / 0.1f); - _acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f); - //m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString()); - - // Note here that linearvelocity is affecting angular velocity... so I'm guessing this is a vehicle specific thing... - // it does make sense to do this for tiny little instabilities with physical prim, however 0.5m/frame is fairly large. - // reducing this to 0.02m/frame seems to help the angular rubberbanding quite a bit, however, to make sure it doesn't affect elevators and vehicles - // adding these logical exclusion situations to maintain this where I think it was intended to be. - if (m_throttleUpdates || m_usePID || (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE) || (Amotor != IntPtr.Zero)) - { - m_minvelocity = 0.5f; - } - else - { - m_minvelocity = 0.02f; - } - - if (_velocity.ApproxEquals(pv, m_minvelocity)) - { - m_rotationalVelocity = pv; - } - else - { - m_rotationalVelocity = new Vector3(rotvel.X, rotvel.Y, rotvel.Z); - } - - //m_log.Debug("ODE: " + m_rotationalVelocity.ToString()); - _orientation.X = ori.X; - _orientation.Y = ori.Y; - _orientation.Z = ori.Z; - _orientation.W = ori.W; - m_lastUpdateSent = false; - if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate) - { - if (_parent == null) - { - base.RequestPhysicsterseUpdate(); - } - } - else - { - throttleCounter++; - } - } - m_lastposition = l_position; - } - else - { - // Not a body.. so Make sure the client isn't interpolating - _velocity.X = 0; - _velocity.Y = 0; - _velocity.Z = 0; - - _acceleration.X = 0; - _acceleration.Y = 0; - _acceleration.Z = 0; - - m_rotationalVelocity.X = 0; - m_rotationalVelocity.Y = 0; - m_rotationalVelocity.Z = 0; - _zeroFlag = true; - } - } - } - - public override bool FloatOnWater - { - set { - m_taintCollidesWater = value; - _parent_scene.AddPhysicsActorTaint(this); - } - } - - public override void SetMomentum(Vector3 momentum) - { - } - - public override Vector3 PIDTarget - { - set - { - if (value.IsFinite()) - { - m_PIDTarget = value; - } - else - m_log.WarnFormat("[PHYSICS]: Got NaN PIDTarget from Scene on Object {0}", Name); - } - } - public override bool PIDActive { set { m_usePID = value; } } - public override float PIDTau { set { m_PIDTau = value; } } - - public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } } - public override bool PIDHoverActive { set { m_useHoverPID = value; } } - public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } } - public override float PIDHoverTau { set { m_PIDHoverTau = value; } } - - public override Quaternion APIDTarget{ set { return; } } - - public override bool APIDActive{ set { return; } } - - public override float APIDStrength{ set { return; } } - - public override float APIDDamping{ set { return; } } - - private void createAMotor(Vector3 axis) - { - if (Body == IntPtr.Zero) - return; - - if (Amotor != IntPtr.Zero) - { - d.JointDestroy(Amotor); - Amotor = IntPtr.Zero; - } - - float axisnum = 3; - - axisnum = (axisnum - (axis.X + axis.Y + axis.Z)); - - // PhysicsVector totalSize = new PhysicsVector(_size.X, _size.Y, _size.Z); - - - // Inverse Inertia Matrix, set the X, Y, and/r Z inertia to 0 then invert it again. - d.Mass objMass; - d.MassSetZero(out objMass); - DMassCopy(ref pMass, ref objMass); - - //m_log.DebugFormat("1-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", objMass.I.M00, objMass.I.M01, objMass.I.M02, objMass.I.M10, objMass.I.M11, objMass.I.M12, objMass.I.M20, objMass.I.M21, objMass.I.M22); - - Matrix4 dMassMat = FromDMass(objMass); - - Matrix4 mathmat = Inverse(dMassMat); - - /* - //m_log.DebugFormat("2-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", mathmat[0, 0], mathmat[0, 1], mathmat[0, 2], mathmat[1, 0], mathmat[1, 1], mathmat[1, 2], mathmat[2, 0], mathmat[2, 1], mathmat[2, 2]); - - mathmat = Inverse(mathmat); - - - objMass = FromMatrix4(mathmat, ref objMass); - //m_log.DebugFormat("3-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", objMass.I.M00, objMass.I.M01, objMass.I.M02, objMass.I.M10, objMass.I.M11, objMass.I.M12, objMass.I.M20, objMass.I.M21, objMass.I.M22); - - mathmat = Inverse(mathmat); - */ - if (axis.X == 0) - { - mathmat.M33 = 50.0000001f; - //objMass.I.M22 = 0; - } - if (axis.Y == 0) - { - mathmat.M22 = 50.0000001f; - //objMass.I.M11 = 0; - } - if (axis.Z == 0) - { - mathmat.M11 = 50.0000001f; - //objMass.I.M00 = 0; - } - - - - mathmat = Inverse(mathmat); - objMass = FromMatrix4(mathmat, ref objMass); - //m_log.DebugFormat("4-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", objMass.I.M00, objMass.I.M01, objMass.I.M02, objMass.I.M10, objMass.I.M11, objMass.I.M12, objMass.I.M20, objMass.I.M21, objMass.I.M22); - - //return; - if (d.MassCheck(ref objMass)) - { - d.BodySetMass(Body, ref objMass); - } - else - { - //m_log.Debug("[PHYSICS]: Mass invalid, ignoring"); - } - - if (axisnum <= 0) - return; - // int dAMotorEuler = 1; - - Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero); - d.JointAttach(Amotor, Body, IntPtr.Zero); - d.JointSetAMotorMode(Amotor, 0); - - d.JointSetAMotorNumAxes(Amotor,(int)axisnum); - int i = 0; - - if (axis.X == 0) - { - d.JointSetAMotorAxis(Amotor, i, 0, 1, 0, 0); - i++; - } - - if (axis.Y == 0) - { - d.JointSetAMotorAxis(Amotor, i, 0, 0, 1, 0); - i++; - } - - if (axis.Z == 0) - { - d.JointSetAMotorAxis(Amotor, i, 0, 0, 0, 1); - i++; - } - - for (int j = 0; j < (int)axisnum; j++) - { - //d.JointSetAMotorAngle(Amotor, j, 0); - } - - //d.JointSetAMotorAngle(Amotor, 1, 0); - //d.JointSetAMotorAngle(Amotor, 2, 0); - - // These lowstops and high stops are effectively (no wiggle room) - d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0f); - d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f); - d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0f); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0f); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); - d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0f); - //d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 9000f); - d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f); - d.JointSetAMotorParam(Amotor, (int)dParam.FMax, Mass * 50f);// - } - - private Matrix4 FromDMass(d.Mass pMass) - { - Matrix4 obj; - obj.M11 = pMass.I.M00; - obj.M12 = pMass.I.M01; - obj.M13 = pMass.I.M02; - obj.M14 = 0; - obj.M21 = pMass.I.M10; - obj.M22 = pMass.I.M11; - obj.M23 = pMass.I.M12; - obj.M24 = 0; - obj.M31 = pMass.I.M20; - obj.M32 = pMass.I.M21; - obj.M33 = pMass.I.M22; - obj.M34 = 0; - obj.M41 = 0; - obj.M42 = 0; - obj.M43 = 0; - obj.M44 = 1; - return obj; - } - - private d.Mass FromMatrix4(Matrix4 pMat, ref d.Mass obj) - { - obj.I.M00 = pMat[0, 0]; - obj.I.M01 = pMat[0, 1]; - obj.I.M02 = pMat[0, 2]; - obj.I.M10 = pMat[1, 0]; - obj.I.M11 = pMat[1, 1]; - obj.I.M12 = pMat[1, 2]; - obj.I.M20 = pMat[2, 0]; - obj.I.M21 = pMat[2, 1]; - obj.I.M22 = pMat[2, 2]; - return obj; - } - - public override void SubscribeEvents(int ms) - { - m_eventsubscription = ms; - _parent_scene.AddCollisionEventReporting(this); - } - - public override void UnSubscribeEvents() - { - _parent_scene.RemoveCollisionEventReporting(this); - m_eventsubscription = 0; - } - - public void AddCollisionEvent(uint CollidedWith, ContactPoint contact) - { - CollisionEventsThisFrame.AddCollider(CollidedWith, contact); - } - - public void SendCollisions() - { - if (m_collisionsOnPreviousFrame || CollisionEventsThisFrame.Count > 0) - { - base.SendCollisionUpdate(CollisionEventsThisFrame); - - if (CollisionEventsThisFrame.Count > 0) - { - m_collisionsOnPreviousFrame = true; - CollisionEventsThisFrame.Clear(); - } - else - { - m_collisionsOnPreviousFrame = false; - } - } - } - - public override bool SubscribedEvents() - { - if (m_eventsubscription > 0) - return true; - return false; - } - - public static Matrix4 Inverse(Matrix4 pMat) - { - if (determinant3x3(pMat) == 0) - { - return Matrix4.Identity; // should probably throw an error. singluar matrix inverse not possible - } - - return (Adjoint(pMat) / determinant3x3(pMat)); - } - - public static Matrix4 Adjoint(Matrix4 pMat) - { - Matrix4 adjointMatrix = new Matrix4(); - for (int i=0; i<4; i++) - { - for (int j=0; j<4; j++) - { - Matrix4SetValue(ref adjointMatrix, i, j, (float)(Math.Pow(-1, i + j) * (determinant3x3(Minor(pMat, i, j))))); - } - } - - adjointMatrix = Transpose(adjointMatrix); - return adjointMatrix; - } - - public static Matrix4 Minor(Matrix4 matrix, int iRow, int iCol) - { - Matrix4 minor = new Matrix4(); - int m = 0, n = 0; - for (int i = 0; i < 4; i++) - { - if (i == iRow) - continue; - n = 0; - for (int j = 0; j < 4; j++) - { - if (j == iCol) - continue; - Matrix4SetValue(ref minor, m,n, matrix[i, j]); - n++; - } - m++; - } - - return minor; - } - - public static Matrix4 Transpose(Matrix4 pMat) - { - Matrix4 transposeMatrix = new Matrix4(); - for (int i = 0; i < 4; i++) - for (int j = 0; j < 4; j++) - Matrix4SetValue(ref transposeMatrix, i, j, pMat[j, i]); - return transposeMatrix; - } - - public static void Matrix4SetValue(ref Matrix4 pMat, int r, int c, float val) - { - switch (r) - { - case 0: - switch (c) - { - case 0: - pMat.M11 = val; - break; - case 1: - pMat.M12 = val; - break; - case 2: - pMat.M13 = val; - break; - case 3: - pMat.M14 = val; - break; - } - - break; - case 1: - switch (c) - { - case 0: - pMat.M21 = val; - break; - case 1: - pMat.M22 = val; - break; - case 2: - pMat.M23 = val; - break; - case 3: - pMat.M24 = val; - break; - } - - break; - case 2: - switch (c) - { - case 0: - pMat.M31 = val; - break; - case 1: - pMat.M32 = val; - break; - case 2: - pMat.M33 = val; - break; - case 3: - pMat.M34 = val; - break; - } - - break; - case 3: - switch (c) - { - case 0: - pMat.M41 = val; - break; - case 1: - pMat.M42 = val; - break; - case 2: - pMat.M43 = val; - break; - case 3: - pMat.M44 = val; - break; - } - - break; - } - } - - private static float determinant3x3(Matrix4 pMat) - { - float det = 0; - float diag1 = pMat[0, 0]*pMat[1, 1]*pMat[2, 2]; - float diag2 = pMat[0, 1]*pMat[2, 1]*pMat[2, 0]; - float diag3 = pMat[0, 2]*pMat[1, 0]*pMat[2, 1]; - float diag4 = pMat[2, 0]*pMat[1, 1]*pMat[0, 2]; - float diag5 = pMat[2, 1]*pMat[1, 2]*pMat[0, 0]; - float diag6 = pMat[2, 2]*pMat[1, 0]*pMat[0, 1]; - - det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6); - return det; - } - - private static void DMassCopy(ref d.Mass src, ref d.Mass dst) - { - dst.c.W = src.c.W; - dst.c.X = src.c.X; - dst.c.Y = src.c.Y; - dst.c.Z = src.c.Z; - dst.mass = src.mass; - dst.I.M00 = src.I.M00; - dst.I.M01 = src.I.M01; - dst.I.M02 = src.I.M02; - dst.I.M10 = src.I.M10; - dst.I.M11 = src.I.M11; - dst.I.M12 = src.I.M12; - dst.I.M20 = src.I.M20; - dst.I.M21 = src.I.M21; - dst.I.M22 = src.I.M22; - } - - public override void SetMaterial(int pMaterial) - { - m_material = pMaterial; - } - - private void CheckMeshAsset() - { - if (_pbs.SculptEntry && !m_assetFailed && _pbs.SculptTexture != UUID.Zero) - { - m_assetFailed = true; - Util.FireAndForget(delegate - { - RequestAssetDelegate assetProvider = _parent_scene.RequestAssetMethod; - if (assetProvider != null) - assetProvider(_pbs.SculptTexture, MeshAssetReceived); - }); - } - } - - private void MeshAssetReceived(AssetBase asset) - { - if (asset != null && asset.Data != null && asset.Data.Length > 0) - { - if (!_pbs.SculptEntry) - return; - if (_pbs.SculptTexture.ToString() != asset.ID) - return; - - _pbs.SculptData = new byte[asset.Data.Length]; - asset.Data.CopyTo(_pbs.SculptData, 0); -// m_assetFailed = false; - -// m_log.DebugFormat( -// "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}", -// _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name); - - m_taintshape = true; - _parent_scene.AddPhysicsActorTaint(this); - } - else - { - m_log.WarnFormat( - "[ODE PRIM]: Could not get mesh/sculpt asset {0} for {1} at {2} in {3}", - _pbs.SculptTexture, Name, _position, _parent_scene.Name); - } - } - } -} \ No newline at end of file diff --git a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs deleted file mode 100644 index 8d7d3b3..0000000 --- a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using OpenMetaverse; -using OpenSim.Region.Physics.Manager; -using Ode.NET; -using log4net; - -namespace OpenSim.Region.Physics.OdePlugin -{ - /// - /// Processes raycast requests as ODE is in a state to be able to do them. - /// This ensures that it's thread safe and there will be no conflicts. - /// Requests get returned by a different thread then they were requested by. - /// - public class ODERayCastRequestManager - { - /// - /// Pending raycast requests - /// - protected List m_PendingRequests = new List(); - - /// - /// Pending ray requests - /// - protected List m_PendingRayRequests = new List(); - - /// - /// Scene that created this object. - /// - private OdeScene m_scene; - - /// - /// ODE contact array to be filled by the collision testing - /// - d.ContactGeom[] contacts = new d.ContactGeom[5]; - - /// - /// ODE near callback delegate - /// - private d.NearCallback nearCallback; - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private List m_contactResults = new List(); - - - public ODERayCastRequestManager(OdeScene pScene) - { - m_scene = pScene; - nearCallback = near; - - } - - /// - /// Queues a raycast - /// - /// Origin of Ray - /// Ray normal - /// Ray length - /// Return method to send the results - public void QueueRequest(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod) - { - lock (m_PendingRequests) - { - ODERayCastRequest req = new ODERayCastRequest(); - req.callbackMethod = retMethod; - req.length = length; - req.Normal = direction; - req.Origin = position; - - m_PendingRequests.Add(req); - } - } - - /// - /// Queues a raycast - /// - /// Origin of Ray - /// Ray normal - /// Ray length - /// - /// Return method to send the results - public void QueueRequest(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod) - { - lock (m_PendingRequests) - { - ODERayRequest req = new ODERayRequest(); - req.callbackMethod = retMethod; - req.length = length; - req.Normal = direction; - req.Origin = position; - req.Count = count; - - m_PendingRayRequests.Add(req); - } - } - - /// - /// Process all queued raycast requests - /// - /// Time in MS the raycasts took to process. - public int ProcessQueuedRequests() - { - int time = System.Environment.TickCount; - lock (m_PendingRequests) - { - if (m_PendingRequests.Count > 0) - { - ODERayCastRequest[] reqs = m_PendingRequests.ToArray(); - for (int i = 0; i < reqs.Length; i++) - { - if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast - RayCast(reqs[i]); // if there isn't anyone to send results - } - - m_PendingRequests.Clear(); - } - } - - lock (m_PendingRayRequests) - { - if (m_PendingRayRequests.Count > 0) - { - ODERayRequest[] reqs = m_PendingRayRequests.ToArray(); - for (int i = 0; i < reqs.Length; i++) - { - if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast - RayCast(reqs[i]); // if there isn't anyone to send results - } - - m_PendingRayRequests.Clear(); - } - } - - lock (m_contactResults) - m_contactResults.Clear(); - - return System.Environment.TickCount - time; - } - - /// - /// Method that actually initiates the raycast - /// - /// - private void RayCast(ODERayCastRequest req) - { - // Create the ray - IntPtr ray = d.CreateRay(m_scene.space, req.length); - d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z); - - // Collide test - d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback); - - // Remove Ray - d.GeomDestroy(ray); - - // Define default results - bool hitYN = false; - uint hitConsumerID = 0; - float distance = 999999999999f; - Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f); - Vector3 snormal = Vector3.Zero; - - // Find closest contact and object. - lock (m_contactResults) - { - foreach (ContactResult cResult in m_contactResults) - { - if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact)) - { - closestcontact = cResult.Pos; - hitConsumerID = cResult.ConsumerID; - distance = cResult.Depth; - hitYN = true; - snormal = cResult.Normal; - } - } - - m_contactResults.Clear(); - } - - // Return results - if (req.callbackMethod != null) - req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal); - } - - /// - /// Method that actually initiates the raycast - /// - /// - private void RayCast(ODERayRequest req) - { - // Create the ray - IntPtr ray = d.CreateRay(m_scene.space, req.length); - d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z); - - // Collide test - d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback); - - // Remove Ray - d.GeomDestroy(ray); - - // Find closest contact and object. - lock (m_contactResults) - { - // Return results - if (req.callbackMethod != null) - req.callbackMethod(m_contactResults); - } - } - - // This is the standard Near. Uses space AABBs to speed up detection. - private void near(IntPtr space, IntPtr g1, IntPtr g2) - { - - //Don't test against heightfield Geom, or you'll be sorry! - - /* - terminate called after throwing an instance of 'std::bad_alloc' - what(): std::bad_alloc - Stacktrace: - - at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0x00004> - at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0xffffffff> - at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0x00280> - at (wrapper native-to-managed) OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0xfff - fffff> - at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0x00004> - at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0xffffffff> - at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.RayCast (OpenSim.Region.Physics.OdePlugin.ODERayCastRequest) < - 0x00114> - at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.ProcessQueuedRequests () <0x000eb> - at OpenSim.Region.Physics.OdePlugin.OdeScene.Simulate (single) <0x017e6> - at OpenSim.Region.Framework.Scenes.SceneGraph.UpdatePhysics (double) <0x00042> - at OpenSim.Region.Framework.Scenes.Scene.Update () <0x0039e> - at OpenSim.Region.Framework.Scenes.Scene.Heartbeat (object) <0x00019> - at (wrapper runtime-invoke) object.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <0xffffffff> - - Native stacktrace: - - mono [0x80d2a42] - [0xb7f5840c] - /lib/i686/cmov/libc.so.6(abort+0x188) [0xb7d1a018] - /usr/lib/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x158) [0xb45fc988] - /usr/lib/libstdc++.so.6 [0xb45fa865] - /usr/lib/libstdc++.so.6 [0xb45fa8a2] - /usr/lib/libstdc++.so.6 [0xb45fa9da] - /usr/lib/libstdc++.so.6(_Znwj+0x83) [0xb45fb033] - /usr/lib/libstdc++.so.6(_Znaj+0x1d) [0xb45fb11d] - libode.so(_ZN13dxHeightfield23dCollideHeightfieldZoneEiiiiP6dxGeomiiP12dContactGeomi+0xd04) [0xb46678e4] - libode.so(_Z19dCollideHeightfieldP6dxGeomS0_iP12dContactGeomi+0x54b) [0xb466832b] - libode.so(dCollide+0x102) [0xb46571b2] - [0x95cfdec9] - [0x8ea07fe1] - [0xab260146] - libode.so [0xb465a5c4] - libode.so(_ZN11dxHashSpace8collide2EPvP6dxGeomPFvS0_S2_S2_E+0x75) [0xb465bcf5] - libode.so(dSpaceCollide2+0x177) [0xb465ac67] - [0x95cf978e] - [0x8ea07945] - [0x95cf2bbc] - [0xab2787e7] - [0xab419fb3] - [0xab416657] - [0xab415bda] - [0xb609b08e] - mono(mono_runtime_delegate_invoke+0x34) [0x8192534] - mono [0x81a2f0f] - mono [0x81d28b6] - mono [0x81ea2c6] - /lib/i686/cmov/libpthread.so.0 [0xb7e744c0] - /lib/i686/cmov/libc.so.6(clone+0x5e) [0xb7dcd6de] - */ - - // Exclude heightfield geom - - if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) - return; - if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass || d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass) - return; - - // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms. - if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) - { - if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) - return; - - // Separating static prim geometry spaces. - // We'll be calling near recursivly if one - // of them is a space to find all of the - // contact points in the space - try - { - d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); - } - catch (AccessViolationException) - { - m_log.Warn("[PHYSICS]: Unable to collide test a space"); - return; - } - //Colliding a space or a geom with a space or a geom. so drill down - - //Collide all geoms in each space.. - //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback); - //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback); - return; - } - - if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) - return; - - int count = 0; - try - { - - if (g1 == g2) - return; // Can't collide with yourself - - lock (contacts) - { - count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf); - } - } - catch (SEHException) - { - m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim."); - } - catch (Exception e) - { - m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message); - return; - } - - PhysicsActor p1 = null; - PhysicsActor p2 = null; - - if (g1 != IntPtr.Zero) - m_scene.actor_name_map.TryGetValue(g1, out p1); - - if (g2 != IntPtr.Zero) - m_scene.actor_name_map.TryGetValue(g1, out p2); - - // Loop over contacts, build results. - for (int i = 0; i < count; i++) - { - if (p1 != null) - { - if (p1 is OdePrim) - { - ContactResult collisionresult = new ContactResult(); - - collisionresult.ConsumerID = p1.LocalID; - collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z); - collisionresult.Depth = contacts[i].depth; - collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y, - contacts[i].normal.Z); - lock (m_contactResults) - m_contactResults.Add(collisionresult); - } - } - - if (p2 != null) - { - if (p2 is OdePrim) - { - ContactResult collisionresult = new ContactResult(); - - collisionresult.ConsumerID = p2.LocalID; - collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z); - collisionresult.Depth = contacts[i].depth; - collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y, - contacts[i].normal.Z); - - lock (m_contactResults) - m_contactResults.Add(collisionresult); - } - } - } - } - - /// - /// Dereference the creator scene so that it can be garbage collected if needed. - /// - internal void Dispose() - { - m_scene = null; - } - } - - public struct ODERayCastRequest - { - public Vector3 Origin; - public Vector3 Normal; - public float length; - public RaycastCallback callbackMethod; - } - - public struct ODERayRequest - { - public Vector3 Origin; - public Vector3 Normal; - public int Count; - public float length; - public RayCallback callbackMethod; - } -} \ No newline at end of file diff --git a/OpenSim/Region/Physics/OdePlugin/OdePhysicsJoint.cs b/OpenSim/Region/Physics/OdePlugin/OdePhysicsJoint.cs deleted file mode 100644 index b4a3c48..0000000 --- a/OpenSim/Region/Physics/OdePlugin/OdePhysicsJoint.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using OpenMetaverse; -using Ode.NET; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; -using OpenSim.Region.Physics.OdePlugin; - -namespace OpenSim.Region.Physics.OdePlugin -{ - class OdePhysicsJoint : PhysicsJoint - { - public override bool IsInPhysicsEngine - { - get - { - return (jointID != IntPtr.Zero); - } - } - public IntPtr jointID; - } -} diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs deleted file mode 100644 index 478dd95..0000000 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Threading; -using System.IO; -using System.Diagnostics; -using log4net; -using Nini.Config; -using Ode.NET; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.OdePlugin -{ - /// - /// ODE plugin - /// - public class OdePlugin : IPhysicsPlugin - { - private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - private OdeScene m_scene; - - public bool Init() - { - return true; - } - - public PhysicsScene GetScene(String sceneIdentifier) - { - if (m_scene == null) - { - // We do this so that OpenSimulator on Windows loads the correct native ODE library depending on whether - // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports - // will find it already loaded later on. - // - // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be - // controlled in Ode.NET.dll.config - if (Util.IsWindows()) - Util.LoadArchSpecificWindowsDll("ode.dll"); - - // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to - // http://opensimulator.org/mantis/view.php?id=2750). - d.InitODE(); - - m_scene = new OdeScene(sceneIdentifier); - } - - return m_scene; - } - - public string GetName() - { - return ("OpenDynamicsEngine"); - } - - public void Dispose() - { - } - } -} \ No newline at end of file diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs deleted file mode 100644 index d53bd90..0000000 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ /dev/null @@ -1,4323 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -//#define USE_DRAWSTUFF -//#define SPAM - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Threading; -using log4net; -using Nini.Config; -using Ode.NET; -using OpenMetaverse; -#if USE_DRAWSTUFF -using Drawstuff.NET; -#endif -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.OdePlugin -{ - public enum StatusIndicators : int - { - Generic = 0, - Start = 1, - End = 2 - } - -// public struct sCollisionData -// { -// public uint ColliderLocalId; -// public uint CollidedWithLocalId; -// public int NumberOfCollisions; -// public int CollisionType; -// public int StatusIndicator; -// public int lastframe; -// } - - [Flags] - public enum CollisionCategories : int - { - Disabled = 0, - Geom = 0x00000001, - Body = 0x00000002, - Space = 0x00000004, - Character = 0x00000008, - Land = 0x00000010, - Water = 0x00000020, - Wind = 0x00000040, - Sensor = 0x00000080, - Selected = 0x00000100 - } - - /// - /// Material type for a primitive - /// - public enum Material : int - { - /// - Stone = 0, - /// - Metal = 1, - /// - Glass = 2, - /// - Wood = 3, - /// - Flesh = 4, - /// - Plastic = 5, - /// - Rubber = 6 - } - - public class OdeScene : PhysicsScene - { - private readonly ILog m_log; - // private Dictionary m_storedCollisions = new Dictionary(); - - /// - /// Provide a sync object so that only one thread calls d.Collide() at a time across all OdeScene instances. - /// - /// - /// With ODE as of r1755 (though also tested on r1860), only one thread can call d.Collide() at a - /// time, even where physics objects are in entirely different ODE worlds. This is because generating contacts - /// uses a static cache at the ODE level. - /// - /// Without locking, simulators running multiple regions will eventually crash with a native stack trace similar - /// to - /// - /// mono() [0x489171] - /// mono() [0x4d154f] - /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f6ded592c60] - /// .../opensim/bin/libode-x86_64.so(_ZN6Opcode11OBBCollider8_CollideEPKNS_14AABBNoLeafNodeE+0xd7a) [0x7f6dd822628a] - /// - /// ODE provides an experimental option to cache in thread local storage but compiling ODE with this option - /// causes OpenSimulator to immediately crash with a native stack trace similar to - /// - /// mono() [0x489171] - /// mono() [0x4d154f] - /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f03c9849c60] - /// .../opensim/bin/libode-x86_64.so(_Z12dCollideCCTLP6dxGeomS0_iP12dContactGeomi+0x92) [0x7f03b44bcf82] - /// - internal static Object UniversalColliderSyncObject = new Object(); - - /// - /// Is stats collecting enabled for this ODE scene? - /// - public bool CollectStats { get; set; } - - /// - /// Statistics for this scene. - /// - private Dictionary m_stats = new Dictionary(); - - /// - /// Stat name for total number of avatars in this ODE scene. - /// - public const string ODETotalAvatarsStatName = "ODETotalAvatars"; - - /// - /// Stat name for total number of prims in this ODE scene. - /// - public const string ODETotalPrimsStatName = "ODETotalPrims"; - - /// - /// Stat name for total number of prims with active physics in this ODE scene. - /// - public const string ODEActivePrimsStatName = "ODEActivePrims"; - - /// - /// Stat name for the total time spent in ODE frame processing. - /// - /// - /// A sanity check for the main scene loop physics time. - /// - public const string ODETotalFrameMsStatName = "ODETotalFrameMS"; - - /// - /// Stat name for time spent processing avatar taints per frame - /// - public const string ODEAvatarTaintMsStatName = "ODEAvatarTaintFrameMS"; - - /// - /// Stat name for time spent processing prim taints per frame - /// - public const string ODEPrimTaintMsStatName = "ODEPrimTaintFrameMS"; - - /// - /// Stat name for time spent calculating avatar forces per frame. - /// - public const string ODEAvatarForcesFrameMsStatName = "ODEAvatarForcesFrameMS"; - - /// - /// Stat name for time spent calculating prim forces per frame - /// - public const string ODEPrimForcesFrameMsStatName = "ODEPrimForcesFrameMS"; - - /// - /// Stat name for time spent fulfilling raycasting requests per frame - /// - public const string ODERaycastingFrameMsStatName = "ODERaycastingFrameMS"; - - /// - /// Stat name for time spent in native code that actually steps through the simulation. - /// - public const string ODENativeStepFrameMsStatName = "ODENativeStepFrameMS"; - - /// - /// Stat name for the number of milliseconds that ODE spends in native space collision code. - /// - public const string ODENativeSpaceCollisionFrameMsStatName = "ODENativeSpaceCollisionFrameMS"; - - /// - /// Stat name for milliseconds that ODE spends in native geom collision code. - /// - public const string ODENativeGeomCollisionFrameMsStatName = "ODENativeGeomCollisionFrameMS"; - - /// - /// Time spent in collision processing that is not spent in native space or geom collision code. - /// - public const string ODEOtherCollisionFrameMsStatName = "ODEOtherCollisionFrameMS"; - - /// - /// Stat name for time spent notifying listeners of collisions - /// - public const string ODECollisionNotificationFrameMsStatName = "ODECollisionNotificationFrameMS"; - - /// - /// Stat name for milliseconds spent updating avatar position and velocity - /// - public const string ODEAvatarUpdateFrameMsStatName = "ODEAvatarUpdateFrameMS"; - - /// - /// Stat name for the milliseconds spent updating prim position and velocity - /// - public const string ODEPrimUpdateFrameMsStatName = "ODEPrimUpdateFrameMS"; - - /// - /// Stat name for avatar collisions with another entity. - /// - public const string ODEAvatarContactsStatsName = "ODEAvatarContacts"; - - /// - /// Stat name for prim collisions with another entity. - /// - public const string ODEPrimContactsStatName = "ODEPrimContacts"; - - /// - /// Used to hold tick numbers for stat collection purposes. - /// - private int m_nativeCollisionStartTick; - - /// - /// A messy way to tell if we need to avoid adding a collision time because this was already done in the callback. - /// - private bool m_inCollisionTiming; - - /// - /// A temporary holder for the number of avatar collisions in a frame, so we can work out how many object - /// collisions occured using the _perloopcontact if stats collection is enabled. - /// - private int m_tempAvatarCollisionsThisFrame; - - /// - /// Used in calculating physics frame time dilation - /// - private int tickCountFrameRun; - - /// - /// Used in calculating physics frame time dilation - /// - private int latertickcount; - - private Random fluidRandomizer = new Random(Environment.TickCount); - - private const uint m_regionWidth = Constants.RegionSize; - private const uint m_regionHeight = Constants.RegionSize; - - private float ODE_STEPSIZE = 0.0178f; - private float metersInSpace = 29.9f; - private float m_timeDilation = 1.0f; - - public float gravityx = 0f; - public float gravityy = 0f; - public float gravityz = -9.8f; - - public float AvatarTerminalVelocity { get; set; } - - private float contactsurfacelayer = 0.001f; - - private int worldHashspaceLow = -4; - private int worldHashspaceHigh = 128; - - private int smallHashspaceLow = -4; - private int smallHashspaceHigh = 66; - - private float waterlevel = 0f; - private int framecount = 0; - //private int m_returncollisions = 10; - - private readonly IntPtr contactgroup; - - internal IntPtr WaterGeom; - - private float nmTerrainContactFriction = 255.0f; - private float nmTerrainContactBounce = 0.1f; - private float nmTerrainContactERP = 0.1025f; - - private float mTerrainContactFriction = 75f; - private float mTerrainContactBounce = 0.1f; - private float mTerrainContactERP = 0.05025f; - - private float nmAvatarObjectContactFriction = 250f; - private float nmAvatarObjectContactBounce = 0.1f; - - private float mAvatarObjectContactFriction = 75f; - private float mAvatarObjectContactBounce = 0.1f; - - private float avPIDD = 3200f; - private float avPIDP = 1400f; - private float avCapRadius = 0.37f; - private float avStandupTensor = 2000000f; - - /// - /// true = old compatibility mode with leaning capsule; false = new corrected mode - /// - /// - /// Even when set to false, the capsule still tilts but this is done in a different way. - /// - public bool IsAvCapsuleTilted { get; private set; } - - private float avDensity = 80f; -// private float avHeightFudgeFactor = 0.52f; - private float avMovementDivisorWalk = 1.3f; - private float avMovementDivisorRun = 0.8f; - private float minimumGroundFlightOffset = 3f; - public float maximumMassObject = 10000.01f; - - public bool meshSculptedPrim = true; - public bool forceSimplePrimMeshing = false; - - public float meshSculptLOD = 32; - public float MeshSculptphysicalLOD = 16; - - public float geomDefaultDensity = 10.000006836f; - - public int geomContactPointsStartthrottle = 3; - public int geomUpdatesPerThrottledUpdate = 15; - private const int avatarExpectedContacts = 3; - - public float bodyPIDD = 35f; - public float bodyPIDG = 25; - - public int geomCrossingFailuresBeforeOutofbounds = 5; - - public float bodyMotorJointMaxforceTensor = 2; - - public int bodyFramesAutoDisable = 20; - - private float[] _watermap; - private bool m_filterCollisions = true; - - private d.NearCallback nearCallback; - public d.TriCallback triCallback; - public d.TriArrayCallback triArrayCallback; - - /// - /// Avatars in the physics scene. - /// - private readonly HashSet _characters = new HashSet(); - - /// - /// Prims in the physics scene. - /// - private readonly HashSet _prims = new HashSet(); - - /// - /// Prims in the physics scene that are subject to physics, not just collisions. - /// - private readonly HashSet _activeprims = new HashSet(); - - /// - /// Prims that the simulator has created/deleted/updated and so need updating in ODE. - /// - private readonly HashSet _taintedPrims = new HashSet(); - - /// - /// Record a character that has taints to be processed. - /// - private readonly HashSet _taintedActors = new HashSet(); - - /// - /// Keep record of contacts in the physics loop so that we can remove duplicates. - /// - private readonly List _perloopContact = new List(); - - /// - /// A dictionary of actors that should receive collision events. - /// - private readonly Dictionary m_collisionEventActors = new Dictionary(); - - /// - /// A dictionary of collision event changes that are waiting to be processed. - /// - private readonly Dictionary m_collisionEventActorsChanges = new Dictionary(); - - /// - /// Maps a unique geometry id (a memory location) to a physics actor name. - /// - /// - /// Only actors participating in collisions have geometries. This has to be maintained separately from - /// actor_name_map because terrain and water currently don't conceptually have a physics actor of their own - /// apart from the singleton PANull - /// - public Dictionary geom_name_map = new Dictionary(); - - /// - /// Maps a unique geometry id (a memory location) to a physics actor. - /// - /// - /// Only actors participating in collisions have geometries. - /// - public Dictionary actor_name_map = new Dictionary(); - - /// - /// Defects list to remove characters that no longer have finite positions due to some other bug. - /// - /// - /// Used repeatedly in Simulate() but initialized once here. - /// - private readonly List defects = new List(); - - private bool m_NINJA_physics_joints_enabled = false; - //private Dictionary jointpart_name_map = new Dictionary(); - private readonly Dictionary> joints_connecting_actor = new Dictionary>(); - private d.ContactGeom[] contacts; - - /// - /// Lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active - /// - private readonly List requestedJointsToBeCreated = new List(); - - /// - /// can lock for longer. accessed only by OdeScene. - /// - private readonly List pendingJoints = new List(); - - /// - /// can lock for longer. accessed only by OdeScene. - /// - private readonly List activeJoints = new List(); - - /// - /// lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active - /// - private readonly List requestedJointsToBeDeleted = new List(); - - private Object externalJointRequestsLock = new Object(); - private readonly Dictionary SOPName_to_activeJoint = new Dictionary(); - private readonly Dictionary SOPName_to_pendingJoint = new Dictionary(); - private readonly DoubleDictionary RegionTerrain = new DoubleDictionary(); - private readonly Dictionary TerrainHeightFieldHeights = new Dictionary(); - - private d.Contact contact; - private d.Contact TerrainContact; - private d.Contact AvatarMovementprimContact; - private d.Contact AvatarMovementTerrainContact; - private d.Contact WaterContact; - private d.Contact[,] m_materialContacts; - -//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it -//Ckrinke private int m_randomizeWater = 200; - private int m_physicsiterations = 10; - private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag - private readonly PhysicsActor PANull = new NullPhysicsActor(); -// private float step_time = 0.0f; -//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it -//Ckrinke private int ms = 0; - public IntPtr world; - //private bool returncollisions = false; - // private uint obj1LocalID = 0; - private uint obj2LocalID = 0; - //private int ctype = 0; - private OdeCharacter cc1; - private OdePrim cp1; - private OdeCharacter cc2; - private OdePrim cp2; - private int p1ExpectedPoints = 0; - private int p2ExpectedPoints = 0; - //private int cStartStop = 0; - //private string cDictKey = ""; - - public IntPtr space; - - //private IntPtr tmpSpace; - // split static geometry collision handling into spaces of 30 meters - public IntPtr[,] staticPrimspace; - - /// - /// Used to lock the entire physics scene. Locked during the main part of Simulate() - /// - internal Object OdeLock = new Object(); - - private bool _worldInitialized = false; - - public IMesher mesher; - - private IConfigSource m_config; - - public bool physics_logging = false; - public int physics_logging_interval = 0; - public bool physics_logging_append_existing_logfile = false; - - private bool avplanted = false; - private bool av_av_collisions_off = false; - - public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); - public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); - - // TODO: unused: private uint heightmapWidth = m_regionWidth + 1; - // TODO: unused: private uint heightmapHeight = m_regionHeight + 1; - // TODO: unused: private uint heightmapWidthSamples; - // TODO: unused: private uint heightmapHeightSamples; - - private volatile int m_global_contactcount = 0; - - private Vector3 m_worldOffset = Vector3.Zero; - public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); - private PhysicsScene m_parentScene = null; - - private ODERayCastRequestManager m_rayCastManager; - - /// - /// Initiailizes the scene - /// Sets many properties that ODE requires to be stable - /// These settings need to be tweaked 'exactly' right or weird stuff happens. - /// - /// Name of the scene. Useful in debug messages. - public OdeScene(string name) - { - m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + name); - - Name = name; - - nearCallback = near; - triCallback = TriCallback; - triArrayCallback = TriArrayCallback; - m_rayCastManager = new ODERayCastRequestManager(this); - - // Create the world and the first space - world = d.WorldCreate(); - space = d.HashSpaceCreate(IntPtr.Zero); - - contactgroup = d.JointGroupCreate(0); - - d.WorldSetAutoDisableFlag(world, false); - - #if USE_DRAWSTUFF - Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization)); - viewthread.Start(); - #endif - - _watermap = new float[258 * 258]; - - // Zero out the prim spaces array (we split our space into smaller spaces so - // we can hit test less. - } - -#if USE_DRAWSTUFF - public void startvisualization(object o) - { - ds.Functions fn; - fn.version = ds.VERSION; - fn.start = new ds.CallbackFunction(start); - fn.step = new ds.CallbackFunction(step); - fn.command = new ds.CallbackFunction(command); - fn.stop = null; - fn.path_to_textures = "./textures"; - string[] args = new string[0]; - ds.SimulationLoop(args.Length, args, 352, 288, ref fn); - } -#endif - - // Initialize the mesh plugin - public override void Initialise(IMesher meshmerizer, IConfigSource config) - { - InitializeExtraStats(); - - mesher = meshmerizer; - m_config = config; - // Defaults - - if (Environment.OSVersion.Platform == PlatformID.Unix) - { - avPIDD = 3200.0f; - avPIDP = 1400.0f; - avStandupTensor = 2000000f; - } - else - { - avPIDD = 2200.0f; - avPIDP = 900.0f; - avStandupTensor = 550000f; - } - - int contactsPerCollision = 80; - - if (m_config != null) - { - IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"]; - if (physicsconfig != null) - { - CollectStats = physicsconfig.GetBoolean("collect_stats", false); - - gravityx = physicsconfig.GetFloat("world_gravityx", 0f); - gravityy = physicsconfig.GetFloat("world_gravityy", 0f); - gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f); - - float avatarTerminalVelocity = physicsconfig.GetFloat("avatar_terminal_velocity", 54f); - AvatarTerminalVelocity = Util.Clamp(avatarTerminalVelocity, 0, 255f); - if (AvatarTerminalVelocity != avatarTerminalVelocity) - { - m_log.WarnFormat( - "[ODE SCENE]: avatar_terminal_velocity of {0} is invalid. Clamping to {1}", - avatarTerminalVelocity, AvatarTerminalVelocity); - } - - worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4); - worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128); - - metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f); - smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4); - smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66); - - contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f); - - nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f); - nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f); - nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f); - - mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f); - mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f); - mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f); - - nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f); - nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f); - - mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f); - mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f); - - ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE); - m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10); - - avDensity = physicsconfig.GetFloat("av_density", 80f); -// avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f); - avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f); - avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f); - avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); - avplanted = physicsconfig.GetBoolean("av_planted", false); - av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false); - - IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false); - - contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); - - geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5); - geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15); - geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5); - - geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f); - bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20); - - bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f); - bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f); - - forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing); - meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true); - meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f); - MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f); - m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false); - - - - if (Environment.OSVersion.Platform == PlatformID.Unix) - { - avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f); - avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f); - avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f); - bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f); - } - else - { - avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f); - avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f); - avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f); - bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f); - } - - physics_logging = physicsconfig.GetBoolean("physics_logging", false); - physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0); - physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false); - - m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false); - minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f); - maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f); - } - } - - contacts = new d.ContactGeom[contactsPerCollision]; - - staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)]; - - // Centeral contact friction and bounce - // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why - // an avatar falls through in Z but not in X or Y when walking on a prim. - contact.surface.mode |= d.ContactFlags.SoftERP; - contact.surface.mu = nmAvatarObjectContactFriction; - contact.surface.bounce = nmAvatarObjectContactBounce; - contact.surface.soft_cfm = 0.010f; - contact.surface.soft_erp = 0.010f; - - // Terrain contact friction and Bounce - // This is the *non* moving version. Use this when an avatar - // isn't moving to keep it in place better - TerrainContact.surface.mode |= d.ContactFlags.SoftERP; - TerrainContact.surface.mu = nmTerrainContactFriction; - TerrainContact.surface.bounce = nmTerrainContactBounce; - TerrainContact.surface.soft_erp = nmTerrainContactERP; - - WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM); - WaterContact.surface.mu = 0f; // No friction - WaterContact.surface.bounce = 0.0f; // No bounce - WaterContact.surface.soft_cfm = 0.010f; - WaterContact.surface.soft_erp = 0.010f; - - // Prim contact friction and bounce - // THis is the *non* moving version of friction and bounce - // Use this when an avatar comes in contact with a prim - // and is moving - AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction; - AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce; - - // Terrain contact friction bounce and various error correcting calculations - // Use this when an avatar is in contact with the terrain and moving. - AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP; - AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction; - AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce; - AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP; - - /* - - Stone = 0, - /// - Metal = 1, - /// - Glass = 2, - /// - Wood = 3, - /// - Flesh = 4, - /// - Plastic = 5, - /// - Rubber = 6 - */ - - m_materialContacts = new d.Contact[7,2]; - - m_materialContacts[(int)Material.Stone, 0] = new d.Contact(); - m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction; - m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce; - m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Stone, 1] = new d.Contact(); - m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction; - m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce; - m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Metal, 0] = new d.Contact(); - m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction; - m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce; - m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Metal, 1] = new d.Contact(); - m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction; - m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce; - m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Glass, 0] = new d.Contact(); - m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f; - m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f; - m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f; - - /* - private float nmAvatarObjectContactFriction = 250f; - private float nmAvatarObjectContactBounce = 0.1f; - - private float mAvatarObjectContactFriction = 75f; - private float mAvatarObjectContactBounce = 0.1f; - */ - m_materialContacts[(int)Material.Glass, 1] = new d.Contact(); - m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f; - m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f; - m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Wood, 0] = new d.Contact(); - m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction; - m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce; - m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Wood, 1] = new d.Contact(); - m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction; - m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce; - m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Flesh, 0] = new d.Contact(); - m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction; - m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce; - m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Flesh, 1] = new d.Contact(); - m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction; - m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce; - m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Plastic, 0] = new d.Contact(); - m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction; - m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce; - m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Plastic, 1] = new d.Contact(); - m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction; - m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce; - m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Rubber, 0] = new d.Contact(); - m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction; - m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce; - m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f; - - m_materialContacts[(int)Material.Rubber, 1] = new d.Contact(); - m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP; - m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction; - m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce; - m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f; - m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f; - - d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh); - - // Set the gravity,, don't disable things automatically (we set it explicitly on some things) - - d.WorldSetGravity(world, gravityx, gravityy, gravityz); - d.WorldSetContactSurfaceLayer(world, contactsurfacelayer); - - d.WorldSetLinearDamping(world, 256f); - d.WorldSetAngularDamping(world, 256f); - d.WorldSetAngularDampingThreshold(world, 256f); - d.WorldSetLinearDampingThreshold(world, 256f); - d.WorldSetMaxAngularSpeed(world, 256f); - - // Set how many steps we go without running collision testing - // This is in addition to the step size. - // Essentially Steps * m_physicsiterations - d.WorldSetQuickStepNumIterations(world, m_physicsiterations); - //d.WorldSetContactMaxCorrectingVel(world, 1000.0f); - - for (int i = 0; i < staticPrimspace.GetLength(0); i++) - { - for (int j = 0; j < staticPrimspace.GetLength(1); j++) - { - staticPrimspace[i, j] = IntPtr.Zero; - } - } - - _worldInitialized = true; - } - -// internal void waitForSpaceUnlock(IntPtr space) -// { -// //if (space != IntPtr.Zero) -// //while (d.SpaceLockQuery(space)) { } // Wait and do nothing -// } - -// /// -// /// Debug space message for printing the space that a prim/avatar is in. -// /// -// /// -// /// Returns which split up space the given position is in. -// public string whichspaceamIin(Vector3 pos) -// { -// return calculateSpaceForGeom(pos).ToString(); -// } - - #region Collision Detection - - /// - /// Collides two geometries. - /// - /// - /// - /// /param> - /// - /// - /// - private int CollideGeoms( - IntPtr geom1, IntPtr geom2, int maxContacts, Ode.NET.d.ContactGeom[] contactsArray, int contactGeomSize) - { - int count; - - lock (OdeScene.UniversalColliderSyncObject) - { - // We do this inside the lock so that we don't count any delay in acquiring it - if (CollectStats) - m_nativeCollisionStartTick = Util.EnvironmentTickCount(); - - count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize); - } - - // We do this outside the lock so that any waiting threads aren't held up, though the effect is probably - // negligable - if (CollectStats) - m_stats[ODENativeGeomCollisionFrameMsStatName] - += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); - - return count; - } - - /// - /// Collide two spaces or a space and a geometry. - /// - /// - /// /param> - /// - private void CollideSpaces(IntPtr space1, IntPtr space2, IntPtr data) - { - if (CollectStats) - { - m_inCollisionTiming = true; - m_nativeCollisionStartTick = Util.EnvironmentTickCount(); - } - - d.SpaceCollide2(space1, space2, data, nearCallback); - - if (CollectStats && m_inCollisionTiming) - { - m_stats[ODENativeSpaceCollisionFrameMsStatName] - += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); - m_inCollisionTiming = false; - } - } - - /// - /// This is our near callback. A geometry is near a body - /// - /// The space that contains the geoms. Remember, spaces are also geoms - /// a geometry or space - /// another geometry or space - private void near(IntPtr space, IntPtr g1, IntPtr g2) - { - if (CollectStats && m_inCollisionTiming) - { - m_stats[ODENativeSpaceCollisionFrameMsStatName] - += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); - m_inCollisionTiming = false; - } - -// m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space); - // no lock here! It's invoked from within Simulate(), which is thread-locked - - // Test if we're colliding a geom with a space. - // If so we have to drill down into the space recursively - - if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) - { - if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) - return; - - // Separating static prim geometry spaces. - // We'll be calling near recursivly if one - // of them is a space to find all of the - // contact points in the space - try - { - CollideSpaces(g1, g2, IntPtr.Zero); - } - catch (AccessViolationException) - { - m_log.Error("[ODE SCENE]: Unable to collide test a space"); - return; - } - //Colliding a space or a geom with a space or a geom. so drill down - - //Collide all geoms in each space.. - //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback); - //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback); - return; - } - - if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) - return; - - IntPtr b1 = d.GeomGetBody(g1); - IntPtr b2 = d.GeomGetBody(g2); - - // d.GeomClassID id = d.GeomGetClass(g1); - - String name1 = null; - String name2 = null; - - if (!geom_name_map.TryGetValue(g1, out name1)) - { - name1 = "null"; - } - if (!geom_name_map.TryGetValue(g2, out name2)) - { - name2 = "null"; - } - - //if (id == d.GeomClassId.TriMeshClass) - //{ - // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2); - //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2); - //} - - // Figure out how many contact points we have - int count = 0; - - try - { - // Colliding Geom To Geom - // This portion of the function 'was' blatantly ripped off from BoxStack.cs - - if (g1 == g2) - return; // Can't collide with yourself - - if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) - return; - - count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf); - - // All code after this is only relevant if we have any collisions - if (count <= 0) - return; - - if (count > contacts.Length) - m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); - } - catch (SEHException) - { - m_log.Error( - "[ODE SCENE]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim."); - base.TriggerPhysicsBasedRestart(); - } - catch (Exception e) - { - m_log.ErrorFormat("[ODE SCENE]: Unable to collide test an object: {0}", e.Message); - return; - } - - PhysicsActor p1; - PhysicsActor p2; - - p1ExpectedPoints = 0; - p2ExpectedPoints = 0; - - if (!actor_name_map.TryGetValue(g1, out p1)) - { - p1 = PANull; - } - - if (!actor_name_map.TryGetValue(g2, out p2)) - { - p2 = PANull; - } - - ContactPoint maxDepthContact = new ContactPoint(); - if (p1.CollisionScore + count >= float.MaxValue) - p1.CollisionScore = 0; - p1.CollisionScore += count; - - if (p2.CollisionScore + count >= float.MaxValue) - p2.CollisionScore = 0; - p2.CollisionScore += count; - - for (int i = 0; i < count; i++) - { - d.ContactGeom curContact = contacts[i]; - - if (curContact.depth > maxDepthContact.PenetrationDepth) - { - maxDepthContact = new ContactPoint( - new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z), - new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z), - curContact.depth - ); - } - - //m_log.Warn("[CCOUNT]: " + count); - IntPtr joint; - // If we're colliding with terrain, use 'TerrainContact' instead of contact. - // allows us to have different settings - - // We only need to test p2 for 'jump crouch purposes' - if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim) - { - // Testing if the collision is at the feet of the avatar - - //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f)); - if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f)) - p2.IsColliding = true; - } - else - { - p2.IsColliding = true; - } - - //if ((framecount % m_returncollisions) == 0) - - switch (p1.PhysicsActorType) - { - case (int)ActorTypes.Agent: - p1ExpectedPoints = avatarExpectedContacts; - p2.CollidingObj = true; - break; - case (int)ActorTypes.Prim: - if (p1 != null && p1 is OdePrim) - p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts; - - if (p2.Velocity.LengthSquared() > 0.0f) - p2.CollidingObj = true; - break; - case (int)ActorTypes.Unknown: - p2.CollidingGround = true; - break; - default: - p2.CollidingGround = true; - break; - } - - // we don't want prim or avatar to explode - - #region InterPenetration Handling - Unintended physics explosions -# region disabled code1 - - if (curContact.depth >= 0.08f) - { - //This is disabled at the moment only because it needs more tweaking - //It will eventually be uncommented - /* - if (contact.depth >= 1.00f) - { - //m_log.Debug("[PHYSICS]: " + contact.depth.ToString()); - } - - //If you interpenetrate a prim with an agent - if ((p2.PhysicsActorType == (int) ActorTypes.Agent && - p1.PhysicsActorType == (int) ActorTypes.Prim) || - (p1.PhysicsActorType == (int) ActorTypes.Agent && - p2.PhysicsActorType == (int) ActorTypes.Prim)) - { - - //contact.depth = contact.depth * 4.15f; - /* - if (p2.PhysicsActorType == (int) ActorTypes.Agent) - { - p2.CollidingObj = true; - contact.depth = 0.003f; - p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f); - OdeCharacter character = (OdeCharacter) p2; - character.SetPidStatus(true); - contact.pos = new d.Vector3(contact.pos.X + (p1.Size.X / 2), contact.pos.Y + (p1.Size.Y / 2), contact.pos.Z + (p1.Size.Z / 2)); - - } - else - { - - //contact.depth = 0.0000000f; - } - if (p1.PhysicsActorType == (int) ActorTypes.Agent) - { - - p1.CollidingObj = true; - contact.depth = 0.003f; - p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f); - contact.pos = new d.Vector3(contact.pos.X + (p2.Size.X / 2), contact.pos.Y + (p2.Size.Y / 2), contact.pos.Z + (p2.Size.Z / 2)); - OdeCharacter character = (OdeCharacter)p1; - character.SetPidStatus(true); - } - else - { - - //contact.depth = 0.0000000f; - } - - - - } -*/ - // If you interpenetrate a prim with another prim - /* - if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim) - { - #region disabledcode2 - //OdePrim op1 = (OdePrim)p1; - //OdePrim op2 = (OdePrim)p2; - //op1.m_collisionscore++; - //op2.m_collisionscore++; - - //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000) - //{ - //op1.m_taintdisable = true; - //AddPhysicsActorTaint(p1); - //op2.m_taintdisable = true; - //AddPhysicsActorTaint(p2); - //} - - //if (contact.depth >= 0.25f) - //{ - // Don't collide, one or both prim will expld. - - //op1.m_interpenetrationcount++; - //op2.m_interpenetrationcount++; - //interpenetrations_before_disable = 200; - //if (op1.m_interpenetrationcount >= interpenetrations_before_disable) - //{ - //op1.m_taintdisable = true; - //AddPhysicsActorTaint(p1); - //} - //if (op2.m_interpenetrationcount >= interpenetrations_before_disable) - //{ - // op2.m_taintdisable = true; - //AddPhysicsActorTaint(p2); - //} - - //contact.depth = contact.depth / 8f; - //contact.normal = new d.Vector3(0, 0, 1); - //} - //if (op1.m_disabled || op2.m_disabled) - //{ - //Manually disabled objects stay disabled - //contact.depth = 0f; - //} - #endregion - } - */ -#endregion - if (curContact.depth >= 1.00f) - { - //m_log.Info("[P]: " + contact.depth.ToString()); - if ((p2.PhysicsActorType == (int) ActorTypes.Agent && - p1.PhysicsActorType == (int) ActorTypes.Unknown) || - (p1.PhysicsActorType == (int) ActorTypes.Agent && - p2.PhysicsActorType == (int) ActorTypes.Unknown)) - { - if (p2.PhysicsActorType == (int) ActorTypes.Agent) - { - if (p2 is OdeCharacter) - { - OdeCharacter character = (OdeCharacter) p2; - - //p2.CollidingObj = true; - curContact.depth = 0.00000003f; - p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f); - curContact.pos = - new d.Vector3(curContact.pos.X + (p1.Size.X/2), - curContact.pos.Y + (p1.Size.Y/2), - curContact.pos.Z + (p1.Size.Z/2)); - character.SetPidStatus(true); - } - } - - if (p1.PhysicsActorType == (int) ActorTypes.Agent) - { - if (p1 is OdeCharacter) - { - OdeCharacter character = (OdeCharacter) p1; - - //p2.CollidingObj = true; - curContact.depth = 0.00000003f; - p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f); - curContact.pos = - new d.Vector3(curContact.pos.X + (p1.Size.X/2), - curContact.pos.Y + (p1.Size.Y/2), - curContact.pos.Z + (p1.Size.Z/2)); - character.SetPidStatus(true); - } - } - } - } - } - - #endregion - - // Logic for collision handling - // Note, that if *all* contacts are skipped (VolumeDetect) - // The prim still detects (and forwards) collision events but - // appears to be phantom for the world - Boolean skipThisContact = false; - - if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) - skipThisContact = true; // No collision on volume detect prims - - if (av_av_collisions_off) - if ((p1 is OdeCharacter) && (p2 is OdeCharacter)) - skipThisContact = true; - - if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) - skipThisContact = true; // No collision on volume detect prims - - if (!skipThisContact && curContact.depth < 0f) - skipThisContact = true; - - if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType)) - skipThisContact = true; - - const int maxContactsbeforedeath = 4000; - joint = IntPtr.Zero; - - if (!skipThisContact) - { - _perloopContact.Add(curContact); - - if (name1 == "Terrain" || name2 == "Terrain") - { - if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && - (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) - { - p2ExpectedPoints = avatarExpectedContacts; - // Avatar is moving on terrain, use the movement terrain contact - AvatarMovementTerrainContact.geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact); - m_global_contactcount++; - } - } - else - { - if (p2.PhysicsActorType == (int)ActorTypes.Agent) - { - p2ExpectedPoints = avatarExpectedContacts; - // Avatar is standing on terrain, use the non moving terrain contact - TerrainContact.geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref TerrainContact); - m_global_contactcount++; - } - } - else - { - if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim) - { - // prim prim contact - // int pj294950 = 0; - int movintYN = 0; - int material = (int) Material.Wood; - // prim terrain contact - if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) - { - movintYN = 1; - } - - if (p2 is OdePrim) - { - material = ((OdePrim) p2).m_material; - p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; - } - - // Unnessesary because p1 is defined above - //if (p1 is OdePrim) - // { - // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts; - // } - //m_log.DebugFormat("Material: {0}", material); - - m_materialContacts[material, movintYN].geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); - m_global_contactcount++; - } - } - else - { - int movintYN = 0; - // prim terrain contact - if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) - { - movintYN = 1; - } - - int material = (int)Material.Wood; - - if (p2 is OdePrim) - { - material = ((OdePrim)p2).m_material; - p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; - } - - //m_log.DebugFormat("Material: {0}", material); - m_materialContacts[material, movintYN].geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); - m_global_contactcount++; - } - } - } - } - //if (p2.PhysicsActorType == (int)ActorTypes.Prim) - //{ - //m_log.Debug("[PHYSICS]: prim contacting with ground"); - //} - } - else if (name1 == "Water" || name2 == "Water") - { - /* - if ((p2.PhysicsActorType == (int) ActorTypes.Prim)) - { - } - else - { - } - */ - //WaterContact.surface.soft_cfm = 0.0000f; - //WaterContact.surface.soft_erp = 0.00000f; - if (curContact.depth > 0.1f) - { - curContact.depth *= 52; - //contact.normal = new d.Vector3(0, 0, 1); - //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f); - } - - WaterContact.geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref WaterContact); - m_global_contactcount++; - } - //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth); - } - else - { - if ((p2.PhysicsActorType == (int)ActorTypes.Agent)) - { - p2ExpectedPoints = avatarExpectedContacts; - if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) - { - // Avatar is moving on a prim, use the Movement prim contact - AvatarMovementprimContact.geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact); - m_global_contactcount++; - } - } - else - { - // Avatar is standing still on a prim, use the non movement contact - contact.geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref contact); - m_global_contactcount++; - } - } - } - else if (p2.PhysicsActorType == (int)ActorTypes.Prim) - { - //p1.PhysicsActorType - int material = (int)Material.Wood; - - if (p2 is OdePrim) - { - material = ((OdePrim)p2).m_material; - p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; - } - - //m_log.DebugFormat("Material: {0}", material); - m_materialContacts[material, 0].geom = curContact; - - if (m_global_contactcount < maxContactsbeforedeath) - { - joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]); - m_global_contactcount++; - } - } - } - - if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide! - { - d.JointAttach(joint, b1, b2); - m_global_contactcount++; - } - } - - collision_accounting_events(p1, p2, maxDepthContact); - - if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle)) - { - // If there are more then 3 contact points, it's likely - // that we've got a pile of objects, so ... - // We don't want to send out hundreds of terse updates over and over again - // so lets throttle them and send them again after it's somewhat sorted out. - p2.ThrottleUpdates = true; - } - //m_log.Debug(count.ToString()); - //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2); - } - } - - private bool checkDupe(d.ContactGeom contactGeom, int atype) - { - if (!m_filterCollisions) - return false; - - bool result = false; - - ActorTypes at = (ActorTypes)atype; - - foreach (d.ContactGeom contact in _perloopContact) - { - //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2)) - //{ - // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2) - if (at == ActorTypes.Agent) - { - if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) - && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) - && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f))) - { - if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f) - { - //contactGeom.depth *= .00005f; - //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); - // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); - result = true; - break; - } -// else -// { -// //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); -// } - } -// else -// { -// //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); -// //int i = 0; -// } - } - else if (at == ActorTypes.Prim) - { - //d.AABB aabb1 = new d.AABB(); - //d.AABB aabb2 = new d.AABB(); - - //d.GeomGetAABB(contactGeom.g2, out aabb2); - //d.GeomGetAABB(contactGeom.g1, out aabb1); - //aabb1. - if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f))) - { - if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z) - { - if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f) - { - result = true; - break; - } - } - //m_log.DebugFormat("[Collision]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); - //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); - } - } - } - - return result; - } - - private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact) - { - // obj1LocalID = 0; - //returncollisions = false; - obj2LocalID = 0; - //ctype = 0; - //cStartStop = 0; - if (!p2.SubscribedEvents() && !p1.SubscribedEvents()) - return; - - switch ((ActorTypes)p2.PhysicsActorType) - { - case ActorTypes.Agent: - cc2 = (OdeCharacter)p2; - - // obj1LocalID = cc2.m_localID; - switch ((ActorTypes)p1.PhysicsActorType) - { - case ActorTypes.Agent: - cc1 = (OdeCharacter)p1; - obj2LocalID = cc1.LocalID; - cc1.AddCollisionEvent(cc2.LocalID, contact); - //ctype = (int)CollisionCategories.Character; - - //if (cc1.CollidingObj) - //cStartStop = (int)StatusIndicators.Generic; - //else - //cStartStop = (int)StatusIndicators.Start; - - //returncollisions = true; - break; - - case ActorTypes.Prim: - if (p1 is OdePrim) - { - cp1 = (OdePrim) p1; - obj2LocalID = cp1.LocalID; - cp1.AddCollisionEvent(cc2.LocalID, contact); - } - //ctype = (int)CollisionCategories.Geom; - - //if (cp1.CollidingObj) - //cStartStop = (int)StatusIndicators.Generic; - //else - //cStartStop = (int)StatusIndicators.Start; - - //returncollisions = true; - break; - - case ActorTypes.Ground: - case ActorTypes.Unknown: - obj2LocalID = 0; - //ctype = (int)CollisionCategories.Land; - //returncollisions = true; - break; - } - - cc2.AddCollisionEvent(obj2LocalID, contact); - break; - - case ActorTypes.Prim: - - if (p2 is OdePrim) - { - cp2 = (OdePrim) p2; - - // obj1LocalID = cp2.m_localID; - switch ((ActorTypes) p1.PhysicsActorType) - { - case ActorTypes.Agent: - if (p1 is OdeCharacter) - { - cc1 = (OdeCharacter) p1; - obj2LocalID = cc1.LocalID; - cc1.AddCollisionEvent(cp2.LocalID, contact); - //ctype = (int)CollisionCategories.Character; - - //if (cc1.CollidingObj) - //cStartStop = (int)StatusIndicators.Generic; - //else - //cStartStop = (int)StatusIndicators.Start; - //returncollisions = true; - } - break; - case ActorTypes.Prim: - - if (p1 is OdePrim) - { - cp1 = (OdePrim) p1; - obj2LocalID = cp1.LocalID; - cp1.AddCollisionEvent(cp2.LocalID, contact); - //ctype = (int)CollisionCategories.Geom; - - //if (cp1.CollidingObj) - //cStartStop = (int)StatusIndicators.Generic; - //else - //cStartStop = (int)StatusIndicators.Start; - - //returncollisions = true; - } - break; - - case ActorTypes.Ground: - case ActorTypes.Unknown: - obj2LocalID = 0; - //ctype = (int)CollisionCategories.Land; - - //returncollisions = true; - break; - } - - cp2.AddCollisionEvent(obj2LocalID, contact); - } - break; - } - //if (returncollisions) - //{ - - //lock (m_storedCollisions) - //{ - //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString(); - //if (m_storedCollisions.ContainsKey(cDictKey)) - //{ - //sCollisionData objd = m_storedCollisions[cDictKey]; - //objd.NumberOfCollisions += 1; - //objd.lastframe = framecount; - //m_storedCollisions[cDictKey] = objd; - //} - //else - //{ - //sCollisionData objd = new sCollisionData(); - //objd.ColliderLocalId = obj1LocalID; - //objd.CollidedWithLocalId = obj2LocalID; - //objd.CollisionType = ctype; - //objd.NumberOfCollisions = 1; - //objd.lastframe = framecount; - //objd.StatusIndicator = cStartStop; - //m_storedCollisions.Add(cDictKey, objd); - //} - //} - // } - } - - private int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount) - { - /* String name1 = null; - String name2 = null; - - if (!geom_name_map.TryGetValue(trimesh, out name1)) - { - name1 = "null"; - } - if (!geom_name_map.TryGetValue(refObject, out name2)) - { - name2 = "null"; - } - - m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2); - */ - return 1; - } - - private int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex) - { -// String name1 = null; -// String name2 = null; -// -// if (!geom_name_map.TryGetValue(trimesh, out name1)) -// { -// name1 = "null"; -// } -// -// if (!geom_name_map.TryGetValue(refObject, out name2)) -// { -// name2 = "null"; -// } - - // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex); - - d.Vector3 v0 = new d.Vector3(); - d.Vector3 v1 = new d.Vector3(); - d.Vector3 v2 = new d.Vector3(); - - d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2); - // m_log.DebugFormat("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z); - - return 1; - } - - /// - /// This is our collision testing routine in ODE - /// - private void collision_optimized() - { - _perloopContact.Clear(); - - foreach (OdeCharacter chr in _characters) - { - // Reset the collision values to false - // since we don't know if we're colliding yet - if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero) - continue; - - chr.IsColliding = false; - chr.CollidingGround = false; - chr.CollidingObj = false; - - // Test the avatar's geometry for collision with the space - // This will return near and the space that they are the closest to - // And we'll run this again against the avatar and the space segment - // This will return with a bunch of possible objects in the space segment - // and we'll run it again on all of them. - try - { - CollideSpaces(space, chr.Shell, IntPtr.Zero); - } - catch (AccessViolationException) - { - m_log.ErrorFormat("[ODE SCENE]: Unable to space collide {0}", Name); - } - - //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y); - //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10) - //{ - //chr.Position.Z = terrainheight + 10.0f; - //forcedZ = true; - //} - } - - if (CollectStats) - { - m_tempAvatarCollisionsThisFrame = _perloopContact.Count; - m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame; - } - - List removeprims = null; - foreach (OdePrim chr in _activeprims) - { - if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled)) - { - try - { - lock (chr) - { - if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false) - { - CollideSpaces(space, chr.prim_geom, IntPtr.Zero); - } - else - { - if (removeprims == null) - { - removeprims = new List(); - } - removeprims.Add(chr); - m_log.Error( - "[ODE SCENE]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!"); - } - } - } - catch (AccessViolationException) - { - m_log.Error("[ODE SCENE]: Unable to space collide"); - } - } - } - - if (CollectStats) - m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame; - - if (removeprims != null) - { - foreach (OdePrim chr in removeprims) - { - _activeprims.Remove(chr); - } - } - } - - #endregion - - public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) - { - m_worldOffset = offset; - WorldExtents = new Vector2(extents.X, extents.Y); - m_parentScene = pScene; - } - - // Recovered for use by fly height. Kitto Flora - internal float GetTerrainHeightAtXY(float x, float y) - { - int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize; - int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize; - - IntPtr heightFieldGeom = IntPtr.Zero; - - if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom)) - { - if (heightFieldGeom != IntPtr.Zero) - { - if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom)) - { - - int index; - - - if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y || - (int)x < 0.001f || (int)y < 0.001f) - return 0; - - x = x - offsetX; - y = y - offsetY; - - index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y); - - if (index < TerrainHeightFieldHeights[heightFieldGeom].Length) - { - //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]); - return (float)TerrainHeightFieldHeights[heightFieldGeom][index]; - } - - else - return 0f; - } - else - { - return 0f; - } - - } - else - { - return 0f; - } - - } - else - { - return 0f; - } - } -// End recovered. Kitto Flora - - /// - /// Add actor to the list that should receive collision events in the simulate loop. - /// - /// - internal void AddCollisionEventReporting(PhysicsActor obj) - { -// m_log.DebugFormat("[PHYSICS]: Adding {0} {1} to collision event reporting", obj.SOPName, obj.LocalID); - - lock (m_collisionEventActorsChanges) - m_collisionEventActorsChanges[obj.LocalID] = obj; - } - - /// - /// Remove actor from the list that should receive collision events in the simulate loop. - /// - /// - internal void RemoveCollisionEventReporting(PhysicsActor obj) - { -// m_log.DebugFormat("[PHYSICS]: Removing {0} {1} from collision event reporting", obj.SOPName, obj.LocalID); - - lock (m_collisionEventActorsChanges) - m_collisionEventActorsChanges[obj.LocalID] = null; - } - - #region Add/Remove Entities - - public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) - { - Vector3 pos; - pos.X = position.X; - pos.Y = position.Y; - pos.Z = position.Z; - - OdeCharacter newAv - = new OdeCharacter( - avName, this, pos, size, avPIDD, avPIDP, - avCapRadius, avStandupTensor, avDensity, - avMovementDivisorWalk, avMovementDivisorRun); - - newAv.Flying = isFlying; - newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; - newAv.m_avatarplanted = avplanted; - - return newAv; - } - - public override void RemoveAvatar(PhysicsActor actor) - { -// m_log.DebugFormat( -// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}", -// actor.Name, actor.LocalID, Name); - - ((OdeCharacter) actor).Destroy(); - } - - internal void AddCharacter(OdeCharacter chr) - { - chr.m_avatarplanted = avplanted; - if (!_characters.Contains(chr)) - { - _characters.Add(chr); - -// m_log.DebugFormat( -// "[ODE SCENE]: Adding physics character {0} {1} to physics scene {2}. Count now {3}", -// chr.Name, chr.LocalID, Name, _characters.Count); - - if (chr.bad) - m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to characters list", chr.m_uuid); - } - else - { - m_log.ErrorFormat( - "[ODE SCENE]: Tried to add character {0} {1} but they are already in the set!", - chr.Name, chr.LocalID); - } - } - - internal void RemoveCharacter(OdeCharacter chr) - { - if (_characters.Contains(chr)) - { - _characters.Remove(chr); - -// m_log.DebugFormat( -// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}. Count now {3}", -// chr.Name, chr.LocalID, Name, _characters.Count); - } - else - { - m_log.ErrorFormat( - "[ODE SCENE]: Tried to remove character {0} {1} but they are not in the list!", - chr.Name, chr.LocalID); - } - } - - private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, - PrimitiveBaseShape pbs, bool isphysical, uint localID) - { - Vector3 pos = position; - Vector3 siz = size; - Quaternion rot = rotation; - - OdePrim newPrim; - lock (OdeLock) - { - newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical); - - lock (_prims) - _prims.Add(newPrim); - } - newPrim.LocalID = localID; - return newPrim; - } - - /// - /// Make this prim subject to physics. - /// - /// - internal void ActivatePrim(OdePrim prim) - { - // adds active prim.. (ones that should be iterated over in collisions_optimized - if (!_activeprims.Contains(prim)) - _activeprims.Add(prim); - //else - // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent"); - } - - public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, - Vector3 size, Quaternion rotation, bool isPhysical, uint localid) - { -// m_log.DebugFormat("[ODE SCENE]: Adding physics prim {0} {1} to physics scene {2}", primName, localid, Name); - - return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid); - } - - public override float TimeDilation - { - get { return m_timeDilation; } - } - - public override bool SupportsNINJAJoints - { - get { return m_NINJA_physics_joints_enabled; } - } - - // internal utility function: must be called within a lock (OdeLock) - private void InternalAddActiveJoint(PhysicsJoint joint) - { - activeJoints.Add(joint); - SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint); - } - - // internal utility function: must be called within a lock (OdeLock) - private void InternalAddPendingJoint(OdePhysicsJoint joint) - { - pendingJoints.Add(joint); - SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint); - } - - // internal utility function: must be called within a lock (OdeLock) - private void InternalRemovePendingJoint(PhysicsJoint joint) - { - pendingJoints.Remove(joint); - SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene); - } - - // internal utility function: must be called within a lock (OdeLock) - private void InternalRemoveActiveJoint(PhysicsJoint joint) - { - activeJoints.Remove(joint); - SOPName_to_activeJoint.Remove(joint.ObjectNameInScene); - } - - public override void DumpJointInfo() - { - string hdr = "[NINJA] JOINTINFO: "; - foreach (PhysicsJoint j in pendingJoints) - { - m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); - } - m_log.Debug(hdr + pendingJoints.Count + " total pending joints"); - foreach (string jointName in SOPName_to_pendingJoint.Keys) - { - m_log.Debug(hdr + " pending joints dict contains Name: " + jointName); - } - m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries"); - foreach (PhysicsJoint j in activeJoints) - { - m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); - } - m_log.Debug(hdr + activeJoints.Count + " total active joints"); - foreach (string jointName in SOPName_to_activeJoint.Keys) - { - m_log.Debug(hdr + " active joints dict contains Name: " + jointName); - } - m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries"); - - m_log.Debug(hdr + " Per-body joint connectivity information follows."); - m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints."); - foreach (string actorName in joints_connecting_actor.Keys) - { - m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it"); - foreach (PhysicsJoint j in joints_connecting_actor[actorName]) - { - m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); - } - m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor"); - } - } - - public override void RequestJointDeletion(string ObjectNameInScene) - { - lock (externalJointRequestsLock) - { - if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously - { - requestedJointsToBeDeleted.Add(ObjectNameInScene); - } - } - } - - private void DeleteRequestedJoints() - { - List myRequestedJointsToBeDeleted; - lock (externalJointRequestsLock) - { - // make a local copy of the shared list for processing (threading issues) - myRequestedJointsToBeDeleted = new List(requestedJointsToBeDeleted); - } - - foreach (string jointName in myRequestedJointsToBeDeleted) - { - lock (OdeLock) - { - //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName); - if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName)) - { - OdePhysicsJoint joint = null; - if (SOPName_to_activeJoint.ContainsKey(jointName)) - { - joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint; - InternalRemoveActiveJoint(joint); - } - else if (SOPName_to_pendingJoint.ContainsKey(jointName)) - { - joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint; - InternalRemovePendingJoint(joint); - } - - if (joint != null) - { - //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames); - for (int iBodyName = 0; iBodyName < 2; iBodyName++) - { - string bodyName = joint.BodyNames[iBodyName]; - if (bodyName != "NULL") - { - joints_connecting_actor[bodyName].Remove(joint); - if (joints_connecting_actor[bodyName].Count == 0) - { - joints_connecting_actor.Remove(bodyName); - } - } - } - - DoJointDeactivated(joint); - if (joint.jointID != IntPtr.Zero) - { - d.JointDestroy(joint.jointID); - joint.jointID = IntPtr.Zero; - //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName); - } - else - { - //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName); - } - } - else - { - // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName); - } - } - else - { - // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName); - } - } - } - - // remove processed joints from the shared list - lock (externalJointRequestsLock) - { - foreach (string jointName in myRequestedJointsToBeDeleted) - { - requestedJointsToBeDeleted.Remove(jointName); - } - } - } - - // for pending joints we don't know if their associated bodies exist yet or not. - // the joint is actually created during processing of the taints - private void CreateRequestedJoints() - { - List myRequestedJointsToBeCreated; - lock (externalJointRequestsLock) - { - // make a local copy of the shared list for processing (threading issues) - myRequestedJointsToBeCreated = new List(requestedJointsToBeCreated); - } - - foreach (PhysicsJoint joint in myRequestedJointsToBeCreated) - { - lock (OdeLock) - { - if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null) - { - DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation); - continue; - } - if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null) - { - DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation); - continue; - } - - InternalAddPendingJoint(joint as OdePhysicsJoint); - - if (joint.BodyNames.Count >= 2) - { - for (int iBodyName = 0; iBodyName < 2; iBodyName++) - { - string bodyName = joint.BodyNames[iBodyName]; - if (bodyName != "NULL") - { - if (!joints_connecting_actor.ContainsKey(bodyName)) - { - joints_connecting_actor.Add(bodyName, new List()); - } - joints_connecting_actor[bodyName].Add(joint); - } - } - } - } - } - - // remove processed joints from shared list - lock (externalJointRequestsLock) - { - foreach (PhysicsJoint joint in myRequestedJointsToBeCreated) - { - requestedJointsToBeCreated.Remove(joint); - } - } - } - - /// - /// Add a request for joint creation. - /// - /// - /// this joint will just be added to a waiting list that is NOT processed during the main - /// Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public override PhysicsJoint RequestJointCreation( - string objectNameInScene, PhysicsJointType jointType, Vector3 position, - Quaternion rotation, string parms, List bodyNames, string trackedBodyName, Quaternion localRotation) - { - OdePhysicsJoint joint = new OdePhysicsJoint(); - joint.ObjectNameInScene = objectNameInScene; - joint.Type = jointType; - joint.Position = position; - joint.Rotation = rotation; - joint.RawParams = parms; - joint.BodyNames = new List(bodyNames); - joint.TrackedBodyName = trackedBodyName; - joint.LocalRotation = localRotation; - joint.jointID = IntPtr.Zero; - joint.ErrorMessageCount = 0; - - lock (externalJointRequestsLock) - { - if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice - { - requestedJointsToBeCreated.Add(joint); - } - } - - return joint; - } - - private void RemoveAllJointsConnectedToActor(PhysicsActor actor) - { - //m_log.Debug("RemoveAllJointsConnectedToActor: start"); - if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null) - { - List jointsToRemove = new List(); - //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism) - foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName]) - { - jointsToRemove.Add(j); - } - foreach (PhysicsJoint j in jointsToRemove) - { - //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene); - RequestJointDeletion(j.ObjectNameInScene); - //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene); - j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing) - } - } - } - - public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor) - { - //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start"); - lock (OdeLock) - { - //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock"); - RemoveAllJointsConnectedToActor(actor); - } - } - - // normally called from within OnJointMoved, which is called from within a lock (OdeLock) - public override Vector3 GetJointAnchor(PhysicsJoint joint) - { - Debug.Assert(joint.IsInPhysicsEngine); - d.Vector3 pos = new d.Vector3(); - - if (!(joint is OdePhysicsJoint)) - { - DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); - } - else - { - OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; - switch (odeJoint.Type) - { - case PhysicsJointType.Ball: - d.JointGetBallAnchor(odeJoint.jointID, out pos); - break; - case PhysicsJointType.Hinge: - d.JointGetHingeAnchor(odeJoint.jointID, out pos); - break; - } - } - return new Vector3(pos.X, pos.Y, pos.Z); - } - - /// - /// Get joint axis. - /// - /// - /// normally called from within OnJointMoved, which is called from within a lock (OdeLock) - /// WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function - /// appears to be unreliable. Fortunately we can compute the joint axis ourselves by - /// keeping track of the joint's original orientation relative to one of the involved bodies. - /// - /// - /// - public override Vector3 GetJointAxis(PhysicsJoint joint) - { - Debug.Assert(joint.IsInPhysicsEngine); - d.Vector3 axis = new d.Vector3(); - - if (!(joint is OdePhysicsJoint)) - { - DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); - } - else - { - OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; - switch (odeJoint.Type) - { - case PhysicsJointType.Ball: - DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene); - break; - case PhysicsJointType.Hinge: - d.JointGetHingeAxis(odeJoint.jointID, out axis); - break; - } - } - return new Vector3(axis.X, axis.Y, axis.Z); - } - - /// - /// Stop this prim being subject to physics - /// - /// - internal void DeactivatePrim(OdePrim prim) - { - _activeprims.Remove(prim); - } - - public override void RemovePrim(PhysicsActor prim) - { - // As with all ODE physics operations, we don't remove the prim immediately but signal that it should be - // removed in the next physics simulate pass. - if (prim is OdePrim) - { - lock (OdeLock) - { - OdePrim p = (OdePrim) prim; - - p.setPrimForRemoval(); - AddPhysicsActorTaint(prim); - } - } - } - - /// - /// This is called from within simulate but outside the locked portion - /// We need to do our own locking here - /// (Note: As of 20110801 this no longer appears to be true - this is being called within lock (odeLock) in - /// Simulate() -- justincc). - /// - /// Essentially, we need to remove the prim from our space segment, whatever segment it's in. - /// - /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory - /// that the space was using. - /// - /// - internal void RemovePrimThreadLocked(OdePrim prim) - { -// m_log.DebugFormat("[ODE SCENE]: Removing physical prim {0} {1}", prim.Name, prim.LocalID); - - lock (prim) - { - RemoveCollisionEventReporting(prim); - - if (prim.prim_geom != IntPtr.Zero) - { - prim.ResetTaints(); - - if (prim.IsPhysical) - { - prim.disableBody(); - if (prim.childPrim) - { - prim.childPrim = false; - prim.Body = IntPtr.Zero; - prim.m_disabled = true; - prim.IsPhysical = false; - } - - - } - // we don't want to remove the main space - - // If the geometry is in the targetspace, remove it from the target space - //m_log.Warn(prim.m_targetSpace); - - //if (prim.m_targetSpace != IntPtr.Zero) - //{ - //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom)) - //{ - - //if (d.GeomIsSpace(prim.m_targetSpace)) - //{ - //waitForSpaceUnlock(prim.m_targetSpace); - //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom); - prim.m_targetSpace = IntPtr.Zero; - //} - //else - //{ - // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" + - //((OdePrim)prim).m_targetSpace.ToString()); - //} - - //} - //} - //m_log.Warn(prim.prim_geom); - - if (!prim.RemoveGeom()) - m_log.Warn("[ODE SCENE]: Unable to remove prim from physics scene"); - - lock (_prims) - _prims.Remove(prim); - - //If there are no more geometries in the sub-space, we don't need it in the main space anymore - //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0) - //{ - //if (prim.m_targetSpace != null) - //{ - //if (d.GeomIsSpace(prim.m_targetSpace)) - //{ - //waitForSpaceUnlock(prim.m_targetSpace); - //d.SpaceRemove(space, prim.m_targetSpace); - // free up memory used by the space. - //d.SpaceDestroy(prim.m_targetSpace); - //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position); - //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]); - //} - //else - //{ - //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" + - //((OdePrim) prim).m_targetSpace.ToString()); - //} - //} - //} - - if (SupportsNINJAJoints) - RemoveAllJointsConnectedToActorThreadLocked(prim); - } - } - } - - #endregion - - #region Space Separation Calculation - - /// - /// Takes a space pointer and zeros out the array we're using to hold the spaces - /// - /// - private void resetSpaceArrayItemToZero(IntPtr pSpace) - { - for (int x = 0; x < staticPrimspace.GetLength(0); x++) - { - for (int y = 0; y < staticPrimspace.GetLength(1); y++) - { - if (staticPrimspace[x, y] == pSpace) - staticPrimspace[x, y] = IntPtr.Zero; - } - } - } - -// private void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY) -// { -// staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero; -// } - - /// - /// Called when a static prim moves. Allocates a space for the prim based on its position - /// - /// the pointer to the geom that moved - /// the position that the geom moved to - /// a pointer to the space it was in before it was moved. - /// a pointer to the new space it's in - internal IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace) - { - // Called from setting the Position and Size of an ODEPrim so - // it's already in locked space. - - // we don't want to remove the main space - // we don't need to test physical here because this function should - // never be called if the prim is physical(active) - - // All physical prim end up in the root space - //Thread.Sleep(20); - if (currentspace != space) - { - //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString()); - //if (currentspace == IntPtr.Zero) - //{ - //int adfadf = 0; - //} - if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero) - { - if (d.GeomIsSpace(currentspace)) - { -// waitForSpaceUnlock(currentspace); - d.SpaceRemove(currentspace, geom); - } - else - { - m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace + - " Geom:" + geom); - } - } - else - { - IntPtr sGeomIsIn = d.GeomGetSpace(geom); - if (sGeomIsIn != IntPtr.Zero) - { - if (d.GeomIsSpace(currentspace)) - { -// waitForSpaceUnlock(sGeomIsIn); - d.SpaceRemove(sGeomIsIn, geom); - } - else - { - m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + - sGeomIsIn + " Geom:" + geom); - } - } - } - - //If there are no more geometries in the sub-space, we don't need it in the main space anymore - if (d.SpaceGetNumGeoms(currentspace) == 0) - { - if (currentspace != IntPtr.Zero) - { - if (d.GeomIsSpace(currentspace)) - { -// waitForSpaceUnlock(currentspace); -// waitForSpaceUnlock(space); - d.SpaceRemove(space, currentspace); - // free up memory used by the space. - - //d.SpaceDestroy(currentspace); - resetSpaceArrayItemToZero(currentspace); - } - else - { - m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + - currentspace + " Geom:" + geom); - } - } - } - } - else - { - // this is a physical object that got disabled. ;.; - if (currentspace != IntPtr.Zero && geom != IntPtr.Zero) - { - if (d.SpaceQuery(currentspace, geom)) - { - if (d.GeomIsSpace(currentspace)) - { -// waitForSpaceUnlock(currentspace); - d.SpaceRemove(currentspace, geom); - } - else - { - m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + - currentspace + " Geom:" + geom); - } - } - else - { - IntPtr sGeomIsIn = d.GeomGetSpace(geom); - if (sGeomIsIn != IntPtr.Zero) - { - if (d.GeomIsSpace(sGeomIsIn)) - { -// waitForSpaceUnlock(sGeomIsIn); - d.SpaceRemove(sGeomIsIn, geom); - } - else - { - m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + - sGeomIsIn + " Geom:" + geom); - } - } - } - } - } - - // The routines in the Position and Size sections do the 'inserting' into the space, - // so all we have to do is make sure that the space that we're putting the prim into - // is in the 'main' space. - int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos); - IntPtr newspace = calculateSpaceForGeom(pos); - - if (newspace == IntPtr.Zero) - { - newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]); - d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh); - } - - return newspace; - } - - /// - /// Creates a new space at X Y - /// - /// - /// - /// A pointer to the created space - internal IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY) - { - // creating a new space for prim and inserting it into main space. - staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero); - d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space); -// waitForSpaceUnlock(space); - d.SpaceSetSublevel(space, 1); - d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]); - - return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]; - } - - /// - /// Calculates the space the prim should be in by its position - /// - /// - /// a pointer to the space. This could be a new space or reused space. - internal IntPtr calculateSpaceForGeom(Vector3 pos) - { - int[] xyspace = calculateSpaceArrayItemFromPos(pos); - //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString()); - return staticPrimspace[xyspace[0], xyspace[1]]; - } - - /// - /// Holds the space allocation logic - /// - /// - /// an array item based on the position - internal int[] calculateSpaceArrayItemFromPos(Vector3 pos) - { - int[] returnint = new int[2]; - - returnint[0] = (int) (pos.X/metersInSpace); - - if (returnint[0] > ((int) (259f/metersInSpace))) - returnint[0] = ((int) (259f/metersInSpace)); - if (returnint[0] < 0) - returnint[0] = 0; - - returnint[1] = (int) (pos.Y/metersInSpace); - if (returnint[1] > ((int) (259f/metersInSpace))) - returnint[1] = ((int) (259f/metersInSpace)); - if (returnint[1] < 0) - returnint[1] = 0; - - return returnint; - } - - #endregion - - /// - /// Routine to figure out if we need to mesh this prim with our mesher - /// - /// - /// - internal bool needsMeshing(PrimitiveBaseShape pbs) - { - // most of this is redundant now as the mesher will return null if it cant mesh a prim - // but we still need to check for sculptie meshing being enabled so this is the most - // convenient place to do it for now... - - // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f) - // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString()); - int iPropertiesNotSupportedDefault = 0; - - if (pbs.SculptEntry && !meshSculptedPrim) - { -#if SPAM - m_log.Warn("NonMesh"); -#endif - return false; - } - - // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim - if (!forceSimplePrimMeshing && !pbs.SculptEntry) - { - if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) - || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 - && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) - { - - if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 - && pbs.ProfileHollow == 0 - && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 - && pbs.PathBegin == 0 && pbs.PathEnd == 0 - && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 - && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 - && pbs.PathShearX == 0 && pbs.PathShearY == 0) - { -#if SPAM - m_log.Warn("NonMesh"); -#endif - return false; - } - } - } - - if (pbs.ProfileHollow != 0) - iPropertiesNotSupportedDefault++; - - if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) - iPropertiesNotSupportedDefault++; - - if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) - iPropertiesNotSupportedDefault++; - - if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0) - iPropertiesNotSupportedDefault++; - - if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100)) - iPropertiesNotSupportedDefault++; - - if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0)) - iPropertiesNotSupportedDefault++; - - if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight) - iPropertiesNotSupportedDefault++; - - if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X)) - iPropertiesNotSupportedDefault++; - - if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1) - iPropertiesNotSupportedDefault++; - - // test for torus - if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square) - { - if (pbs.PathCurve == (byte)Extrusion.Curve1) - { - iPropertiesNotSupportedDefault++; - } - } - else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) - { - if (pbs.PathCurve == (byte)Extrusion.Straight) - { - iPropertiesNotSupportedDefault++; - } - - // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits - else if (pbs.PathCurve == (byte)Extrusion.Curve1) - { - iPropertiesNotSupportedDefault++; - } - } - else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) - { - if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2) - { - iPropertiesNotSupportedDefault++; - } - } - else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) - { - if (pbs.PathCurve == (byte)Extrusion.Straight) - { - iPropertiesNotSupportedDefault++; - } - else if (pbs.PathCurve == (byte)Extrusion.Curve1) - { - iPropertiesNotSupportedDefault++; - } - } - - if (pbs.SculptEntry && meshSculptedPrim) - iPropertiesNotSupportedDefault++; - - if (iPropertiesNotSupportedDefault == 0) - { -#if SPAM - m_log.Warn("NonMesh"); -#endif - return false; - } -#if SPAM - m_log.Debug("Mesh"); -#endif - return true; - } - - /// - /// Called after our prim properties are set Scale, position etc. - /// - /// - /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex - /// This assures us that we have no race conditions - /// - /// - public override void AddPhysicsActorTaint(PhysicsActor actor) - { - if (actor is OdePrim) - { - OdePrim taintedprim = ((OdePrim)actor); - lock (_taintedPrims) - _taintedPrims.Add(taintedprim); - } - else if (actor is OdeCharacter) - { - OdeCharacter taintedchar = ((OdeCharacter)actor); - lock (_taintedActors) - { - _taintedActors.Add(taintedchar); - if (taintedchar.bad) - m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid); - } - } - } - - /// - /// This is our main simulate loop - /// - /// - /// It's thread locked by a Mutex in the scene. - /// It holds Collisions, it instructs ODE to step through the physical reactions - /// It moves the objects around in memory - /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup) - /// - /// - /// The number of frames simulated over that period. - public override float Simulate(float timeStep) - { - if (!_worldInitialized) return 11f; - - int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0; - int tempTick = 0, tempTick2 = 0; - - if (framecount >= int.MaxValue) - framecount = 0; - - framecount++; - - float fps = 0; - - float timeLeft = timeStep; - - //m_log.Info(timeStep.ToString()); -// step_time += timeSte -// -// // If We're loaded down by something else, -// // or debugging with the Visual Studio project on pause -// // skip a few frames to catch up gracefully. -// // without shooting the physicsactors all over the place -// -// if (step_time >= m_SkipFramesAtms) -// { -// // Instead of trying to catch up, it'll do 5 physics frames only -// step_time = ODE_STEPSIZE; -// m_physicsiterations = 5; -// } -// else -// { -// m_physicsiterations = 10; -// } - - // We change _collisionEventPrimChanges to avoid locking _collisionEventPrim itself and causing potential - // deadlock if the collision event tries to lock something else later on which is already locked by a - // caller that is adding or removing the collision event. - lock (m_collisionEventActorsChanges) - { - foreach (KeyValuePair kvp in m_collisionEventActorsChanges) - { - if (kvp.Value == null) - m_collisionEventActors.Remove(kvp.Key); - else - m_collisionEventActors[kvp.Key] = kvp.Value; - } - - m_collisionEventActorsChanges.Clear(); - } - - if (SupportsNINJAJoints) - { - DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks - CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks - } - - lock (OdeLock) - { - // Process 10 frames if the sim is running normal.. - // process 5 frames if the sim is running slow - //try - //{ - //d.WorldSetQuickStepNumIterations(world, m_physicsiterations); - //} - //catch (StackOverflowException) - //{ - // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim."); - // ode.drelease(world); - //base.TriggerPhysicsBasedRestart(); - //} - - // Figure out the Frames Per Second we're going at. - //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size - - fps = (timeStep / ODE_STEPSIZE) * 1000; - // HACK: Using a time dilation of 1.0 to debug rubberbanding issues - //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f); - - while (timeLeft > 0.0f) - { - try - { - if (CollectStats) - tempTick = Util.EnvironmentTickCount(); - - lock (_taintedActors) - { - foreach (OdeCharacter character in _taintedActors) - character.ProcessTaints(); - - _taintedActors.Clear(); - } - - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODEAvatarTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } - - lock (_taintedPrims) - { - foreach (OdePrim prim in _taintedPrims) - { - if (prim.m_taintremove) - { -// Console.WriteLine("Simulate calls RemovePrimThreadLocked for {0}", prim.Name); - RemovePrimThreadLocked(prim); - } - else - { -// Console.WriteLine("Simulate calls ProcessTaints for {0}", prim.Name); - prim.ProcessTaints(); - } - - prim.m_collisionscore = 0; - - // This loop can block up the Heartbeat for a very long time on large regions. - // We need to let the Watchdog know that the Heartbeat is not dead - // NOTE: This is currently commented out, but if things like OAR loading are - // timing the heartbeat out we will need to uncomment it - //Watchdog.UpdateThread(); - } - - if (SupportsNINJAJoints) - SimulatePendingNINJAJoints(); - - _taintedPrims.Clear(); - } - - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODEPrimTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } - - // Move characters - foreach (OdeCharacter actor in _characters) - actor.Move(defects); - - if (defects.Count != 0) - { - foreach (OdeCharacter actor in defects) - { - m_log.ErrorFormat( - "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when moving", - actor.Name, actor.LocalID, Name); - - RemoveCharacter(actor); - actor.DestroyOdeStructures(); - } - - defects.Clear(); - } - - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODEAvatarForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } - - // Move other active objects - foreach (OdePrim prim in _activeprims) - { - prim.m_collisionscore = 0; - prim.Move(timeStep); - } - - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODEPrimForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } - - //if ((framecount % m_randomizeWater) == 0) - // randomizeWater(waterlevel); - - //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests(); - m_rayCastManager.ProcessQueuedRequests(); - - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODERaycastingFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } - - collision_optimized(); - - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODEOtherCollisionFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } - - foreach (PhysicsActor obj in m_collisionEventActors.Values) - { -// m_log.DebugFormat("[PHYSICS]: Assessing {0} {1} for collision events", obj.SOPName, obj.LocalID); - - switch ((ActorTypes)obj.PhysicsActorType) - { - case ActorTypes.Agent: - OdeCharacter cobj = (OdeCharacter)obj; - cobj.AddCollisionFrameTime(100); - cobj.SendCollisions(); - break; - - case ActorTypes.Prim: - OdePrim pobj = (OdePrim)obj; - pobj.SendCollisions(); - break; - } - } - -// if (m_global_contactcount > 0) -// m_log.DebugFormat( -// "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount); - - m_global_contactcount = 0; - - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODECollisionNotificationFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } - - d.WorldQuickStep(world, ODE_STEPSIZE); - - if (CollectStats) - m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); - - d.JointGroupEmpty(contactgroup); - } - catch (Exception e) - { - m_log.ErrorFormat("[ODE SCENE]: {0}, {1}, {2}", e.Message, e.TargetSite, e); - } - - timeLeft -= ODE_STEPSIZE; - } - - if (CollectStats) - tempTick = Util.EnvironmentTickCount(); - - foreach (OdeCharacter actor in _characters) - { - if (actor.bad) - m_log.ErrorFormat("[ODE SCENE]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); - - actor.UpdatePositionAndVelocity(defects); - } - - if (defects.Count != 0) - { - foreach (OdeCharacter actor in defects) - { - m_log.ErrorFormat( - "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when updating position and velocity", - actor.Name, actor.LocalID, Name); - - RemoveCharacter(actor); - actor.DestroyOdeStructures(); - } - - defects.Clear(); - } - - if (CollectStats) - { - tempTick2 = Util.EnvironmentTickCount(); - m_stats[ODEAvatarUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); - tempTick = tempTick2; - } - - //if (timeStep < 0.2f) - - foreach (OdePrim prim in _activeprims) - { - if (prim.IsPhysical && (d.BodyIsEnabled(prim.Body) || !prim._zeroFlag)) - { - prim.UpdatePositionAndVelocity(); - - if (SupportsNINJAJoints) - SimulateActorPendingJoints(prim); - } - } - - if (CollectStats) - m_stats[ODEPrimUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); - - //DumpJointInfo(); - - // Finished with all sim stepping. If requested, dump world state to file for debugging. - // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed? - // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots? - if (physics_logging && (physics_logging_interval > 0) && (framecount % physics_logging_interval == 0)) - { - string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename - string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file - - if (physics_logging_append_existing_logfile) - { - string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------"; - TextWriter fwriter = File.AppendText(fname); - fwriter.WriteLine(header); - fwriter.Close(); - } - - d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); - } - - latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun); - - // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics - // has a max of 100 ms to run theoretically. - // If the main loop stalls, it calls Simulate later which makes the tick count ms larger. - // If Physics stalls, it takes longer which makes the tick count ms larger. - - if (latertickcount < 100) - { - m_timeDilation = 1.0f; - } - else - { - m_timeDilation = 100f / latertickcount; - //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f); - } - - tickCountFrameRun = Util.EnvironmentTickCount(); - - if (CollectStats) - m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick); - } - - return fps; - } - - /// - /// Simulate pending NINJA joints. - /// - /// - /// Called by the main Simulate() loop if NINJA joints are active. Should not be called from anywhere else. - /// - private void SimulatePendingNINJAJoints() - { - // Create pending joints, if possible - - // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating - // a joint requires specifying the body id of both involved bodies - if (pendingJoints.Count > 0) - { - List successfullyProcessedPendingJoints = new List(); - //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints"); - foreach (PhysicsJoint joint in pendingJoints) - { - //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams); - string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries); - List jointBodies = new List(); - bool allJointBodiesAreReady = true; - foreach (string jointParam in jointParams) - { - if (jointParam == "NULL") - { - //DoJointErrorMessage(joint, "attaching NULL joint to world"); - jointBodies.Add(IntPtr.Zero); - } - else - { - //DoJointErrorMessage(joint, "looking for prim name: " + jointParam); - bool foundPrim = false; - lock (_prims) - { - foreach (OdePrim prim in _prims) // FIXME: inefficient - { - if (prim.SOPName == jointParam) - { - //DoJointErrorMessage(joint, "found for prim name: " + jointParam); - if (prim.IsPhysical && prim.Body != IntPtr.Zero) - { - jointBodies.Add(prim.Body); - foundPrim = true; - break; - } - else - { - DoJointErrorMessage(joint, "prim name " + jointParam + - " exists but is not (yet) physical; deferring joint creation. " + - "IsPhysical property is " + prim.IsPhysical + - " and body is " + prim.Body); - foundPrim = false; - break; - } - } - } - } - if (foundPrim) - { - // all is fine - } - else - { - allJointBodiesAreReady = false; - break; - } - } - } - - if (allJointBodiesAreReady) - { - //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams); - if (jointBodies[0] == jointBodies[1]) - { - DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams); - } - else - { - switch (joint.Type) - { - case PhysicsJointType.Ball: - { - IntPtr odeJoint; - //DoJointErrorMessage(joint, "ODE creating ball joint "); - odeJoint = d.JointCreateBall(world, IntPtr.Zero); - //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); - d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); - //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position); - d.JointSetBallAnchor(odeJoint, - joint.Position.X, - joint.Position.Y, - joint.Position.Z); - //DoJointErrorMessage(joint, "ODE joint setting OK"); - //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: "); - //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment")); - //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: "); - //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment")); - - if (joint is OdePhysicsJoint) - { - ((OdePhysicsJoint)joint).jointID = odeJoint; - } - else - { - DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); - } - } - break; - case PhysicsJointType.Hinge: - { - IntPtr odeJoint; - //DoJointErrorMessage(joint, "ODE creating hinge joint "); - odeJoint = d.JointCreateHinge(world, IntPtr.Zero); - //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); - d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); - //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position); - d.JointSetHingeAnchor(odeJoint, - joint.Position.X, - joint.Position.Y, - joint.Position.Z); - // We use the orientation of the x-axis of the joint's coordinate frame - // as the axis for the hinge. - - // Therefore, we must get the joint's coordinate frame based on the - // joint.Rotation field, which originates from the orientation of the - // joint's proxy object in the scene. - - // The joint's coordinate frame is defined as the transformation matrix - // that converts a vector from joint-local coordinates into world coordinates. - // World coordinates are defined as the XYZ coordinate system of the sim, - // as shown in the top status-bar of the viewer. - - // Once we have the joint's coordinate frame, we extract its X axis (AtAxis) - // and use that as the hinge axis. - - //joint.Rotation.Normalize(); - Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation); - - // Now extract the X axis of the joint's coordinate frame. - - // Do not try to use proxyFrame.AtAxis or you will become mired in the - // tar pit of transposed, inverted, and generally messed-up orientations. - // (In other words, Matrix4.AtAxis() is borked.) - // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness - - // Instead, compute the X axis of the coordinate frame by transforming - // the (1,0,0) vector. At least that works. - - //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame); - Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame); - //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis); - //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis); - d.JointSetHingeAxis(odeJoint, - jointAxis.X, - jointAxis.Y, - jointAxis.Z); - //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f); - if (joint is OdePhysicsJoint) - { - ((OdePhysicsJoint)joint).jointID = odeJoint; - } - else - { - DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); - } - } - break; - } - successfullyProcessedPendingJoints.Add(joint); - } - } - else - { - DoJointErrorMessage(joint, "joint could not yet be created; still pending"); - } - } - - foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints) - { - //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams); - //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending"); - InternalRemovePendingJoint(successfullyProcessedJoint); - //DoJointErrorMessage(successfullyProcessedJoint, "adding to active"); - InternalAddActiveJoint(successfullyProcessedJoint); - //DoJointErrorMessage(successfullyProcessedJoint, "done"); - } - } - } - - /// - /// Simulate the joint proxies of a NINJA actor. - /// - /// - /// Called as part of the Simulate() loop if NINJA physics is active. Must only be called from there. - /// - /// - private void SimulateActorPendingJoints(OdePrim actor) - { - // If an actor moved, move its joint proxy objects as well. - // There seems to be an event PhysicsActor.OnPositionUpdate that could be used - // for this purpose but it is never called! So we just do the joint - // movement code here. - - if (actor.SOPName != null && - joints_connecting_actor.ContainsKey(actor.SOPName) && - joints_connecting_actor[actor.SOPName] != null && - joints_connecting_actor[actor.SOPName].Count > 0) - { - foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName]) - { - if (affectedJoint.IsInPhysicsEngine) - { - DoJointMoved(affectedJoint); - } - else - { - DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams); - } - } - } - } - - public override void GetResults() - { - } - - public override bool IsThreaded - { - // for now we won't be multithreaded - get { return false; } - } - - #region ODE Specific Terrain Fixes - private float[] ResizeTerrain512NearestNeighbour(float[] heightMap) - { - float[] returnarr = new float[262144]; - float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y]; - - // Filling out the array into its multi-dimensional components - for (int y = 0; y < WorldExtents.Y; y++) - { - for (int x = 0; x < WorldExtents.X; x++) - { - resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x]; - } - } - - // Resize using Nearest Neighbour - - // This particular way is quick but it only works on a multiple of the original - - // The idea behind this method can be described with the following diagrams - // second pass and third pass happen in the same loop really.. just separated - // them to show what this does. - - // First Pass - // ResultArr: - // 1,1,1,1,1,1 - // 1,1,1,1,1,1 - // 1,1,1,1,1,1 - // 1,1,1,1,1,1 - // 1,1,1,1,1,1 - // 1,1,1,1,1,1 - - // Second Pass - // ResultArr2: - // 1,,1,,1,,1,,1,,1, - // ,,,,,,,,,, - // 1,,1,,1,,1,,1,,1, - // ,,,,,,,,,, - // 1,,1,,1,,1,,1,,1, - // ,,,,,,,,,, - // 1,,1,,1,,1,,1,,1, - // ,,,,,,,,,, - // 1,,1,,1,,1,,1,,1, - // ,,,,,,,,,, - // 1,,1,,1,,1,,1,,1, - - // Third pass fills in the blanks - // ResultArr2: - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - - // X,Y = . - // X+1,y = ^ - // X,Y+1 = * - // X+1,Y+1 = # - - // Filling in like this; - // .* - // ^# - // 1st . - // 2nd * - // 3rd ^ - // 4th # - // on single loop. - - float[,] resultarr2 = new float[512, 512]; - for (int y = 0; y < WorldExtents.Y; y++) - { - for (int x = 0; x < WorldExtents.X; x++) - { - resultarr2[y * 2, x * 2] = resultarr[y, x]; - - if (y < WorldExtents.Y) - { - resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x]; - } - if (x < WorldExtents.X) - { - resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x]; - } - if (x < WorldExtents.X && y < WorldExtents.Y) - { - resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x]; - } - } - } - - //Flatten out the array - int i = 0; - for (int y = 0; y < 512; y++) - { - for (int x = 0; x < 512; x++) - { - if (resultarr2[y, x] <= 0) - returnarr[i] = 0.0000001f; - else - returnarr[i] = resultarr2[y, x]; - - i++; - } - } - - return returnarr; - } - - private float[] ResizeTerrain512Interpolation(float[] heightMap) - { - float[] returnarr = new float[262144]; - float[,] resultarr = new float[512,512]; - - // Filling out the array into its multi-dimensional components - for (int y = 0; y < 256; y++) - { - for (int x = 0; x < 256; x++) - { - resultarr[y, x] = heightMap[y * 256 + x]; - } - } - - // Resize using interpolation - - // This particular way is quick but it only works on a multiple of the original - - // The idea behind this method can be described with the following diagrams - // second pass and third pass happen in the same loop really.. just separated - // them to show what this does. - - // First Pass - // ResultArr: - // 1,1,1,1,1,1 - // 1,1,1,1,1,1 - // 1,1,1,1,1,1 - // 1,1,1,1,1,1 - // 1,1,1,1,1,1 - // 1,1,1,1,1,1 - - // Second Pass - // ResultArr2: - // 1,,1,,1,,1,,1,,1, - // ,,,,,,,,,, - // 1,,1,,1,,1,,1,,1, - // ,,,,,,,,,, - // 1,,1,,1,,1,,1,,1, - // ,,,,,,,,,, - // 1,,1,,1,,1,,1,,1, - // ,,,,,,,,,, - // 1,,1,,1,,1,,1,,1, - // ,,,,,,,,,, - // 1,,1,,1,,1,,1,,1, - - // Third pass fills in the blanks - // ResultArr2: - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - // 1,1,1,1,1,1,1,1,1,1,1,1 - - // X,Y = . - // X+1,y = ^ - // X,Y+1 = * - // X+1,Y+1 = # - - // Filling in like this; - // .* - // ^# - // 1st . - // 2nd * - // 3rd ^ - // 4th # - // on single loop. - - float[,] resultarr2 = new float[512,512]; - for (int y = 0; y < (int)Constants.RegionSize; y++) - { - for (int x = 0; x < (int)Constants.RegionSize; x++) - { - resultarr2[y*2, x*2] = resultarr[y, x]; - - if (y < (int)Constants.RegionSize) - { - if (y + 1 < (int)Constants.RegionSize) - { - if (x + 1 < (int)Constants.RegionSize) - { - resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] + - resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4); - } - else - { - resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2); - } - } - else - { - resultarr2[(y*2) + 1, x*2] = resultarr[y, x]; - } - } - if (x < (int)Constants.RegionSize) - { - if (x + 1 < (int)Constants.RegionSize) - { - if (y + 1 < (int)Constants.RegionSize) - { - resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] + - resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4); - } - else - { - resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2); - } - } - else - { - resultarr2[y*2, (x*2) + 1] = resultarr[y, x]; - } - } - if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize) - { - if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize)) - { - resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] + - resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4); - } - else - { - resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x]; - } - } - } - } - //Flatten out the array - int i = 0; - for (int y = 0; y < 512; y++) - { - for (int x = 0; x < 512; x++) - { - if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x])) - { - m_log.Warn("[ODE SCENE]: Non finite heightfield element detected. Setting it to 0"); - resultarr2[y, x] = 0; - } - returnarr[i] = resultarr2[y, x]; - i++; - } - } - - return returnarr; - } - - #endregion - - public override void SetTerrain(float[] heightMap) - { - if (m_worldOffset != Vector3.Zero && m_parentScene != null) - { - if (m_parentScene is OdeScene) - { - ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset); - } - } - else - { - SetTerrain(heightMap, m_worldOffset); - } - } - - private void SetTerrain(float[] heightMap, Vector3 pOffset) - { - int startTime = Util.EnvironmentTickCount(); - m_log.DebugFormat("[ODE SCENE]: Setting terrain for {0} with offset {1}", Name, pOffset); - - // this._heightmap[i] = (double)heightMap[i]; - // dbm (danx0r) -- creating a buffer zone of one extra sample all around - //_origheightmap = heightMap; - - float[] _heightmap; - - // zero out a heightmap array float array (single dimension [flattened])) - //if ((int)Constants.RegionSize == 256) - // _heightmap = new float[514 * 514]; - //else - - _heightmap = new float[(((int)Constants.RegionSize + 2) * ((int)Constants.RegionSize + 2))]; - - uint heightmapWidth = Constants.RegionSize + 1; - uint heightmapHeight = Constants.RegionSize + 1; - - uint heightmapWidthSamples; - - uint heightmapHeightSamples; - - //if (((int)Constants.RegionSize) == 256) - //{ - // heightmapWidthSamples = 2 * (uint)Constants.RegionSize + 2; - // heightmapHeightSamples = 2 * (uint)Constants.RegionSize + 2; - // heightmapWidth++; - // heightmapHeight++; - //} - //else - //{ - - heightmapWidthSamples = (uint)Constants.RegionSize + 1; - heightmapHeightSamples = (uint)Constants.RegionSize + 1; - //} - - const float scale = 1.0f; - const float offset = 0.0f; - const float thickness = 0.2f; - const int wrap = 0; - - int regionsize = (int) Constants.RegionSize + 2; - //Double resolution - //if (((int)Constants.RegionSize) == 256) - // heightMap = ResizeTerrain512Interpolation(heightMap); - - - // if (((int)Constants.RegionSize) == 256 && (int)Constants.RegionSize == 256) - // regionsize = 512; - - float hfmin = 2000; - float hfmax = -2000; - - for (int x = 0; x < heightmapWidthSamples; x++) - { - for (int y = 0; y < heightmapHeightSamples; y++) - { - int xx = Util.Clip(x - 1, 0, regionsize - 1); - int yy = Util.Clip(y - 1, 0, regionsize - 1); - - - float val= heightMap[yy * (int)Constants.RegionSize + xx]; - _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val; - - hfmin = (val < hfmin) ? val : hfmin; - hfmax = (val > hfmax) ? val : hfmax; - } - } - - lock (OdeLock) - { - IntPtr GroundGeom = IntPtr.Zero; - if (RegionTerrain.TryGetValue(pOffset, out GroundGeom)) - { - RegionTerrain.Remove(pOffset); - if (GroundGeom != IntPtr.Zero) - { - if (TerrainHeightFieldHeights.ContainsKey(GroundGeom)) - { - TerrainHeightFieldHeights.Remove(GroundGeom); - } - d.SpaceRemove(space, GroundGeom); - d.GeomDestroy(GroundGeom); - } - - } - IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); - d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, heightmapWidth + 1, heightmapHeight + 1, - (int)heightmapWidthSamples + 1, (int)heightmapHeightSamples + 1, scale, - offset, thickness, wrap); - d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); - GroundGeom = d.CreateHeightfield(space, HeightmapData, 1); - if (GroundGeom != IntPtr.Zero) - { - d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land)); - d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space)); - - } - geom_name_map[GroundGeom] = "Terrain"; - - d.Matrix3 R = new d.Matrix3(); - - Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f); - Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f); - //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1)); - - q1 = q1 * q2; - //q1 = q1 * q3; - Vector3 v3; - float angle; - q1.GetAxisAngle(out v3, out angle); - - d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); - d.GeomSetRotation(GroundGeom, ref R); - d.GeomSetPosition(GroundGeom, (pOffset.X + ((int)Constants.RegionSize * 0.5f)), (pOffset.Y + ((int)Constants.RegionSize * 0.5f)), 0); - IntPtr testGround = IntPtr.Zero; - if (RegionTerrain.TryGetValue(pOffset, out testGround)) - { - RegionTerrain.Remove(pOffset); - } - RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); - TerrainHeightFieldHeights.Add(GroundGeom,_heightmap); - } - - m_log.DebugFormat( - "[ODE SCENE]: Setting terrain for {0} took {1}ms", Name, Util.EnvironmentTickCountSubtract(startTime)); - } - - public override void DeleteTerrain() - { - } - - internal float GetWaterLevel() - { - return waterlevel; - } - - public override bool SupportsCombining() - { - return true; - } - -// public override void UnCombine(PhysicsScene pScene) -// { -// IntPtr localGround = IntPtr.Zero; -//// float[] localHeightfield; -// bool proceed = false; -// List geomDestroyList = new List(); -// -// lock (OdeLock) -// { -// if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround)) -// { -// foreach (IntPtr geom in TerrainHeightFieldHeights.Keys) -// { -// if (geom == localGround) -// { -//// localHeightfield = TerrainHeightFieldHeights[geom]; -// proceed = true; -// } -// else -// { -// geomDestroyList.Add(geom); -// } -// } -// -// if (proceed) -// { -// m_worldOffset = Vector3.Zero; -// WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); -// m_parentScene = null; -// -// foreach (IntPtr g in geomDestroyList) -// { -// // removingHeightField needs to be done or the garbage collector will -// // collect the terrain data before we tell ODE to destroy it causing -// // memory corruption -// if (TerrainHeightFieldHeights.ContainsKey(g)) -// { -//// float[] removingHeightField = TerrainHeightFieldHeights[g]; -// TerrainHeightFieldHeights.Remove(g); -// -// if (RegionTerrain.ContainsKey(g)) -// { -// RegionTerrain.Remove(g); -// } -// -// d.GeomDestroy(g); -// //removingHeightField = new float[0]; -// } -// } -// -// } -// else -// { -// m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data."); -// } -// } -// } -// } - - public override void SetWaterLevel(float baseheight) - { - waterlevel = baseheight; - randomizeWater(waterlevel); - } - - private void randomizeWater(float baseheight) - { - const uint heightmapWidth = m_regionWidth + 2; - const uint heightmapHeight = m_regionHeight + 2; - const uint heightmapWidthSamples = m_regionWidth + 2; - const uint heightmapHeightSamples = m_regionHeight + 2; - const float scale = 1.0f; - const float offset = 0.0f; - const float thickness = 2.9f; - const int wrap = 0; - - for (int i = 0; i < (258 * 258); i++) - { - _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f); - // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f)); - } - - lock (OdeLock) - { - if (WaterGeom != IntPtr.Zero) - { - d.SpaceRemove(space, WaterGeom); - } - IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); - d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight, - (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale, - offset, thickness, wrap); - d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight); - WaterGeom = d.CreateHeightfield(space, HeightmapData, 1); - if (WaterGeom != IntPtr.Zero) - { - d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water)); - d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space)); - } - - geom_name_map[WaterGeom] = "Water"; - - d.Matrix3 R = new d.Matrix3(); - - Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f); - Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f); - //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1)); - - q1 = q1 * q2; - //q1 = q1 * q3; - Vector3 v3; - float angle; - q1.GetAxisAngle(out v3, out angle); - - d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); - d.GeomSetRotation(WaterGeom, ref R); - d.GeomSetPosition(WaterGeom, 128, 128, 0); - } - } - - public override void Dispose() - { - _worldInitialized = false; - - m_rayCastManager.Dispose(); - m_rayCastManager = null; - - lock (OdeLock) - { - lock (_prims) - { - foreach (OdePrim prm in _prims) - { - RemovePrim(prm); - } - } - - //foreach (OdeCharacter act in _characters) - //{ - //RemoveAvatar(act); - //} - d.WorldDestroy(world); - //d.CloseODE(); - } - - } - - public override Dictionary GetTopColliders() - { - Dictionary topColliders; - - lock (_prims) - { - List orderedPrims = new List(_prims); - orderedPrims.OrderByDescending(p => p.CollisionScore).Take(25); - topColliders = orderedPrims.ToDictionary(p => p.LocalID, p => p.CollisionScore); - - foreach (OdePrim p in _prims) - p.CollisionScore = 0; - } - - return topColliders; - } - - public override bool SupportsRayCast() - { - return true; - } - - public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod) - { - if (retMethod != null) - { - m_rayCastManager.QueueRequest(position, direction, length, retMethod); - } - } - - public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod) - { - if (retMethod != null) - { - m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); - } - } - - public override List RaycastWorld(Vector3 position, Vector3 direction, float length, int Count) - { - ContactResult[] ourResults = null; - RayCallback retMethod = delegate(List results) - { - ourResults = new ContactResult[results.Count]; - results.CopyTo(ourResults, 0); - }; - int waitTime = 0; - m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); - while (ourResults == null && waitTime < 1000) - { - Thread.Sleep(1); - waitTime++; - } - if (ourResults == null) - return new List (); - return new List(ourResults); - } - -#if USE_DRAWSTUFF - // Keyboard callback - public void command(int cmd) - { - IntPtr geom; - d.Mass mass; - d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f); - - - - Char ch = Char.ToLower((Char)cmd); - switch ((Char)ch) - { - case 'w': - try - { - Vector3 rotate = (new Vector3(1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD)); - - xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z; - ds.SetViewpoint(ref xyz, ref hpr); - } - catch (ArgumentException) - { hpr.X = 0; } - break; - - case 'a': - hpr.X++; - ds.SetViewpoint(ref xyz, ref hpr); - break; - - case 's': - try - { - Vector3 rotate2 = (new Vector3(-1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD)); - - xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z; - ds.SetViewpoint(ref xyz, ref hpr); - } - catch (ArgumentException) - { hpr.X = 0; } - break; - case 'd': - hpr.X--; - ds.SetViewpoint(ref xyz, ref hpr); - break; - case 'r': - xyz.Z++; - ds.SetViewpoint(ref xyz, ref hpr); - break; - case 'f': - xyz.Z--; - ds.SetViewpoint(ref xyz, ref hpr); - break; - case 'e': - xyz.Y++; - ds.SetViewpoint(ref xyz, ref hpr); - break; - case 'q': - xyz.Y--; - ds.SetViewpoint(ref xyz, ref hpr); - break; - } - } - - public void step(int pause) - { - - ds.SetColor(1.0f, 1.0f, 0.0f); - ds.SetTexture(ds.Texture.Wood); - lock (_prims) - { - foreach (OdePrim prm in _prims) - { - //IntPtr body = d.GeomGetBody(prm.prim_geom); - if (prm.prim_geom != IntPtr.Zero) - { - d.Vector3 pos; - d.GeomCopyPosition(prm.prim_geom, out pos); - //d.BodyCopyPosition(body, out pos); - - d.Matrix3 R; - d.GeomCopyRotation(prm.prim_geom, out R); - //d.BodyCopyRotation(body, out R); - - - d.Vector3 sides = new d.Vector3(); - sides.X = prm.Size.X; - sides.Y = prm.Size.Y; - sides.Z = prm.Size.Z; - - ds.DrawBox(ref pos, ref R, ref sides); - } - } - } - ds.SetColor(1.0f, 0.0f, 0.0f); - - foreach (OdeCharacter chr in _characters) - { - if (chr.Shell != IntPtr.Zero) - { - IntPtr body = d.GeomGetBody(chr.Shell); - - d.Vector3 pos; - d.GeomCopyPosition(chr.Shell, out pos); - //d.BodyCopyPosition(body, out pos); - - d.Matrix3 R; - d.GeomCopyRotation(chr.Shell, out R); - //d.BodyCopyRotation(body, out R); - - ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f); - d.Vector3 sides = new d.Vector3(); - sides.X = 0.5f; - sides.Y = 0.5f; - sides.Z = 0.5f; - - ds.DrawBox(ref pos, ref R, ref sides); - } - } - } - - public void start(int unused) - { - ds.SetViewpoint(ref xyz, ref hpr); - } -#endif - - public override Dictionary GetStats() - { - if (!CollectStats) - return null; - - Dictionary returnStats; - - lock (OdeLock) - { - returnStats = new Dictionary(m_stats); - - // FIXME: This is a SUPER DUMB HACK until we can establish stats that aren't subject to a division by - // 3 from the SimStatsReporter. - returnStats[ODETotalAvatarsStatName] = _characters.Count * 3; - returnStats[ODETotalPrimsStatName] = _prims.Count * 3; - returnStats[ODEActivePrimsStatName] = _activeprims.Count * 3; - - InitializeExtraStats(); - } - - returnStats[ODEOtherCollisionFrameMsStatName] - = returnStats[ODEOtherCollisionFrameMsStatName] - - returnStats[ODENativeSpaceCollisionFrameMsStatName] - - returnStats[ODENativeGeomCollisionFrameMsStatName]; - - return returnStats; - } - - private void InitializeExtraStats() - { - m_stats[ODETotalFrameMsStatName] = 0; - m_stats[ODEAvatarTaintMsStatName] = 0; - m_stats[ODEPrimTaintMsStatName] = 0; - m_stats[ODEAvatarForcesFrameMsStatName] = 0; - m_stats[ODEPrimForcesFrameMsStatName] = 0; - m_stats[ODERaycastingFrameMsStatName] = 0; - m_stats[ODENativeStepFrameMsStatName] = 0; - m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0; - m_stats[ODENativeGeomCollisionFrameMsStatName] = 0; - m_stats[ODEOtherCollisionFrameMsStatName] = 0; - m_stats[ODECollisionNotificationFrameMsStatName] = 0; - m_stats[ODEAvatarContactsStatsName] = 0; - m_stats[ODEPrimContactsStatName] = 0; - m_stats[ODEAvatarUpdateFrameMsStatName] = 0; - m_stats[ODEPrimUpdateFrameMsStatName] = 0; - } - } -} diff --git a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs deleted file mode 100644 index 16404c6..0000000 --- a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using Nini.Config; -using NUnit.Framework; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; -using OpenSim.Region.Physics.OdePlugin; -using OpenSim.Tests.Common; -using log4net; -using System.Reflection; - -namespace OpenSim.Region.Physics.OdePlugin.Tests -{ - [TestFixture] - public class ODETestClass : OpenSimTestCase - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private OpenSim.Region.Physics.OdePlugin.OdePlugin cbt; - private PhysicsScene ps; - private IMeshingPlugin imp; - - [SetUp] - public void Initialize() - { - IConfigSource TopConfig = new IniConfigSource(); - IConfig config = TopConfig.AddConfig("Startup"); - config.Set("DecodedSculptMapPath","j2kDecodeCache"); - - // Loading ODEPlugin - cbt = new OdePlugin(); - // Loading Zero Mesher - imp = new ZeroMesherPlugin(); - // Getting Physics Scene - ps = cbt.GetScene("test"); - // Initializing Physics Scene. - ps.Initialise(imp.GetMesher(TopConfig),null); - float[] _heightmap = new float[(int)Constants.RegionSize * (int)Constants.RegionSize]; - for (int i = 0; i < ((int)Constants.RegionSize * (int)Constants.RegionSize); i++) - { - _heightmap[i] = 21f; - } - ps.SetTerrain(_heightmap); - } - - [TearDown] - public void Terminate() - { - ps.DeleteTerrain(); - ps.Dispose(); - - } - - [Test] - public void CreateAndDropPhysicalCube() - { - PrimitiveBaseShape newcube = PrimitiveBaseShape.CreateBox(); - Vector3 position = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 128f); - Vector3 size = new Vector3(0.5f, 0.5f, 0.5f); - Quaternion rot = Quaternion.Identity; - PhysicsActor prim = ps.AddPrimShape("CoolShape", newcube, position, size, rot, true, 0); - OdePrim oprim = (OdePrim)prim; - OdeScene pscene = (OdeScene) ps; - - Assert.That(oprim.m_taintadd); - - prim.LocalID = 5; - - for (int i = 0; i < 58; i++) - { - ps.Simulate(0.133f); - - Assert.That(oprim.prim_geom != (IntPtr)0); - - Assert.That(oprim.m_targetSpace != (IntPtr)0); - - //Assert.That(oprim.m_targetSpace == pscene.space); - m_log.Info("TargetSpace: " + oprim.m_targetSpace + " - SceneMainSpace: " + pscene.space); - - Assert.That(!oprim.m_taintadd); - m_log.Info("Prim Position (" + oprim.LocalID + "): " + prim.Position); - - // Make sure we're above the ground - //Assert.That(prim.Position.Z > 20f); - //m_log.Info("PrimCollisionScore (" + oprim.m_localID + "): " + oprim.m_collisionscore); - - // Make sure we've got a Body - Assert.That(oprim.Body != (IntPtr)0); - //m_log.Info( - } - - // Make sure we're not somewhere above the ground - Assert.That(prim.Position.Z < 21.5f); - - ps.RemovePrim(prim); - Assert.That(oprim.m_taintremove); - ps.Simulate(0.133f); - Assert.That(oprim.Body == (IntPtr)0); - } - } -} diff --git a/OpenSim/Region/Physics/OdePlugin/drawstuff.cs b/OpenSim/Region/Physics/OdePlugin/drawstuff.cs deleted file mode 100644 index 87ca446..0000000 --- a/OpenSim/Region/Physics/OdePlugin/drawstuff.cs +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright ODE - * Ode.NET - .NET bindings for ODE - * Jason Perkins (starkos@industriousone.com) - * Licensed under the New BSD - * Part of the OpenDynamicsEngine -Open Dynamics Engine -Copyright (c) 2001-2007, Russell L. Smith. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -Neither the names of ODE's copyright owner nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - */ - -using System; -using System.Runtime.InteropServices; -using Ode.NET; - -namespace Drawstuff.NET -{ -#if dDOUBLE - using dReal = System.Double; -#else - using dReal = System.Single; -#endif - - public static class ds - { - public const int VERSION = 2; - - public enum Texture - { - None, - Wood - } - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void CallbackFunction(int arg); - - [StructLayout(LayoutKind.Sequential)] - public struct Functions - { - public int version; - public CallbackFunction start; - public CallbackFunction step; - public CallbackFunction command; - public CallbackFunction stop; - public string path_to_textures; - } - - [DllImport("drawstuff", EntryPoint = "dsDrawBox")] - public static extern void DrawBox(ref d.Vector3 pos, ref d.Matrix3 R, ref d.Vector3 sides); - - [DllImport("drawstuff", EntryPoint = "dsDrawCapsule")] - public static extern void DrawCapsule(ref d.Vector3 pos, ref d.Matrix3 R, dReal length, dReal radius); - - [DllImport("drawstuff", EntryPoint = "dsDrawConvex")] - public static extern void DrawConvex(ref d.Vector3 pos, ref d.Matrix3 R, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons); - - [DllImport("drawstuff", EntryPoint = "dsSetColor")] - public static extern void SetColor(float red, float green, float blue); - - [DllImport("drawstuff", EntryPoint = "dsSetTexture")] - public static extern void SetTexture(Texture texture); - - [DllImport("drawstuff", EntryPoint = "dsSetViewpoint")] - public static extern void SetViewpoint(ref d.Vector3 xyz, ref d.Vector3 hpr); - - [DllImport("drawstuff", EntryPoint = "dsSimulationLoop")] - public static extern void SimulationLoop(int argc, string[] argv, int window_width, int window_height, ref Functions fn); - } -} diff --git a/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs deleted file mode 100644 index d07df02..0000000 --- a/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Reflection; -using System.Runtime.InteropServices; - -// Information about this assembly is defined by the following -// attributes. -// -// change them to the information which is associated with the assembly -// you compile. - -[assembly : AssemblyTitle("POSPlugin")] -[assembly : AssemblyDescription("")] -[assembly : AssemblyConfiguration("")] -[assembly : AssemblyCompany("http://opensimulator.org")] -[assembly : AssemblyProduct("POSPlugin")] -[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] -[assembly : AssemblyTrademark("")] -[assembly : AssemblyCulture("")] - -// This sets the default COM visibility of types in the assembly to invisible. -// If you need to expose a type to COM, use [ComVisible(true)] on that type. - -[assembly : ComVisible(false)] - -// The assembly version has following format : -// -// Major.Minor.Build.Revision -// -// You can specify all values by your own or you can build default build and revision -// numbers with the '*' character (the default): - -[assembly : AssemblyVersion("0.7.5.*")] diff --git a/OpenSim/Region/Physics/POSPlugin/POSCharacter.cs b/OpenSim/Region/Physics/POSPlugin/POSCharacter.cs deleted file mode 100644 index ae534ea..0000000 --- a/OpenSim/Region/Physics/POSPlugin/POSCharacter.cs +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.POSPlugin -{ - public class POSCharacter : PhysicsActor - { - private Vector3 _position; - public Vector3 _velocity; - public Vector3 _target_velocity = Vector3.Zero; - public Vector3 _size = Vector3.Zero; - private Vector3 _acceleration; - private Vector3 m_rotationalVelocity = Vector3.Zero; - private bool flying; - private bool isColliding; - - public POSCharacter() - { - } - - public override int PhysicsActorType - { - get { return (int) ActorTypes.Agent; } - set { return; } - } - - public override Vector3 RotationalVelocity - { - get { return m_rotationalVelocity; } - set { m_rotationalVelocity = value; } - } - - public override bool SetAlwaysRun - { - get { return false; } - set { return; } - } - - public override uint LocalID - { - set { return; } - } - - public override bool Grabbed - { - set { return; } - } - - public override bool Selected - { - set { return; } - } - - public override float Buoyancy - { - get { return 0f; } - set { return; } - } - - public override bool FloatOnWater - { - set { return; } - } - - public override bool IsPhysical - { - get { return false; } - set { return; } - } - - public override bool ThrottleUpdates - { - get { return false; } - set { return; } - } - - public override bool Flying - { - get { return flying; } - set { flying = value; } - } - - public override bool IsColliding - { - get { return isColliding; } - set { isColliding = value; } - } - - public override bool CollidingGround - { - get { return false; } - set { return; } - } - - public override bool CollidingObj - { - get { return false; } - set { return; } - } - - public override bool Stopped - { - get { return false; } - } - - public override Vector3 Position - { - get { return _position; } - set { _position = value; } - } - - public override Vector3 Size - { - get { return _size; } - set - { - _size = value; - _size.Z = _size.Z / 2.0f; - } - } - - public override float Mass - { - get { return 0f; } - } - - public override Vector3 Force - { - get { return Vector3.Zero; } - set { return; } - } - - public override int VehicleType - { - get { return 0; } - set { return; } - } - - public override void VehicleFloatParam(int param, float value) - { - - } - - public override void VehicleVectorParam(int param, Vector3 value) - { - - } - - public override void VehicleRotationParam(int param, Quaternion rotation) - { - - } - - public override void VehicleFlags(int param, bool remove) { } - - public override void SetVolumeDetect(int param) - { - - } - - public override Vector3 CenterOfMass - { - get { return Vector3.Zero; } - } - - public override Vector3 GeometricCenter - { - get { return Vector3.Zero; } - } - - public override PrimitiveBaseShape Shape - { - set { return; } - } - - public override Vector3 Velocity - { - get { return _velocity; } - set { _target_velocity = value; } - } - - public override Vector3 Torque - { - get { return Vector3.Zero; } - set { return; } - } - - public override float CollisionScore - { - get { return 0f; } - set { } - } - - public override Quaternion Orientation - { - get { return Quaternion.Identity; } - set { } - } - - public override Vector3 Acceleration - { - get { return _acceleration; } - set { _acceleration = value; } - } - - public override bool Kinematic - { - get { return true; } - set { } - } - - public override void link(PhysicsActor obj) - { - } - - public override void delink() - { - } - - public override void LockAngularMotion(Vector3 axis) - { - } - - public override void AddForce(Vector3 force, bool pushforce) - { - } - - public override void AddAngularForce(Vector3 force, bool pushforce) - { - } - - public override void SetMomentum(Vector3 momentum) - { - } - - public override void CrossingFailure() - { - } - - public override Vector3 PIDTarget - { - set { return; } - } - - public override bool PIDActive - { - set { return; } - } - - public override float PIDTau - { - set { return; } - } - - public override float PIDHoverHeight - { - set { return; } - } - - public override bool PIDHoverActive - { - set { return; } - } - - public override PIDHoverType PIDHoverType - { - set { return; } - } - - public override float PIDHoverTau - { - set { return; } - } - - public override Quaternion APIDTarget - { - set { return; } - } - - public override bool APIDActive - { - set { return; } - } - - public override float APIDStrength - { - set { return; } - } - - public override float APIDDamping - { - set { return; } - } - - - public override void SubscribeEvents(int ms) - { - } - - public override void UnSubscribeEvents() - { - } - - public override bool SubscribedEvents() - { - return false; - } - } -} diff --git a/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs b/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs deleted file mode 100644 index e6b42e6..0000000 --- a/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.POSPlugin -{ - /// - /// for now will be a very POS physics engine - /// - public class POSPlugin : IPhysicsPlugin - { - public POSPlugin() - { - } - - public bool Init() - { - return true; - } - - public PhysicsScene GetScene(string sceneIdentifier) - { - return new POSScene(sceneIdentifier); - } - - public string GetName() - { - return ("POS"); - } - - public void Dispose() - { - } - } -} diff --git a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs b/OpenSim/Region/Physics/POSPlugin/POSPrim.cs deleted file mode 100644 index e4fd7eb..0000000 --- a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.POSPlugin -{ - public class POSPrim : PhysicsActor - { - private Vector3 _position; - private Vector3 _velocity; - private Vector3 _acceleration; - private Vector3 _size; - private Vector3 m_rotationalVelocity = Vector3.Zero; - private Quaternion _orientation; - private bool iscolliding; - - public POSPrim() - { - } - - public override int PhysicsActorType - { - get { return (int) ActorTypes.Prim; } - set { return; } - } - - public override Vector3 RotationalVelocity - { - get { return m_rotationalVelocity; } - set { m_rotationalVelocity = value; } - } - - public override bool IsPhysical - { - get { return false; } - set { return; } - } - - public override bool ThrottleUpdates - { - get { return false; } - set { return; } - } - - public override bool IsColliding - { - get { return iscolliding; } - set { iscolliding = value; } - } - - public override bool CollidingGround - { - get { return false; } - set { return; } - } - - public override bool CollidingObj - { - get { return false; } - set { return; } - } - - public override bool Stopped - { - get { return false; } - } - - public override Vector3 Position - { - get { return _position; } - set { _position = value; } - } - - public override Vector3 Size - { - get { return _size; } - set { _size = value; } - } - - public override float Mass - { - get { return 0f; } - } - - public override Vector3 Force - { - get { return Vector3.Zero; } - set { return; } - } - - public override int VehicleType - { - get { return 0; } - set { return; } - } - - public override void VehicleFloatParam(int param, float value) - { - - } - - public override void VehicleVectorParam(int param, Vector3 value) - { - - } - - public override void VehicleRotationParam(int param, Quaternion rotation) - { - - } - - public override void VehicleFlags(int param, bool remove) { } - - public override void SetVolumeDetect(int param) - { - - } - - public override Vector3 CenterOfMass - { - get { return Vector3.Zero; } - } - - public override Vector3 GeometricCenter - { - get { return Vector3.Zero; } - } - - public override PrimitiveBaseShape Shape - { - set { return; } - } - - public override float Buoyancy - { - get { return 0f; } - set { return; } - } - - public override bool FloatOnWater - { - set { return; } - } - - public override Vector3 Velocity - { - get { return _velocity; } - set { _velocity = value; } - } - - public override float CollisionScore - { - get { return 0f; } - set { } - } - - public override Quaternion Orientation - { - get { return _orientation; } - set { _orientation = value; } - } - - public override Vector3 Acceleration - { - get { return _acceleration; } - set { _acceleration = value; } - } - - public override bool Kinematic - { - get { return true; } - set { } - } - - public override void AddForce(Vector3 force, bool pushforce) - { - } - - public override void AddAngularForce(Vector3 force, bool pushforce) - { - } - - public override Vector3 Torque - { - get { return Vector3.Zero; } - set { return; } - } - - public override void SetMomentum(Vector3 momentum) - { - } - - public override bool Flying - { - get { return false; } - set { } - } - - public override bool SetAlwaysRun - { - get { return false; } - set { return; } - } - - public override uint LocalID - { - set { return; } - } - - public override bool Grabbed - { - set { return; } - } - - public override void link(PhysicsActor obj) - { - } - - public override void delink() - { - } - - public override void LockAngularMotion(Vector3 axis) - { - } - - public override bool Selected - { - set { return; } - } - - public override void CrossingFailure() - { - } - - public override Vector3 PIDTarget - { - set { return; } - } - - public override bool PIDActive - { - set { return; } - } - - public override float PIDTau - { - set { return; } - } - - public override float PIDHoverHeight - { - set { return; } - } - - public override bool PIDHoverActive - { - set { return; } - } - - public override PIDHoverType PIDHoverType - { - set { return; } - } - - public override float PIDHoverTau - { - set { return; } - } - - public override Quaternion APIDTarget - { - set { return; } - } - - public override bool APIDActive - { - set { return; } - } - - public override float APIDStrength - { - set { return; } - } - - public override float APIDDamping - { - set { return; } - } - - - public override void SubscribeEvents(int ms) - { - } - - public override void UnSubscribeEvents() - { - } - - public override bool SubscribedEvents() - { - return false; - } - } -} diff --git a/OpenSim/Region/Physics/POSPlugin/POSScene.cs b/OpenSim/Region/Physics/POSPlugin/POSScene.cs deleted file mode 100644 index 2f24a50..0000000 --- a/OpenSim/Region/Physics/POSPlugin/POSScene.cs +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.POSPlugin -{ - public class POSScene : PhysicsScene - { - private List _characters = new List(); - private List _prims = new List(); - private float[] _heightMap; - private const float gravity = -9.8f; - - //protected internal string sceneIdentifier; - - public POSScene(String _sceneIdentifier) - { - //sceneIdentifier = _sceneIdentifier; - } - - public override void Initialise(IMesher meshmerizer, IConfigSource config) - { - } - - public override void Dispose() - { - } - - public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) - { - POSCharacter act = new POSCharacter(); - act.Position = position; - act.Flying = isFlying; - _characters.Add(act); - return act; - } - - public override void RemovePrim(PhysicsActor prim) - { - POSPrim p = (POSPrim) prim; - if (_prims.Contains(p)) - { - _prims.Remove(p); - } - } - - public override void RemoveAvatar(PhysicsActor character) - { - POSCharacter act = (POSCharacter) character; - if (_characters.Contains(act)) - { - _characters.Remove(act); - } - } - -/* - public override PhysicsActor AddPrim(Vector3 position, Vector3 size, Quaternion rotation) - { - return null; - } -*/ - - public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, - Vector3 size, Quaternion rotation, bool isPhysical, uint localid) - { - POSPrim prim = new POSPrim(); - prim.Position = position; - prim.Orientation = rotation; - prim.Size = size; - _prims.Add(prim); - return prim; - } - - private bool isColliding(POSCharacter c, POSPrim p) - { - Vector3 rotatedPos = new Vector3(c.Position.X - p.Position.X, c.Position.Y - p.Position.Y, - c.Position.Z - p.Position.Z) * Quaternion.Inverse(p.Orientation); - Vector3 avatarSize = new Vector3(c.Size.X, c.Size.Y, c.Size.Z) * Quaternion.Inverse(p.Orientation); - - return (Math.Abs(rotatedPos.X) < (p.Size.X*0.5 + Math.Abs(avatarSize.X)) && - Math.Abs(rotatedPos.Y) < (p.Size.Y*0.5 + Math.Abs(avatarSize.Y)) && - Math.Abs(rotatedPos.Z) < (p.Size.Z*0.5 + Math.Abs(avatarSize.Z))); - } - - private bool isCollidingWithPrim(POSCharacter c) - { - foreach (POSPrim p in _prims) - { - if (isColliding(c, p)) - { - return true; - } - } - - return false; - } - - public override void AddPhysicsActorTaint(PhysicsActor prim) - { - } - - public override float Simulate(float timeStep) - { - float fps = 0; - for (int i = 0; i < _characters.Count; ++i) - { - fps++; - POSCharacter character = _characters[i]; - - float oldposX = character.Position.X; - float oldposY = character.Position.Y; - float oldposZ = character.Position.Z; - - if (!character.Flying) - { - character._target_velocity.Z += gravity * timeStep; - } - - Vector3 characterPosition = character.Position; - - characterPosition.X += character._target_velocity.X * timeStep; - characterPosition.Y += character._target_velocity.Y * timeStep; - - characterPosition.X = Util.Clamp(character.Position.X, 0.01f, Constants.RegionSize - 0.01f); - characterPosition.Y = Util.Clamp(character.Position.Y, 0.01f, Constants.RegionSize - 0.01f); - - bool forcedZ = false; - - float terrainheight = _heightMap[(int)character.Position.Y * Constants.RegionSize + (int)character.Position.X]; - if (character.Position.Z + (character._target_velocity.Z * timeStep) < terrainheight + 2) - { - characterPosition.Z = terrainheight + character.Size.Z; - forcedZ = true; - } - else - { - characterPosition.Z += character._target_velocity.Z*timeStep; - } - - /// this is it -- the magic you've all been waiting for! Ladies and gentlemen -- - /// Completely Bogus Collision Detection!!! - /// better known as the CBCD algorithm - - if (isCollidingWithPrim(character)) - { - characterPosition.Z = oldposZ; // first try Z axis - if (isCollidingWithPrim(character)) - { - characterPosition.Z = oldposZ + character.Size.Z / 4.4f; // try harder - if (isCollidingWithPrim(character)) - { - characterPosition.Z = oldposZ + character.Size.Z / 2.2f; // try very hard - if (isCollidingWithPrim(character)) - { - characterPosition.X = oldposX; - characterPosition.Y = oldposY; - characterPosition.Z = oldposZ; - - characterPosition.X += character._target_velocity.X * timeStep; - if (isCollidingWithPrim(character)) - { - characterPosition.X = oldposX; - } - - characterPosition.Y += character._target_velocity.Y * timeStep; - if (isCollidingWithPrim(character)) - { - characterPosition.Y = oldposY; - } - } - else - { - forcedZ = true; - } - } - else - { - forcedZ = true; - } - } - else - { - forcedZ = true; - } - } - - characterPosition.X = Util.Clamp(character.Position.X, 0.01f, Constants.RegionSize - 0.01f); - characterPosition.Y = Util.Clamp(character.Position.Y, 0.01f, Constants.RegionSize - 0.01f); - - character.Position = characterPosition; - - character._velocity.X = (character.Position.X - oldposX)/timeStep; - character._velocity.Y = (character.Position.Y - oldposY)/timeStep; - - if (forcedZ) - { - character._velocity.Z = 0; - character._target_velocity.Z = 0; - ((PhysicsActor)character).IsColliding = true; - character.RequestPhysicsterseUpdate(); - } - else - { - ((PhysicsActor)character).IsColliding = false; - character._velocity.Z = (character.Position.Z - oldposZ)/timeStep; - } - } - return fps; - } - - public override void GetResults() - { - } - - public override bool IsThreaded - { - // for now we won't be multithreaded - get { return (false); } - } - - public override void SetTerrain(float[] heightMap) - { - _heightMap = heightMap; - } - - public override void DeleteTerrain() - { - } - - public override void SetWaterLevel(float baseheight) - { - } - - public override Dictionary GetTopColliders() - { - Dictionary returncolliders = new Dictionary(); - return returncolliders; - } - } -} diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/AssemblyInfo.cs new file mode 100644 index 0000000..1765ae0 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BasicPhysics/AssemblyInfo.cs @@ -0,0 +1,62 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Reflection; +using System.Runtime.InteropServices; +using Mono.Addins; + +// Information about this assembly is defined by the following +// attributes. +// +// change them to the information which is associated with the assembly +// you compile. + +[assembly : AssemblyTitle("BasicPhysicsModule")] +[assembly : AssemblyDescription("")] +[assembly : AssemblyConfiguration("")] +[assembly : AssemblyCompany("http://opensimulator.org")] +[assembly : AssemblyProduct("BasicPhysicsModule")] +[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] +[assembly : AssemblyTrademark("")] +[assembly : AssemblyCulture("")] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. + +[assembly : ComVisible(false)] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all values by your own or you can build default build and revision +// numbers with the '*' character (the default): + +[assembly : AssemblyVersion("0.8.2.*")] + +[assembly: Addin("OpenSim.Region.PhysicsModule.BasicPhysics", OpenSim.VersionInfo.VersionNumber)] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs new file mode 100644 index 0000000..e7b30ba --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs @@ -0,0 +1,303 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +namespace OpenSim.Region.PhysicsModule.BasicPhysics +{ + public class BasicActor : PhysicsActor + { + public BasicActor(Vector3 size) + { + Size = size; + } + + public override int PhysicsActorType + { + get { return (int) ActorTypes.Agent; } + set { return; } + } + + public override Vector3 RotationalVelocity { get; set; } + + public override bool SetAlwaysRun + { + get { return false; } + set { return; } + } + + public override uint LocalID + { + set { return; } + } + + public override bool Grabbed + { + set { return; } + } + + public override bool Selected + { + set { return; } + } + + public override float Buoyancy + { + get { return 0f; } + set { return; } + } + + public override bool FloatOnWater + { + set { return; } + } + + public override bool IsPhysical + { + get { return false; } + set { return; } + } + + public override bool ThrottleUpdates + { + get { return false; } + set { return; } + } + + public override bool Flying { get; set; } + + public override bool IsColliding { get; set; } + + public override bool CollidingGround + { + get { return false; } + set { return; } + } + + public override bool CollidingObj + { + get { return false; } + set { return; } + } + + public override bool Stopped + { + get { return false; } + } + + public override Vector3 Position { get; set; } + + public override Vector3 Size { get; set; } + + public override PrimitiveBaseShape Shape + { + set { return; } + } + + public override float Mass + { + get { return 0f; } + } + + public override Vector3 Force + { + get { return Vector3.Zero; } + set { return; } + } + + public override int VehicleType + { + get { return 0; } + set { return; } + } + + public override void VehicleFloatParam(int param, float value) + { + + } + + public override void VehicleVectorParam(int param, Vector3 value) + { + + } + + public override void VehicleRotationParam(int param, Quaternion rotation) + { + + } + + public override void VehicleFlags(int param, bool remove) + { + + } + + public override void SetVolumeDetect(int param) + { + + } + + public override Vector3 CenterOfMass + { + get { return Vector3.Zero; } + } + + public override Vector3 GeometricCenter + { + get { return Vector3.Zero; } + } + + public override Vector3 Velocity { get; set; } + + public override Vector3 Torque + { + get { return Vector3.Zero; } + set { return; } + } + + public override float CollisionScore + { + get { return 0f; } + set { } + } + + public override Quaternion Orientation + { + get { return Quaternion.Identity; } + set { } + } + + public override Vector3 Acceleration { get; set; } + + public override bool Kinematic + { + get { return true; } + set { } + } + + public override void link(PhysicsActor obj) + { + } + + public override void delink() + { + } + + public override void LockAngularMotion(Vector3 axis) + { + } + + public override void AddForce(Vector3 force, bool pushforce) + { + } + + public override void AddAngularForce(Vector3 force, bool pushforce) + { + } + + public override void SetMomentum(Vector3 momentum) + { + } + + public override void CrossingFailure() + { + } + + public override Vector3 PIDTarget + { + set { return; } + } + + public override bool PIDActive + { + get { return false; } + set { return; } + } + + public override float PIDTau + { + set { return; } + } + + public override float PIDHoverHeight + { + set { return; } + } + + public override bool PIDHoverActive + { + set { return; } + } + + public override PIDHoverType PIDHoverType + { + set { return; } + } + + public override float PIDHoverTau + { + set { return; } + } + + public override Quaternion APIDTarget + { + set { return; } + } + + public override bool APIDActive + { + set { return; } + } + + public override float APIDStrength + { + set { return; } + } + + public override float APIDDamping + { + set { return; } + } + + public override void SubscribeEvents(int ms) + { + } + + public override void UnSubscribeEvents() + { + } + + public override bool SubscribedEvents() + { + return false; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs new file mode 100644 index 0000000..5383f1b --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs @@ -0,0 +1,316 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +namespace OpenSim.Region.PhysicsModule.BasicPhysics +{ + public class BasicPhysicsPrim : PhysicsActor + { + private Vector3 _size; +// private PrimitiveBaseShape _shape; + + public BasicPhysicsPrim( + string name, uint localId, Vector3 position, Vector3 size, Quaternion orientation, PrimitiveBaseShape shape) + { + Name = name; + LocalID = localId; + Position = position; + Size = size; + Orientation = orientation; + Shape = shape; + } + + public override int PhysicsActorType + { + get { return (int) ActorTypes.Agent; } + set { return; } + } + + public override Vector3 RotationalVelocity { get; set; } + + public override bool SetAlwaysRun + { + get { return false; } + set { return; } + } + + public override uint LocalID + { + set { return; } + } + + public override bool Grabbed + { + set { return; } + } + + public override bool Selected + { + set { return; } + } + + public override float Buoyancy + { + get { return 0f; } + set { return; } + } + + public override bool FloatOnWater + { + set { return; } + } + + public override bool IsPhysical + { + get { return false; } + set { return; } + } + + public override bool ThrottleUpdates + { + get { return false; } + set { return; } + } + + public override bool Flying { get; set; } + + public override bool IsColliding { get; set; } + + public override bool CollidingGround + { + get { return false; } + set { return; } + } + + public override bool CollidingObj + { + get { return false; } + set { return; } + } + + public override bool Stopped + { + get { return false; } + } + + public override Vector3 Position { get; set; } + + public override Vector3 Size + { + get { return _size; } + set { + _size = value; + _size.Z = _size.Z / 2.0f; + } + } + + public override PrimitiveBaseShape Shape + { +// set { _shape = value; } + set {} + } + + public override float Mass + { + get { return 0f; } + } + + public override Vector3 Force + { + get { return Vector3.Zero; } + set { return; } + } + + public override int VehicleType + { + get { return 0; } + set { return; } + } + + public override void VehicleFloatParam(int param, float value) + { + + } + + public override void VehicleVectorParam(int param, Vector3 value) + { + + } + + public override void VehicleRotationParam(int param, Quaternion rotation) + { + + } + + public override void VehicleFlags(int param, bool remove) + { + + } + + public override void SetVolumeDetect(int param) + { + + } + + public override Vector3 CenterOfMass + { + get { return Vector3.Zero; } + } + + public override Vector3 GeometricCenter + { + get { return Vector3.Zero; } + } + + public override Vector3 Velocity { get; set; } + + public override Vector3 Torque + { + get { return Vector3.Zero; } + set { return; } + } + + public override float CollisionScore + { + get { return 0f; } + set { } + } + + public override Quaternion Orientation { get; set; } + + public override Vector3 Acceleration { get; set; } + + public override bool Kinematic + { + get { return true; } + set { } + } + + public override void link(PhysicsActor obj) + { + } + + public override void delink() + { + } + + public override void LockAngularMotion(Vector3 axis) + { + } + + public override void AddForce(Vector3 force, bool pushforce) + { + } + + public override void AddAngularForce(Vector3 force, bool pushforce) + { + } + + public override void SetMomentum(Vector3 momentum) + { + } + + public override void CrossingFailure() + { + } + + public override Vector3 PIDTarget + { + set { return; } + } + + public override bool PIDActive + { + get { return false; } + set { return; } + } + + public override float PIDTau + { + set { return; } + } + + public override float PIDHoverHeight + { + set { return; } + } + + public override bool PIDHoverActive + { + set { return; } + } + + public override PIDHoverType PIDHoverType + { + set { return; } + } + + public override float PIDHoverTau + { + set { return; } + } + + public override Quaternion APIDTarget + { + set { return; } + } + + public override bool APIDActive + { + set { return; } + } + + public override float APIDStrength + { + set { return; } + } + + public override float APIDDamping + { + set { return; } + } + + public override void SubscribeEvents(int ms) + { + } + + public override void UnSubscribeEvents() + { + } + + public override bool SubscribedEvents() + { + return false; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs new file mode 100644 index 0000000..20b337a --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs @@ -0,0 +1,256 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using Nini.Config; +using Mono.Addins; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.PhysicsModule.BasicPhysics +{ + /// + /// This is an incomplete extremely basic physics implementation + /// + /// + /// Not useful for anything at the moment apart from some regression testing in other components where some form + /// of physics plugin is needed. + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BasicPhysicsScene")] + public class BasicScene : PhysicsScene, INonSharedRegionModule + { + private List _actors = new List(); + private List _prims = new List(); + private float[] _heightMap; + private Vector3 m_regionExtent; + + private bool m_Enabled = false; + + //protected internal string sceneIdentifier; + #region INonSharedRegionModule + public string Name + { + get { return "basicphysics"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Initialise(IConfigSource source) + { + // TODO: Move this out of Startup + IConfig config = source.Configs["Startup"]; + if (config != null) + { + string physics = config.GetString("physics", string.Empty); + if (physics == Name) + m_Enabled = true; + } + + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + EngineType = Name; + PhysicsSceneName = EngineType + "/" + scene.RegionInfo.RegionName; + + scene.RegisterModuleInterface(this); + m_regionExtent = new Vector3(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, scene.RegionInfo.RegionSizeZ); + base.Initialise(scene.PhysicsRequestAsset, + (scene.Heightmap != null ? scene.Heightmap.GetFloatsSerialised() : new float[scene.RegionInfo.RegionSizeX * scene.RegionInfo.RegionSizeY]), + (float)scene.RegionInfo.RegionSettings.WaterHeight); + + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + } + #endregion + + public override void Dispose() {} + + public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, + Vector3 size, Quaternion rotation, bool isPhysical, uint localid) + { + BasicPhysicsPrim prim = new BasicPhysicsPrim(primName, localid, position, size, rotation, pbs); + prim.IsPhysical = isPhysical; + + _prims.Add(prim); + + return prim; + } + + public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) + { + BasicActor act = new BasicActor(size); + act.Position = position; + act.Velocity = velocity; + act.Flying = isFlying; + _actors.Add(act); + return act; + } + + public override void RemovePrim(PhysicsActor actor) + { + BasicPhysicsPrim prim = (BasicPhysicsPrim)actor; + if (_prims.Contains(prim)) + _prims.Remove(prim); + } + + public override void RemoveAvatar(PhysicsActor actor) + { + BasicActor act = (BasicActor)actor; + if (_actors.Contains(act)) + _actors.Remove(act); + } + + public override void AddPhysicsActorTaint(PhysicsActor prim) + { + } + + public override float Simulate(float timeStep) + { +// Console.WriteLine("Simulating"); + + float fps = 0; + for (int i = 0; i < _actors.Count; ++i) + { + BasicActor actor = _actors[i]; + Vector3 actorPosition = actor.Position; + Vector3 actorVelocity = actor.Velocity; + + //Console.WriteLine( + // "Processing actor {0}, starting pos {1}, starting vel {2}", i, actorPosition, actorVelocity); + + actorPosition.X += actor.Velocity.X * timeStep; + actorPosition.Y += actor.Velocity.Y * timeStep; + + if (actor.Position.Y < 0) + { + actorPosition.Y = 0.1F; + } + else if (actor.Position.Y >= m_regionExtent.Y) + { + actorPosition.Y = (m_regionExtent.Y - 0.1f); + } + + if (actor.Position.X < 0) + { + actorPosition.X = 0.1F; + } + else if (actor.Position.X >= m_regionExtent.X) + { + actorPosition.X = (m_regionExtent.X - 0.1f); + } + + float terrainHeight = 0; + if (_heightMap != null) + terrainHeight = _heightMap[(int)actor.Position.Y * (int)m_regionExtent.Y + (int)actor.Position.X]; + + float height = terrainHeight + actor.Size.Z; +// Console.WriteLine("height {0}, actorPosition {1}", height, actorPosition); + + if (actor.Flying) + { + if (actor.Position.Z + (actor.Velocity.Z * timeStep) < terrainHeight + 2) + { + actorPosition.Z = height; + actorVelocity.Z = 0; + actor.IsColliding = true; + } + else + { + actorPosition.Z += actor.Velocity.Z * timeStep; + actor.IsColliding = false; + } + } + else + { + actorPosition.Z = height; + actorVelocity.Z = 0; + actor.IsColliding = true; + } + + actor.Position = actorPosition; + actor.Velocity = actorVelocity; + } + + return fps; + } + + public override void GetResults() + { + } + + public override bool IsThreaded + { + get { return (false); // for now we won't be multithreaded + } + } + + public override void SetTerrain(float[] heightMap) + { + _heightMap = heightMap; + } + + public override void DeleteTerrain() + { + } + + public override void SetWaterLevel(float baseheight) + { + } + + public override Dictionary GetTopColliders() + { + Dictionary returncolliders = new Dictionary(); + return returncolliders; + } + + } +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs new file mode 100755 index 0000000..c4a923c --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs @@ -0,0 +1,2120 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; + +using OpenSim.Framework; + +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public sealed class BSAPIUnman : BSAPITemplate +{ + +private sealed class BulletWorldUnman : BulletWorld +{ + public IntPtr ptr; + public BulletWorldUnman(uint id, BSScene physScene, IntPtr xx) + : base(id, physScene) + { + ptr = xx; + } +} + +private sealed class BulletBodyUnman : BulletBody +{ + public IntPtr ptr; + public BulletBodyUnman(uint id, IntPtr xx) + : base(id) + { + ptr = xx; + } + public override bool HasPhysicalBody + { + get { return ptr != IntPtr.Zero; } + } + public override void Clear() + { + ptr = IntPtr.Zero; + } + public override string AddrString + { + get { return ptr.ToString("X"); } + } +} + +private sealed class BulletShapeUnman : BulletShape +{ + public IntPtr ptr; + public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) + : base() + { + ptr = xx; + shapeType = typ; + } + public override bool HasPhysicalShape + { + get { return ptr != IntPtr.Zero; } + } + public override void Clear() + { + ptr = IntPtr.Zero; + } + public override BulletShape Clone() + { + return new BulletShapeUnman(ptr, shapeType); + } + public override bool ReferenceSame(BulletShape other) + { + BulletShapeUnman otheru = other as BulletShapeUnman; + return (otheru != null) && (this.ptr == otheru.ptr); + + } + public override string AddrString + { + get { return ptr.ToString("X"); } + } +} +private sealed class BulletConstraintUnman : BulletConstraint +{ + public BulletConstraintUnman(IntPtr xx) : base() + { + ptr = xx; + } + public IntPtr ptr; + + public override void Clear() + { + ptr = IntPtr.Zero; + } + public override bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } } + + // Used for log messages for a unique display of the memory/object allocated to this instance + public override string AddrString + { + get { return ptr.ToString("X"); } + } +} + +// We pin the memory passed between the managed and unmanaged code. +GCHandle m_paramsHandle; +private GCHandle m_collisionArrayPinnedHandle; +private GCHandle m_updateArrayPinnedHandle; + +// Handle to the callback used by the unmanaged code to call into the managed code. +// Used for debug logging. +// Need to store the handle in a persistant variable so it won't be freed. +private BSAPICPP.DebugLogCallback m_DebugLogCallbackHandle; + +private BSScene PhysicsScene { get; set; } + +public override string BulletEngineName { get { return "BulletUnmanaged"; } } +public override string BulletEngineVersion { get; protected set; } + +public BSAPIUnman(string paramName, BSScene physScene) +{ + PhysicsScene = physScene; + + // Do something fancy with the paramName to get the right DLL implementation + // like "Bullet-2.80-OpenCL-Intel" loading the version for Intel based OpenCL implementation, etc. + if (Util.IsWindows()) + Util.LoadArchSpecificWindowsDll("BulletSim.dll"); + // If not Windows, loading is performed by the + // Mono loader as specified in + // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". +} + +// Initialization and simulation +public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, + int maxCollisions, ref CollisionDesc[] collisionArray, + int maxUpdates, ref EntityProperties[] updateArray + ) +{ + // Pin down the memory that will be used to pass object collisions and updates back from unmanaged code + m_paramsHandle = GCHandle.Alloc(parms, GCHandleType.Pinned); + m_collisionArrayPinnedHandle = GCHandle.Alloc(collisionArray, GCHandleType.Pinned); + m_updateArrayPinnedHandle = GCHandle.Alloc(updateArray, GCHandleType.Pinned); + + // If Debug logging level, enable logging from the unmanaged code + m_DebugLogCallbackHandle = null; + if (BSScene.m_log.IsDebugEnabled && PhysicsScene.PhysicsLogging.Enabled) + { + BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader); + if (PhysicsScene.PhysicsLogging.Enabled) + // The handle is saved in a variable to make sure it doesn't get freed after this call + m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLoggerPhysLog); + else + m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLogger); + } + + // Get the version of the DLL + // TODO: this doesn't work yet. Something wrong with marshaling the returned string. + // BulletEngineVersion = BulletSimAPI.GetVersion2(); + BulletEngineVersion = ""; + + // Call the unmanaged code with the buffers and other information + return new BulletWorldUnman(0, PhysicsScene, BSAPICPP.Initialize2(maxPosition, m_paramsHandle.AddrOfPinnedObject(), + maxCollisions, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), + maxUpdates, m_updateArrayPinnedHandle.AddrOfPinnedObject(), + m_DebugLogCallbackHandle)); + +} + +// Called directly from unmanaged code so don't do much +private void BulletLogger(string msg) +{ + BSScene.m_log.Debug("[BULLETS UNMANAGED]:" + msg); +} + +// Called directly from unmanaged code so don't do much +private void BulletLoggerPhysLog(string msg) +{ + PhysicsScene.DetailLog("[BULLETS UNMANAGED]:" + msg); +} + +public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, + out int updatedEntityCount, out int collidersCount) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount); +} + +public override void Shutdown(BulletWorld world) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.Shutdown2(worldu.ptr); + + if (m_paramsHandle.IsAllocated) + { + m_paramsHandle.Free(); + } + if (m_collisionArrayPinnedHandle.IsAllocated) + { + m_collisionArrayPinnedHandle.Free(); + } + if (m_updateArrayPinnedHandle.IsAllocated) + { + m_updateArrayPinnedHandle.Free(); + } +} + +public override bool PushUpdate(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.PushUpdate2(bodyu.ptr); +} + +public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + return BSAPICPP.UpdateParameter2(worldu.ptr, localID, parm, value); +} + +// ===================================================================================== +// Mesh, hull, shape and body creation helper routines +public override BulletShape CreateMeshShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.CreateMeshShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), + BSPhysicsShapeType.SHAPE_MESH); +} + +public override BulletShape CreateGImpactShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.CreateGImpactShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), + BSPhysicsShapeType.SHAPE_GIMPACT); +} + +public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), + BSPhysicsShapeType.SHAPE_HULL); +} + +public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman shapeu = meshShape as BulletShapeUnman; + return new BulletShapeUnman( + BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms), + BSPhysicsShapeType.SHAPE_HULL); +} + +public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman shapeu = meshShape as BulletShapeUnman; + return new BulletShapeUnman( + BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr), + BSPhysicsShapeType.SHAPE_CONVEXHULL); +} + +public override BulletShape CreateConvexHullShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), + BSPhysicsShapeType.SHAPE_CONVEXHULL); +} + +public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type); +} + +public override bool IsNativeShape(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + if (shapeu != null && shapeu.HasPhysicalShape) + return BSAPICPP.IsNativeShape2(shapeu.ptr); + return false; +} + +public override void SetShapeCollisionMargin(BulletShape shape, float margin) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + if (shapeu != null && shapeu.HasPhysicalShape) + BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin); +} + +public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale), + BSPhysicsShapeType.SHAPE_CAPSULE); +} + +public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree), + BSPhysicsShapeType.SHAPE_COMPOUND); + +} + +public override int GetNumberOfCompoundChildren(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + if (shapeu != null && shapeu.HasPhysicalShape) + return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr); + return 0; +} + +public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + BulletShapeUnman addShapeu = addShape as BulletShapeUnman; + BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot); +} + +public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); +} + +public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); +} + +public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman; + BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr); +} + +public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) +{ + BulletShapeUnman shapeu = pShape as BulletShapeUnman; + BSAPICPP.UpdateChildTransform2(shapeu.ptr, childIndex, pos, rot, shouldRecalculateLocalAabb); +} + +public override void RecalculateCompoundShapeLocalAabb(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr); +} + +public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; + return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType); +} + +public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr); +} + +public override CollisionObjectTypes GetBodyType(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr); +} + +public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); +} + +public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot)); +} + +public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); +} + +public override void DestroyObject(BulletWorld world, BulletBody obj) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr); +} + +// ===================================================================================== +// Terrain creation and helper routines +public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin) +{ + return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE); +} + +public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, + float scaleFactor, float collisionMargin) +{ + return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin), + BSPhysicsShapeType.SHAPE_TERRAIN); +} + +// ===================================================================================== +// Constraint creation and helper routines +public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, + frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); +} + +public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 joinPoint, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, + joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); +} + +public override BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, + Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintFixed2(worldu.ptr, bodyu1.ptr, + frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies)); +} + +public override BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.Create6DofSpringConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, + frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); +} + +public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 pivotinA, Vector3 pivotinB, + Vector3 axisInA, Vector3 axisInB, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, + pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); +} + +public override BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.CreateSliderConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, + frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); +} + +public override BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool disableCollisionsBetweenLinkedBodies) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.CreateConeTwistConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, + frame2loc, frame2rot, disableCollisionsBetweenLinkedBodies)); +} + +public override BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 axisInA, Vector3 axisInB, + float ratio, bool disableCollisionsBetweenLinkedBodies) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.CreateGearConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, axisInA, axisInB, + ratio, disableCollisionsBetweenLinkedBodies)); +} + +public override BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 pivotInA, Vector3 pivotInB, + bool disableCollisionsBetweenLinkedBodies) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.CreatePoint2PointConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, pivotInA, pivotInB, + disableCollisionsBetweenLinkedBodies)); +} + +public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse); +} + +public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations); +} + +public override bool SetFrames(BulletConstraint constrain, + Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot); +} + +public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi); +} + +public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi); +} + +public override bool UseFrameOffset(BulletConstraint constrain, float enable) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable); +} + +public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce); +} + +public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold); +} + +public override bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.HingeSetLimits2(constrainu.ptr, low, high, softness, bias, relaxation); +} + +public override bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.ConstraintSpringEnable2(constrainu.ptr, index, numericTrueFalse); +} + +public override bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.ConstraintSpringSetEquilibriumPoint2(constrainu.ptr, index, equilibriumPoint); +} + +public override bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.ConstraintSpringSetStiffness2(constrainu.ptr, index, stiffnesss); +} + +public override bool SpringSetDamping(BulletConstraint constrain, int index, float damping) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.ConstraintSpringSetDamping2(constrainu.ptr, index, damping); +} + +public override bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SliderSetLimits2(constrainu.ptr, lowerUpper, linAng, val); +} + +public override bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SliderSet2(constrainu.ptr, softRestDamp, dirLimOrtho, linAng, val); +} + +public override bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SliderMotorEnable2(constrainu.ptr, linAng, numericTrueFalse); +} + +public override bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SliderMotor2(constrainu.ptr, forceVel, linAng, val); +} + +public override bool CalculateTransforms(BulletConstraint constrain) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.CalculateTransforms2(constrainu.ptr); +} + +public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis); +} + +public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr); +} + +// ===================================================================================== +// btCollisionWorld entries +public override void UpdateSingleAabb(BulletWorld world, BulletBody obj) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr); +} + +public override void UpdateAabbs(BulletWorld world) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.UpdateAabbs2(worldu.ptr); +} + +public override bool GetForceUpdateAllAabbs(BulletWorld world) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr); +} + +public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force); +} + +// ===================================================================================== +// btDynamicsWorld entries +public override bool AddObjectToWorld(BulletWorld world, BulletBody obj) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = obj as BulletBodyUnman; + + // Bullet resets several variables when an object is added to the world. + // Gravity is reset to world default depending on the static/dynamic + // type. Of course, the collision flags in the broadphase proxy are initialized to default. + Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr); + + bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr); + + if (ret) + { + BSAPICPP.SetGravity2(bodyu.ptr, origGrav); + obj.ApplyCollisionMask(world.physicsScene); + } + return ret; +} + +public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr); +} + +public override bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.ClearCollisionProxyCache2(worldu.ptr, bodyu.ptr); +} + +public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects); +} + +public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr); +} +// ===================================================================================== +// btCollisionObject entries +public override Vector3 GetAnisotripicFriction(BulletConstraint constrain) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr); +} + +public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict); +} + +public override bool HasAnisotripicFriction(BulletConstraint constrain) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr); +} + +public override void SetContactProcessingThreshold(BulletBody obj, float val) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val); +} + +public override float GetContactProcessingThreshold(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr); +} + +public override bool IsStaticObject(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.IsStaticObject2(bodyu.ptr); +} + +public override bool IsKinematicObject(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.IsKinematicObject2(bodyu.ptr); +} + +public override bool IsStaticOrKinematicObject(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr); +} + +public override bool HasContactResponse(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.HasContactResponse2(bodyu.ptr); +} + +public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BulletShapeUnman shapeu = shape as BulletShapeUnman; + if (worldu != null && bodyu != null) + { + // Special case to allow the caller to zero out the reference to any physical shape + if (shapeu != null) + BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr); + else + BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero); + } +} + +public override BulletShape GetCollisionShape(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN); +} + +public override int GetActivationState(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetActivationState2(bodyu.ptr); +} + +public override void SetActivationState(BulletBody obj, int state) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetActivationState2(bodyu.ptr, state); +} + +public override void SetDeactivationTime(BulletBody obj, float dtime) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime); +} + +public override float GetDeactivationTime(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetDeactivationTime2(bodyu.ptr); +} + +public override void ForceActivationState(BulletBody obj, ActivationState state) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ForceActivationState2(bodyu.ptr, state); +} + +public override void Activate(BulletBody obj, bool forceActivation) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.Activate2(bodyu.ptr, forceActivation); +} + +public override bool IsActive(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.IsActive2(bodyu.ptr); +} + +public override void SetRestitution(BulletBody obj, float val) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetRestitution2(bodyu.ptr, val); +} + +public override float GetRestitution(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetRestitution2(bodyu.ptr); +} + +public override void SetFriction(BulletBody obj, float val) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetFriction2(bodyu.ptr, val); +} + +public override float GetFriction(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetFriction2(bodyu.ptr); +} + +public override Vector3 GetPosition(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetPosition2(bodyu.ptr); +} + +public override Quaternion GetOrientation(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetOrientation2(bodyu.ptr); +} + +public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation); +} + + /* +public override IntPtr GetBroadphaseHandle(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr); +} + +public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetUserPointer2(bodyu.ptr, handle); +} + */ + +public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel); +} + +public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel); +} + +public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel); +} + +public override float GetHitFraction(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetHitFraction2(bodyu.ptr); +} + +public override void SetHitFraction(BulletBody obj, float val) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetHitFraction2(bodyu.ptr, val); +} + +public override CollisionFlags GetCollisionFlags(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetCollisionFlags2(bodyu.ptr); +} + +public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags); +} + +public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags); +} + +public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags); +} + +public override float GetCcdMotionThreshold(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr); +} + + +public override void SetCcdMotionThreshold(BulletBody obj, float val) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val); +} + +public override float GetCcdSweptSphereRadius(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr); +} + +public override void SetCcdSweptSphereRadius(BulletBody obj, float val) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val); +} + +public override IntPtr GetUserPointer(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetUserPointer2(bodyu.ptr); +} + +public override void SetUserPointer(BulletBody obj, IntPtr val) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetUserPointer2(bodyu.ptr, val); +} + +// ===================================================================================== +// btRigidBody entries +public override void ApplyGravity(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyGravity2(bodyu.ptr); +} + +public override void SetGravity(BulletBody obj, Vector3 val) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetGravity2(bodyu.ptr, val); +} + +public override Vector3 GetGravity(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetGravity2(bodyu.ptr); +} + +public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping); +} + +public override void SetLinearDamping(BulletBody obj, float lin_damping) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping); +} + +public override void SetAngularDamping(BulletBody obj, float ang_damping) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping); +} + +public override float GetLinearDamping(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetLinearDamping2(bodyu.ptr); +} + +public override float GetAngularDamping(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetAngularDamping2(bodyu.ptr); +} + +public override float GetLinearSleepingThreshold(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr); +} + +public override void ApplyDamping(BulletBody obj, float timeStep) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep); +} + +public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia); +} + +public override Vector3 GetLinearFactor(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetLinearFactor2(bodyu.ptr); +} + +public override void SetLinearFactor(BulletBody obj, Vector3 factor) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetLinearFactor2(bodyu.ptr, factor); +} + +public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot); +} + +// Add a force to the object as if its mass is one. +// Deep down in Bullet: m_totalForce += force*m_linearFactor; +public override void ApplyCentralForce(BulletBody obj, Vector3 force) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyCentralForce2(bodyu.ptr, force); +} + +// Set the force being applied to the object as if its mass is one. +public override void SetObjectForce(BulletBody obj, Vector3 force) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetObjectForce2(bodyu.ptr, force); +} + +public override Vector3 GetTotalForce(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetTotalForce2(bodyu.ptr); +} + +public override Vector3 GetTotalTorque(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetTotalTorque2(bodyu.ptr); +} + +public override Vector3 GetInvInertiaDiagLocal(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr); +} + +public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert); +} + +public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold); +} + +// Deep down in Bullet: m_totalTorque += torque*m_angularFactor; +public override void ApplyTorque(BulletBody obj, Vector3 torque) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyTorque2(bodyu.ptr, torque); +} + +// Apply force at the given point. Will add torque to the object. +// Deep down in Bullet: applyCentralForce(force); +// applyTorque(rel_pos.cross(force*m_linearFactor)); +public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyForce2(bodyu.ptr, force, pos); +} + +// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. +// Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass; +public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp); +} + +// Apply impulse to the object's torque. Force is scaled by object's mass. +// Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor; +public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp); +} + +// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. +// Deep down in Bullet: applyCentralImpulse(impulse); +// applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor)); +public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos); +} + +public override void ClearForces(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ClearForces2(bodyu.ptr); +} + +public override void ClearAllForces(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ClearAllForces2(bodyu.ptr); +} + +public override void UpdateInertiaTensor(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.UpdateInertiaTensor2(bodyu.ptr); +} + +public override Vector3 GetLinearVelocity(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetLinearVelocity2(bodyu.ptr); +} + +public override Vector3 GetAngularVelocity(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetAngularVelocity2(bodyu.ptr); +} + +public override void SetLinearVelocity(BulletBody obj, Vector3 vel) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel); +} + +public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity); +} + +public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos); +} + +public override void Translate(BulletBody obj, Vector3 trans) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.Translate2(bodyu.ptr, trans); +} + +public override void UpdateDeactivation(BulletBody obj, float timeStep) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep); +} + +public override bool WantsSleeping(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.WantsSleeping2(bodyu.ptr); +} + +public override void SetAngularFactor(BulletBody obj, float factor) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetAngularFactor2(bodyu.ptr, factor); +} + +public override void SetAngularFactorV(BulletBody obj, Vector3 factor) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor); +} + +public override Vector3 GetAngularFactor(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetAngularFactor2(bodyu.ptr); +} + +public override bool IsInWorld(BulletWorld world, BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.IsInWorld2(bodyu.ptr); +} + +public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr); +} + +public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr); +} + +public override BulletConstraint GetConstraintRef(BulletBody obj, int index) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index)); +} + +public override int GetNumConstraintRefs(BulletBody obj) +{ + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr); +} + +public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask) +{ + BulletBodyUnman bodyu = body as BulletBodyUnman; + return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask); +} + +// ===================================================================================== +// btCollisionShape entries + +public override float GetAngularMotionDisc(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr); +} + +public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor); +} + +public override bool IsPolyhedral(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsPolyhedral2(shapeu.ptr); +} + +public override bool IsConvex2d(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsConvex2d2(shapeu.ptr); +} + +public override bool IsConvex(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsConvex2(shapeu.ptr); +} + +public override bool IsNonMoving(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsNonMoving2(shapeu.ptr); +} + +public override bool IsConcave(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsConcave2(shapeu.ptr); +} + +public override bool IsCompound(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsCompound2(shapeu.ptr); +} + +public override bool IsSoftBody(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsSoftBody2(shapeu.ptr); +} + +public override bool IsInfinite(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsInfinite2(shapeu.ptr); +} + +public override void SetLocalScaling(BulletShape shape, Vector3 scale) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + BSAPICPP.SetLocalScaling2(shapeu.ptr, scale); +} + +public override Vector3 GetLocalScaling(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.GetLocalScaling2(shapeu.ptr); +} + +public override Vector3 CalculateLocalInertia(BulletShape shape, float mass) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass); +} + +public override int GetShapeType(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.GetShapeType2(shapeu.ptr); +} + +public override void SetMargin(BulletShape shape, float val) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + BSAPICPP.SetMargin2(shapeu.ptr, val); +} + +public override float GetMargin(BulletShape shape) +{ + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.GetMargin2(shapeu.ptr); +} + +// ===================================================================================== +// Debugging +public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = collisionObject as BulletBodyUnman; + BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr); +} + +public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman shapeu = collisionShape as BulletShapeUnman; + BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr); +} + +public override void DumpConstraint(BulletWorld world, BulletConstraint constrain) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr); +} + +public override void DumpActivationInfo(BulletWorld world) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.DumpActivationInfo2(worldu.ptr); +} + +public override void DumpAllInfo(BulletWorld world) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.DumpAllInfo2(worldu.ptr); +} + +public override void DumpPhysicsStatistics(BulletWorld world) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.DumpPhysicsStatistics2(worldu.ptr); +} +public override void ResetBroadphasePool(BulletWorld world) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.ResetBroadphasePool(worldu.ptr); +} +public override void ResetConstraintSolver(BulletWorld world) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.ResetConstraintSolver(worldu.ptr); +} + +// ===================================================================================== +// ===================================================================================== +// ===================================================================================== +// ===================================================================================== +// ===================================================================================== +// The actual interface to the unmanaged code +static class BSAPICPP +{ +// =============================================================================== +// Link back to the managed code for outputting log messages +[UnmanagedFunctionPointer(CallingConvention.Cdecl)] +public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); + +// =============================================================================== +// Initialization and simulation +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, + int maxCollisions, IntPtr collisionArray, + int maxUpdates, IntPtr updateArray, + DebugLogCallback logRoutine); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, + out int updatedEntityCount, out int collidersCount); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void Shutdown2(IntPtr sim); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool PushUpdate2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); + +// ===================================================================================== +// Mesh, hull, shape and body creation helper routines +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateMeshShape2(IntPtr world, + int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, + int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateGImpactShape2(IntPtr world, + int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, + int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateHullShape2(IntPtr world, + int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateConvexHullShape2(IntPtr world, + int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, + int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsNativeShape2(IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetShapeCollisionMargin(IntPtr shape, float margin); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern int GetNumberOfCompoundChildren2(IntPtr cShape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern int GetBodyType2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void DestroyObject2(IntPtr sim, IntPtr obj); + +// ===================================================================================== +// Terrain creation and helper routines +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, + [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, + float scaleFactor, float collisionMargin); + +// ===================================================================================== +// Constraint creation and helper routines +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 joinPoint, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr Create6DofConstraintFixed2(IntPtr world, IntPtr obj1, + Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr Create6DofSpringConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 pivotinA, Vector3 pivotinB, + Vector3 axisInA, Vector3 axisInB, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateSliderConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateConeTwistConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool disableCollisionsBetweenLinkedBodies); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateGearConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 axisInA, Vector3 axisInB, + float ratio, bool disableCollisionsBetweenLinkedBodies); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreatePoint2PointConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 pivotInA, Vector3 pivotInB, + bool disableCollisionsBetweenLinkedBodies); + + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetFrames2(IntPtr constrain, + Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool UseFrameOffset2(IntPtr constrain, float enable); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool HingeSetLimits2(IntPtr constrain, float low, float high, float softness, float bias, float relaxation); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool ConstraintSpringEnable2(IntPtr constrain, int index, float numericTrueFalse); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool ConstraintSpringSetEquilibriumPoint2(IntPtr constrain, int index, float equilibriumPoint); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool ConstraintSpringSetStiffness2(IntPtr constrain, int index, float stiffness); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool ConstraintSpringSetDamping2(IntPtr constrain, int index, float damping); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SliderSetLimits2(IntPtr constrain, int lowerUpper, int linAng, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SliderSet2(IntPtr constrain, int softRestDamp, int dirLimOrtho, int linAng, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SliderMotorEnable2(IntPtr constrain, int linAng, float numericTrueFalse); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SliderMotor2(IntPtr constrain, int forceVel, int linAng, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool CalculateTransforms2(IntPtr constrain); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); + +// ===================================================================================== +// btCollisionWorld entries +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void UpdateAabbs2(IntPtr world); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool GetForceUpdateAllAabbs2(IntPtr world); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force); + +// ===================================================================================== +// btDynamicsWorld entries +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool ClearCollisionProxyCache2(IntPtr world, IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain); +// ===================================================================================== +// btCollisionObject entries +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool HasAnisotripicFriction2(IntPtr constrain); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetContactProcessingThreshold2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetContactProcessingThreshold2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsStaticObject2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsKinematicObject2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsStaticOrKinematicObject2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool HasContactResponse2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr GetCollisionShape2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern int GetActivationState2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetActivationState2(IntPtr obj, int state); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetDeactivationTime2(IntPtr obj, float dtime); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetDeactivationTime2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void ForceActivationState2(IntPtr obj, ActivationState state); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void Activate2(IntPtr obj, bool forceActivation); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsActive2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetRestitution2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetRestitution2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetFriction2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetFriction2(IntPtr obj); + + /* Haven't defined the type 'Transform' +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Transform GetWorldTransform2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void setWorldTransform2(IntPtr obj, Transform trans); + */ + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetPosition2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Quaternion GetOrientation2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr GetBroadphaseHandle2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle); + + /* +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Transform GetInterpolationWorldTransform2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans); + */ + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetHitFraction2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetHitFraction2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetCcdMotionThreshold2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetCcdSweptSphereRadius2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr GetUserPointer2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetUserPointer2(IntPtr obj, IntPtr val); + +// ===================================================================================== +// btRigidBody entries +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void ApplyGravity2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetGravity2(IntPtr obj, Vector3 val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetGravity2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetLinearDamping2(IntPtr obj, float lin_damping); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetAngularDamping2(IntPtr obj, float ang_damping); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetLinearDamping2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetAngularDamping2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetLinearSleepingThreshold2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetAngularSleepingThreshold2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void ApplyDamping2(IntPtr obj, float timeStep); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetLinearFactor2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor); + + /* +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans); + */ + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot); + +// Add a force to the object as if its mass is one. +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force); + +// Set the force being applied to the object as if its mass is one. +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetObjectForce2(IntPtr obj, Vector3 force); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetTotalForce2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetTotalTorque2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void ApplyTorque2(IntPtr obj, Vector3 torque); + +// Apply force at the given point. Will add torque to the object. +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos); + +// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp); + +// Apply impulse to the object's torque. Force is scaled by object's mass. +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp); + +// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void ClearForces2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void ClearAllForces2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void UpdateInertiaTensor2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj); + + /* +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Transform GetCenterOfMassTransform2(IntPtr obj); + */ + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetLinearVelocity2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetAngularVelocity2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void Translate2(IntPtr obj, Vector3 trans); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void UpdateDeactivation2(IntPtr obj, float timeStep); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool WantsSleeping2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetAngularFactor2(IntPtr obj, float factor); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetAngularFactor2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsInWorld2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern int GetNumConstraintRefs2(IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask); + +// ===================================================================================== +// btCollisionShape entries + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetAngularMotionDisc2(IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsPolyhedral2(IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsConvex2d2(IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsConvex2(IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsNonMoving2(IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsConcave2(IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsCompound2(IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsSoftBody2(IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool IsInfinite2(IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 GetLocalScaling2(IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern int GetShapeType2(IntPtr shape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetMargin2(IntPtr shape, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern float GetMargin2(IntPtr shape); + +// ===================================================================================== +// Debugging +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void DumpActivationInfo2(IntPtr sim); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void DumpAllInfo2(IntPtr sim); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void DumpPhysicsStatistics2(IntPtr sim); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void ResetBroadphasePool(IntPtr sim); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void ResetConstraintSolver(IntPtr sim); + +} + +} + +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs new file mode 100755 index 0000000..887311d --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs @@ -0,0 +1,2589 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +using OpenSim.Framework; + +using OpenMetaverse; + +using BulletXNA; +using BulletXNA.LinearMath; +using BulletXNA.BulletCollision; +using BulletXNA.BulletDynamics; +using BulletXNA.BulletCollision.CollisionDispatch; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public sealed class BSAPIXNA : BSAPITemplate +{ +private sealed class BulletWorldXNA : BulletWorld +{ + public DiscreteDynamicsWorld world; + public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx) + : base(id, physScene) + { + world = xx; + } +} + +private sealed class BulletBodyXNA : BulletBody +{ + public CollisionObject body; + public RigidBody rigidBody { get { return RigidBody.Upcast(body); } } + + public BulletBodyXNA(uint id, CollisionObject xx) + : base(id) + { + body = xx; + } + public override bool HasPhysicalBody + { + get { return body != null; } + } + public override void Clear() + { + body = null; + } + public override string AddrString + { + get { return "XNARigidBody"; } + } +} + +private sealed class BulletShapeXNA : BulletShape +{ + public CollisionShape shape; + public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) + : base() + { + shape = xx; + shapeType = typ; + } + public override bool HasPhysicalShape + { + get { return shape != null; } + } + public override void Clear() + { + shape = null; + } + public override BulletShape Clone() + { + return new BulletShapeXNA(shape, shapeType); + } + public override bool ReferenceSame(BulletShape other) + { + BulletShapeXNA otheru = other as BulletShapeXNA; + return (otheru != null) && (this.shape == otheru.shape); + + } + public override string AddrString + { + get { return "XNACollisionShape"; } + } +} +private sealed class BulletConstraintXNA : BulletConstraint +{ + public TypedConstraint constrain; + public BulletConstraintXNA(TypedConstraint xx) : base() + { + constrain = xx; + } + + public override void Clear() + { + constrain = null; + } + public override bool HasPhysicalConstraint { get { return constrain != null; } } + + // Used for log messages for a unique display of the memory/object allocated to this instance + public override string AddrString + { + get { return "XNAConstraint"; } + } +} + internal int m_maxCollisions; + internal CollisionDesc[] UpdatedCollisions; + internal int LastCollisionDesc = 0; + internal int m_maxUpdatesPerFrame; + internal int LastEntityProperty = 0; + + internal EntityProperties[] UpdatedObjects; + internal Dictionary specialCollisionObjects; + + private static int m_collisionsThisFrame; + private BSScene PhysicsScene { get; set; } + + public override string BulletEngineName { get { return "BulletXNA"; } } + public override string BulletEngineVersion { get; protected set; } + + public BSAPIXNA(string paramName, BSScene physScene) + { + PhysicsScene = physScene; + } + + /// + /// + /// + /// + /// + public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody body = ((BulletBodyXNA)pBody).rigidBody; + CollisionObject collisionObject = ((BulletBodyXNA)pBody).body; + if (body != null) + world.RemoveRigidBody(body); + else if (collisionObject != null) + world.RemoveCollisionObject(collisionObject); + else + return false; + return true; + } + + public override bool ClearCollisionProxyCache(BulletWorld pWorld, BulletBody pBody) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody body = ((BulletBodyXNA)pBody).rigidBody; + CollisionObject collisionObject = ((BulletBodyXNA)pBody).body; + if (body != null && collisionObject != null && collisionObject.GetBroadphaseHandle() != null) + { + world.RemoveCollisionObject(collisionObject); + world.AddCollisionObject(collisionObject); + } + return true; + } + + public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; + world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); + + return true; + + } + + public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; + world.RemoveConstraint(constraint); + return true; + } + + public override void SetRestitution(BulletBody pCollisionObject, float pRestitution) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + collisionObject.SetRestitution(pRestitution); + } + + public override int GetShapeType(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return (int)shape.GetShapeType(); + } + public override void SetMargin(BulletShape pShape, float pMargin) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + shape.SetMargin(pMargin); + } + + public override float GetMargin(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.GetMargin(); + } + + public override void SetLocalScaling(BulletShape pShape, Vector3 pScale) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); + shape.SetLocalScaling(ref vec); + + } + + public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + collisionObject.SetContactProcessingThreshold(contactprocessingthreshold); + } + + public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + collisionObject.SetCcdMotionThreshold(pccdMotionThreashold); + } + + public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius); + } + + public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z)); + } + + public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags(); + existingcollisionFlags |= pcollisionFlags; + collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); + return (CollisionFlags) (uint) existingcollisionFlags; + } + + public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionObject cbody = (pBody as BulletBodyXNA).body; + RigidBody rbody = cbody as RigidBody; + + // Bullet resets several variables when an object is added to the world. In particular, + // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic + // type. Of course, the collision flags in the broadphase proxy are initialized to default. + IndexedMatrix origPos = cbody.GetWorldTransform(); + if (rbody != null) + { + IndexedVector3 origGrav = rbody.GetGravity(); + world.AddRigidBody(rbody); + rbody.SetGravity(origGrav); + } + else + { + world.AddCollisionObject(cbody); + } + cbody.SetWorldTransform(origPos); + + pBody.ApplyCollisionMask(pWorld.physicsScene); + + //if (body.GetBroadphaseHandle() != null) + // world.UpdateSingleAabb(body); + return true; + } + + public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState); + } + + public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + world.UpdateSingleAabb(collisionObject); + } + + public override void UpdateAabbs(BulletWorld pWorld) { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + world.UpdateAabbs(); + } + public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + return world.GetForceUpdateAllAabbs(); + + } + public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + world.SetForceUpdateAllAabbs(pForce); + } + + public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; + collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; + if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0) + return false; + return true; + } + + public override void ClearAllForces(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0); + collisionObject.SetInterpolationLinearVelocity(ref zeroVector); + collisionObject.SetInterpolationAngularVelocity(ref zeroVector); + IndexedMatrix bodytransform = collisionObject.GetWorldTransform(); + + collisionObject.SetInterpolationWorldTransform(ref bodytransform); + + if (collisionObject is RigidBody) + { + RigidBody rigidbody = collisionObject as RigidBody; + rigidbody.SetLinearVelocity(zeroVector); + rigidbody.SetAngularVelocity(zeroVector); + rigidbody.ClearForces(); + } + } + + public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); + collisionObject.SetInterpolationAngularVelocity(ref vec); + } + + public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); + body.SetAngularVelocity(ref vec); + } + public override Vector3 GetTotalForce(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = body.GetTotalForce(); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + public override Vector3 GetTotalTorque(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = body.GetTotalTorque(); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = body.GetInvInertiaDiagLocal(); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z); + body.SetInvInertiaDiagLocal(ref iv3); + } + public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z); + IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); + body.ApplyForce(ref forceiv3, ref posiv3); + } + public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z); + IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); + body.ApplyImpulse(ref impiv3, ref posiv3); + } + + public override void ClearForces(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.ClearForces(); + } + + public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); + IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, + _orientation.W); + IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); + mat._origin = vposition; + collisionObject.SetWorldTransform(mat); + + } + + public override Vector3 GetPosition(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin; + return new Vector3(pos.X, pos.Y, pos.Z); + } + + public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + IndexedVector3 inertia = IndexedVector3.Zero; + shape.CalculateLocalInertia(pphysMass, out inertia); + return new Vector3(inertia.X, inertia.Y, inertia.Z); + } + + public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + if (body != null) // Can't set mass props on collision object. + { + IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z); + body.SetMassProps(pphysMass, inertia); + } + } + + + public override void SetObjectForce(BulletBody pBody, Vector3 _force) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z); + body.SetTotalForce(ref force); + } + + public override void SetFriction(BulletBody pCollisionObject, float _currentFriction) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + collisionObject.SetFriction(_currentFriction); + } + + public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z); + body.SetLinearVelocity(velocity); + } + + public override void Activate(BulletBody pCollisionObject, bool pforceactivation) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + collisionObject.Activate(pforceactivation); + + } + + public override Quaternion GetOrientation(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation(); + return new Quaternion(mat.X, mat.Y, mat.Z, mat.W); + } + + public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags(); + existingcollisionFlags &= ~pcollisionFlags; + collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); + return (CollisionFlags)(uint)existingcollisionFlags; + } + + public override float GetCcdMotionThreshold(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + return collisionObject.GetCcdSquareMotionThreshold(); + } + + public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + return collisionObject.GetCcdSweptSphereRadius(); + + } + + public override IntPtr GetUserPointer(BulletBody pCollisionObject) + { + CollisionObject shape = (pCollisionObject as BulletBodyXNA).body; + return (IntPtr)shape.GetUserPointer(); + } + + public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val) + { + CollisionObject shape = (pCollisionObject as BulletBodyXNA).body; + shape.SetUserPointer(val); + } + + public override void SetGravity(BulletBody pBody, Vector3 pGravity) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + if (body != null) // Can't set collisionobject.set gravity + { + IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z); + body.SetGravity(gravity); + } + } + + public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; + world.RemoveConstraint(constraint); + return true; + } + + public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); + IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); + constraint.SetLinearLowerLimit(lowlimit); + constraint.SetLinearUpperLimit(highlimit); + return true; + } + + public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); + IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); + constraint.SetAngularLowerLimit(lowlimit); + constraint.SetAngularUpperLimit(highlimit); + return true; + } + + public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + constraint.SetOverrideNumSolverIterations((int)cnt); + } + + public override bool CalculateTransforms(BulletConstraint pConstraint) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + constraint.CalculateTransforms(); + return true; + } + + public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + constraint.SetEnabled((p_2 == 0) ? false : true); + } + + + public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, + bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) + + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; + IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); + IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); + IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); + frame1._origin = frame1v; + + IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); + IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); + IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); + frame2._origin = frame1v; + + Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, + puseLinearReferenceFrameA); + consttr.CalculateTransforms(); + world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); + + return new BulletConstraintXNA(consttr); + } + + public override BulletConstraint Create6DofConstraintFixed(BulletWorld pWorld, BulletBody pBody1, + Vector3 pframe1, Quaternion pframe1rot, + bool pUseLinearReferenceFrameB, bool pdisableCollisionsBetweenLinkedBodies) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; + IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); + IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); + IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); + frame1._origin = frame1v; + + Generic6DofConstraint consttr = new Generic6DofConstraint(body1, ref frame1, pUseLinearReferenceFrameB); + consttr.CalculateTransforms(); + world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); + + return new BulletConstraintXNA(consttr); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; + IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); + IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); + + IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); + IndexedMatrix mat = IndexedMatrix.Identity; + mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); + frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint; + frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint; + + Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); + consttr.CalculateTransforms(); + world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies); + + return new BulletConstraintXNA(consttr); + } + //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); + public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); + IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); + IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); + frame1._origin = frame1v; + + IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); + IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); + IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); + frame2._origin = frame2v; + constraint.SetFrames(ref frame1, ref frame2); + return true; + } + + public override Vector3 GetLinearVelocity(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = body.GetLinearVelocity(); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + public override Vector3 GetAngularVelocity(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = body.GetAngularVelocity(); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); + IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + public override void Translate(BulletBody pCollisionObject, Vector3 trans) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z)); + } + public override void UpdateDeactivation(BulletBody pBody, float timeStep) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.UpdateDeactivation(timeStep); + } + + public override bool WantsSleeping(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + return body.WantsSleeping(); + } + + public override void SetAngularFactor(BulletBody pBody, float factor) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.SetAngularFactor(factor); + } + + public override Vector3 GetAngularFactor(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = body.GetAngularFactor(); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + + public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + return world.IsInWorld(collisionObject); + } + + public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain; + body.AddConstraintRef(constrain); + } + + public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain; + body.RemoveConstraintRef(constrain); + } + + public override BulletConstraint GetConstraintRef(BulletBody pBody, int index) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + return new BulletConstraintXNA(body.GetConstraintRef(index)); + } + + public override int GetNumConstraintRefs(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + return body.GetNumConstraintRefs(); + } + + public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z); + collisionObject.SetInterpolationLinearVelocity(ref velocity); + } + + public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + constraint.SetUseFrameOffset((onOff == 0) ? false : true); + return true; + } + //SetBreakingImpulseThreshold(m_constraint.ptr, threshold); + public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + constraint.SetBreakingImpulseThreshold(threshold); + return true; + } + public override bool HingeSetLimits(BulletConstraint pConstraint, float low, float high, float softness, float bias, float relaxation) + { + HingeConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as HingeConstraint; + if (softness == HINGE_NOT_SPECIFIED) + constraint.SetLimit(low, high); + else + constraint.SetLimit(low, high, softness, bias, relaxation); + return true; + } + public override bool SpringEnable(BulletConstraint pConstraint, int index, float numericTrueFalse) + { + Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; + constraint.EnableSpring(index, (numericTrueFalse == 0f ? false : true)); + return true; + } + + public override bool SpringSetEquilibriumPoint(BulletConstraint pConstraint, int index, float equilibriumPoint) + { + Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; + if (index == SPRING_NOT_SPECIFIED) + { + constraint.SetEquilibriumPoint(); + } + else + { + if (equilibriumPoint == SPRING_NOT_SPECIFIED) + constraint.SetEquilibriumPoint(index); + else + constraint.SetEquilibriumPoint(index, equilibriumPoint); + } + return true; + } + + public override bool SpringSetStiffness(BulletConstraint pConstraint, int index, float stiffness) + { + Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; + constraint.SetStiffness(index, stiffness); + return true; + } + + public override bool SpringSetDamping(BulletConstraint pConstraint, int index, float damping) + { + Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; + constraint.SetDamping(index, damping); + return true; + } + + public override bool SliderSetLimits(BulletConstraint pConstraint, int lowerUpper, int linAng, float val) + { + SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; + switch (lowerUpper) + { + case SLIDER_LOWER_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetLowerLinLimit(val); + break; + case SLIDER_ANGULAR: + constraint.SetLowerAngLimit(val); + break; + } + break; + case SLIDER_UPPER_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetUpperLinLimit(val); + break; + case SLIDER_ANGULAR: + constraint.SetUpperAngLimit(val); + break; + } + break; + } + return true; + } + public override bool SliderSet(BulletConstraint pConstraint, int softRestDamp, int dirLimOrtho, int linAng, float val) + { + SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; + switch (softRestDamp) + { + case SLIDER_SET_SOFTNESS: + switch (dirLimOrtho) + { + case SLIDER_SET_DIRECTION: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetSoftnessDirLin(val); break; + case SLIDER_ANGULAR: constraint.SetSoftnessDirAng(val); break; + } + break; + case SLIDER_SET_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetSoftnessLimLin(val); break; + case SLIDER_ANGULAR: constraint.SetSoftnessLimAng(val); break; + } + break; + case SLIDER_SET_ORTHO: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetSoftnessOrthoLin(val); break; + case SLIDER_ANGULAR: constraint.SetSoftnessOrthoAng(val); break; + } + break; + } + break; + case SLIDER_SET_RESTITUTION: + switch (dirLimOrtho) + { + case SLIDER_SET_DIRECTION: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetRestitutionDirLin(val); break; + case SLIDER_ANGULAR: constraint.SetRestitutionDirAng(val); break; + } + break; + case SLIDER_SET_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetRestitutionLimLin(val); break; + case SLIDER_ANGULAR: constraint.SetRestitutionLimAng(val); break; + } + break; + case SLIDER_SET_ORTHO: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetRestitutionOrthoLin(val); break; + case SLIDER_ANGULAR: constraint.SetRestitutionOrthoAng(val); break; + } + break; + } + break; + case SLIDER_SET_DAMPING: + switch (dirLimOrtho) + { + case SLIDER_SET_DIRECTION: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetDampingDirLin(val); break; + case SLIDER_ANGULAR: constraint.SetDampingDirAng(val); break; + } + break; + case SLIDER_SET_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetDampingLimLin(val); break; + case SLIDER_ANGULAR: constraint.SetDampingLimAng(val); break; + } + break; + case SLIDER_SET_ORTHO: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetDampingOrthoLin(val); break; + case SLIDER_ANGULAR: constraint.SetDampingOrthoAng(val); break; + } + break; + } + break; + } + return true; + } + public override bool SliderMotorEnable(BulletConstraint pConstraint, int linAng, float numericTrueFalse) + { + SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetPoweredLinMotor(numericTrueFalse == 0.0 ? false : true); + break; + case SLIDER_ANGULAR: + constraint.SetPoweredAngMotor(numericTrueFalse == 0.0 ? false : true); + break; + } + return true; + } + public override bool SliderMotor(BulletConstraint pConstraint, int forceVel, int linAng, float val) + { + SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; + switch (forceVel) + { + case SLIDER_MOTOR_VELOCITY: + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetTargetLinMotorVelocity(val); + break; + case SLIDER_ANGULAR: + constraint.SetTargetAngMotorVelocity(val); + break; + } + break; + case SLIDER_MAX_MOTOR_FORCE: + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetMaxLinMotorForce(val); + break; + case SLIDER_ANGULAR: + constraint.SetMaxAngMotorForce(val); + break; + } + break; + } + return true; + } + + //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping); + public override void SetAngularDamping(BulletBody pBody, float angularDamping) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + float lineardamping = body.GetLinearDamping(); + body.SetDamping(lineardamping, angularDamping); + + } + + public override void UpdateInertiaTensor(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + if (body != null) // can't update inertia tensor on CollisionObject + body.UpdateInertiaTensor(); + } + + public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape) + { + CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape; + shape.RecalculateLocalAabb(); + } + + //BulletSimAPI.GetCollisionFlags(PhysBody.ptr) + public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + uint flags = (uint)collisionObject.GetCollisionFlags(); + return (CollisionFlags) flags; + } + + public override void SetDamping(BulletBody pBody, float pLinear, float pAngular) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.SetDamping(pLinear, pAngular); + } + //PhysBody.ptr, PhysicsScene.Params.deactivationTime); + public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + collisionObject.SetDeactivationTime(pDeactivationTime); + } + //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); + public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold); + } + + public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + return (CollisionObjectTypes)(int) collisionObject.GetInternalType(); + } + + public override void ApplyGravity(BulletBody pBody) + { + + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.ApplyGravity(); + } + + public override Vector3 GetGravity(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 gravity = body.GetGravity(); + return new Vector3(gravity.X, gravity.Y, gravity.Z); + } + + public override void SetLinearDamping(BulletBody pBody, float lin_damping) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + float angularDamping = body.GetAngularDamping(); + body.SetDamping(lin_damping, angularDamping); + } + + public override float GetLinearDamping(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + return body.GetLinearDamping(); + } + + public override float GetAngularDamping(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + return body.GetAngularDamping(); + } + + public override float GetLinearSleepingThreshold(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + return body.GetLinearSleepingThreshold(); + } + + public override void ApplyDamping(BulletBody pBody, float timeStep) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.ApplyDamping(timeStep); + } + + public override Vector3 GetLinearFactor(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 linearFactor = body.GetLinearFactor(); + return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z); + } + + public override void SetLinearFactor(BulletBody pBody, Vector3 factor) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z)); + } + + public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W); + IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat); + mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z); + body.SetCenterOfMassTransform( ref mat); + /* TODO: double check this */ + } + + //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum); + public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); + body.ApplyCentralForce(ref fSum); + } + public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); + body.ApplyCentralImpulse(ref fSum); + } + public override void ApplyTorque(BulletBody pBody, Vector3 pfSum) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); + body.ApplyTorque(ref fSum); + } + public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); + body.ApplyTorqueImpulse(ref fSum); + } + + public override void DestroyObject(BulletWorld pWorld, BulletBody pBody) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionObject co = (pBody as BulletBodyXNA).rigidBody; + RigidBody bo = co as RigidBody; + if (bo == null) + { + + if (world.IsInWorld(co)) + { + world.RemoveCollisionObject(co); + } + } + else + { + + if (world.IsInWorld(bo)) + { + world.RemoveRigidBody(bo); + } + } + if (co != null) + { + if (co.GetUserPointer() != null) + { + uint localId = (uint) co.GetUserPointer(); + if (specialCollisionObjects.ContainsKey(localId)) + { + specialCollisionObjects.Remove(localId); + } + } + } + + } + + public override void Shutdown(BulletWorld pWorld) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + world.Cleanup(); + } + + public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id) + { + CollisionShape shape1 = (pShape as BulletShapeXNA).shape; + + // TODO: Turn this from a reference copy to a Value Copy. + BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); + + return shape2; + } + + public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape) + { + //TODO: + return false; + } + //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); + + public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) + { + CollisionWorld world = (pWorld as BulletWorldXNA).world; + IndexedMatrix mat = + IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, + pRawOrientation.Z, pRawOrientation.W)); + mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); + CollisionShape shape = (pShape as BulletShapeXNA).shape; + //UpdateSingleAabb(world, shape); + // TODO: Feed Update array into null + SimMotionState motionState = new SimMotionState(this, pLocalID, mat, null); + RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero); + RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, motionState, shape, IndexedVector3.Zero) + { + m_mass = 0 + }; + /* + m_mass = mass; + m_motionState =motionState; + m_collisionShape = collisionShape; + m_localInertia = localInertia; + m_linearDamping = 0f; + m_angularDamping = 0f; + m_friction = 0.5f; + m_restitution = 0f; + m_linearSleepingThreshold = 0.8f; + m_angularSleepingThreshold = 1f; + m_additionalDamping = false; + m_additionalDampingFactor = 0.005f; + m_additionalLinearDampingThresholdSqr = 0.01f; + m_additionalAngularDampingThresholdSqr = 0.01f; + m_additionalAngularDampingFactor = 0.01f; + m_startWorldTransform = IndexedMatrix.Identity; + */ + body.SetUserPointer(pLocalID); + + return new BulletBodyXNA(pLocalID, body); + } + + + public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) + { + + IndexedMatrix mat = + IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, + pRawOrientation.Z, pRawOrientation.W)); + mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); + + CollisionShape shape = (pShape as BulletShapeXNA).shape; + + // TODO: Feed Update array into null + RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero); + body.SetWorldTransform(mat); + body.SetUserPointer(pLocalID); + return new BulletBodyXNA(pLocalID, body); + } + //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); + public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags); + return (CollisionFlags)collisionObject.GetCollisionFlags(); + } + + public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) + { + + /* TODO */ + return Vector3.Zero; + } + public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } + public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; } + public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; } + public override bool IsStaticObject(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + return collisionObject.IsStaticObject(); + + } + public override bool IsKinematicObject(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + return collisionObject.IsKinematicObject(); + } + public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + return collisionObject.IsStaticOrKinematicObject(); + } + public override bool HasContactResponse(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + return collisionObject.HasContactResponse(); + } + public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; } + public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ } + public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; } + public override bool IsActive(BulletBody pBody) { /* TODO */ return false; } + public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; } + public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; } + public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ } + public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; } + + //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); + public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + collisionObject.SetHitFraction(pHitFraction); + } + //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale); + public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); + CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight); + capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin); + capsuleShapeZ.SetLocalScaling(ref scale); + + return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ; + } + + public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, + int maxCollisions, ref CollisionDesc[] collisionArray, + int maxUpdates, ref EntityProperties[] updateArray + ) + { + + UpdatedObjects = updateArray; + UpdatedCollisions = collisionArray; + /* TODO */ + ConfigurationParameters[] configparms = new ConfigurationParameters[1]; + configparms[0] = parms; + Vector3 worldExtent = maxPosition; + m_maxCollisions = maxCollisions; + m_maxUpdatesPerFrame = maxUpdates; + specialCollisionObjects = new Dictionary(); + + return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); + } + + private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, + ConfigurationParameters[] o, + int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, + int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, + object mDebugLogCallbackHandle) + { + CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); + + p.angularDamping = BSParam.AngularDamping; + p.defaultFriction = o[0].defaultFriction; + p.defaultFriction = o[0].defaultFriction; + p.defaultDensity = o[0].defaultDensity; + p.defaultRestitution = o[0].defaultRestitution; + p.collisionMargin = o[0].collisionMargin; + p.gravity = o[0].gravity; + + p.linearDamping = BSParam.LinearDamping; + p.angularDamping = BSParam.AngularDamping; + p.deactivationTime = BSParam.DeactivationTime; + p.linearSleepingThreshold = BSParam.LinearSleepingThreshold; + p.angularSleepingThreshold = BSParam.AngularSleepingThreshold; + p.ccdMotionThreshold = BSParam.CcdMotionThreshold; + p.ccdSweptSphereRadius = BSParam.CcdSweptSphereRadius; + p.contactProcessingThreshold = BSParam.ContactProcessingThreshold; + + p.terrainImplementation = BSParam.TerrainImplementation; + p.terrainFriction = BSParam.TerrainFriction; + + p.terrainHitFraction = BSParam.TerrainHitFraction; + p.terrainRestitution = BSParam.TerrainRestitution; + p.terrainCollisionMargin = BSParam.TerrainCollisionMargin; + + p.avatarFriction = BSParam.AvatarFriction; + p.avatarStandingFriction = BSParam.AvatarStandingFriction; + p.avatarDensity = BSParam.AvatarDensity; + p.avatarRestitution = BSParam.AvatarRestitution; + p.avatarCapsuleWidth = BSParam.AvatarCapsuleWidth; + p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; + p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; + p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; + + p.vehicleAngularDamping = BSParam.VehicleAngularDamping; + + p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; + p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; + p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; + p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs; + p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder; + p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands; + p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching; + p.numberOfSolverIterations = o[0].numberOfSolverIterations; + + p.linksetImplementation = BSParam.LinksetImplementation; + p.linkConstraintUseFrameOffset = BSParam.NumericBool(BSParam.LinkConstraintUseFrameOffset); + p.linkConstraintEnableTransMotor = BSParam.NumericBool(BSParam.LinkConstraintEnableTransMotor); + p.linkConstraintTransMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; + p.linkConstraintTransMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; + p.linkConstraintERP = BSParam.LinkConstraintERP; + p.linkConstraintCFM = BSParam.LinkConstraintCFM; + p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; + p.physicsLoggingFrames = o[0].physicsLoggingFrames; + DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); + + DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); + CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); + + + if (p.maxPersistantManifoldPoolSize > 0) + cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize; + if (p.shouldDisableContactPoolDynamicAllocation !=0) + m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION); + //if (p.maxCollisionAlgorithmPoolSize >0 ) + + DbvtBroadphase m_broadphase = new DbvtBroadphase(); + //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0); + //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256); + + //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true); + m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback()); + + SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver(); + + DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci); + + world.LastCollisionDesc = 0; + world.LastEntityProperty = 0; + + world.WorldSettings.Params = p; + world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0); + world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD; + if (p.shouldRandomizeSolverOrder != 0) + world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER; + + world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0); + //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port + + if (p.shouldEnableFrictionCaching != 0) + world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING; + + if (p.numberOfSolverIterations > 0) + world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations; + + + world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping; + world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution; + world.GetSolverInfo().m_globalCfm = 0.0f; + world.GetSolverInfo().m_tau = 0.6f; + world.GetSolverInfo().m_friction = 0.3f; + world.GetSolverInfo().m_maxErrorReduction = 20f; + world.GetSolverInfo().m_numIterations = 10; + world.GetSolverInfo().m_erp = 0.2f; + world.GetSolverInfo().m_erp2 = 0.1f; + world.GetSolverInfo().m_sor = 1.0f; + world.GetSolverInfo().m_splitImpulse = false; + world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f; + world.GetSolverInfo().m_linearSlop = 0.0f; + world.GetSolverInfo().m_warmstartingFactor = 0.85f; + world.GetSolverInfo().m_restingContactRestitutionThreshold = 2; + world.SetForceUpdateAllAabbs(true); + + //BSParam.TerrainImplementation = 0; + world.SetGravity(new IndexedVector3(0,0,p.gravity)); + + // Turn off Pooling since globals and pooling are bad for threading. + BulletGlobals.VoronoiSimplexSolverPool.SetPoolingEnabled(false); + BulletGlobals.SubSimplexConvexCastPool.SetPoolingEnabled(false); + BulletGlobals.ManifoldPointPool.SetPoolingEnabled(false); + BulletGlobals.CastResultPool.SetPoolingEnabled(false); + BulletGlobals.SphereShapePool.SetPoolingEnabled(false); + BulletGlobals.DbvtNodePool.SetPoolingEnabled(false); + BulletGlobals.SingleRayCallbackPool.SetPoolingEnabled(false); + BulletGlobals.SubSimplexClosestResultPool.SetPoolingEnabled(false); + BulletGlobals.GjkPairDetectorPool.SetPoolingEnabled(false); + BulletGlobals.DbvtTreeColliderPool.SetPoolingEnabled(false); + BulletGlobals.SingleSweepCallbackPool.SetPoolingEnabled(false); + BulletGlobals.BroadphaseRayTesterPool.SetPoolingEnabled(false); + BulletGlobals.ClosestNotMeConvexResultCallbackPool.SetPoolingEnabled(false); + BulletGlobals.GjkEpaPenetrationDepthSolverPool.SetPoolingEnabled(false); + BulletGlobals.ContinuousConvexCollisionPool.SetPoolingEnabled(false); + BulletGlobals.DbvtStackDataBlockPool.SetPoolingEnabled(false); + + BulletGlobals.BoxBoxCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.CompoundCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.ConvexConcaveCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.ConvexConvexAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.ConvexPlaneAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.SphereBoxCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.SphereSphereCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.SphereTriangleCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.GImpactCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.GjkEpaSolver2MinkowskiDiffPool.SetPoolingEnabled(false); + BulletGlobals.PersistentManifoldPool.SetPoolingEnabled(false); + BulletGlobals.ManifoldResultPool.SetPoolingEnabled(false); + BulletGlobals.GJKPool.SetPoolingEnabled(false); + BulletGlobals.GIM_ShapeRetrieverPool.SetPoolingEnabled(false); + BulletGlobals.TriangleShapePool.SetPoolingEnabled(false); + BulletGlobals.SphereTriangleDetectorPool.SetPoolingEnabled(false); + BulletGlobals.CompoundLeafCallbackPool.SetPoolingEnabled(false); + BulletGlobals.GjkConvexCastPool.SetPoolingEnabled(false); + BulletGlobals.LocalTriangleSphereCastCallbackPool.SetPoolingEnabled(false); + BulletGlobals.BridgeTriangleRaycastCallbackPool.SetPoolingEnabled(false); + BulletGlobals.BridgeTriangleConcaveRaycastCallbackPool.SetPoolingEnabled(false); + BulletGlobals.BridgeTriangleConvexcastCallbackPool.SetPoolingEnabled(false); + BulletGlobals.MyNodeOverlapCallbackPool.SetPoolingEnabled(false); + BulletGlobals.ClosestRayResultCallbackPool.SetPoolingEnabled(false); + BulletGlobals.DebugDrawcallbackPool.SetPoolingEnabled(false); + + return world; + } + //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL + public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis) + { + Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) + { + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0); + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1); + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2); + } + if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) + { + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3); + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4); + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5); + } + if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL) + { + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis); + } + return true; + } + + public override bool PushUpdate(BulletBody pCollisionObject) + { + bool ret = false; + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + RigidBody rb = collisionObject as RigidBody; + if (rb != null) + { + SimMotionState sms = rb.GetMotionState() as SimMotionState; + if (sms != null) + { + IndexedMatrix wt = IndexedMatrix.Identity; + sms.GetWorldTransform(out wt); + sms.SetWorldTransform(ref wt, true); + ret = true; + } + } + return ret; + + } + + public override float GetAngularMotionDisc(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.GetAngularMotionDisc(); + } + public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.GetContactBreakingThreshold(defaultFactor); + } + public override bool IsCompound(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsCompound(); + } + public override bool IsSoftBody(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsSoftBody(); + } + public override bool IsPolyhedral(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsPolyhedral(); + } + public override bool IsConvex2d(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsConvex2d(); + } + public override bool IsConvex(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsConvex(); + } + public override bool IsNonMoving(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsNonMoving(); + } + public override bool IsConcave(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsConcave(); + } + public override bool IsInfinite(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsInfinite(); + } + public override bool IsNativeShape(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + bool ret; + switch (shape.GetShapeType()) + { + case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: + case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: + case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: + case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: + ret = true; + break; + default: + ret = false; + break; + } + return ret; + } + + public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + shape.SetMargin(pMargin); + } + + //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation + public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + IndexedMatrix bodyTransform = new IndexedMatrix(); + bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); + bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W)); + GhostObject gObj = new PairCachingGhostObject(); + gObj.SetWorldTransform(bodyTransform); + CollisionShape shape = (pShape as BulletShapeXNA).shape; + gObj.SetCollisionShape(shape); + gObj.SetUserPointer(pLocalID); + + if (specialCollisionObjects.ContainsKey(pLocalID)) + specialCollisionObjects[pLocalID] = gObj; + else + specialCollisionObjects.Add(pLocalID, gObj); + + // TODO: Add to Special CollisionObjects! + return new BulletBodyXNA(pLocalID, gObj); + } + + public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + if (pShape == null) + { + collisionObject.SetCollisionShape(new EmptyShape()); + } + else + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + collisionObject.SetCollisionShape(shape); + } + } + public override BulletShape GetCollisionShape(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + CollisionShape shape = collisionObject.GetCollisionShape(); + return new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); + } + + //(PhysicsScene.World.ptr, nativeShapeData) + public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionShape shape = null; + switch (pShapeData.Type) + { + case BSPhysicsShapeType.SHAPE_BOX: + shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f)); + break; + case BSPhysicsShapeType.SHAPE_CONE: + shape = new ConeShapeZ(0.5f, 1.0f); + break; + case BSPhysicsShapeType.SHAPE_CYLINDER: + shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f)); + break; + case BSPhysicsShapeType.SHAPE_SPHERE: + shape = new SphereShape(0.5f); + break; + + } + if (shape != null) + { + IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z); + shape.SetMargin(world.WorldSettings.Params.collisionMargin); + shape.SetLocalScaling(ref scaling); + + } + return new BulletShapeXNA(shape, pShapeData.Type); + } + //PhysicsScene.World.ptr, false + public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree) + { + return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND); + } + + public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape) + { + CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape; + return compoundshape.GetNumChildShapes(); + } + //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot + public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot) + { + IndexedMatrix relativeTransform = new IndexedMatrix(); + CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape; + CollisionShape addshape = (paddShape as BulletShapeXNA).shape; + + relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z); + relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W)); + compoundshape.AddChildShape(ref relativeTransform, addshape); + + } + + public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii) + { + CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape; + CollisionShape ret = null; + ret = compoundshape.GetChildShape(pii); + compoundshape.RemoveChildShapeByIndex(pii); + return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); + } + + public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { + + if (cShape == null) + return null; + CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; + CollisionShape shape = compoundShape.GetChildShape(indx); + BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); + + + return retShape; + } + + public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) + { + BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + switch (pin) + { + case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_BOX; + break; + case BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + + case BroadphaseNativeTypes.TETRAHEDRAL_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; + break; + case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_HULL; + break; + case BroadphaseNativeTypes.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.CUSTOM_POLYHEDRAL_SHAPE_TYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + //implicit convex shapes + case BroadphaseNativeTypes.IMPLICIT_CONVEX_SHAPES_START_HERE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_SPHERE; + break; + case BroadphaseNativeTypes.MULTI_SPHERE_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_CAPSULE; + break; + case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_CONE; + break; + case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; + break; + case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_CYLINDER; + break; + case BroadphaseNativeTypes.UNIFORM_SCALING_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.MINKOWSKI_SUM_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.BOX_2D_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.CONVEX_2D_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.CUSTOM_CONVEX_SHAPE_TYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + //concave shape + case BroadphaseNativeTypes.CONCAVE_SHAPES_START_HERE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy! + case BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_MESH; + break; + case BroadphaseNativeTypes.SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_MESH; + break; + ///used for demo integration FAST/Swift collision library and Bullet + case BroadphaseNativeTypes.FAST_CONCAVE_MESH_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_MESH; + break; + //terrain + case BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_HEIGHTMAP; + break; + ///Used for GIMPACT Trimesh integration + case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_GIMPACT; + break; + ///Multimaterial mesh + case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_MESH; + break; + + case BroadphaseNativeTypes.EMPTY_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_GROUNDPLANE; + break; + case BroadphaseNativeTypes.CUSTOM_CONCAVE_SHAPE_TYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.CONCAVE_SHAPES_END_HERE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + + case BroadphaseNativeTypes.COMPOUND_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_COMPOUND; + break; + + case BroadphaseNativeTypes.SOFTBODY_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_MESH; + break; + case BroadphaseNativeTypes.HFFLUID_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.INVALID_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + } + return ret; + } + + public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ } + public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ } + + public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin) + { + StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight ); + m_planeshape.SetMargin(pcollisionMargin); + m_planeshape.SetUserPointer(pLocalId); + return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); + } + + public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, + bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) + + { + Generic6DofSpringConstraint constrain = null; + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; + if (body1 != null && body2 != null) + { + IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); + IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); + IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); + frame1._origin = frame1v; + + IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); + IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); + IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); + frame2._origin = frame1v; + + constrain = new Generic6DofSpringConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); + world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); + + constrain.CalculateTransforms(); + } + + return new BulletConstraintXNA(constrain); + } + + public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, + bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) + { + HingeConstraint constrain = null; + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; + if (rb1 != null && rb2 != null) + { + IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); + IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); + IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); + IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); + constrain = new HingeConstraint(rb1, rb2, ref pivotInA, ref pivotInB, ref axisInA, ref axisInB, puseLinearReferenceFrameA); + world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); + } + return new BulletConstraintXNA(constrain); + } + + public override BulletConstraint CreateSliderConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 pframe1, Quaternion pframe1rot, + Vector3 pframe2, Quaternion pframe2rot, + bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) + { + SliderConstraint constrain = null; + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; + if (rb1 != null && rb2 != null) + { + IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); + IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); + IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); + frame1._origin = frame1v; + + IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); + IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); + IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); + frame2._origin = frame1v; + + constrain = new SliderConstraint(rb1, rb2, ref frame1, ref frame2, puseLinearReferenceFrameA); + world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); + } + return new BulletConstraintXNA(constrain); + } + + public override BulletConstraint CreateConeTwistConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 pframe1, Quaternion pframe1rot, + Vector3 pframe2, Quaternion pframe2rot, + bool pdisableCollisionsBetweenLinkedBodies) + { + ConeTwistConstraint constrain = null; + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; + if (rb1 != null && rb2 != null) + { + IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); + IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); + IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); + frame1._origin = frame1v; + + IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); + IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); + IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); + frame2._origin = frame1v; + + constrain = new ConeTwistConstraint(rb1, rb2, ref frame1, ref frame2); + world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); + } + return new BulletConstraintXNA(constrain); + } + + public override BulletConstraint CreateGearConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 paxisInA, Vector3 paxisInB, + float pratio, bool pdisableCollisionsBetweenLinkedBodies) + { + Generic6DofConstraint constrain = null; + /* BulletXNA does not have a gear constraint + GearConstraint constrain = null; + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; + if (rb1 != null && rb2 != null) + { + IndexedVector3 axis1 = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); + IndexedVector3 axis2 = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); + constrain = new GearConstraint(rb1, rb2, ref axis1, ref axis2, pratio); + world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); + } + */ + return new BulletConstraintXNA(constrain); + } + + public override BulletConstraint CreatePoint2PointConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 ppivotInA, Vector3 ppivotInB, + bool pdisableCollisionsBetweenLinkedBodies) + { + Point2PointConstraint constrain = null; + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; + if (rb1 != null && rb2 != null) + { + IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); + IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); + constrain = new Point2PointConstraint(rb1, rb2, ref pivotInA, ref pivotInB); + world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); + } + return new BulletConstraintXNA(constrain); + } + + public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CompoundShape compoundshape = new CompoundShape(false); + + compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); + int ii = 1; + + for (int i = 0; i < pHullCount; i++) + { + int vertexCount = (int) pConvHulls[ii]; + + IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]); + IndexedMatrix childTrans = IndexedMatrix.Identity; + childTrans._origin = centroid; + + List virts = new List(); + int ender = ((ii + 4) + (vertexCount*3)); + for (int iii = ii + 4; iii < ender; iii+=3) + { + + virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); + } + ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); + convexShape.SetMargin(world.WorldSettings.Params.collisionMargin); + compoundshape.AddChildShape(ref childTrans, convexShape); + ii += (vertexCount*3 + 4); + } + + return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); + } + + public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) + { + /* TODO */ return null; + } + + public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) + { + /* TODO */ return null; + } + + public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) + { + /* TODO */ return null; + } + + public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) + { + //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); + + for (int iter = 0; iter < pVerticesCount; iter++) + { + if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; + if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; + } + + ObjectArray indicesarr = new ObjectArray(indices); + ObjectArray vertices = new ObjectArray(verticesAsFloats); + DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + IndexedMesh mesh = new IndexedMesh(); + mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; + mesh.m_numTriangles = pIndicesCount/3; + mesh.m_numVertices = pVerticesCount; + mesh.m_triangleIndexBase = indicesarr; + mesh.m_vertexBase = vertices; + mesh.m_vertexStride = 3; + mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; + mesh.m_triangleIndexStride = 3; + + TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); + tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); + BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); + meshShape.SetMargin(world.WorldSettings.Params.collisionMargin); + // world.UpdateSingleAabb(meshShape); + return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); + + } + public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) + { + // TODO: + return null; + } + public static void DumpRaw(ObjectArrayindices, ObjectArray vertices, int pIndicesCount,int pVerticesCount ) + { + + String fileName = "objTest3.raw"; + String completePath = System.IO.Path.Combine(Util.configDir(), fileName); + StreamWriter sw = new StreamWriter(completePath); + IndexedMesh mesh = new IndexedMesh(); + + mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; + mesh.m_numTriangles = pIndicesCount / 3; + mesh.m_numVertices = pVerticesCount; + mesh.m_triangleIndexBase = indices; + mesh.m_vertexBase = vertices; + mesh.m_vertexStride = 3; + mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; + mesh.m_triangleIndexStride = 3; + + TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); + tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); + + + + for (int i = 0; i < pVerticesCount; i++) + { + + string s = vertices[indices[i * 3]].ToString("0.0000"); + s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); + s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); + + sw.Write(s + "\n"); + } + + sw.Close(); + } + public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount) + { + + String fileName = "objTest6.raw"; + String completePath = System.IO.Path.Combine(Util.configDir(), fileName); + StreamWriter sw = new StreamWriter(completePath); + IndexedMesh mesh = new IndexedMesh(); + + mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; + mesh.m_numTriangles = pIndicesCount / 3; + mesh.m_numVertices = pVerticesCount; + mesh.m_triangleIndexBase = indices; + mesh.m_vertexBase = vertices; + mesh.m_vertexStride = 3; + mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; + mesh.m_triangleIndexStride = 3; + + TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); + tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); + + + sw.WriteLine("Indices"); + sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount)); + for (int iter = 0; iter < indices.Length; iter++) + { + sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter])); + } + sw.WriteLine("VerticesFloats"); + sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount)); + for (int iter = 0; iter < vertices.Length; iter++) + { + sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000"))); + } + + // for (int i = 0; i < pVerticesCount; i++) + // { + // + // string s = vertices[indices[i * 3]].ToString("0.0000"); + // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); + // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); + // + // sw.Write(s + "\n"); + //} + + sw.Close(); + } + + public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, + float scaleFactor, float collisionMargin) + { + const int upAxis = 2; + HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y, + heightMap, scaleFactor, + minHeight, maxHeight, upAxis, + false); + terrainShape.SetMargin(collisionMargin); + terrainShape.SetUseDiamondSubdivision(true); + terrainShape.SetUserPointer(id); + return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN); + } + + public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce) + { + TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain; + bool onOff = ponOff != 0; + bool ret = false; + + switch (tconstrain.GetConstraintType()) + { + case TypedConstraintType.D6_CONSTRAINT_TYPE: + Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint; + constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff; + constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity; + constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce; + ret = true; + break; + } + + + return ret; + + } + + public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, + out int updatedEntityCount, out int collidersCount) + { + /* TODO */ + updatedEntityCount = 0; + collidersCount = 0; + + + int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); + + return ret; + } + + private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, + out int updatedEntityCount, out EntityProperties[] updatedEntities, + out int collidersCount, out CollisionDesc[] colliders) + { + int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities, + out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame); + return epic; + } + + private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, + out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) + { + int numSimSteps = 0; + Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); + Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); + LastEntityProperty=0; + + + + + + + LastCollisionDesc=0; + + updatedEntityCount = 0; + collidersCount = 0; + + + if (pWorld is BulletWorldXNA) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + + world.LastCollisionDesc = 0; + world.LastEntityProperty = 0; + numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep); + + PersistentManifold contactManifold; + CollisionObject objA; + CollisionObject objB; + ManifoldPoint manifoldPoint; + PairCachingGhostObject pairCachingGhostObject; + + m_collisionsThisFrame = 0; + int numManifolds = world.GetDispatcher().GetNumManifolds(); + for (int j = 0; j < numManifolds; j++) + { + contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j); + int numContacts = contactManifold.GetNumContacts(); + if (numContacts == 0) + continue; + + objA = contactManifold.GetBody0() as CollisionObject; + objB = contactManifold.GetBody1() as CollisionObject; + + manifoldPoint = contactManifold.GetContactPoint(0); + //IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB(); + // IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A + + RecordCollision(this, objA, objB, manifoldPoint.GetPositionWorldOnB(), -manifoldPoint.m_normalWorldOnB, manifoldPoint.GetDistance()); + m_collisionsThisFrame ++; + if (m_collisionsThisFrame >= 9999999) + break; + + + } + + foreach (GhostObject ghostObject in specialCollisionObjects.Values) + { + pairCachingGhostObject = ghostObject as PairCachingGhostObject; + if (pairCachingGhostObject != null) + { + RecordGhostCollisions(pairCachingGhostObject); + } + + } + + + updatedEntityCount = LastEntityProperty; + updatedEntities = UpdatedObjects; + + collidersCount = LastCollisionDesc; + colliders = UpdatedCollisions; + + + } + else + { + //if (updatedEntities is null) + //updatedEntities = new List(); + //updatedEntityCount = 0; + + + //collidersCount = 0; + + updatedEntities = new EntityProperties[0]; + + + colliders = new CollisionDesc[0]; + + } + return numSimSteps; + } + public void RecordGhostCollisions(PairCachingGhostObject obj) + { + IOverlappingPairCache cache = obj.GetOverlappingPairCache(); + ObjectArray pairs = cache.GetOverlappingPairArray(); + + DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; + PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); + BroadphasePair collisionPair; + PersistentManifold contactManifold; + + CollisionObject objA; + CollisionObject objB; + + ManifoldPoint pt; + + int numPairs = pairs.Count; + + for (int i = 0; i < numPairs; i++) + { + manifoldArray.Clear(); + if (LastCollisionDesc < UpdatedCollisions.Length) + break; + collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); + if (collisionPair == null) + continue; + + collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); + for (int j = 0; j < manifoldArray.Count; j++) + { + contactManifold = manifoldArray[j]; + int numContacts = contactManifold.GetNumContacts(); + objA = contactManifold.GetBody0() as CollisionObject; + objB = contactManifold.GetBody1() as CollisionObject; + for (int p = 0; p < numContacts; p++) + { + pt = contactManifold.GetContactPoint(p); + if (pt.GetDistance() < 0.0f) + { + RecordCollision(this, objA, objB, pt.GetPositionWorldOnA(), -pt.m_normalWorldOnB,pt.GetDistance()); + break; + } + } + } + } + + } + private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) + { + + IndexedVector3 contactNormal = norm; + if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && + (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) + { + return; + } + uint idA = (uint)objA.GetUserPointer(); + uint idB = (uint)objB.GetUserPointer(); + if (idA > idB) + { + uint temp = idA; + idA = idB; + idB = temp; + contactNormal = -contactNormal; + } + + //ulong collisionID = ((ulong) idA << 32) | idB; + + CollisionDesc cDesc = new CollisionDesc() + { + aID = idA, + bID = idB, + point = new Vector3(contact.X,contact.Y,contact.Z), + normal = new Vector3(contactNormal.X,contactNormal.Y,contactNormal.Z), + penetration = penetration + + }; + if (world.LastCollisionDesc < world.UpdatedCollisions.Length) + world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc); + m_collisionsThisFrame++; + + + } + private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject) + { + EntityProperties ent = new EntityProperties(); + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + IndexedMatrix transform = collisionObject.GetWorldTransform(); + IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity(); + IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity(); + IndexedQuaternion rotation = transform.GetRotation(); + ent.Acceleration = Vector3.Zero; + ent.ID = (uint)collisionObject.GetUserPointer(); + ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z); + ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W); + ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z); + ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z); + return ent; + } + + public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ + return false; } + + public override Vector3 GetLocalScaling(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + IndexedVector3 scale = shape.GetLocalScaling(); + return new Vector3(scale.X,scale.Y,scale.Z); + } + + public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + if (world != null) + { + if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) + { + CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; + + IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); + IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); + using ( + ClosestNotMeRayResultCallback rayCallback = + new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) + ) + { + world.RayTest(ref rOrigin, ref rEnd, rayCallback); + if (rayCallback.HasHit()) + { + IndexedVector3 hitLocation = rayCallback.m_hitPointWorld; + } + return rayCallback.HasHit(); + } + } + } + return false; + } +} + + + + + public class SimMotionState : DefaultMotionState + { + public RigidBody Rigidbody; + public Vector3 ZeroVect; + + private IndexedMatrix m_xform; + + private EntityProperties m_properties; + private EntityProperties m_lastProperties; + private BSAPIXNA m_world; + + const float POSITION_TOLERANCE = 0.05f; + const float VELOCITY_TOLERANCE = 0.001f; + const float ROTATION_TOLERANCE = 0.01f; + const float ANGULARVELOCITY_TOLERANCE = 0.01f; + + public SimMotionState(BSAPIXNA pWorld, uint id, IndexedMatrix starTransform, object frameUpdates) + { + IndexedQuaternion OrientationQuaterion = starTransform.GetRotation(); + m_properties = new EntityProperties() + { + ID = id, + Position = new Vector3(starTransform._origin.X, starTransform._origin.Y,starTransform._origin.Z), + Rotation = new Quaternion(OrientationQuaterion.X,OrientationQuaterion.Y,OrientationQuaterion.Z,OrientationQuaterion.W) + }; + m_lastProperties = new EntityProperties() + { + ID = id, + Position = new Vector3(starTransform._origin.X, starTransform._origin.Y, starTransform._origin.Z), + Rotation = new Quaternion(OrientationQuaterion.X, OrientationQuaterion.Y, OrientationQuaterion.Z, OrientationQuaterion.W) + }; + m_world = pWorld; + m_xform = starTransform; + } + + public override void GetWorldTransform(out IndexedMatrix worldTrans) + { + worldTrans = m_xform; + } + + public override void SetWorldTransform(IndexedMatrix worldTrans) + { + SetWorldTransform(ref worldTrans); + } + + public override void SetWorldTransform(ref IndexedMatrix worldTrans) + { + SetWorldTransform(ref worldTrans, false); + } + public void SetWorldTransform(ref IndexedMatrix worldTrans, bool force) + { + m_xform = worldTrans; + // Put the new transform into m_properties + IndexedQuaternion OrientationQuaternion = m_xform.GetRotation(); + IndexedVector3 LinearVelocityVector = Rigidbody.GetLinearVelocity(); + IndexedVector3 AngularVelocityVector = Rigidbody.GetAngularVelocity(); + m_properties.Position = new Vector3(m_xform._origin.X, m_xform._origin.Y, m_xform._origin.Z); + m_properties.Rotation = new Quaternion(OrientationQuaternion.X, OrientationQuaternion.Y, + OrientationQuaternion.Z, OrientationQuaternion.W); + // A problem with stock Bullet is that we don't get an event when an object is deactivated. + // This means that the last non-zero values for linear and angular velocity + // are left in the viewer who does dead reconning and the objects look like + // they float off. + // BulletSim ships with a patch to Bullet which creates such an event. + m_properties.Velocity = new Vector3(LinearVelocityVector.X, LinearVelocityVector.Y, LinearVelocityVector.Z); + m_properties.RotationalVelocity = new Vector3(AngularVelocityVector.X, AngularVelocityVector.Y, AngularVelocityVector.Z); + + if (force + + || !AlmostEqual(ref m_lastProperties.Position, ref m_properties.Position, POSITION_TOLERANCE) + || !AlmostEqual(ref m_properties.Rotation, ref m_lastProperties.Rotation, ROTATION_TOLERANCE) + // If the Velocity and AngularVelocity are zero, most likely the object has + // been deactivated. If they both are zero and they have become zero recently, + // make sure a property update is sent so the zeros make it to the viewer. + || ((m_properties.Velocity == ZeroVect && m_properties.RotationalVelocity == ZeroVect) + && + (m_properties.Velocity != m_lastProperties.Velocity || + m_properties.RotationalVelocity != m_lastProperties.RotationalVelocity)) + // If Velocity and AngularVelocity are non-zero but have changed, send an update. + || !AlmostEqual(ref m_properties.Velocity, ref m_lastProperties.Velocity, VELOCITY_TOLERANCE) + || + !AlmostEqual(ref m_properties.RotationalVelocity, ref m_lastProperties.RotationalVelocity, + ANGULARVELOCITY_TOLERANCE) + ) + + + { + // Add this update to the list of updates for this frame. + m_lastProperties = m_properties; + if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) + m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); + + //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; + } + + + + + } + public override void SetRigidBody(RigidBody body) + { + Rigidbody = body; + } + internal static bool AlmostEqual(ref Vector3 v1, ref Vector3 v2, float nEpsilon) + { + return + (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) && + (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) && + (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))); + } + + internal static bool AlmostEqual(ref Quaternion v1, ref Quaternion v2, float nEpsilon) + { + return + (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) && + (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) && + (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && + (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); + } + + } +} + diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs new file mode 100755 index 0000000..0191893 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs @@ -0,0 +1,457 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public class BSActorAvatarMove : BSActor +{ + BSVMotor m_velocityMotor; + + // Set to true if we think we're going up stairs. + // This state is remembered because collisions will turn on and off as we go up stairs. + int m_walkingUpStairs; + // The amount the step up is applying. Used to smooth stair walking. + float m_lastStepUp; + + // Jumping happens over several frames. If use applies up force while colliding, start the + // jump and allow the jump to continue for this number of frames. + int m_jumpFrames = 0; + float m_jumpVelocity = 0f; + + public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_velocityMotor = null; + m_walkingUpStairs = 0; + m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID); + } + + // BSActor.isActive + public override bool isActive + { + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() + { + base.SetEnabled(false); + DeactivateAvatarMove(); + } + + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() + { + m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID); + + // If the object is physically active, add the hoverer prestep action + if (isActive) + { + ActivateAvatarMove(); + } + else + { + DeactivateAvatarMove(); + } + } + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveDependencies() + public override void RemoveDependencies() + { + // Nothing to do for the hoverer since it is all software at pre-step action time. + } + + // Usually called when target velocity changes to set the current velocity and the target + // into the movement motor. + public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime) + { + m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate() + { + if (m_velocityMotor != null) + { +// if (targ == OMV.Vector3.Zero) +// Util.PrintCallStack(); +// +// Console.WriteLine("SetVelocityAndTarget, {0} {1}", vel, targ); + m_velocityMotor.Reset(); + m_velocityMotor.SetTarget(targ); + m_velocityMotor.SetCurrent(vel); + m_velocityMotor.Enabled = true; + } + }); + } + + // If a hover motor has not been created, create one and start the hovering. + private void ActivateAvatarMove() + { + if (m_velocityMotor == null) + { + // Infinite decay and timescale values so motor only changes current to target values. + m_velocityMotor = new BSVMotor("BSCharacter.Velocity", + 0.2f, // time scale + BSMotor.Infinite, // decay time scale + 1f // efficiency + ); + m_velocityMotor.ErrorZeroThreshold = BSParam.AvatarStopZeroThreshold; + // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. + SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); + + m_physicsScene.BeforeStep += Mover; + m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty; + + m_walkingUpStairs = 0; + } + } + + private void DeactivateAvatarMove() + { + if (m_velocityMotor != null) + { + m_controllingPrim.OnPreUpdateProperty -= Process_OnPreUpdateProperty; + m_physicsScene.BeforeStep -= Mover; + m_velocityMotor = null; + } + } + + // Called just before the simulation step. Update the vertical position for hoverness. + private void Mover(float timeStep) + { + // Don't do movement while the object is selected. + if (!isActive) + return; + + // TODO: Decide if the step parameters should be changed depending on the avatar's + // state (flying, colliding, ...). There is code in ODE to do this. + + // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity + // specified for the avatar is the one that should be used. For falling, if the avatar + // is not flying and is not colliding then it is presumed to be falling and the Z + // component is not fooled with (thus allowing gravity to do its thing). + // When the avatar is standing, though, the user has specified a velocity of zero and + // the avatar should be standing. But if the avatar is pushed by something in the world + // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to + // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity + // errors can creap in and the avatar will slowly float off in some direction. + // So, the problem is that, when an avatar is standing, we cannot tell creaping error + // from real pushing. + // The code below uses whether the collider is static or moving to decide whether to zero motion. + + m_velocityMotor.Step(timeStep); + m_controllingPrim.IsStationary = false; + + // If we're not supposed to be moving, make sure things are zero. + if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero) + { + // The avatar shouldn't be moving + m_velocityMotor.Zero(); + + if (m_controllingPrim.IsColliding) + { + // If we are colliding with a stationary object, presume we're standing and don't move around + if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.ColliderIsVolumeDetect) + { + m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID); + m_controllingPrim.IsStationary = true; + m_controllingPrim.ZeroMotion(true /* inTaintTime */); + } + + // Standing has more friction on the ground + if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction) + { + m_controllingPrim.Friction = BSParam.AvatarStandingFriction; + m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); + } + } + else + { + if (m_controllingPrim.Flying) + { + // Flying and not colliding and velocity nearly zero. + m_controllingPrim.ZeroMotion(true /* inTaintTime */); + } + else + { + //We are falling but are not touching any keys make sure not falling too fast + if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity) + { + + OMV.Vector3 slowingForce = new OMV.Vector3(0f, 0f, BSParam.AvatarTerminalVelocity - m_controllingPrim.RawVelocity.Z) * m_controllingPrim.Mass; + m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, slowingForce); + } + + } + } + + m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", + m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding); + } + else + { + // Supposed to be moving. + OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue; + + if (m_controllingPrim.Friction != BSParam.AvatarFriction) + { + // Probably starting to walk. Set friction to moving friction. + m_controllingPrim.Friction = BSParam.AvatarFriction; + m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); + } + + if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) + { + stepVelocity.Z = m_controllingPrim.RawVelocity.Z; + } + + // Colliding and not flying with an upward force. The avatar must be trying to jump. + if (!m_controllingPrim.Flying && m_controllingPrim.IsColliding && stepVelocity.Z > 0) + { + // We allow the upward force to happen for this many frames. + m_jumpFrames = BSParam.AvatarJumpFrames; + m_jumpVelocity = stepVelocity.Z; + } + + // The case where the avatar is not colliding and is not flying is special. + // The avatar is either falling or jumping and the user can be applying force to the avatar + // (force in some direction or force up or down). + // If the avatar has negative Z velocity and is not colliding, presume we're falling and keep the velocity. + // If the user is trying to apply upward force but we're not colliding, assume the avatar + // is trying to jump and don't apply the upward force if not touching the ground any more. + if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) + { + // If upward velocity is being applied, this must be a jump and only allow that to go on so long + if (m_jumpFrames > 0) + { + // Since not touching the ground, only apply upward force for so long. + m_jumpFrames--; + stepVelocity.Z = m_jumpVelocity; + } + else + { + + // Since we're not affected by anything, the avatar must be falling and we do not want that to be too fast. + if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity) + { + + stepVelocity.Z = BSParam.AvatarTerminalVelocity; + } + else + { + stepVelocity.Z = m_controllingPrim.RawVelocity.Z; + } + } + // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); + } + + //Alicia: Maintain minimum height when flying. + // SL has a flying effect that keeps the avatar flying above the ground by some margin + if (m_controllingPrim.Flying) + { + float hover_height = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition) + + BSParam.AvatarFlyingGroundMargin; + + if( m_controllingPrim.Position.Z < hover_height) + { + stepVelocity.Z += BSParam.AvatarFlyingGroundUpForce; + } + } + + // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. + OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass; + + // Add special movement force to allow avatars to walk up stepped surfaces. + moveForce += WalkUpStairs(); + + m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", + m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce); + m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce); + } + } + + // Called just as the property update is received from the physics engine. + // Do any mode necessary for avatar movement. + private void Process_OnPreUpdateProperty(ref EntityProperties entprop) + { + // Don't change position if standing on a stationary object. + if (m_controllingPrim.IsStationary) + { + entprop.Position = m_controllingPrim.RawPosition; + entprop.Velocity = OMV.Vector3.Zero; + m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation); + } + + } + + // Decide if the character is colliding with a low object and compute a force to pop the + // avatar up so it can walk up and over the low objects. + private OMV.Vector3 WalkUpStairs() + { + OMV.Vector3 ret = OMV.Vector3.Zero; + + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}", + m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying, + m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z); + + // Check for stairs climbing if colliding, not flying and moving forward + if ( m_controllingPrim.IsColliding + && !m_controllingPrim.Flying + && m_controllingPrim.TargetVelocitySpeed > 0.1f ) + { + // The range near the character's feet where we will consider stairs + // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f; + // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off + // from the height. Revisit size and this computation when height is scaled properly. + float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - BSParam.AvatarStepGroundFudge; + float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; + + // Look for a collision point that is near the character's feet and is oriented the same as the charactor is. + // Find the highest 'good' collision. + OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero; + foreach (KeyValuePair kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList) + { + // Don't care about collisions with the terrain + if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID) + { + BSPhysObject collisionObject; + if (m_physicsScene.PhysObjects.TryGetValue(kvp.Key, out collisionObject)) + { + if (!collisionObject.IsVolumeDetect) + { + OMV.Vector3 touchPosition = kvp.Value.Position; + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", + m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); + if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) + { + // This contact is within the 'near the feet' range. + // The step is presumed to be more or less vertical. Thus the Z component should + // be nearly horizontal. + OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation; + OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); + const float PIOver2 = 1.571f; // Used to make unit vector axis into approx radian angles + // m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,avNormal={1},colNormal={2},diff={3}", + // m_controllingPrim.LocalID, directionFacing, touchNormal, + // Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)) ); + if ((Math.Abs(directionFacing.Z) * PIOver2) < BSParam.AvatarStepAngle + && (Math.Abs(touchNormal.Z) * PIOver2) < BSParam.AvatarStepAngle) + { + // The normal should be our contact point to the object so it is pointing away + // thus the difference between our facing orientation and the normal should be small. + float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); + if (diff < BSParam.AvatarStepApproachFactor) + { + if (highestTouchPosition.Z < touchPosition.Z) + highestTouchPosition = touchPosition; + } + } + } + } + } + } + } + m_walkingUpStairs = 0; + // If there is a good step sensing, move the avatar over the step. + if (highestTouchPosition != OMV.Vector3.Zero) + { + // Remember that we are going up stairs. This is needed because collisions + // will stop when we move up so this smoothes out that effect. + m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps; + + m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin; + ret = ComputeStairCorrection(m_lastStepUp); + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}", + m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret); + } + } + else + { + // If we used to be going up stairs but are not now, smooth the case where collision goes away while + // we are bouncing up the stairs. + if (m_walkingUpStairs > 0) + { + m_walkingUpStairs--; + ret = ComputeStairCorrection(m_lastStepUp); + } + } + + return ret; + } + + private OMV.Vector3 ComputeStairCorrection(float stepUp) + { + OMV.Vector3 ret = OMV.Vector3.Zero; + OMV.Vector3 displacement = OMV.Vector3.Zero; + + if (stepUp > 0f) + { + // Found the stairs contact point. Push up a little to raise the character. + if (BSParam.AvatarStepForceFactor > 0f) + { + float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; + ret = new OMV.Vector3(0f, 0f, upForce); + } + + // Also move the avatar up for the new height + if (BSParam.AvatarStepUpCorrectionFactor > 0f) + { + // Move the avatar up related to the height of the collision + displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor); + m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; + } + else + { + if (BSParam.AvatarStepUpCorrectionFactor < 0f) + { + // Move the avatar up about the specified step height + displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight); + m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; + } + } + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,stepUp={1},isp={2},force={3}", + m_controllingPrim.LocalID, stepUp, displacement, ret); + + } + return ret; + } +} +} + + diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs new file mode 100755 index 0000000..7ff171e --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs @@ -0,0 +1,174 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenSim.Region.PhysicsModules.SharedBase; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public class BSActorHover : BSActor +{ + private BSFMotor m_hoverMotor; + + public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_hoverMotor = null; + m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID); + } + + // BSActor.isActive + public override bool isActive + { + get { return Enabled; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() + { + Enabled = false; + DeactivateHover(); + } + + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() + { + m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID); + + // If not active any more, turn me off + if (!m_controllingPrim.HoverActive) + { + SetEnabled(false); + } + + // If the object is physically active, add the hoverer prestep action + if (isActive) + { + ActivateHover(); + } + else + { + DeactivateHover(); + } + } + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveDependencies() + public override void RemoveDependencies() + { + // Nothing to do for the hoverer since it is all software at pre-step action time. + } + + // If a hover motor has not been created, create one and start the hovering. + private void ActivateHover() + { + if (m_hoverMotor == null) + { + // Turning the target on + m_hoverMotor = new BSFMotor("BSActorHover", + m_controllingPrim.HoverTau, // timeScale + BSMotor.Infinite, // decay time scale + 1f // efficiency + ); + m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); + m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z); + m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. + + m_physicsScene.BeforeStep += Hoverer; + } + } + + private void DeactivateHover() + { + if (m_hoverMotor != null) + { + m_physicsScene.BeforeStep -= Hoverer; + m_hoverMotor = null; + } + } + + // Called just before the simulation step. Update the vertical position for hoverness. + private void Hoverer(float timeStep) + { + // Don't do hovering while the object is selected. + if (!isActive) + return; + + m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z); + m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); + float targetHeight = m_hoverMotor.Step(timeStep); + + // 'targetHeight' is where we'd like the Z of the prim to be at this moment. + // Compute the amount of force to push us there. + float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass; + // Undo anything the object thinks it's doing at the moment + moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass; + + m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce)); + m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", + m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass); + } + + // Based on current position, determine what we should be hovering at now. + // Must recompute often. What if we walked offa cliff> + private float ComputeCurrentHoverHeight() + { + float ret = m_controllingPrim.HoverHeight; + float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition); + + switch (m_controllingPrim.HoverType) + { + case PIDHoverType.Ground: + ret = groundHeight + m_controllingPrim.HoverHeight; + break; + case PIDHoverType.GroundAndWater: + float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition); + if (groundHeight > waterHeight) + { + ret = groundHeight + m_controllingPrim.HoverHeight; + } + else + { + ret = waterHeight + m_controllingPrim.HoverHeight; + } + break; + } + return ret; + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs new file mode 100755 index 0000000..78c1b6a --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs @@ -0,0 +1,219 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public class BSActorLockAxis : BSActor +{ + private BSConstraint LockAxisConstraint = null; + private bool HaveRegisteredForBeforeStepCallback = false; + + // The lock access flags (which axises were locked) when the contraint was built. + // Used to see if locking has changed since when the constraint was built. + OMV.Vector3 LockAxisLinearFlags; + OMV.Vector3 LockAxisAngularFlags; + + public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID); + LockAxisConstraint = null; + HaveRegisteredForBeforeStepCallback = false; + } + + // BSActor.isActive + public override bool isActive + { + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() + { + Enabled = false; + UnRegisterForBeforeStepCallback(); + RemoveAxisLockConstraint(); + } + + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() + { + // Since the axis logging is done with a constraint, Refresh() time is good for + // changing parameters but this needs to wait until the prim/linkset is physically + // constructed. Therefore, the constraint itself is placed at pre-step time. + + // If all the axis are free, we don't need to exist + // Refresh() only turns off. Enabling is done by InitializeAxisActor() + // whenever parameters are changed. + // This leaves 'enable' free to turn off an actor when it is not wanted to run. + if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree + && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree) + { + Enabled = false; + } + + if (isActive) + { + RegisterForBeforeStepCallback(); + } + else + { + RemoveDependencies(); + UnRegisterForBeforeStepCallback(); + } + } + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveDependencies() + public override void RemoveDependencies() + { + RemoveAxisLockConstraint(); + } + + private void RegisterForBeforeStepCallback() + { + if (!HaveRegisteredForBeforeStepCallback) + { + m_physicsScene.BeforeStep += PhysicsScene_BeforeStep; + HaveRegisteredForBeforeStepCallback = true; + } + } + + private void UnRegisterForBeforeStepCallback() + { + if (HaveRegisteredForBeforeStepCallback) + { + m_physicsScene.BeforeStep -= PhysicsScene_BeforeStep; + HaveRegisteredForBeforeStepCallback = false; + } + } + + private void PhysicsScene_BeforeStep(float timestep) + { + // If all the axis are free, we don't need to exist + if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree + && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree) + { + Enabled = false; + } + + // If the object is physically active, add the axis locking constraint + if (isActive) + { + // Check to see if the locking parameters have changed + if (m_controllingPrim.LockedLinearAxis != this.LockAxisLinearFlags + || m_controllingPrim.LockedAngularAxis != this.LockAxisAngularFlags) + { + // The locking has changed. Remove the old constraint and build a new one + RemoveAxisLockConstraint(); + } + + AddAxisLockConstraint(); + } + else + { + RemoveAxisLockConstraint(); + } + } + + // Note that this relies on being called at TaintTime + private void AddAxisLockConstraint() + { + if (LockAxisConstraint == null) + { + // Lock that axis by creating a 6DOF constraint that has one end in the world and + // the other in the object. + // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 + // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 + + // Remove any existing axis constraint (just to be sure) + RemoveAxisLockConstraint(); + + BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody, + OMV.Vector3.Zero, OMV.Quaternion.Identity, + false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */); + LockAxisConstraint = axisConstrainer; + m_physicsScene.Constraints.AddConstraint(LockAxisConstraint); + + // Remember the clocking being inforced so we can notice if they have changed + LockAxisLinearFlags = m_controllingPrim.LockedLinearAxis; + LockAxisAngularFlags = m_controllingPrim.LockedAngularAxis; + + // The constraint is tied to the world and oriented to the prim. + + if (!axisConstrainer.SetLinearLimits(m_controllingPrim.LockedLinearAxisLow, m_controllingPrim.LockedLinearAxisHigh)) + { + m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetLinearLimits", + m_controllingPrim.LocalID); + } + + if (!axisConstrainer.SetAngularLimits(m_controllingPrim.LockedAngularAxisLow, m_controllingPrim.LockedAngularAxisHigh)) + { + m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", + m_controllingPrim.LocalID); + } + + m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", + m_controllingPrim.LocalID, + m_controllingPrim.LockedLinearAxisLow, + m_controllingPrim.LockedLinearAxisHigh, + m_controllingPrim.LockedAngularAxisLow, + m_controllingPrim.LockedAngularAxisHigh); + + // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. + axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); + + axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass); + + RegisterForBeforeStepCallback(); + } + } + + private void RemoveAxisLockConstraint() + { + UnRegisterForBeforeStepCallback(); + if (LockAxisConstraint != null) + { + m_physicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint); + LockAxisConstraint = null; + m_physicsScene.DetailLog("{0},BSActorLockAxis.RemoveAxisLockConstraint,destroyingConstraint", m_controllingPrim.LocalID); + } + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs new file mode 100755 index 0000000..3db8f2c --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs @@ -0,0 +1,220 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenSim.Region.PhysicsModules.SharedBase; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public class BSActorMoveToTarget : BSActor +{ + private BSVMotor m_targetMotor; + + public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_targetMotor = null; + m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID); + } + + // BSActor.isActive + public override bool isActive + { + // MoveToTarget only works on physical prims + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() + { + Enabled = false; + DeactivateMoveToTarget(); + } + + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() + { + m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}", + m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive, + m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau ); + + // If not active any more... + if (!m_controllingPrim.MoveToTargetActive) + { + Enabled = false; + } + + if (isActive) + { + ActivateMoveToTarget(); + } + else + { + DeactivateMoveToTarget(); + } + } + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveDependencies() + public override void RemoveDependencies() + { + // Nothing to do for the moveToTarget since it is all software at pre-step action time. + } + + // If a hover motor has not been created, create one and start the hovering. + private void ActivateMoveToTarget() + { + if (m_targetMotor == null) + { + // We're taking over after this. + m_controllingPrim.ZeroMotion(true); + + /* Someday use the PID controller + m_targetMotor = new BSPIDVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString()); + m_targetMotor.TimeScale = m_controllingPrim.MoveToTargetTau; + m_targetMotor.Efficiency = 1f; + */ + m_targetMotor = new BSVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString(), + m_controllingPrim.MoveToTargetTau, // timeScale + BSMotor.Infinite, // decay time scale + 1f // efficiency + ); + m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. + m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); + m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); + + // m_physicsScene.BeforeStep += Mover; + m_physicsScene.BeforeStep += Mover2; + } + else + { + // If already allocated, make sure the target and other paramters are current + m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); + m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); + } + } + + private void DeactivateMoveToTarget() + { + if (m_targetMotor != null) + { + // m_physicsScene.BeforeStep -= Mover; + m_physicsScene.BeforeStep -= Mover2; + m_targetMotor = null; + } + } + + // Origional mover that set the objects position to move to the target. + // The problem was that gravity would keep trying to push the object down so + // the overall downward velocity would increase to infinity. + // Called just before the simulation step. + private void Mover(float timeStep) + { + // Don't do hovering while the object is selected. + if (!isActive) + return; + + OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) + + // 'movePosition' is where we'd like the prim to be at this moment. + OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep); + + // If we are very close to our target, turn off the movement motor. + if (m_targetMotor.ErrorIsZero()) + { + m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}", + m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass); + m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; + m_controllingPrim.ForceVelocity = OMV.Vector3.Zero; + // Setting the position does not cause the physics engine to generate a property update. Force it. + m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); + } + else + { + m_controllingPrim.ForcePosition = movePosition; + // Setting the position does not cause the physics engine to generate a property update. Force it. + m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); + } + m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", + m_controllingPrim.LocalID, origPosition, movePosition); + } + + // Version of mover that applies forces to move the physical object to the target. + // Also overcomes gravity so the object doesn't just drop to the ground. + // Called just before the simulation step. + private void Mover2(float timeStep) + { + // Don't do hovering while the object is selected. + if (!isActive) + return; + + OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) + OMV.Vector3 addedForce = OMV.Vector3.Zero; + + // CorrectionVector is the movement vector required this step + OMV.Vector3 correctionVector = m_targetMotor.Step(timeStep, m_controllingPrim.RawPosition); + + // If we are very close to our target, turn off the movement motor. + if (m_targetMotor.ErrorIsZero()) + { + m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,zeroMovement,pos={1},mass={2}", + m_controllingPrim.LocalID, m_controllingPrim.RawPosition, m_controllingPrim.Mass); + m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; + m_controllingPrim.ForceVelocity = OMV.Vector3.Zero; + // Setting the position does not cause the physics engine to generate a property update. Force it. + m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); + } + else + { + // First force to move us there -- the motor return a timestep scaled value. + addedForce = correctionVector / timeStep; + // Remove the existing velocity (only the moveToTarget force counts) + addedForce -= m_controllingPrim.RawVelocity; + // Overcome gravity. + addedForce -= m_controllingPrim.Gravity; + + // Add enough force to overcome the mass of the object + addedForce *= m_controllingPrim.Mass; + + m_controllingPrim.AddForce(addedForce, false /* pushForce */, true /* inTaintTime */); + } + m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,move,fromPos={1},addedForce={2}", + m_controllingPrim.LocalID, origPosition, addedForce); + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs new file mode 100755 index 0000000..ecb4b7f --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs @@ -0,0 +1,138 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenSim.Region.PhysicsModules.SharedBase; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public class BSActorSetForce : BSActor +{ + BSFMotor m_forceMotor; + + public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_forceMotor = null; + m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID); + } + + // BSActor.isActive + public override bool isActive + { + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() + { + Enabled = false; + DeactivateSetForce(); + } + + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() + { + m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID); + + // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) + if (m_controllingPrim.RawForce == OMV.Vector3.Zero) + { + m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName); + Enabled = false; + return; + } + + // If the object is physically active, add the hoverer prestep action + if (isActive) + { + ActivateSetForce(); + } + else + { + DeactivateSetForce(); + } + } + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveDependencies() + public override void RemoveDependencies() + { + // Nothing to do for the hoverer since it is all software at pre-step action time. + } + + // If a hover motor has not been created, create one and start the hovering. + private void ActivateSetForce() + { + if (m_forceMotor == null) + { + // A fake motor that might be used someday + m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f); + + m_physicsScene.BeforeStep += Mover; + } + } + + private void DeactivateSetForce() + { + if (m_forceMotor != null) + { + m_physicsScene.BeforeStep -= Mover; + m_forceMotor = null; + } + } + + // Called just before the simulation step. Update the vertical position for hoverness. + private void Mover(float timeStep) + { + // Don't do force while the object is selected. + if (!isActive) + return; + + m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce); + if (m_controllingPrim.PhysBody.HasPhysicalBody) + { + m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce); + m_controllingPrim.ActivateIfPhysical(false); + } + + // TODO: + } +} +} + diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs new file mode 100755 index 0000000..a1cf4db --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs @@ -0,0 +1,139 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenSim.Region.PhysicsModules.SharedBase; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public class BSActorSetTorque : BSActor +{ + BSFMotor m_torqueMotor; + + public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_torqueMotor = null; + m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID); + } + + // BSActor.isActive + public override bool isActive + { + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() + { + Enabled = false; + DeactivateSetTorque(); + } + + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() + { + m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); + + // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) + if (m_controllingPrim.RawTorque == OMV.Vector3.Zero) + { + m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName); + Enabled = false; + return; + } + + // If the object is physically active, add the hoverer prestep action + if (isActive) + { + ActivateSetTorque(); + } + else + { + DeactivateSetTorque(); + } + } + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveDependencies() + public override void RemoveDependencies() + { + // Nothing to do for the hoverer since it is all software at pre-step action time. + } + + // If a hover motor has not been created, create one and start the hovering. + private void ActivateSetTorque() + { + if (m_torqueMotor == null) + { + // A fake motor that might be used someday + m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f); + + m_physicsScene.BeforeStep += Mover; + } + } + + private void DeactivateSetTorque() + { + if (m_torqueMotor != null) + { + m_physicsScene.BeforeStep -= Mover; + m_torqueMotor = null; + } + } + + // Called just before the simulation step. Update the vertical position for hoverness. + private void Mover(float timeStep) + { + // Don't do force while the object is selected. + if (!isActive) + return; + + m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); + if (m_controllingPrim.PhysBody.HasPhysicalBody) + { + m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true); + m_controllingPrim.ActivateIfPhysical(false); + } + + // TODO: + } +} +} + + diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs new file mode 100755 index 0000000..851347b --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs @@ -0,0 +1,154 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public class BSActorCollection +{ + private Dictionary m_actors; + + public BSActorCollection() + { + m_actors = new Dictionary(); + } + public void Add(string name, BSActor actor) + { + lock (m_actors) + { + if (!m_actors.ContainsKey(name)) + { + m_actors[name] = actor; + } + } + } + public bool RemoveAndRelease(string name) + { + bool ret = false; + lock (m_actors) + { + if (m_actors.ContainsKey(name)) + { + BSActor beingRemoved = m_actors[name]; + m_actors.Remove(name); + beingRemoved.Dispose(); + ret = true; + } + } + return ret; + } + public void Clear() + { + lock (m_actors) + { + ForEachActor(a => a.Dispose()); + m_actors.Clear(); + } + } + public void Dispose() + { + Clear(); + } + public bool HasActor(string name) + { + return m_actors.ContainsKey(name); + } + public bool TryGetActor(string actorName, out BSActor theActor) + { + return m_actors.TryGetValue(actorName, out theActor); + } + public void ForEachActor(Action act) + { + lock (m_actors) + { + foreach (KeyValuePair kvp in m_actors) + act(kvp.Value); + } + } + + public void Enable(bool enabl) + { + ForEachActor(a => a.SetEnabled(enabl)); + } + public void Refresh() + { + ForEachActor(a => a.Refresh()); + } + public void RemoveDependencies() + { + ForEachActor(a => a.RemoveDependencies()); + } +} + +// ============================================================================= +/// +/// Each physical object can have 'actors' who are pushing the object around. +/// This can be used for hover, locking axis, making vehicles, etc. +/// Each physical object can have multiple actors acting on it. +/// +/// An actor usually registers itself with physics scene events (pre-step action) +/// and modifies the parameters on the host physical object. +/// +public abstract class BSActor +{ + protected BSScene m_physicsScene { get; private set; } + protected BSPhysObject m_controllingPrim { get; private set; } + public virtual bool Enabled { get; set; } + public string ActorName { get; private set; } + + public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName) + { + m_physicsScene = physicsScene; + m_controllingPrim = pObj; + ActorName = actorName; + Enabled = true; + } + + // Return 'true' if activily updating the prim + public virtual bool isActive + { + get { return Enabled; } + } + + // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled. + // Anyone else should assign true/false to 'Enabled'. + public void SetEnabled(bool setEnabled) + { + Enabled = setEnabled; + } + // Release any connections and resources used by the actor. + public abstract void Dispose(); + // Called when physical parameters (properties set in Bullet) need to be re-applied. + public abstract void Refresh(); + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + public abstract void RemoveDependencies(); + +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs new file mode 100644 index 0000000..7756b10 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs @@ -0,0 +1,763 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS { + + // Constraint type values as defined by Bullet +public enum ConstraintType : int +{ + POINT2POINT_CONSTRAINT_TYPE = 3, + HINGE_CONSTRAINT_TYPE, + CONETWIST_CONSTRAINT_TYPE, + D6_CONSTRAINT_TYPE, + SLIDER_CONSTRAINT_TYPE, + CONTACT_CONSTRAINT_TYPE, + D6_SPRING_CONSTRAINT_TYPE, + GEAR_CONSTRAINT_TYPE, // added in Bullet 2.82 + FIXED_CONSTRAINT_TYPE, // added in Bullet 2.82 + MAX_CONSTRAINT_TYPE, // last type defined by Bullet + // + BS_FIXED_CONSTRAINT_TYPE = 1234 // BulletSim constraint that is fixed and unmoving +} + +// =============================================================================== +[StructLayout(LayoutKind.Sequential)] +public struct ConvexHull +{ + Vector3 Offset; + int VertexCount; + Vector3[] Vertices; +} +public enum BSPhysicsShapeType +{ + SHAPE_UNKNOWN = 0, + SHAPE_CAPSULE = 1, + SHAPE_BOX = 2, + SHAPE_CONE = 3, + SHAPE_CYLINDER = 4, + SHAPE_SPHERE = 5, + SHAPE_MESH = 6, + SHAPE_HULL = 7, + // following defined by BulletSim + SHAPE_GROUNDPLANE = 20, + SHAPE_TERRAIN = 21, + SHAPE_COMPOUND = 22, + SHAPE_HEIGHTMAP = 23, + SHAPE_AVATAR = 24, + SHAPE_CONVEXHULL= 25, + SHAPE_GIMPACT = 26, +}; + +// The native shapes have predefined shape hash keys +public enum FixedShapeKey : ulong +{ + KEY_NONE = 0, + KEY_BOX = 1, + KEY_SPHERE = 2, + KEY_CONE = 3, + KEY_CYLINDER = 4, + KEY_CAPSULE = 5, + KEY_AVATAR = 6, +} + +[StructLayout(LayoutKind.Sequential)] +public struct ShapeData +{ + public UInt32 ID; + public BSPhysicsShapeType Type; + public Vector3 Position; + public Quaternion Rotation; + public Vector3 Velocity; + public Vector3 Scale; + public float Mass; + public float Buoyancy; + public System.UInt64 HullKey; + public System.UInt64 MeshKey; + public float Friction; + public float Restitution; + public float Collidable; // true of things bump into this + public float Static; // true if a static object. Otherwise gravity, etc. + public float Solid; // true if object cannot be passed through + public Vector3 Size; + + // note that bools are passed as floats since bool size changes by language and architecture + public const float numericTrue = 1f; + public const float numericFalse = 0f; +} +[StructLayout(LayoutKind.Sequential)] +public struct SweepHit +{ + public UInt32 ID; + public float Fraction; + public Vector3 Normal; + public Vector3 Point; +} +[StructLayout(LayoutKind.Sequential)] +public struct RaycastHit +{ + public UInt32 ID; + public float Fraction; + public Vector3 Normal; +} +[StructLayout(LayoutKind.Sequential)] +public struct CollisionDesc +{ + public UInt32 aID; + public UInt32 bID; + public Vector3 point; + public Vector3 normal; + public float penetration; +} +[StructLayout(LayoutKind.Sequential)] +public struct EntityProperties +{ + public UInt32 ID; + public Vector3 Position; + public Quaternion Rotation; + public Vector3 Velocity; + public Vector3 Acceleration; + public Vector3 RotationalVelocity; + + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + buff.Append(""); + return buff.ToString(); + } +} + +// Format of this structure must match the definition in the C++ code +// NOTE: adding the X causes compile breaks if used. These are unused symbols +// that can be removed from both here and the unmanaged definition of this structure. +[StructLayout(LayoutKind.Sequential)] +public struct ConfigurationParameters +{ + public float defaultFriction; + public float defaultDensity; + public float defaultRestitution; + public float collisionMargin; + public float gravity; + + public float maxPersistantManifoldPoolSize; + public float maxCollisionAlgorithmPoolSize; + public float shouldDisableContactPoolDynamicAllocation; + public float shouldForceUpdateAllAabbs; + public float shouldRandomizeSolverOrder; + public float shouldSplitSimulationIslands; + public float shouldEnableFrictionCaching; + public float numberOfSolverIterations; + public float useSingleSidedMeshes; + public float globalContactBreakingThreshold; + + public float physicsLoggingFrames; + + public const float numericTrue = 1f; + public const float numericFalse = 0f; +} + +// Parameters passed for the conversion of a mesh to a hull using Bullet's HACD library. +[StructLayout(LayoutKind.Sequential)] +public struct HACDParams +{ + // usual default values + public float maxVerticesPerHull; // 100 + public float minClusters; // 2 + public float compacityWeight; // 0.1 + public float volumeWeight; // 0.0 + public float concavity; // 100 + public float addExtraDistPoints; // false + public float addNeighboursDistPoints; // false + public float addFacesPoints; // false + public float shouldAdjustCollisionMargin; // false + // VHACD + public float whichHACD; // zero if Bullet HACD, non-zero says VHACD + // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html + public float vHACDresolution; // 100,000 max number of voxels generated during voxelization stage + public float vHACDdepth; // 20 max number of clipping stages + public float vHACDconcavity; // 0.0025 maximum concavity + public float vHACDplaneDownsampling; // 4 granularity of search for best clipping plane + public float vHACDconvexHullDownsampling; // 4 precision of hull gen process + public float vHACDalpha; // 0.05 bias toward clipping along symmetry planes + public float vHACDbeta; // 0.05 bias toward clipping along revolution axis + public float vHACDgamma; // 0.00125 max concavity when merging + public float vHACDpca; // 0 on/off normalizing mesh before decomp + public float vHACDmode; // 0 0:voxel based, 1: tetrahedron based + public float vHACDmaxNumVerticesPerCH; // 64 max triangles per convex hull + public float vHACDminVolumePerCH; // 0.0001 sampling of generated convex hulls +} + +// The states a bullet collision object can have +public enum ActivationState : uint +{ + ACTIVE_TAG = 1, + ISLAND_SLEEPING, + WANTS_DEACTIVATION, + DISABLE_DEACTIVATION, + DISABLE_SIMULATION, +} + +public enum CollisionObjectTypes : int +{ + CO_COLLISION_OBJECT = 1 << 0, + CO_RIGID_BODY = 1 << 1, + CO_GHOST_OBJECT = 1 << 2, + CO_SOFT_BODY = 1 << 3, + CO_HF_FLUID = 1 << 4, + CO_USER_TYPE = 1 << 5, +} + +// Values used by Bullet and BulletSim to control object properties. +// Bullet's "CollisionFlags" has more to do with operations on the +// object (if collisions happen, if gravity effects it, ...). +public enum CollisionFlags : uint +{ + CF_STATIC_OBJECT = 1 << 0, + CF_KINEMATIC_OBJECT = 1 << 1, + CF_NO_CONTACT_RESPONSE = 1 << 2, + CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3, + CF_CHARACTER_OBJECT = 1 << 4, + CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, + CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, + // Following used by BulletSim to control collisions and updates + BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed + BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level + BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking + BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape + BS_NONE = 0, + BS_ALL = 0x7FFF // collision flags are a signed short +}; + +// Values f collisions groups and masks +public enum CollisionFilterGroups : uint +{ + // Don't use the bit definitions!! Define the use in a + // filter/mask definition below. This way collision interactions + // are more easily found and debugged. + BNoneGroup = 0, + BDefaultGroup = 1 << 0, // 0001 + BStaticGroup = 1 << 1, // 0002 + BKinematicGroup = 1 << 2, // 0004 + BDebrisGroup = 1 << 3, // 0008 + BSensorTrigger = 1 << 4, // 0010 + BCharacterGroup = 1 << 5, // 0020 + BAllGroup = 0x0007FFF, // collision flags are a signed short + // Filter groups defined by BulletSim + BGroundPlaneGroup = 1 << 8, // 0400 + BTerrainGroup = 1 << 9, // 0800 + BRaycastGroup = 1 << 10, // 1000 + BSolidGroup = 1 << 11, // 2000 + // BLinksetGroup = xx // a linkset proper is either static or dynamic + BLinksetChildGroup = 1 << 12, // 4000 +}; + +// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 +// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. +public enum ConstraintParams : int +{ + BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730 + BT_CONSTRAINT_STOP_ERP, + BT_CONSTRAINT_CFM, + BT_CONSTRAINT_STOP_CFM, +}; +public enum ConstraintParamAxis : int +{ + AXIS_LINEAR_X = 0, + AXIS_LINEAR_Y, + AXIS_LINEAR_Z, + AXIS_ANGULAR_X, + AXIS_ANGULAR_Y, + AXIS_ANGULAR_Z, + AXIS_LINEAR_ALL = 20, // added by BulletSim so we don't have to do zillions of calls + AXIS_ANGULAR_ALL, + AXIS_ALL +}; + +public abstract class BSAPITemplate +{ +// Returns the name of the underlying Bullet engine +public abstract string BulletEngineName { get; } +public abstract string BulletEngineVersion { get; protected set;} + +// Initialization and simulation +public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, + int maxCollisions, ref CollisionDesc[] collisionArray, + int maxUpdates, ref EntityProperties[] updateArray + ); + +public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, + out int updatedEntityCount, out int collidersCount); + +public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value); + +public abstract void Shutdown(BulletWorld sim); + +public abstract bool PushUpdate(BulletBody obj); + +// ===================================================================================== +// Mesh, hull, shape and body creation helper routines +public abstract BulletShape CreateMeshShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices ); + +public abstract BulletShape CreateGImpactShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices ); + +public abstract BulletShape CreateHullShape(BulletWorld world, + int hullCount, float[] hulls); + +public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms); + +public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape); + +public abstract BulletShape CreateConvexHullShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices ); + +public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); + +public abstract bool IsNativeShape(BulletShape shape); + +public abstract void SetShapeCollisionMargin(BulletShape shape, float margin); + +public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale); + +public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree); + +public abstract int GetNumberOfCompoundChildren(BulletShape cShape); + +public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot); + +public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); + +public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); + +public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape); + +public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb); + +public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape); + +public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id); + +public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape); + +public abstract CollisionObjectTypes GetBodyType(BulletBody obj); + +public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); + +public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); + +public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); + +public abstract void DestroyObject(BulletWorld sim, BulletBody obj); + +// ===================================================================================== +public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); + +public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, + float scaleFactor, float collisionMargin); + +// ===================================================================================== +// Constraint creation and helper routines +public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + +public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 joinPoint, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + +public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, + Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); + +public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + +public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 pivotinA, Vector3 pivotinB, + Vector3 axisInA, Vector3 axisInB, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + +public abstract BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + +public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool disableCollisionsBetweenLinkedBodies); + +public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 axisInA, Vector3 axisInB, + float ratio, bool disableCollisionsBetweenLinkedBodies); + +public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 pivotInA, Vector3 pivotInB, + bool disableCollisionsBetweenLinkedBodies); + +public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse); + +public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations); + +public abstract bool SetFrames(BulletConstraint constrain, + Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); + +public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); + +public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); + +public abstract bool UseFrameOffset(BulletConstraint constrain, float enable); + +public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce); + +public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold); + +public const int HINGE_NOT_SPECIFIED = -1; +public abstract bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation); + +public abstract bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse); + +public const int SPRING_NOT_SPECIFIED = -1; +public abstract bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint); + +public abstract bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss); + +public abstract bool SpringSetDamping(BulletConstraint constrain, int index, float damping); + +public const int SLIDER_LOWER_LIMIT = 0; +public const int SLIDER_UPPER_LIMIT = 1; +public const int SLIDER_LINEAR = 2; +public const int SLIDER_ANGULAR = 3; +public abstract bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val); + +public const int SLIDER_SET_SOFTNESS = 4; +public const int SLIDER_SET_RESTITUTION = 5; +public const int SLIDER_SET_DAMPING = 6; +public const int SLIDER_SET_DIRECTION = 7; +public const int SLIDER_SET_LIMIT = 8; +public const int SLIDER_SET_ORTHO = 9; +public abstract bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val); + +public abstract bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse); + +public const int SLIDER_MOTOR_VELOCITY = 10; +public const int SLIDER_MAX_MOTOR_FORCE = 11; +public abstract bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val); + +public abstract bool CalculateTransforms(BulletConstraint constrain); + +public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); + +public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain); + +// ===================================================================================== +// btCollisionWorld entries +public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj); + +public abstract void UpdateAabbs(BulletWorld world); + +public abstract bool GetForceUpdateAllAabbs(BulletWorld world); + +public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force); + +// ===================================================================================== +// btDynamicsWorld entries +// public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot); +public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj); + +public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj); + +public abstract bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj); + +public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects); + +public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain); +// ===================================================================================== +// btCollisionObject entries +public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain); + +public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict); + +public abstract bool HasAnisotripicFriction(BulletConstraint constrain); + +public abstract void SetContactProcessingThreshold(BulletBody obj, float val); + +public abstract float GetContactProcessingThreshold(BulletBody obj); + +public abstract bool IsStaticObject(BulletBody obj); + +public abstract bool IsKinematicObject(BulletBody obj); + +public abstract bool IsStaticOrKinematicObject(BulletBody obj); + +public abstract bool HasContactResponse(BulletBody obj); + +public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape); + +public abstract BulletShape GetCollisionShape(BulletBody obj); + +public abstract int GetActivationState(BulletBody obj); + +public abstract void SetActivationState(BulletBody obj, int state); + +public abstract void SetDeactivationTime(BulletBody obj, float dtime); + +public abstract float GetDeactivationTime(BulletBody obj); + +public abstract void ForceActivationState(BulletBody obj, ActivationState state); + +public abstract void Activate(BulletBody obj, bool forceActivation); + +public abstract bool IsActive(BulletBody obj); + +public abstract void SetRestitution(BulletBody obj, float val); + +public abstract float GetRestitution(BulletBody obj); + +public abstract void SetFriction(BulletBody obj, float val); + +public abstract float GetFriction(BulletBody obj); + +public abstract Vector3 GetPosition(BulletBody obj); + +public abstract Quaternion GetOrientation(BulletBody obj); + +public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation); + +// public abstract IntPtr GetBroadphaseHandle(BulletBody obj); + +// public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle); + +public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel); + +public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel); + +public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel); + +public abstract float GetHitFraction(BulletBody obj); + +public abstract void SetHitFraction(BulletBody obj, float val); + +public abstract CollisionFlags GetCollisionFlags(BulletBody obj); + +public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags); + +public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags); + +public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags); + +public abstract float GetCcdMotionThreshold(BulletBody obj); + +public abstract void SetCcdMotionThreshold(BulletBody obj, float val); + +public abstract float GetCcdSweptSphereRadius(BulletBody obj); + +public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val); + +public abstract IntPtr GetUserPointer(BulletBody obj); + +public abstract void SetUserPointer(BulletBody obj, IntPtr val); + +// ===================================================================================== +// btRigidBody entries +public abstract void ApplyGravity(BulletBody obj); + +public abstract void SetGravity(BulletBody obj, Vector3 val); + +public abstract Vector3 GetGravity(BulletBody obj); + +public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping); + +public abstract void SetLinearDamping(BulletBody obj, float lin_damping); + +public abstract void SetAngularDamping(BulletBody obj, float ang_damping); + +public abstract float GetLinearDamping(BulletBody obj); + +public abstract float GetAngularDamping(BulletBody obj); + +public abstract float GetLinearSleepingThreshold(BulletBody obj); + +public abstract void ApplyDamping(BulletBody obj, float timeStep); + +public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia); + +public abstract Vector3 GetLinearFactor(BulletBody obj); + +public abstract void SetLinearFactor(BulletBody obj, Vector3 factor); + +public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot); + +// Add a force to the object as if its mass is one. +public abstract void ApplyCentralForce(BulletBody obj, Vector3 force); + +// Set the force being applied to the object as if its mass is one. +public abstract void SetObjectForce(BulletBody obj, Vector3 force); + +public abstract Vector3 GetTotalForce(BulletBody obj); + +public abstract Vector3 GetTotalTorque(BulletBody obj); + +public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj); + +public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert); + +public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold); + +public abstract void ApplyTorque(BulletBody obj, Vector3 torque); + +// Apply force at the given point. Will add torque to the object. +public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos); + +// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. +public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp); + +// Apply impulse to the object's torque. Force is scaled by object's mass. +public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp); + +// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. +public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos); + +public abstract void ClearForces(BulletBody obj); + +public abstract void ClearAllForces(BulletBody obj); + +public abstract void UpdateInertiaTensor(BulletBody obj); + +public abstract Vector3 GetLinearVelocity(BulletBody obj); + +public abstract Vector3 GetAngularVelocity(BulletBody obj); + +public abstract void SetLinearVelocity(BulletBody obj, Vector3 val); + +public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity); + +public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos); + +public abstract void Translate(BulletBody obj, Vector3 trans); + +public abstract void UpdateDeactivation(BulletBody obj, float timeStep); + +public abstract bool WantsSleeping(BulletBody obj); + +public abstract void SetAngularFactor(BulletBody obj, float factor); + +public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor); + +public abstract Vector3 GetAngularFactor(BulletBody obj); + +public abstract bool IsInWorld(BulletWorld world, BulletBody obj); + +public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain); + +public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain); + +public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index); + +public abstract int GetNumConstraintRefs(BulletBody obj); + +public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask); + +// ===================================================================================== +// btCollisionShape entries + +public abstract float GetAngularMotionDisc(BulletShape shape); + +public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor); + +public abstract bool IsPolyhedral(BulletShape shape); + +public abstract bool IsConvex2d(BulletShape shape); + +public abstract bool IsConvex(BulletShape shape); + +public abstract bool IsNonMoving(BulletShape shape); + +public abstract bool IsConcave(BulletShape shape); + +public abstract bool IsCompound(BulletShape shape); + +public abstract bool IsSoftBody(BulletShape shape); + +public abstract bool IsInfinite(BulletShape shape); + +public abstract void SetLocalScaling(BulletShape shape, Vector3 scale); + +public abstract Vector3 GetLocalScaling(BulletShape shape); + +public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass); + +public abstract int GetShapeType(BulletShape shape); + +public abstract void SetMargin(BulletShape shape, float val); + +public abstract float GetMargin(BulletShape shape); + +// ===================================================================================== +// Debugging +public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { } + +public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { } + +public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { } + +public virtual void DumpActivationInfo(BulletWorld sim) { } + +public virtual void DumpAllInfo(BulletWorld sim) { } + +public virtual void DumpPhysicsStatistics(BulletWorld sim) { } + +public virtual void ResetBroadphasePool(BulletWorld sim) { } + +public virtual void ResetConstraintSolver(BulletWorld sim) { } + +}; +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs new file mode 100644 index 0000000..83fc3a6 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs @@ -0,0 +1,813 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Reflection; +using log4net; +using OMV = OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public sealed class BSCharacter : BSPhysObject +{ + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly string LogHeader = "[BULLETS CHAR]"; + + // private bool _stopped; + private OMV.Vector3 _size; + private bool _grabbed; + private bool _selected; + private float _mass; + private float _avatarVolume; + private float _collisionScore; + private OMV.Vector3 _acceleration; + private int _physicsActorType; + private bool _isPhysical; + private bool _flying; + private bool _setAlwaysRun; + private bool _throttleUpdates; + private bool _floatOnWater; + private OMV.Vector3 _rotationalVelocity; + private bool _kinematic; + private float _buoyancy; + + private BSActorAvatarMove m_moveActor; + private const string AvatarMoveActorName = "BSCharacter.AvatarMove"; + + private OMV.Vector3 _PIDTarget; + private float _PIDTau; + +// public override OMV.Vector3 RawVelocity +// { get { return base.RawVelocity; } +// set { +// if (value != base.RawVelocity) +// Util.PrintCallStack(); +// Console.WriteLine("Set rawvel to {0}", value); +// base.RawVelocity = value; } +// } + + // Avatars are always complete (in the physics engine sense) + public override bool IsIncomplete { get { return false; } } + + public BSCharacter( + uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, bool isFlying) + + : base(parent_scene, localID, avName, "BSCharacter") + { + _physicsActorType = (int)ActorTypes.Agent; + RawPosition = pos; + + _flying = isFlying; + RawOrientation = OMV.Quaternion.Identity; + RawVelocity = vel; + _buoyancy = ComputeBuoyancyFromFlying(isFlying); + Friction = BSParam.AvatarStandingFriction; + Density = BSParam.AvatarDensity; + + // Old versions of ScenePresence passed only the height. If width and/or depth are zero, + // replace with the default values. + _size = size; + if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; + if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; + + // The dimensions of the physical capsule are kept in the scale. + // Physics creates a unit capsule which is scaled by the physics engine. + Scale = ComputeAvatarScale(_size); + // set _avatarVolume and _mass based on capsule size, _density and Scale + ComputeAvatarVolumeAndMass(); + + DetailLog( + "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}", + LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos, vel); + + // do actual creation in taint time + PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate() + { + DetailLog("{0},BSCharacter.create,taint", LocalID); + + // New body and shape into PhysBody and PhysShape + PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this); + + // The avatar's movement is controlled by this motor that speeds up and slows down + // the avatar seeking to reach the motor's target speed. + // This motor runs as a prestep action for the avatar so it will keep the avatar + // standing as well as moving. Destruction of the avatar will destroy the pre-step action. + m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); + PhysicalActors.Add(AvatarMoveActorName, m_moveActor); + + SetPhysicalProperties(); + + IsInitialized = true; + }); + return; + } + + // called when this character is being destroyed and the resources should be released + public override void Destroy() + { + IsInitialized = false; + + base.Destroy(); + + DetailLog("{0},BSCharacter.Destroy", LocalID); + PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate() + { + PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); + PhysBody.Clear(); + PhysShape.Dereference(PhysScene); + PhysShape = new BSShapeNull(); + }); + } + + private void SetPhysicalProperties() + { + PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); + + ForcePosition = RawPosition; + + // Set the velocity + if (m_moveActor != null) + m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false); + + ForceVelocity = RawVelocity; + TargetVelocity = RawVelocity; + + // This will enable or disable the flying buoyancy of the avatar. + // Needs to be reset especially when an avatar is recreated after crossing a region boundry. + Flying = _flying; + + PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); + PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin); + PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); + PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); + if (BSParam.CcdMotionThreshold > 0f) + { + PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); + PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); + } + + UpdatePhysicalMassProperties(RawMass, false); + + // Make so capsule does not fall over + PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); + + // The avatar mover sets some parameters. + PhysicalActors.Refresh(); + + PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); + + PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); + + // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); + PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); + PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); + + // Do this after the object has been added to the world + if (BSParam.AvatarToAvatarCollisionsByDefault) + PhysBody.collisionType = CollisionType.Avatar; + else + PhysBody.collisionType = CollisionType.PhantomToOthersAvatar; + + PhysBody.ApplyCollisionMask(PhysScene); + } + + public override void RequestPhysicsterseUpdate() + { + base.RequestPhysicsterseUpdate(); + } + + // No one calls this method so I don't know what it could possibly mean + public override bool Stopped { get { return false; } } + + public override OMV.Vector3 Size { + get + { + // Avatar capsule size is kept in the scale parameter. + return _size; + } + + set { + // This is how much the avatar size is changing. Positive means getting bigger. + // The avatar altitude must be adjusted for this change. + float heightChange = value.Z - _size.Z; + + _size = value; + // Old versions of ScenePresence passed only the height. If width and/or depth are zero, + // replace with the default values. + if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; + if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; + + Scale = ComputeAvatarScale(_size); + ComputeAvatarVolumeAndMass(); + DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", + LocalID, _size, Scale, Density, _avatarVolume, RawMass); + + PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate() + { + if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) + { + PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); + UpdatePhysicalMassProperties(RawMass, true); + + // Adjust the avatar's position to account for the increase/decrease in size + ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f); + + // Make sure this change appears as a property update event + PhysScene.PE.PushUpdate(PhysBody); + } + }); + + } + } + + public override PrimitiveBaseShape Shape + { + set { BaseShape = value; } + } + + public override bool Grabbed { + set { _grabbed = value; } + } + public override bool Selected { + set { _selected = value; } + } + public override bool IsSelected + { + get { return _selected; } + } + public override void CrossingFailure() { return; } + public override void link(PhysicsActor obj) { return; } + public override void delink() { return; } + + // Set motion values to zero. + // Do it to the properties so the values get set in the physics engine. + // Push the setting of the values to the viewer. + // Called at taint time! + public override void ZeroMotion(bool inTaintTime) + { + RawVelocity = OMV.Vector3.Zero; + _acceleration = OMV.Vector3.Zero; + _rotationalVelocity = OMV.Vector3.Zero; + + // Zero some other properties directly into the physics engine + PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() + { + if (PhysBody.HasPhysicalBody) + PhysScene.PE.ClearAllForces(PhysBody); + }); + } + + public override void ZeroAngularMotion(bool inTaintTime) + { + _rotationalVelocity = OMV.Vector3.Zero; + + PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() + { + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); + PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); + // The next also get rid of applied linear force but the linear velocity is untouched. + PhysScene.PE.ClearForces(PhysBody); + } + }); + } + + + public override void LockAngularMotion(OMV.Vector3 axis) { return; } + + public override OMV.Vector3 Position { + get { + // Don't refetch the position because this function is called a zillion times + // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); + return RawPosition; + } + set { + RawPosition = value; + + PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate() + { + DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); + PositionSanityCheck(); + ForcePosition = RawPosition; + }); + } + } + public override OMV.Vector3 ForcePosition { + get { + RawPosition = PhysScene.PE.GetPosition(PhysBody); + return RawPosition; + } + set { + RawPosition = value; + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); + } + } + } + + + // Check that the current position is sane and, if not, modify the position to make it so. + // Check for being below terrain or on water. + // Returns 'true' of the position was made sane by some action. + private bool PositionSanityCheck() + { + bool ret = false; + + // TODO: check for out of bounds + if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) + { + // The character is out of the known/simulated area. + // Force the avatar position to be within known. ScenePresence will use the position + // plus the velocity to decide if the avatar is moving out of the region. + RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); + DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); + return true; + } + + // If below the ground, move the avatar up + float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); + if (Position.Z < terrainHeight) + { + DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); + RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters); + ret = true; + } + if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) + { + float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); + if (Position.Z < waterHeight) + { + RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight); + ret = true; + } + } + + return ret; + } + + // A version of the sanity check that also makes sure a new position value is + // pushed back to the physics engine. This routine would be used by anyone + // who is not already pushing the value. + private bool PositionSanityCheck(bool inTaintTime) + { + bool ret = false; + if (PositionSanityCheck()) + { + // The new position value must be pushed into the physics engine but we can't + // just assign to "Position" because of potential call loops. + PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate() + { + DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); + ForcePosition = RawPosition; + }); + ret = true; + } + return ret; + } + + public override float Mass { get { return _mass; } } + + // used when we only want this prim's mass and not the linkset thing + public override float RawMass { + get {return _mass; } + } + public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) + { + OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); + PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia); + } + + public override OMV.Vector3 Force { + get { return RawForce; } + set { + RawForce = value; + // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); + PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate() + { + DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); + if (PhysBody.HasPhysicalBody) + PhysScene.PE.SetObjectForce(PhysBody, RawForce); + }); + } + } + + // Avatars don't do vehicles + public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } } + public override void VehicleFloatParam(int param, float value) { } + public override void VehicleVectorParam(int param, OMV.Vector3 value) {} + public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } + public override void VehicleFlags(int param, bool remove) { } + + // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more + public override void SetVolumeDetect(int param) { return; } + public override bool IsVolumeDetect { get { return false; } } + + public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } + public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } + + // Sets the target in the motor. This starts the changing of the avatar's velocity. + public override OMV.Vector3 TargetVelocity + { + get + { + return base.m_targetVelocity; + } + set + { + DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); + m_targetVelocity = value; + OMV.Vector3 targetVel = value; + if (_setAlwaysRun && !_flying) + targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f); + + if (m_moveActor != null) + m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */); + } + } + // Directly setting velocity means this is what the user really wants now. + public override OMV.Vector3 Velocity { + get { return RawVelocity; } + set { + RawVelocity = value; + OMV.Vector3 vel = RawVelocity; + + DetailLog("{0}: set Velocity = {1}", LocalID, value); + + PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate() + { + if (m_moveActor != null) + m_moveActor.SetVelocityAndTarget(vel, vel, true /* inTaintTime */); + + DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, vel); + ForceVelocity = vel; + }); + } + } + + public override OMV.Vector3 ForceVelocity { + get { return RawVelocity; } + set { + PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity"); +// Util.PrintCallStack(); + DetailLog("{0}: set ForceVelocity = {1}", LocalID, value); + + RawVelocity = value; + PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); + PhysScene.PE.Activate(PhysBody, true); + } + } + + public override OMV.Vector3 Torque { + get { return RawTorque; } + set { RawTorque = value; + } + } + + public override float CollisionScore { + get { return _collisionScore; } + set { _collisionScore = value; + } + } + public override OMV.Vector3 Acceleration { + get { return _acceleration; } + set { _acceleration = value; } + } + public override OMV.Quaternion Orientation { + get { return RawOrientation; } + set { + // Orientation is set zillions of times when an avatar is walking. It's like + // the viewer doesn't trust us. + if (RawOrientation != value) + { + RawOrientation = value; + PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate() + { + // Bullet assumes we know what we are doing when forcing orientation + // so it lets us go against all the rules and just compensates for them later. + // This forces rotation to be only around the Z axis and doesn't change any of the other axis. + // This keeps us from flipping the capsule over which the veiwer does not understand. + float oRoll, oPitch, oYaw; + RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw); + OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw); + // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}", + // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation, + // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation); + ForceOrientation = trimmedOrientation; + }); + } + } + } + // Go directly to Bullet to get/set the value. + public override OMV.Quaternion ForceOrientation + { + get + { + RawOrientation = PhysScene.PE.GetOrientation(PhysBody); + return RawOrientation; + } + set + { + RawOrientation = value; + if (PhysBody.HasPhysicalBody) + { + // RawPosition = PhysicsScene.PE.GetPosition(BSBody); + PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); + } + } + } + public override int PhysicsActorType { + get { return _physicsActorType; } + set { _physicsActorType = value; + } + } + public override bool IsPhysical { + get { return _isPhysical; } + set { _isPhysical = value; + } + } + public override bool IsSolid { + get { return true; } + } + public override bool IsStatic { + get { return false; } + } + public override bool IsPhysicallyActive { + get { return true; } + } + public override bool Flying { + get { return _flying; } + set { + _flying = value; + + // simulate flying by changing the effect of gravity + Buoyancy = ComputeBuoyancyFromFlying(_flying); + } + } + // Flying is implimented by changing the avatar's buoyancy. + // Would this be done better with a vehicle type? + private float ComputeBuoyancyFromFlying(bool ifFlying) { + return ifFlying ? 1f : 0f; + } + public override bool + SetAlwaysRun { + get { return _setAlwaysRun; } + set { _setAlwaysRun = value; } + } + public override bool ThrottleUpdates { + get { return _throttleUpdates; } + set { _throttleUpdates = value; } + } + public override bool FloatOnWater { + set { + _floatOnWater = value; + PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate() + { + if (PhysBody.HasPhysicalBody) + { + if (_floatOnWater) + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); + else + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); + } + }); + } + } + public override OMV.Vector3 RotationalVelocity { + get { return _rotationalVelocity; } + set { _rotationalVelocity = value; } + } + public override OMV.Vector3 ForceRotationalVelocity { + get { return _rotationalVelocity; } + set { _rotationalVelocity = value; } + } + public override bool Kinematic { + get { return _kinematic; } + set { _kinematic = value; } + } + // neg=fall quickly, 0=1g, 1=0g, pos=float up + public override float Buoyancy { + get { return _buoyancy; } + set { _buoyancy = value; + PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate() + { + DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); + ForceBuoyancy = _buoyancy; + }); + } + } + public override float ForceBuoyancy { + get { return _buoyancy; } + set { + PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); + + _buoyancy = value; + DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); + // Buoyancy is faked by changing the gravity applied to the object + float grav = BSParam.Gravity * (1f - _buoyancy); + Gravity = new OMV.Vector3(0f, 0f, grav); + if (PhysBody.HasPhysicalBody) + PhysScene.PE.SetGravity(PhysBody, Gravity); + } + } + + // Used for MoveTo + public override OMV.Vector3 PIDTarget { + set { _PIDTarget = value; } + } + + public override bool PIDActive { get; set; } + + public override float PIDTau { + set { _PIDTau = value; } + } + + public override void AddForce(OMV.Vector3 force, bool pushforce) + { + // Since this force is being applied in only one step, make this a force per second. + OMV.Vector3 addForce = force / PhysScene.LastTimeStep; + AddForce(addForce, pushforce, false); + } + public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { + if (force.IsFinite()) + { + OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); + // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); + + PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate() + { + // Bullet adds this central force to the total force for this tick + // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.ApplyCentralForce(PhysBody, addForce); + } + }); + } + else + { + m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID); + return; + } + } + + public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { + } + public override void SetMomentum(OMV.Vector3 momentum) { + } + + private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) + { + OMV.Vector3 newScale = size; + + // Bullet's capsule total height is the "passed height + radius * 2"; + // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1) + // The number we pass in for 'scaling' is the multiplier to get that base + // shape to be the size desired. + // So, when creating the scale for the avatar height, we take the passed height + // (size.Z) and remove the caps. + // An oddity of the Bullet capsule implementation is that it presumes the Y + // dimension is the radius of the capsule. Even though some of the code allows + // for a asymmetrical capsule, other parts of the code presume it is cylindrical. + + // Scale is multiplier of radius with one of "0.5" + + float heightAdjust = BSParam.AvatarHeightMidFudge; + if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) + { + const float AVATAR_LOW = 1.1f; + const float AVATAR_MID = 1.775f; // 1.87f + const float AVATAR_HI = 2.45f; + // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m. + float midHeightOffset = size.Z - AVATAR_MID; + if (midHeightOffset < 0f) + { + // Small avatar. Add the adjustment based on the distance from midheight + heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge; + } + else + { + // Large avatar. Add the adjustment based on the distance from midheight + heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge; + } + } + if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule) + { + newScale.X = size.X / 2f; + newScale.Y = size.Y / 2f; + // The total scale height is the central cylindar plus the caps on the two ends. + newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f; + } + else + { + newScale.Z = size.Z + heightAdjust; + } + // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale); + + // If smaller than the endcaps, just fake like we're almost that small + if (newScale.Z < 0) + newScale.Z = 0.1f; + + DetailLog("{0},BSCharacter.ComputerAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}", + LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale); + + return newScale; + } + + // set _avatarVolume and _mass based on capsule size, _density and Scale + private void ComputeAvatarVolumeAndMass() + { + _avatarVolume = (float)( + Math.PI + * Size.X / 2f + * Size.Y / 2f // the area of capsule cylinder + * Size.Z // times height of capsule cylinder + + 1.33333333f + * Math.PI + * Size.X / 2f + * Math.Min(Size.X, Size.Y) / 2 + * Size.Y / 2f // plus the volume of the capsule end caps + ); + _mass = Density * BSParam.DensityScaleFactor * _avatarVolume; + } + + // The physics engine says that properties have updated. Update same and inform + // the world that things have changed. + public override void UpdateProperties(EntityProperties entprop) + { + // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. + TriggerPreUpdatePropertyAction(ref entprop); + + RawPosition = entprop.Position; + RawOrientation = entprop.Rotation; + + // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar + // and will send agent updates to the clients if velocity changes by more than + // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many + // extra updates. + // + // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to + // avatar movement rather than removes it. The larger the threshold, the bigger the jitter. + // This is most noticeable in level flight and can be seen with + // the "show updates" option in a viewer. With an update threshold, the RawVelocity cycles between a lower + // bound and an upper bound, where the difference between the two is enough to trigger a large delta v update + // and subsequently trigger an update in ScenePresence.SendTerseUpdateToAllClients(). The cause of this cycle (feedback?) + // has not yet been identified. + // + // If there is a threshold below 0.4 or no threshold check at all (as in ODE), then RawVelocity stays constant and extra + // updates are not triggered in ScenePresence.SendTerseUpdateToAllClients(). +// if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f)) + RawVelocity = entprop.Velocity; + + _acceleration = entprop.Acceleration; + _rotationalVelocity = entprop.RotationalVelocity; + + // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. + if (PositionSanityCheck(true)) + { + DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition); + entprop.Position = RawPosition; + } + + // remember the current and last set values + LastEntityProperties = CurrentEntityProperties; + CurrentEntityProperties = entprop; + + // Tell the linkset about value changes + // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); + + // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. + // PhysScene.PostUpdate(this); + + DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", + LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity); + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs new file mode 100755 index 0000000..e42e868 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs @@ -0,0 +1,144 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + +public abstract class BSConstraint : IDisposable +{ + private static string LogHeader = "[BULLETSIM CONSTRAINT]"; + + protected BulletWorld m_world; + protected BSScene PhysicsScene; + protected BulletBody m_body1; + protected BulletBody m_body2; + protected BulletConstraint m_constraint; + protected bool m_enabled = false; + + public BulletBody Body1 { get { return m_body1; } } + public BulletBody Body2 { get { return m_body2; } } + public BulletConstraint Constraint { get { return m_constraint; } } + public abstract ConstraintType Type { get; } + public bool IsEnabled { get { return m_enabled; } } + + public BSConstraint(BulletWorld world) + { + m_world = world; + PhysicsScene = m_world.physicsScene; + } + + public virtual void Dispose() + { + if (m_enabled) + { + m_enabled = false; + if (m_constraint.HasPhysicalConstraint) + { + bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint); + m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", + m_body1.ID, + m_body1.ID, m_body1.AddrString, + m_body2.ID, m_body2.AddrString, + success); + m_constraint.Clear(); + } + } + } + + public virtual bool SetLinearLimits(Vector3 low, Vector3 high) + { + bool ret = false; + if (m_enabled) + { + m_world.physicsScene.DetailLog("{0},BSConstraint.SetLinearLimits,taint,low={1},high={2}", m_body1.ID, low, high); + ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high); + } + return ret; + } + + public virtual bool SetAngularLimits(Vector3 low, Vector3 high) + { + bool ret = false; + if (m_enabled) + { + m_world.physicsScene.DetailLog("{0},BSConstraint.SetAngularLimits,taint,low={1},high={2}", m_body1.ID, low, high); + ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); + } + return ret; + } + + public virtual bool SetSolverIterations(float cnt) + { + bool ret = false; + if (m_enabled) + { + PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt); + ret = true; + } + return ret; + } + + public virtual bool CalculateTransforms() + { + bool ret = false; + if (m_enabled) + { + // Recompute the internal transforms + PhysicsScene.PE.CalculateTransforms(m_constraint); + ret = true; + } + return ret; + } + + // Reset this constraint making sure it has all its internal structures + // recomputed and is enabled and ready to go. + public virtual bool RecomputeConstraintVariables(float mass) + { + bool ret = false; + if (m_enabled) + { + ret = CalculateTransforms(); + if (ret) + { + // Setting an object's mass to zero (making it static like when it's selected) + // automatically disables the constraints. + // If the link is enabled, be sure to set the constraint itself to enabled. + PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true)); + } + else + { + m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID); + } + } + return ret; + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs new file mode 100755 index 0000000..4bcde2b --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs @@ -0,0 +1,180 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + +public class BSConstraint6Dof : BSConstraint +{ + private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; + + public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } + + public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2) :base(world) + { + m_body1 = obj1; + m_body2 = obj2; + m_enabled = false; + } + + // Create a btGeneric6DofConstraint + public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1, Quaternion frame1rot, + Vector3 frame2, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + : base(world) + { + m_body1 = obj1; + m_body2 = obj2; + m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2, + frame1, frame1rot, + frame2, frame2rot, + useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + m_enabled = true; + PhysicsScene.DetailLog("{0},BS6DofConstraint,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", + m_body1.ID, world.worldID, + obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + PhysicsScene.DetailLog("{0},BS6DofConstraint,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}", + m_body1.ID, frame1, frame1rot, frame2, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + } + + // 6 Dof constraint based on a midpoint between the two constrained bodies + public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 joinPoint, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + : base(world) + { + m_body1 = obj1; + m_body2 = obj2; + if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody) + { + world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", + BSScene.DetailLogZero, world.worldID, + obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", + LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + m_enabled = false; + } + else + { + m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2, + joinPoint, + useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + + PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", + m_body1.ID, world.worldID, m_constraint.AddrString, + obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + + if (!m_constraint.HasPhysicalConstraint) + { + world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", + LogHeader, obj1.ID, obj2.ID); + m_enabled = false; + } + else + { + m_enabled = true; + } + } + } + + // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object + public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies) + : base(world) + { + m_body1 = obj1; + m_body2 = obj1; // Look out for confusion down the road + m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1, + frameInBloc, frameInBrot, + useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); + m_enabled = true; + PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", + m_body1.ID, world.worldID, obj1.ID, obj1.AddrString); + PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed, fBLoc={1},fBRot={2},usefA={3},disCol={4}", + m_body1.ID, frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); + } + + public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) + { + bool ret = false; + if (m_enabled) + { + PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot); + ret = true; + } + return ret; + } + + public bool SetCFMAndERP(float cfm, float erp) + { + bool ret = false; + if (m_enabled) + { + PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); + PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); + PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); + ret = true; + } + return ret; + } + + public bool UseFrameOffset(bool useOffset) + { + bool ret = false; + float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; + if (m_enabled) + ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff); + return ret; + } + + public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce) + { + bool ret = false; + float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; + if (m_enabled) + { + ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce); + m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", + BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); + } + return ret; + } + + public bool SetBreakingImpulseThreshold(float threshold) + { + bool ret = false; + if (m_enabled) + ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold); + return ret; + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs new file mode 100755 index 0000000..5746ac1 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs @@ -0,0 +1,181 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; +using log4net; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + +public sealed class BSConstraintCollection : IDisposable +{ + // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]"; + + delegate bool ConstraintAction(BSConstraint constrain); + + private List m_constraints; + private BulletWorld m_world; + + public BSConstraintCollection(BulletWorld world) + { + m_world = world; + m_constraints = new List(); + } + + public void Dispose() + { + this.Clear(); + } + + public void Clear() + { + lock (m_constraints) + { + foreach (BSConstraint cons in m_constraints) + { + cons.Dispose(); + } + m_constraints.Clear(); + } + } + + public bool AddConstraint(BSConstraint cons) + { + lock (m_constraints) + { + // There is only one constraint between any bodies. Remove any old just to make sure. + RemoveAndDestroyConstraint(cons.Body1, cons.Body2); + + m_constraints.Add(cons); + } + + return true; + } + + // Get the constraint between two bodies. There can be only one. + // Return 'true' if a constraint was found. + public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint) + { + bool found = false; + BSConstraint foundConstraint = null; + + uint lookingID1 = body1.ID; + uint lookingID2 = body2.ID; + lock (m_constraints) + { + foreach (BSConstraint constrain in m_constraints) + { + if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2) + || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1)) + { + foundConstraint = constrain; + found = true; + break; + } + } + } + returnConstraint = foundConstraint; + return found; + } + + // Remove any constraint between the passed bodies. + // Presumed there is only one such constraint possible. + // Return 'true' if a constraint was found and destroyed. + public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2) + { + bool ret = false; + lock (m_constraints) + { + BSConstraint constrain; + if (this.TryGetConstraint(body1, body2, out constrain)) + { + // remove the constraint from our collection + ret = RemoveAndDestroyConstraint(constrain); + } + } + + return ret; + } + + // The constraint MUST exist in the collection + // Could be called if the constraint was previously removed. + // Return 'true' if the constraint was actually removed and disposed. + public bool RemoveAndDestroyConstraint(BSConstraint constrain) + { + bool removed = false; + lock (m_constraints) + { + // remove the constraint from our collection + removed = m_constraints.Remove(constrain); + } + // Dispose() is safe to call multiple times + constrain.Dispose(); + return removed; + } + + // Remove all constraints that reference the passed body. + // Return 'true' if any constraints were destroyed. + public bool RemoveAndDestroyConstraint(BulletBody body1) + { + List toRemove = new List(); + uint lookingID = body1.ID; + lock (m_constraints) + { + foreach (BSConstraint constrain in m_constraints) + { + if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID) + { + toRemove.Add(constrain); + } + } + foreach (BSConstraint constrain in toRemove) + { + m_constraints.Remove(constrain); + constrain.Dispose(); + } + } + return (toRemove.Count > 0); + } + + public bool RecalculateAllConstraints() + { + bool ret = false; + lock (m_constraints) + { + foreach (BSConstraint constrain in m_constraints) + { + constrain.CalculateTransforms(); + ret = true; + } + } + return ret; + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs new file mode 100755 index 0000000..e7566a8 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs @@ -0,0 +1,54 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + +public sealed class BSConstraintConeTwist : BSConstraint +{ + public override ConstraintType Type { get { return ConstraintType.CONETWIST_CONSTRAINT_TYPE; } } + + public BSConstraintConeTwist(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool disableCollisionsBetweenLinkedBodies) + : base(world) + { + m_body1 = obj1; + m_body2 = obj2; + m_constraint = PhysicsScene.PE.CreateConeTwistConstraint(world, obj1, obj2, + frameInAloc, frameInArot, frameInBloc, frameInBrot, + disableCollisionsBetweenLinkedBodies); + m_enabled = true; + } +} + +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs new file mode 100755 index 0000000..d20538d --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs @@ -0,0 +1,55 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + +public sealed class BSConstraintHinge : BSConstraint +{ + public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } + + public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 pivotInA, Vector3 pivotInB, + Vector3 axisInA, Vector3 axisInB, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + : base(world) + { + m_body1 = obj1; + m_body2 = obj2; + m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2, + pivotInA, pivotInB, axisInA, axisInB, + useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + m_enabled = true; + } + +} + +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs new file mode 100755 index 0000000..83d42af --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs @@ -0,0 +1,55 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + +public sealed class BSConstraintSlider : BSConstraint +{ + public override ConstraintType Type { get { return ConstraintType.SLIDER_CONSTRAINT_TYPE; } } + + public BSConstraintSlider(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + : base(world) + { + m_body1 = obj1; + m_body2 = obj2; + m_constraint = PhysicsScene.PE.CreateSliderConstraint(world, obj1, obj2, + frameInAloc, frameInArot, frameInBloc, frameInBrot, + useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + m_enabled = true; + } + +} + +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs new file mode 100755 index 0000000..563a1b1 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs @@ -0,0 +1,103 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + +public sealed class BSConstraintSpring : BSConstraint6Dof +{ + public override ConstraintType Type { get { return ConstraintType.D6_SPRING_CONSTRAINT_TYPE; } } + + public BSConstraintSpring(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1Loc, Quaternion frame1Rot, + Vector3 frame2Loc, Quaternion frame2Rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + :base(world, obj1, obj2) + { + m_constraint = PhysicsScene.PE.Create6DofSpringConstraint(world, obj1, obj2, + frame1Loc, frame1Rot, frame2Loc, frame2Rot, + useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + m_enabled = true; + + PhysicsScene.DetailLog("{0},BSConstraintSpring,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", + obj1.ID, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + PhysicsScene.DetailLog("{0},BSConstraintSpring,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}", + m_body1.ID, frame1Loc, frame1Rot, frame2Loc, frame2Rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + } + + public bool SetAxisEnable(int pIndex, bool pAxisEnable) + { + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEnable,obj1ID={1},obj2ID={2},indx={3},enable={4}", + m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pAxisEnable); + PhysicsScene.PE.SpringEnable(m_constraint, pIndex, BSParam.NumericBool(pAxisEnable)); + return true; + } + + public bool SetStiffness(int pIndex, float pStiffness) + { + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetStiffness,obj1ID={1},obj2ID={2},indx={3},stiff={4}", + m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pStiffness); + PhysicsScene.PE.SpringSetStiffness(m_constraint, pIndex, pStiffness); + return true; + } + + public bool SetDamping(int pIndex, float pDamping) + { + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetDamping,obj1ID={1},obj2ID={2},indx={3},damp={4}", + m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pDamping); + PhysicsScene.PE.SpringSetDamping(m_constraint, pIndex, pDamping); + return true; + } + + public bool SetEquilibriumPoint(int pIndex, float pEqPoint) + { + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},indx={3},eqPoint={4}", + m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pEqPoint); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, pIndex, pEqPoint); + return true; + } + + public bool SetEquilibriumPoint(Vector3 linearEq, Vector3 angularEq) + { + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},linearEq={3},angularEq={4}", + m_body1.ID, m_body1.ID, m_body2.ID, linearEq, angularEq); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 0, linearEq.X); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 1, linearEq.Y); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 2, linearEq.Z); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 3, angularEq.X); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 4, angularEq.Y); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 5, angularEq.Z); + return true; + } + +} + +} \ No newline at end of file diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs new file mode 100644 index 0000000..0fc5577 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs @@ -0,0 +1,1800 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial + * are Copyright (c) 2009 Linden Research, Inc and are used under their license + * of Creative Commons Attribution-Share Alike 3.0 + * (http://creativecommons.org/licenses/by-sa/3.0/). + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + public sealed class BSDynamics : BSActor + { +#pragma warning disable 414 + private static string LogHeader = "[BULLETSIM VEHICLE]"; +#pragma warning restore 414 + + // the prim this dynamic controller belongs to + private BSPrimLinkable ControllingPrim { get; set; } + + private bool m_haveRegisteredForSceneEvents; + + // mass of the vehicle fetched each time we're calles + private float m_vehicleMass; + + // Vehicle properties + public Vehicle Type { get; set; } + + // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier + private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: + // HOVER_TERRAIN_ONLY + // HOVER_GLOBAL_HEIGHT + // NO_DEFLECTION_UP + // HOVER_WATER_ONLY + // HOVER_UP_ONLY + // LIMIT_MOTOR_UP + // LIMIT_ROLL_ONLY + private Vector3 m_BlockingEndPoint = Vector3.Zero; + private Quaternion m_RollreferenceFrame = Quaternion.Identity; + private Quaternion m_referenceFrame = Quaternion.Identity; + + // Linear properties + private BSVMotor m_linearMotor = new BSVMotor("LinearMotor"); + private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time + private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center + private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL + private Vector3 m_linearFrictionTimescale = Vector3.Zero; + private float m_linearMotorDecayTimescale = 1; + private float m_linearMotorTimescale = 1; + private Vector3 m_lastLinearVelocityVector = Vector3.Zero; + private Vector3 m_lastPositionVector = Vector3.Zero; + // private bool m_LinearMotorSetLastFrame = false; + // private Vector3 m_linearMotorOffset = Vector3.Zero; + + //Angular properties + private BSVMotor m_angularMotor = new BSVMotor("AngularMotor"); + private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor + // private int m_angularMotorApply = 0; // application frame counter + private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity + private float m_angularMotorTimescale = 1; // motor angular velocity ramp up rate + private float m_angularMotorDecayTimescale = 1; // motor angular velocity decay rate + private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate + private Vector3 m_lastAngularVelocity = Vector3.Zero; + private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body + + //Deflection properties + private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection"); + private float m_angularDeflectionEfficiency = 0; + private float m_angularDeflectionTimescale = 0; + private float m_linearDeflectionEfficiency = 0; + private float m_linearDeflectionTimescale = 0; + + //Banking properties + private float m_bankingEfficiency = 0; + private float m_bankingMix = 1; + private float m_bankingTimescale = 0; + + //Hover and Buoyancy properties + private BSVMotor m_hoverMotor = new BSVMotor("Hover"); + private float m_VhoverHeight = 0f; + private float m_VhoverEfficiency = 0f; + private float m_VhoverTimescale = 0f; + private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height + // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) + private float m_VehicleBuoyancy = 0f; + private Vector3 m_VehicleGravity = Vector3.Zero; // Gravity computed when buoyancy set + + //Attractor properties + private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); + private float m_verticalAttractionEfficiency = 1.0f; // damped + private float m_verticalAttractionCutoff = 500f; // per the documentation + // Timescale > cutoff means no vert attractor. + private float m_verticalAttractionTimescale = 510f; + + // Just some recomputed constants: +#pragma warning disable 414 + static readonly float TwoPI = ((float)Math.PI) * 2f; + static readonly float FourPI = ((float)Math.PI) * 4f; + static readonly float PIOverFour = ((float)Math.PI) / 4f; + static readonly float PIOverTwo = ((float)Math.PI) / 2f; +#pragma warning restore 414 + + public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName) + : base(myScene, myPrim, actorName) + { + Type = Vehicle.TYPE_NONE; + m_haveRegisteredForSceneEvents = false; + + ControllingPrim = myPrim as BSPrimLinkable; + if (ControllingPrim == null) + { + // THIS CANNOT HAPPEN!! + } + VDetailLog("{0},Creation", ControllingPrim.LocalID); + } + + // Return 'true' if this vehicle is doing vehicle things + public bool IsActive + { + get { return (Type != Vehicle.TYPE_NONE && ControllingPrim.IsPhysicallyActive); } + } + + // Return 'true' if this a vehicle that should be sitting on the ground + public bool IsGroundVehicle + { + get { return (Type == Vehicle.TYPE_CAR || Type == Vehicle.TYPE_SLED); } + } + + #region Vehicle parameter setting + public void ProcessFloatVehicleParam(Vehicle pParam, float pValue) + { + VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); + float clampTemp; + + switch (pParam) + { + case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: + m_angularDeflectionEfficiency = ClampInRange(0f, pValue, 1f); + break; + case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: + m_angularDeflectionTimescale = ClampInRange(0.25f, pValue, 120); + break; + case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: + m_angularMotorDecayTimescale = ClampInRange(0.25f, pValue, 120); + m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; + break; + case Vehicle.ANGULAR_MOTOR_TIMESCALE: + m_angularMotorTimescale = ClampInRange(0.25f, pValue, 120); + m_angularMotor.TimeScale = m_angularMotorTimescale; + break; + case Vehicle.BANKING_EFFICIENCY: + m_bankingEfficiency = ClampInRange(-1f, pValue, 1f); + break; + case Vehicle.BANKING_MIX: + m_bankingMix = ClampInRange(0.01f, pValue, 1); + break; + case Vehicle.BANKING_TIMESCALE: + m_bankingTimescale = ClampInRange(0.25f, pValue, 120); + break; + case Vehicle.BUOYANCY: + m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); + m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); + break; + case Vehicle.HOVER_EFFICIENCY: + m_VhoverEfficiency = ClampInRange(0.01f, pValue, 1f); + break; + case Vehicle.HOVER_HEIGHT: + m_VhoverHeight = ClampInRange(0f, pValue, 1000000f); + break; + case Vehicle.HOVER_TIMESCALE: + m_VhoverTimescale = ClampInRange(0.01f, pValue, 120); + break; + case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: + m_linearDeflectionEfficiency = ClampInRange(0f, pValue, 1f); + break; + case Vehicle.LINEAR_DEFLECTION_TIMESCALE: + m_linearDeflectionTimescale = ClampInRange(0.01f, pValue, 120); + break; + case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: + m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); + m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; + break; + case Vehicle.LINEAR_MOTOR_TIMESCALE: + m_linearMotorTimescale = ClampInRange(0.01f, pValue, 120); + m_linearMotor.TimeScale = m_linearMotorTimescale; + break; + case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: + m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f); + m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; + break; + case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: + m_verticalAttractionTimescale = ClampInRange(0.01f, pValue, 120); + m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale; + break; + + // These are vector properties but the engine lets you use a single float value to + // set all of the components to the same value + case Vehicle.ANGULAR_FRICTION_TIMESCALE: + clampTemp = ClampInRange(0.01f, pValue, 120); + m_angularFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp); + break; + case Vehicle.ANGULAR_MOTOR_DIRECTION: + clampTemp = ClampInRange(-TwoPI, pValue, TwoPI); + m_angularMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp); + m_angularMotor.Zero(); + m_angularMotor.SetTarget(m_angularMotorDirection); + break; + case Vehicle.LINEAR_FRICTION_TIMESCALE: + clampTemp = ClampInRange(0.01f, pValue, 120); + m_linearFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp); + break; + case Vehicle.LINEAR_MOTOR_DIRECTION: + clampTemp = ClampInRange(-BSParam.MaxLinearVelocity, pValue, BSParam.MaxLinearVelocity); + m_linearMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp); + m_linearMotorDirectionLASTSET = new Vector3(clampTemp, clampTemp, clampTemp); + m_linearMotor.SetTarget(m_linearMotorDirection); + break; + case Vehicle.LINEAR_MOTOR_OFFSET: + clampTemp = ClampInRange(-1000, pValue, 1000); + m_linearMotorOffset = new Vector3(clampTemp, clampTemp, clampTemp); + break; + + } + }//end ProcessFloatVehicleParam + + internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) + { + VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); + switch (pParam) + { + case Vehicle.ANGULAR_FRICTION_TIMESCALE: + pValue.X = ClampInRange(0.25f, pValue.X, 120); + pValue.Y = ClampInRange(0.25f, pValue.Y, 120); + pValue.Z = ClampInRange(0.25f, pValue.Z, 120); + m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + case Vehicle.ANGULAR_MOTOR_DIRECTION: + // Limit requested angular speed to 2 rps= 4 pi rads/sec + pValue.X = ClampInRange(-FourPI, pValue.X, FourPI); + pValue.Y = ClampInRange(-FourPI, pValue.Y, FourPI); + pValue.Z = ClampInRange(-FourPI, pValue.Z, FourPI); + m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); + m_angularMotor.Zero(); + m_angularMotor.SetTarget(m_angularMotorDirection); + break; + case Vehicle.LINEAR_FRICTION_TIMESCALE: + pValue.X = ClampInRange(0.25f, pValue.X, 120); + pValue.Y = ClampInRange(0.25f, pValue.Y, 120); + pValue.Z = ClampInRange(0.25f, pValue.Z, 120); + m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + case Vehicle.LINEAR_MOTOR_DIRECTION: + pValue.X = ClampInRange(-BSParam.MaxLinearVelocity, pValue.X, BSParam.MaxLinearVelocity); + pValue.Y = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Y, BSParam.MaxLinearVelocity); + pValue.Z = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Z, BSParam.MaxLinearVelocity); + m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); + m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); + m_linearMotor.SetTarget(m_linearMotorDirection); + break; + case Vehicle.LINEAR_MOTOR_OFFSET: + // Not sure the correct range to limit this variable + pValue.X = ClampInRange(-1000, pValue.X, 1000); + pValue.Y = ClampInRange(-1000, pValue.Y, 1000); + pValue.Z = ClampInRange(-1000, pValue.Z, 1000); + m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + case Vehicle.BLOCK_EXIT: + // Not sure the correct range to limit this variable + pValue.X = ClampInRange(-10000, pValue.X, 10000); + pValue.Y = ClampInRange(-10000, pValue.Y, 10000); + pValue.Z = ClampInRange(-10000, pValue.Z, 10000); + m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + } + }//end ProcessVectorVehicleParam + + internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) + { + VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); + switch (pParam) + { + case Vehicle.REFERENCE_FRAME: + m_referenceFrame = pValue; + break; + case Vehicle.ROLL_FRAME: + m_RollreferenceFrame = pValue; + break; + } + }//end ProcessRotationVehicleParam + + internal void ProcessVehicleFlags(int pParam, bool remove) + { + VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", ControllingPrim.LocalID, pParam, remove); + VehicleFlag parm = (VehicleFlag)pParam; + if (pParam == -1) + m_flags = (VehicleFlag)0; + else + { + if (remove) + m_flags &= ~parm; + else + m_flags |= parm; + } + } + + public void ProcessTypeChange(Vehicle pType) + { + VDetailLog("{0},ProcessTypeChange,type={1}", ControllingPrim.LocalID, pType); + // Set Defaults For Type + Type = pType; + switch (pType) + { + case Vehicle.TYPE_NONE: + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 0; + m_linearMotorDecayTimescale = 0; + m_linearFrictionTimescale = new Vector3(0, 0, 0); + + m_angularMotorDirection = Vector3.Zero; + m_angularMotorDecayTimescale = 0; + m_angularMotorTimescale = 0; + m_angularFrictionTimescale = new Vector3(0, 0, 0); + + m_VhoverHeight = 0; + m_VhoverEfficiency = 0; + m_VhoverTimescale = 0; + m_VehicleBuoyancy = 0; + + m_linearDeflectionEfficiency = 1; + m_linearDeflectionTimescale = 1; + + m_angularDeflectionEfficiency = 0; + m_angularDeflectionTimescale = 1000; + + m_verticalAttractionEfficiency = 0; + m_verticalAttractionTimescale = 0; + + m_bankingEfficiency = 0; + m_bankingTimescale = 1000; + m_bankingMix = 1; + + m_referenceFrame = Quaternion.Identity; + m_flags = (VehicleFlag)0; + + break; + + case Vehicle.TYPE_SLED: + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 1000; + m_linearMotorDecayTimescale = 120; + m_linearFrictionTimescale = new Vector3(30, 1, 1000); + + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 1000; + m_angularMotorDecayTimescale = 120; + m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); + + m_VhoverHeight = 0; + m_VhoverEfficiency = 10; // TODO: this looks wrong!! + m_VhoverTimescale = 10; + m_VehicleBuoyancy = 0; + + m_linearDeflectionEfficiency = 1; + m_linearDeflectionTimescale = 1; + + m_angularDeflectionEfficiency = 1; + m_angularDeflectionTimescale = 1000; + + m_verticalAttractionEfficiency = 0; + m_verticalAttractionTimescale = 0; + + m_bankingEfficiency = 0; + m_bankingTimescale = 10; + m_bankingMix = 1; + + m_referenceFrame = Quaternion.Identity; + m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY + | VehicleFlag.HOVER_TERRAIN_ONLY + | VehicleFlag.HOVER_GLOBAL_HEIGHT + | VehicleFlag.HOVER_UP_ONLY); + m_flags |= (VehicleFlag.NO_DEFLECTION_UP + | VehicleFlag.LIMIT_ROLL_ONLY + | VehicleFlag.LIMIT_MOTOR_UP); + + break; + case Vehicle.TYPE_CAR: + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 1; + m_linearMotorDecayTimescale = 60; + m_linearFrictionTimescale = new Vector3(100, 2, 1000); + + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 1; + m_angularMotorDecayTimescale = 0.8f; + m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); + + m_VhoverHeight = 0; + m_VhoverEfficiency = 0; + m_VhoverTimescale = 1000; + m_VehicleBuoyancy = 0; + + m_linearDeflectionEfficiency = 1; + m_linearDeflectionTimescale = 2; + + m_angularDeflectionEfficiency = 0; + m_angularDeflectionTimescale = 10; + + m_verticalAttractionEfficiency = 1f; + m_verticalAttractionTimescale = 10f; + + m_bankingEfficiency = -0.2f; + m_bankingMix = 1; + m_bankingTimescale = 1; + + m_referenceFrame = Quaternion.Identity; + m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY + | VehicleFlag.HOVER_TERRAIN_ONLY + | VehicleFlag.HOVER_GLOBAL_HEIGHT); + m_flags |= (VehicleFlag.NO_DEFLECTION_UP + | VehicleFlag.LIMIT_ROLL_ONLY + | VehicleFlag.LIMIT_MOTOR_UP + | VehicleFlag.HOVER_UP_ONLY); + break; + case Vehicle.TYPE_BOAT: + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 5; + m_linearMotorDecayTimescale = 60; + m_linearFrictionTimescale = new Vector3(10, 3, 2); + + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 4; + m_angularMotorDecayTimescale = 4; + m_angularFrictionTimescale = new Vector3(10,10,10); + + m_VhoverHeight = 0; + m_VhoverEfficiency = 0.5f; + m_VhoverTimescale = 2; + m_VehicleBuoyancy = 1; + + m_linearDeflectionEfficiency = 0.5f; + m_linearDeflectionTimescale = 3; + + m_angularDeflectionEfficiency = 0.5f; + m_angularDeflectionTimescale = 5; + + m_verticalAttractionEfficiency = 0.5f; + m_verticalAttractionTimescale = 5f; + + m_bankingEfficiency = -0.3f; + m_bankingMix = 0.8f; + m_bankingTimescale = 1; + + m_referenceFrame = Quaternion.Identity; + m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY + | VehicleFlag.HOVER_GLOBAL_HEIGHT + | VehicleFlag.LIMIT_ROLL_ONLY + | VehicleFlag.HOVER_UP_ONLY); + m_flags |= (VehicleFlag.NO_DEFLECTION_UP + | VehicleFlag.LIMIT_MOTOR_UP + | VehicleFlag.HOVER_WATER_ONLY); + break; + case Vehicle.TYPE_AIRPLANE: + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 2; + m_linearMotorDecayTimescale = 60; + m_linearFrictionTimescale = new Vector3(200, 10, 5); + + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 4; + m_angularMotorDecayTimescale = 4; + m_angularFrictionTimescale = new Vector3(20, 20, 20); + + m_VhoverHeight = 0; + m_VhoverEfficiency = 0.5f; + m_VhoverTimescale = 1000; + m_VehicleBuoyancy = 0; + + m_linearDeflectionEfficiency = 0.5f; + m_linearDeflectionTimescale = 3; + + m_angularDeflectionEfficiency = 1; + m_angularDeflectionTimescale = 2; + + m_verticalAttractionEfficiency = 0.9f; + m_verticalAttractionTimescale = 2f; + + m_bankingEfficiency = 1; + m_bankingMix = 0.7f; + m_bankingTimescale = 2; + + m_referenceFrame = Quaternion.Identity; + m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY + | VehicleFlag.HOVER_TERRAIN_ONLY + | VehicleFlag.HOVER_GLOBAL_HEIGHT + | VehicleFlag.HOVER_UP_ONLY + | VehicleFlag.NO_DEFLECTION_UP + | VehicleFlag.LIMIT_MOTOR_UP); + m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); + break; + case Vehicle.TYPE_BALLOON: + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 5; + m_linearFrictionTimescale = new Vector3(5, 5, 5); + m_linearMotorDecayTimescale = 60; + + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 6; + m_angularFrictionTimescale = new Vector3(10, 10, 10); + m_angularMotorDecayTimescale = 10; + + m_VhoverHeight = 5; + m_VhoverEfficiency = 0.8f; + m_VhoverTimescale = 10; + m_VehicleBuoyancy = 1; + + m_linearDeflectionEfficiency = 0; + m_linearDeflectionTimescale = 5; + + m_angularDeflectionEfficiency = 0; + m_angularDeflectionTimescale = 5; + + m_verticalAttractionEfficiency = 1f; + m_verticalAttractionTimescale = 100f; + + m_bankingEfficiency = 0; + m_bankingMix = 0.7f; + m_bankingTimescale = 5; + + m_referenceFrame = Quaternion.Identity; + + m_referenceFrame = Quaternion.Identity; + m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY + | VehicleFlag.HOVER_TERRAIN_ONLY + | VehicleFlag.HOVER_UP_ONLY + | VehicleFlag.NO_DEFLECTION_UP + | VehicleFlag.LIMIT_MOTOR_UP); + m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY + | VehicleFlag.HOVER_GLOBAL_HEIGHT); + break; + } + + m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f); + // m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) + + m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f); + // m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) + + /* Not implemented + m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, + BSMotor.Infinite, BSMotor.InfiniteVector, + m_verticalAttractionEfficiency); + // Z goes away and we keep X and Y + m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) + */ + + if (this.Type == Vehicle.TYPE_NONE) + { + UnregisterForSceneEvents(); + } + else + { + RegisterForSceneEvents(); + } + + // Update any physical parameters based on this type. + Refresh(); + } + #endregion // Vehicle parameter setting + + // BSActor.Refresh() + public override void Refresh() + { + // If asking for a refresh, reset the physical parameters before the next simulation step. + // Called whether active or not since the active state may be updated before the next step. + m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate() + { + SetPhysicalParameters(); + }); + } + + // Some of the properties of this prim may have changed. + // Do any updating needed for a vehicle + private void SetPhysicalParameters() + { + if (IsActive) + { + // Remember the mass so we don't have to fetch it every step + m_vehicleMass = ControllingPrim.TotalMass; + + // Friction affects are handled by this vehicle code + // m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); + // m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); + ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction); + ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution); + + // Moderate angular movement introduced by Bullet. + // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. + // Maybe compute linear and angular factor and damping from params. + m_physicsScene.PE.SetAngularDamping(ControllingPrim.PhysBody, BSParam.VehicleAngularDamping); + m_physicsScene.PE.SetLinearFactor(ControllingPrim.PhysBody, BSParam.VehicleLinearFactor); + m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor); + + // Vehicles report collision events so we know when it's on the ground + // m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); + ControllingPrim.Linkset.AddToPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); + + // Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); + // ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor; + // m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); + // m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); + ControllingPrim.Linkset.ComputeAndSetLocalInertia(BSParam.VehicleInertiaFactor, m_vehicleMass); + + // Set the gravity for the vehicle depending on the buoyancy + // TODO: what should be done if prim and vehicle buoyancy differ? + m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); + // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. + // m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); + ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero); + + VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", + ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity, + BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution, + BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor + ); + } + else + { + if (ControllingPrim.PhysBody.HasPhysicalBody) + m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); + // ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); + } + } + + // BSActor.RemoveBodyDependencies + public override void RemoveDependencies() + { + Refresh(); + } + + // BSActor.Release() + public override void Dispose() + { + VDetailLog("{0},Dispose", ControllingPrim.LocalID); + UnregisterForSceneEvents(); + Type = Vehicle.TYPE_NONE; + Enabled = false; + return; + } + + private void RegisterForSceneEvents() + { + if (!m_haveRegisteredForSceneEvents) + { + m_physicsScene.BeforeStep += this.Step; + m_physicsScene.AfterStep += this.PostStep; + ControllingPrim.OnPreUpdateProperty += this.PreUpdateProperty; + m_haveRegisteredForSceneEvents = true; + } + } + + private void UnregisterForSceneEvents() + { + if (m_haveRegisteredForSceneEvents) + { + m_physicsScene.BeforeStep -= this.Step; + m_physicsScene.AfterStep -= this.PostStep; + ControllingPrim.OnPreUpdateProperty -= this.PreUpdateProperty; + m_haveRegisteredForSceneEvents = false; + } + } + + private void PreUpdateProperty(ref EntityProperties entprop) + { + // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet + // TODO: handle physics introduced by Bullet with computed vehicle physics. + if (IsActive) + { + entprop.RotationalVelocity = Vector3.Zero; + } + } + + #region Known vehicle value functions + // Vehicle physical parameters that we buffer from constant getting and setting. + // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set. + // Changing is remembered and the parameter is stored back into the physics engine only if updated. + // This does two things: 1) saves continuious calls into unmanaged code, and + // 2) signals when a physics property update must happen back to the simulator + // to update values modified for the vehicle. + private int m_knownChanged; + private int m_knownHas; + private float m_knownTerrainHeight; + private float m_knownWaterLevel; + private Vector3 m_knownPosition; + private Vector3 m_knownVelocity; + private Vector3 m_knownForce; + private Vector3 m_knownForceImpulse; + private Quaternion m_knownOrientation; + private Vector3 m_knownRotationalVelocity; + private Vector3 m_knownRotationalForce; + private Vector3 m_knownRotationalImpulse; + + private const int m_knownChangedPosition = 1 << 0; + private const int m_knownChangedVelocity = 1 << 1; + private const int m_knownChangedForce = 1 << 2; + private const int m_knownChangedForceImpulse = 1 << 3; + private const int m_knownChangedOrientation = 1 << 4; + private const int m_knownChangedRotationalVelocity = 1 << 5; + private const int m_knownChangedRotationalForce = 1 << 6; + private const int m_knownChangedRotationalImpulse = 1 << 7; + private const int m_knownChangedTerrainHeight = 1 << 8; + private const int m_knownChangedWaterLevel = 1 << 9; + + public void ForgetKnownVehicleProperties() + { + m_knownHas = 0; + m_knownChanged = 0; + } + // Push all the changed values back into the physics engine + public void PushKnownChanged() + { + if (m_knownChanged != 0) + { + if ((m_knownChanged & m_knownChangedPosition) != 0) + ControllingPrim.ForcePosition = m_knownPosition; + + if ((m_knownChanged & m_knownChangedOrientation) != 0) + ControllingPrim.ForceOrientation = m_knownOrientation; + + if ((m_knownChanged & m_knownChangedVelocity) != 0) + { + ControllingPrim.ForceVelocity = m_knownVelocity; + // Fake out Bullet by making it think the velocity is the same as last time. + // Bullet does a bunch of smoothing for changing parameters. + // Since the vehicle is demanding this setting, we override Bullet's smoothing + // by telling Bullet the value was the same last time. + // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity); + } + + if ((m_knownChanged & m_knownChangedForce) != 0) + ControllingPrim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/); + + if ((m_knownChanged & m_knownChangedForceImpulse) != 0) + ControllingPrim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/); + + if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) + { + ControllingPrim.ForceRotationalVelocity = m_knownRotationalVelocity; + // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); + } + + if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) + ControllingPrim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/); + + if ((m_knownChanged & m_knownChangedRotationalForce) != 0) + { + ControllingPrim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/); + } + + // If we set one of the values (ie, the physics engine didn't do it) we must force + // an UpdateProperties event to send the changes up to the simulator. + m_physicsScene.PE.PushUpdate(ControllingPrim.PhysBody); + } + m_knownChanged = 0; + } + + // Since the computation of terrain height can be a little involved, this routine + // is used to fetch the height only once for each vehicle simulation step. + Vector3 lastRememberedHeightPos = new Vector3(-1, -1, -1); + private float GetTerrainHeight(Vector3 pos) + { + if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) + { + lastRememberedHeightPos = pos; + m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos); + m_knownHas |= m_knownChangedTerrainHeight; + } + return m_knownTerrainHeight; + } + + // Since the computation of water level can be a little involved, this routine + // is used ot fetch the level only once for each vehicle simulation step. + Vector3 lastRememberedWaterHeightPos = new Vector3(-1, -1, -1); + private float GetWaterLevel(Vector3 pos) + { + if ((m_knownHas & m_knownChangedWaterLevel) == 0 || pos != lastRememberedWaterHeightPos) + { + lastRememberedWaterHeightPos = pos; + m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos); + m_knownHas |= m_knownChangedWaterLevel; + } + return m_knownWaterLevel; + } + + private Vector3 VehiclePosition + { + get + { + if ((m_knownHas & m_knownChangedPosition) == 0) + { + m_knownPosition = ControllingPrim.ForcePosition; + m_knownHas |= m_knownChangedPosition; + } + return m_knownPosition; + } + set + { + m_knownPosition = value; + m_knownChanged |= m_knownChangedPosition; + m_knownHas |= m_knownChangedPosition; + } + } + + private Quaternion VehicleOrientation + { + get + { + if ((m_knownHas & m_knownChangedOrientation) == 0) + { + m_knownOrientation = ControllingPrim.ForceOrientation; + m_knownHas |= m_knownChangedOrientation; + } + return m_knownOrientation; + } + set + { + m_knownOrientation = value; + m_knownChanged |= m_knownChangedOrientation; + m_knownHas |= m_knownChangedOrientation; + } + } + + private Vector3 VehicleVelocity + { + get + { + if ((m_knownHas & m_knownChangedVelocity) == 0) + { + m_knownVelocity = ControllingPrim.ForceVelocity; + m_knownHas |= m_knownChangedVelocity; + } + return m_knownVelocity; + } + set + { + m_knownVelocity = value; + m_knownChanged |= m_knownChangedVelocity; + m_knownHas |= m_knownChangedVelocity; + } + } + + private void VehicleAddForce(Vector3 pForce) + { + if ((m_knownHas & m_knownChangedForce) == 0) + { + m_knownForce = Vector3.Zero; + m_knownHas |= m_knownChangedForce; + } + m_knownForce += pForce; + m_knownChanged |= m_knownChangedForce; + } + + private void VehicleAddForceImpulse(Vector3 pImpulse) + { + if ((m_knownHas & m_knownChangedForceImpulse) == 0) + { + m_knownForceImpulse = Vector3.Zero; + m_knownHas |= m_knownChangedForceImpulse; + } + m_knownForceImpulse += pImpulse; + m_knownChanged |= m_knownChangedForceImpulse; + } + + private Vector3 VehicleRotationalVelocity + { + get + { + if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) + { + m_knownRotationalVelocity = ControllingPrim.ForceRotationalVelocity; + m_knownHas |= m_knownChangedRotationalVelocity; + } + return (Vector3)m_knownRotationalVelocity; + } + set + { + m_knownRotationalVelocity = value; + m_knownChanged |= m_knownChangedRotationalVelocity; + m_knownHas |= m_knownChangedRotationalVelocity; + } + } + private void VehicleAddAngularForce(Vector3 aForce) + { + if ((m_knownHas & m_knownChangedRotationalForce) == 0) + { + m_knownRotationalForce = Vector3.Zero; + } + m_knownRotationalForce += aForce; + m_knownChanged |= m_knownChangedRotationalForce; + m_knownHas |= m_knownChangedRotationalForce; + } + private void VehicleAddRotationalImpulse(Vector3 pImpulse) + { + if ((m_knownHas & m_knownChangedRotationalImpulse) == 0) + { + m_knownRotationalImpulse = Vector3.Zero; + m_knownHas |= m_knownChangedRotationalImpulse; + } + m_knownRotationalImpulse += pImpulse; + m_knownChanged |= m_knownChangedRotationalImpulse; + } + + // Vehicle relative forward velocity + private Vector3 VehicleForwardVelocity + { + get + { + return VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleFrameOrientation)); + } + } + + private float VehicleForwardSpeed + { + get + { + return VehicleForwardVelocity.X; + } + } + private Quaternion VehicleFrameOrientation + { + get + { + return VehicleOrientation * m_referenceFrame; + } + } + + #endregion // Known vehicle value functions + + // One step of the vehicle properties for the next 'pTimestep' seconds. + internal void Step(float pTimestep) + { + if (!IsActive) return; + + ForgetKnownVehicleProperties(); + + MoveLinear(pTimestep); + MoveAngular(pTimestep); + + LimitRotation(pTimestep); + + // remember the position so next step we can limit absolute movement effects + m_lastPositionVector = VehiclePosition; + + // If we forced the changing of some vehicle parameters, update the values and + // for the physics engine to note the changes so an UpdateProperties event will happen. + PushKnownChanged(); + + if (m_physicsScene.VehiclePhysicalLoggingEnabled) + m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody); + + VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}", + ControllingPrim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity); + } + + // Called after the simulation step + internal void PostStep(float pTimestep) + { + if (!IsActive) return; + + if (m_physicsScene.VehiclePhysicalLoggingEnabled) + m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody); + } + + // Apply the effect of the linear motor and other linear motions (like hover and float). + private void MoveLinear(float pTimestep) + { + ComputeLinearVelocity(pTimestep); + + ComputeLinearDeflection(pTimestep); + + ComputeLinearTerrainHeightCorrection(pTimestep); + + ComputeLinearHover(pTimestep); + + ComputeLinearBlockingEndPoint(pTimestep); + + ComputeLinearMotorUp(pTimestep); + + ApplyGravity(pTimestep); + + // If not changing some axis, reduce out velocity + if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0) + { + Vector3 vel = VehicleVelocity; + if ((m_flags & (VehicleFlag.NO_X)) != 0) + { + vel.X = 0; + } + if ((m_flags & (VehicleFlag.NO_Y)) != 0) + { + vel.Y = 0; + } + if ((m_flags & (VehicleFlag.NO_Z)) != 0) + { + vel.Z = 0; + } + VehicleVelocity = vel; + } + + // ================================================================== + // Clamp high or low velocities + float newVelocityLengthSq = VehicleVelocity.LengthSquared(); + if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocitySquared) + { + Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG + VehicleVelocity /= VehicleVelocity.Length(); + VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; + VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}", + ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); + } + else if (newVelocityLengthSq < BSParam.VehicleMinLinearVelocitySquared) + { + Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG + VDetailLog("{0}, MoveLinear,clampMin,origVelW={1},lenSq={2}", + ControllingPrim.LocalID, origVelW, newVelocityLengthSq); + VehicleVelocity = Vector3.Zero; + } + + VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity ); + + } // end MoveLinear() + + public void ComputeLinearVelocity(float pTimestep) + { + // Step the motor from the current value. Get the correction needed this step. + Vector3 origVelW = VehicleVelocity; // DEBUG + Vector3 currentVelV = VehicleForwardVelocity; + Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); + + // Friction reduces vehicle motion based on absolute speed. Slow vehicle down by friction. + Vector3 frictionFactorV = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep); + linearMotorCorrectionV -= (currentVelV * frictionFactorV); + + // Motor is vehicle coordinates. Rotate it to world coordinates + Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleFrameOrientation; + + // If we're a ground vehicle, don't add any upward Z movement + if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0) + { + if (linearMotorVelocityW.Z > 0f) + linearMotorVelocityW.Z = 0f; + } + + // Add this correction to the velocity to make it faster/slower. + VehicleVelocity += linearMotorVelocityW; + + VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}", + ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV, + linearMotorVelocityW, VehicleVelocity, frictionFactorV); + } + + //Given a Deflection Effiency and a Velocity, Returns a Velocity that is Partially Deflected onto the X Axis + //Clamped so that a DeflectionTimescale of less then 1 does not increase force over original velocity + private void ComputeLinearDeflection(float pTimestep) + { + Vector3 linearDeflectionV = Vector3.Zero; + Vector3 velocityV = VehicleForwardVelocity; + + if (BSParam.VehicleEnableLinearDeflection) + { + // Velocity in Y and Z dimensions is movement to the side or turning. + // Compute deflection factor from the to the side and rotational velocity + linearDeflectionV.Y = SortedClampInRange(0, (velocityV.Y * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Y); + linearDeflectionV.Z = SortedClampInRange(0, (velocityV.Z * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Z); + + // Velocity to the side and around is corrected and moved into the forward direction + linearDeflectionV.X += Math.Abs(linearDeflectionV.Y); + linearDeflectionV.X += Math.Abs(linearDeflectionV.Z); + + // Scale the deflection to the fractional simulation time + linearDeflectionV *= pTimestep; + + // Subtract the sideways and rotational velocity deflection factors while adding the correction forward + linearDeflectionV *= new Vector3(1, -1, -1); + + // Correction is vehicle relative. Convert to world coordinates. + Vector3 linearDeflectionW = linearDeflectionV * VehicleFrameOrientation; + + // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall. + if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.HasSomeCollision) + { + linearDeflectionW.Z = 0f; + } + + VehicleVelocity += linearDeflectionW; + + VDetailLog("{0}, MoveLinear,LinearDeflection,linDefEff={1},linDefTS={2},linDeflectionV={3}", + ControllingPrim.LocalID, m_linearDeflectionEfficiency, m_linearDeflectionTimescale, linearDeflectionV); + } + } + + public void ComputeLinearTerrainHeightCorrection(float pTimestep) + { + // If below the terrain, move us above the ground a little. + // TODO: Consider taking the rotated size of the object or possibly casting a ray. + if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) + { + // Force position because applying force won't get the vehicle through the terrain + Vector3 newPosition = VehiclePosition; + newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; + VehiclePosition = newPosition; + VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", + ControllingPrim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); + } + } + + public void ComputeLinearHover(float pTimestep) + { + // m_VhoverEfficiency: 0=bouncy, 1=totally damped + // m_VhoverTimescale: time to achieve height + if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0 && (m_VhoverHeight > 0) && (m_VhoverTimescale < 300)) + { + // We should hover, get the target height + if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) + { + m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight; + } + if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) + { + m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight; + } + if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) + { + m_VhoverTargetHeight = m_VhoverHeight; + } + if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) + { + // If body is already heigher, use its height as target height + if (VehiclePosition.Z > m_VhoverTargetHeight) + { + m_VhoverTargetHeight = VehiclePosition.Z; + + // A 'misfeature' of this flag is that if the vehicle is above it's hover height, + // the vehicle's buoyancy goes away. This is an SL bug that got used by so many + // scripts that it could not be changed. + // So, if above the height, reapply gravity if buoyancy had it turned off. + if (m_VehicleBuoyancy != 0) + { + Vector3 appliedGravity = ControllingPrim.ComputeGravity(ControllingPrim.Buoyancy) * m_vehicleMass; + VehicleAddForce(appliedGravity); + } + } + } + + if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) + { + if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) + { + Vector3 pos = VehiclePosition; + pos.Z = m_VhoverTargetHeight; + VehiclePosition = pos; + + VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", ControllingPrim.LocalID, pos); + } + } + else + { + // Error is positive if below the target and negative if above. + Vector3 hpos = VehiclePosition; + float verticalError = m_VhoverTargetHeight - hpos.Z; + float verticalCorrection = verticalError / m_VhoverTimescale; + verticalCorrection *= m_VhoverEfficiency; + + hpos.Z += verticalCorrection; + VehiclePosition = hpos; + + // Since we are hovering, we need to do the opposite of falling -- get rid of world Z + Vector3 vel = VehicleVelocity; + vel.Z = 0f; + VehicleVelocity = vel; + + /* + float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; + Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity); + verticalCorrection *= m_vehicleMass; + + // TODO: implement m_VhoverEfficiency correctly + VehicleAddForceImpulse(verticalCorrection); + */ + + VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}", + ControllingPrim.LocalID, VehiclePosition, m_VhoverEfficiency, + m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, + verticalError, verticalCorrection); + } + } + } + + public bool ComputeLinearBlockingEndPoint(float pTimestep) + { + bool changed = false; + + Vector3 pos = VehiclePosition; + Vector3 posChange = pos - m_lastPositionVector; + if (m_BlockingEndPoint != Vector3.Zero) + { + if (pos.X >= (m_BlockingEndPoint.X - (float)1)) + { + pos.X -= posChange.X + 1; + changed = true; + } + if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) + { + pos.Y -= posChange.Y + 1; + changed = true; + } + if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) + { + pos.Z -= posChange.Z + 1; + changed = true; + } + if (pos.X <= 0) + { + pos.X += posChange.X + 1; + changed = true; + } + if (pos.Y <= 0) + { + pos.Y += posChange.Y + 1; + changed = true; + } + if (changed) + { + VehiclePosition = pos; + VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", + ControllingPrim.LocalID, m_BlockingEndPoint, posChange, pos); + } + } + return changed; + } + + // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : + // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when + // used with conjunction with banking: the strength of the banking will decay when the + // vehicle no longer experiences collisions. The decay timescale is the same as + // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering + // when they are in mid jump. + // TODO: this code is wrong. Also, what should it do for boats (height from water)? + // This is just using the ground and a general collision check. Should really be using + // a downward raycast to find what is below. + public void ComputeLinearMotorUp(float pTimestep) + { + if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) + { + // This code tries to decide if the object is not on the ground and then pushing down + /* + float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); + distanceAboveGround = VehiclePosition.Z - targetHeight; + // Not colliding if the vehicle is off the ground + if (!Prim.HasSomeCollision) + { + // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); + VehicleVelocity += new Vector3(0, 0, -distanceAboveGround); + } + // TODO: this calculation is wrong. From the description at + // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce + // has a decay factor. This says this force should + // be computed with a motor. + // TODO: add interaction with banking. + VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", + Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret); + */ + + // Another approach is to measure if we're going up. If going up and not colliding, + // the vehicle is in the air. Fix that by pushing down. + if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1) + { + // Get rid of any of the velocity vector that is pushing us up. + float upVelocity = VehicleVelocity.Z; + VehicleVelocity += new Vector3(0, 0, -upVelocity); + + /* + // If we're pointed up into the air, we should nose down + Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; + // The rotation around the Y axis is pitch up or down + if (pointingDirection.Y > 0.01f) + { + float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y); + Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f); + // Rotate into world coordinates and apply to vehicle + angularCorrectionVector *= VehicleOrientation; + VehicleAddAngularForce(angularCorrectionVector); + VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}", + Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector); + } + */ + VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", + ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity); + } + } + } + + private void ApplyGravity(float pTimeStep) + { + Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; + + // Hack to reduce downward force if the vehicle is probably sitting on the ground + if (ControllingPrim.HasSomeCollision && IsGroundVehicle) + appliedGravity *= BSParam.VehicleGroundGravityFudge; + + VehicleAddForce(appliedGravity); + + VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}", + ControllingPrim.LocalID, m_VehicleGravity, + ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); + } + + // ======================================================================= + // ======================================================================= + // Apply the effect of the angular motor. + // The 'contribution' is how much angular correction velocity each function wants. + // All the contributions are added together and the resulting velocity is + // set directly on the vehicle. + private void MoveAngular(float pTimestep) + { + ComputeAngularTurning(pTimestep); + + ComputeAngularVerticalAttraction(); + + ComputeAngularDeflection(); + + ComputeAngularBanking(); + + // ================================================================== + if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.0001f)) + { + // The vehicle is not adding anything angular wise. + VehicleRotationalVelocity = Vector3.Zero; + VDetailLog("{0}, MoveAngular,done,zero", ControllingPrim.LocalID); + } + else + { + VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", ControllingPrim.LocalID, VehicleRotationalVelocity); + } + + // ================================================================== + //Offset section + if (m_linearMotorOffset != Vector3.Zero) + { + //Offset of linear velocity doesn't change the linear velocity, + // but causes a torque to be applied, for example... + // + // IIIII >>> IIIII + // IIIII >>> IIIII + // IIIII >>> IIIII + // ^ + // | Applying a force at the arrow will cause the object to move forward, but also rotate + // + // + // The torque created is the linear velocity crossed with the offset + + // TODO: this computation should be in the linear section + // because that is where we know the impulse being applied. + Vector3 torqueFromOffset = Vector3.Zero; + // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); + if (float.IsNaN(torqueFromOffset.X)) + torqueFromOffset.X = 0; + if (float.IsNaN(torqueFromOffset.Y)) + torqueFromOffset.Y = 0; + if (float.IsNaN(torqueFromOffset.Z)) + torqueFromOffset.Z = 0; + + VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); + VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", ControllingPrim.LocalID, torqueFromOffset); + } + + } + + private void ComputeAngularTurning(float pTimestep) + { + // The user wants this many radians per second angular change? + Vector3 origVehicleRotationalVelocity = VehicleRotationalVelocity; // DEBUG DEBUG + Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleFrameOrientation); + Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV); + + // ================================================================== + // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : + // This flag prevents linear deflection parallel to world z-axis. This is useful + // for preventing ground vehicles with large linear deflection, like bumper cars, + // from climbing their linear deflection into the sky. + // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement + // TODO: This is here because this is where ODE put it but documentation says it + // is a linear effect. Where should this check go? + //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) + // { + // angularMotorContributionV.X = 0f; + // angularMotorContributionV.Y = 0f; + // } + + // Reduce any velocity by friction. + Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep); + angularMotorContributionV -= (currentAngularV * frictionFactorW); + + Vector3 angularMotorContributionW = angularMotorContributionV * VehicleFrameOrientation; + VehicleRotationalVelocity += angularMotorContributionW; + + VDetailLog("{0}, MoveAngular,angularTurning,curAngVelV={1},origVehRotVel={2},vehRotVel={3},frictFact={4}, angContribV={5},angContribW={6}", + ControllingPrim.LocalID, currentAngularV, origVehicleRotationalVelocity, VehicleRotationalVelocity, frictionFactorW, angularMotorContributionV, angularMotorContributionW); + } + + // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: + // Some vehicles, like boats, should always keep their up-side up. This can be done by + // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to + // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the + // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency, + // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An + // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an + // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. + public void ComputeAngularVerticalAttraction() + { + + // If vertical attaction timescale is reasonable + if (BSParam.VehicleEnableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) + { + Vector3 vehicleUpAxis = Vector3.UnitZ * VehicleFrameOrientation; + switch (BSParam.VehicleAngularVerticalAttractionAlgorithm) + { + case 0: + { + //Another formula to try got from : + //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html + + // Flipping what was originally a timescale into a speed variable and then multiplying it by 2 + // since only computing half the distance between the angles. + float verticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f; + + // Make a prediction of where the up axis will be when this is applied rather then where it is now as + // this makes for a smoother adjustment and less fighting between the various forces. + Vector3 predictedUp = vehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); + + // This is only half the distance to the target so it will take 2 seconds to complete the turn. + Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ); + + if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != 0) + { + Vector3 vehicleForwardAxis = Vector3.UnitX * VehicleFrameOrientation; + torqueVector = ProjectVector(torqueVector, vehicleForwardAxis); + } + + // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared + Vector3 vertContributionV = torqueVector * verticalAttractionSpeed * verticalAttractionSpeed; + + VehicleRotationalVelocity += vertContributionV; + + VDetailLog("{0}, MoveAngular,verticalAttraction,vertAttrSpeed={1},upAxis={2},PredictedUp={3},torqueVector={4},contrib={5}", + ControllingPrim.LocalID, + verticalAttractionSpeed, + vehicleUpAxis, + predictedUp, + torqueVector, + vertContributionV); + break; + } + case 1: + { + // Possible solution derived from a discussion at: + // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no + + // Create a rotation that is only the vehicle's rotation around Z + Vector3 currentEulerW = Vector3.Zero; + VehicleFrameOrientation.GetEulerAngles(out currentEulerW.X, out currentEulerW.Y, out currentEulerW.Z); + Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEulerW.Z); + + // Create the axis that is perpendicular to the up vector and the rotated up vector. + Vector3 differenceAxisW = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleFrameOrientation); + // Compute the angle between those to vectors. + double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation))); + // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical + + // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied. + // TODO: add 'efficiency'. + // differenceAngle /= m_verticalAttractionTimescale; + + // Create the quaterian representing the correction angle + Quaternion correctionRotationW = Quaternion.CreateFromAxisAngle(differenceAxisW, (float)differenceAngle); + + // Turn that quaternion into Euler values to make it into velocities to apply. + Vector3 vertContributionW = Vector3.Zero; + correctionRotationW.GetEulerAngles(out vertContributionW.X, out vertContributionW.Y, out vertContributionW.Z); + vertContributionW *= -1f; + vertContributionW /= m_verticalAttractionTimescale; + + VehicleRotationalVelocity += vertContributionW; + + VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},diffAxis={2},diffAng={3},corrRot={4},contrib={5}", + ControllingPrim.LocalID, + vehicleUpAxis, + differenceAxisW, + differenceAngle, + correctionRotationW, + vertContributionW); + break; + } + case 2: + { + Vector3 vertContributionV = Vector3.Zero; + Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG + + // Take a vector pointing up and convert it from world to vehicle relative coords. + Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation); + + // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) + // is now: + // leaning to one side: rotated around the X axis with the Y value going + // from zero (nearly straight up) to one (completely to the side)) or + // leaning front-to-back: rotated around the Y axis with the value of X being between + // zero and one. + // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. + + // Y error means needed rotation around X axis and visa versa. + // Since the error goes from zero to one, the asin is the corresponding angle. + vertContributionV.X = (float)Math.Asin(verticalError.Y); + // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) + vertContributionV.Y = -(float)Math.Asin(verticalError.X); + + // If verticalError.Z is negative, the vehicle is upside down. Add additional push. + if (verticalError.Z < 0f) + { + vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour; + // vertContribution.Y -= PIOverFour; + } + + // 'vertContrbution' is now the necessary angular correction to correct tilt in one second. + // Correction happens over a number of seconds. + Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG + + // The correction happens over the user's time period + vertContributionV /= m_verticalAttractionTimescale; + + // Rotate the vehicle rotation to the world coordinates. + VehicleRotationalVelocity += (vertContributionV * VehicleFrameOrientation); + + VDetailLog("{0}, MoveAngular,verticalAttraction,,upAxis={1},origRotVW={2},vertError={3},unscaledV={4},eff={5},ts={6},vertContribV={7}", + ControllingPrim.LocalID, + vehicleUpAxis, + origRotVelW, + verticalError, + unscaledContribVerticalErrorV, + m_verticalAttractionEfficiency, + m_verticalAttractionTimescale, + vertContributionV); + break; + } + default: + { + break; + } + } + } + } + + // Angular correction to correct the direction the vehicle is pointing to be + // the direction is should want to be pointing. + // The vehicle is moving in some direction and correct its orientation to it is pointing + // in that direction. + // TODO: implement reference frame. + public void ComputeAngularDeflection() + { + + if (BSParam.VehicleEnableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2) + { + Vector3 deflectContributionV = Vector3.Zero; + + // The direction the vehicle is moving + Vector3 movingDirection = VehicleVelocity; + movingDirection.Normalize(); + + // If the vehicle is going backward, it is still pointing forward + movingDirection *= Math.Sign(VehicleForwardSpeed); + + // The direction the vehicle is pointing + Vector3 pointingDirection = Vector3.UnitX * VehicleFrameOrientation; + //Predict where the Vehicle will be pointing after AngularVelocity change is applied. This will keep + // from overshooting and allow this correction to merge with the Vertical Attraction peacefully. + Vector3 predictedPointingDirection = pointingDirection * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); + predictedPointingDirection.Normalize(); + + // The difference between what is and what should be. + // Vector3 deflectionError = movingDirection - predictedPointingDirection; + Vector3 deflectionError = Vector3.Cross(movingDirection, predictedPointingDirection); + + // Don't try to correct very large errors (not our job) + // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X); + // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y); + // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z); + if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f; + if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f; + if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f; + + // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); + + // Scale the correction by recovery timescale and efficiency + // Not modeling a spring so clamp the scale to no more then the arc + deflectContributionV = (-deflectionError) * ClampInRange(0, m_angularDeflectionEfficiency/m_angularDeflectionTimescale,1f); + //deflectContributionV /= m_angularDeflectionTimescale; + + VehicleRotationalVelocity += deflectContributionV; + VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", + ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); + VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3},PredictedPointingDir={4}", + ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale, predictedPointingDirection); + } + } + + // Angular change to rotate the vehicle around the Z axis when the vehicle + // is tipped around the X axis. + // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: + // The vertical attractor feature must be enabled in order for the banking behavior to + // function. The way banking works is this: a rotation around the vehicle's roll-axis will + // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude + // of the yaw effect will be proportional to the + // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's + // velocity along its preferred axis of motion. + // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any + // positive rotation (by the right-hand rule) about the roll-axis will effect a + // (negative) torque around the yaw-axis, making it turn to the right--that is the + // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. + // Negating the banking coefficient will make it so that the vehicle leans to the + // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). + // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making + // banking vehicles do what you want rather than what the laws of physics allow. + // For example, consider a real motorcycle...it must be moving forward in order for + // it to turn while banking, however video-game motorcycles are often configured + // to turn in place when at a dead stop--because they are often easier to control + // that way using the limited interface of the keyboard or game controller. The + // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic + // banking by functioning as a slider between a banking that is correspondingly + // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the + // banking effect depends only on the vehicle's rotation about its roll-axis compared + // to "dynamic" where the banking is also proportional to its velocity along its + // roll-axis. Finding the best value of the "mixture" will probably require trial and error. + // The time it takes for the banking behavior to defeat a preexisting angular velocity about the + // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to + // bank quickly then give it a banking timescale of about a second or less, otherwise you can + // make a sluggish vehicle by giving it a timescale of several seconds. + public void ComputeAngularBanking() + { + if (BSParam.VehicleEnableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) + { + Vector3 bankingContributionV = Vector3.Zero; + + // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented. + // As the vehicle rolls to the right or left, the Y value will increase from + // zero (straight up) to 1 or -1 (full tilt right or left) + Vector3 rollComponents = Vector3.UnitZ * VehicleFrameOrientation; + + // Figure out the yaw value for this much roll. + float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency; + // actual error = static turn error + dynamic turn error + float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed); + + // TODO: the banking effect should not go to infinity but what to limit it to? + // And what should happen when this is being added to a user defined yaw that is already PI*4? + mixedYawAngle = ClampInRange(-FourPI, mixedYawAngle, FourPI); + + // Build the force vector to change rotation from what it is to what it should be + bankingContributionV.Z = -mixedYawAngle; + + // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4. + bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge; + + VehicleRotationalVelocity += bankingContributionV; + + + VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", + ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); + } + } + + // This is from previous instantiations of XXXDynamics.cs. + // Applies roll reference frame. + // TODO: is this the right way to separate the code to do this operation? + // Should this be in MoveAngular()? + internal void LimitRotation(float timestep) + { + Quaternion rotq = VehicleOrientation; + Quaternion m_rot = rotq; + if (m_RollreferenceFrame != Quaternion.Identity) + { + if (rotq.X >= m_RollreferenceFrame.X) + { + m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); + } + if (rotq.Y >= m_RollreferenceFrame.Y) + { + m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); + } + if (rotq.X <= -m_RollreferenceFrame.X) + { + m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); + } + if (rotq.Y <= -m_RollreferenceFrame.Y) + { + m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); + } + } + if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) + { + m_rot.X = 0; + m_rot.Y = 0; + } + if (rotq != m_rot) + { + VehicleOrientation = m_rot; + VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", ControllingPrim.LocalID, rotq, m_rot); + } + + } + + // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce + // some value by to apply this friction. + private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep) + { + Vector3 frictionFactor = Vector3.Zero; + if (friction != BSMotor.InfiniteVector) + { + // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; + // Individual friction components can be 'infinite' so compute each separately. + frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X); + frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y); + frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z); + frictionFactor *= pTimestep; + } + return frictionFactor; + } + + private float SortedClampInRange(float clampa, float val, float clampb) + { + if (clampa > clampb) + { + float temp = clampa; + clampa = clampb; + clampb = temp; + } + return ClampInRange(clampa, val, clampb); + + } + + //Given a Vector and a unit vector will return the amount of the vector is on the same axis as the unit. + private Vector3 ProjectVector(Vector3 vector, Vector3 onNormal) + { + float vectorDot = Vector3.Dot(vector, onNormal); + return onNormal * vectorDot; + + } + + private float ClampInRange(float low, float val, float high) + { + return Math.Max(low, Math.Min(val, high)); + // return Utils.Clamp(val, low, high); + } + + // Invoke the detailed logger and output something if it's enabled. + private void VDetailLog(string msg, params Object[] args) + { + if (ControllingPrim.PhysScene.VehicleLoggingEnabled) + ControllingPrim.PhysScene.DetailLog(msg, args); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs new file mode 100755 index 0000000..8312239 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs @@ -0,0 +1,503 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + +public abstract class BSLinkset +{ + // private static string LogHeader = "[BULLETSIM LINKSET]"; + + public enum LinksetImplementation + { + Constraint = 0, // linkset tied together with constraints + Compound = 1, // linkset tied together as a compound object + Manual = 2 // linkset tied together manually (code moves all the pieces) + } + // Create the correct type of linkset for this child + public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent) + { + BSLinkset ret = null; + + switch (parent.LinksetType) + { + case LinksetImplementation.Constraint: + ret = new BSLinksetConstraints(physScene, parent); + break; + case LinksetImplementation.Compound: + ret = new BSLinksetCompound(physScene, parent); + break; + case LinksetImplementation.Manual: + // ret = new BSLinksetManual(physScene, parent); + break; + default: + ret = new BSLinksetCompound(physScene, parent); + break; + } + if (ret == null) + { + physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID); + } + return ret; + } + + public class BSLinkInfo + { + public BSPrimLinkable member; + public BSLinkInfo(BSPrimLinkable pMember) + { + member = pMember; + } + public virtual void ResetLink() { } + public virtual void SetLinkParameters(BSConstraint constrain) { } + // Returns 'true' if physical property updates from the child should be reported to the simulator + public virtual bool ShouldUpdateChildProperties() { return false; } + } + + public LinksetImplementation LinksetImpl { get; protected set; } + + public BSPrimLinkable LinksetRoot { get; protected set; } + + protected BSScene m_physicsScene { get; private set; } + + static int m_nextLinksetID = 1; + public int LinksetID { get; private set; } + + // The children under the root in this linkset. + // protected HashSet m_children; + protected Dictionary m_children; + + // We lock the diddling of linkset classes to prevent any badness. + // This locks the modification of the instances of this class. Changes + // to the physical representation is done via the tainting mechenism. + protected object m_linksetActivityLock = new Object(); + + // We keep the prim's mass in the linkset structure since it could be dependent on other prims + public float LinksetMass { get; protected set; } + + public virtual bool LinksetIsColliding { get { return false; } } + + public OMV.Vector3 CenterOfMass + { + get { return ComputeLinksetCenterOfMass(); } + } + + public OMV.Vector3 GeometricCenter + { + get { return ComputeLinksetGeometricCenter(); } + } + + protected BSLinkset(BSScene scene, BSPrimLinkable parent) + { + // A simple linkset of one (no children) + LinksetID = m_nextLinksetID++; + // We create LOTS of linksets. + if (m_nextLinksetID <= 0) + m_nextLinksetID = 1; + m_physicsScene = scene; + LinksetRoot = parent; + m_children = new Dictionary(); + LinksetMass = parent.RawMass; + Rebuilding = false; + RebuildScheduled = false; + + parent.ClearDisplacement(); + } + + // Link to a linkset where the child knows the parent. + // Parent changing should not happen so do some sanity checking. + // We return the parent's linkset so the child can track its membership. + // Called at runtime. + public BSLinkset AddMeToLinkset(BSPrimLinkable child) + { + lock (m_linksetActivityLock) + { + // Don't add the root to its own linkset + if (!IsRoot(child)) + AddChildToLinkset(child); + LinksetMass = ComputeLinksetMass(); + } + return this; + } + + // Remove a child from a linkset. + // Returns a new linkset for the child which is a linkset of one (just the + // orphened child). + // Called at runtime. + public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime) + { + lock (m_linksetActivityLock) + { + if (IsRoot(child)) + { + // Cannot remove the root from a linkset. + return this; + } + RemoveChildFromLinkset(child, inTaintTime); + LinksetMass = ComputeLinksetMass(); + } + + // The child is down to a linkset of just itself + return BSLinkset.Factory(m_physicsScene, child); + } + + // Return 'true' if the passed object is the root object of this linkset + public bool IsRoot(BSPrimLinkable requestor) + { + return (requestor.LocalID == LinksetRoot.LocalID); + } + + public int NumberOfChildren { get { return m_children.Count; } } + + // Return 'true' if this linkset has any children (more than the root member) + public bool HasAnyChildren { get { return (m_children.Count > 0); } } + + // Return 'true' if this child is in this linkset + public bool HasChild(BSPrimLinkable child) + { + bool ret = false; + lock (m_linksetActivityLock) + { + ret = m_children.ContainsKey(child); + } + return ret; + } + + // Perform an action on each member of the linkset including root prim. + // Depends on the action on whether this should be done at taint time. + public delegate bool ForEachMemberAction(BSPrimLinkable obj); + public virtual bool ForEachMember(ForEachMemberAction action) + { + bool ret = false; + lock (m_linksetActivityLock) + { + action(LinksetRoot); + foreach (BSPrimLinkable po in m_children.Keys) + { + if (action(po)) + break; + } + } + return ret; + } + + public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo) + { + bool ret = false; + BSLinkInfo found = null; + lock (m_linksetActivityLock) + { + ret = m_children.TryGetValue(child, out found); + } + foundInfo = found; + return ret; + } + // Perform an action on each member of the linkset including root prim. + // Depends on the action on whether this should be done at taint time. + public delegate bool ForEachLinkInfoAction(BSLinkInfo obj); + public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action) + { + bool ret = false; + lock (m_linksetActivityLock) + { + foreach (BSLinkInfo po in m_children.Values) + { + if (action(po)) + break; + } + } + return ret; + } + + // Check the type of the link and return 'true' if the link is flexible and the + // updates from the child should be sent to the simulator so things change. + public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child) + { + bool ret = false; + + BSLinkInfo linkInfo; + if (m_children.TryGetValue(child, out linkInfo)) + { + ret = linkInfo.ShouldUpdateChildProperties(); + } + + return ret; + } + + // Called after a simulation step to post a collision with this object. + // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have + // anything to add for the collision and it should be passed through normal processing. + // Default processing for a linkset. + public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee, + OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) + { + bool ret = false; + + // prims in the same linkset cannot collide with each other + BSPrimLinkable convCollidee = collidee as BSPrimLinkable; + if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID)) + { + // By returning 'true', we tell the caller the collision has been 'handled' so it won't + // do anything about this collision and thus, effectivily, ignoring the collision. + ret = true; + } + else + { + // Not a collision between members of the linkset. Must be a real collision. + // So the linkset root can know if there is a collision anywhere in the linkset. + LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep; + } + + return ret; + } + + // I am the root of a linkset and a new child is being added + // Called while LinkActivity is locked. + protected abstract void AddChildToLinkset(BSPrimLinkable child); + + // I am the root of a linkset and one of my children is being removed. + // Safe to call even if the child is not really in my linkset. + protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime); + + // When physical properties are changed the linkset needs to recalculate + // its internal properties. + // May be called at runtime or taint-time. + public virtual void Refresh(BSPrimLinkable requestor) + { + LinksetMass = ComputeLinksetMass(); + } + + // Flag denoting the linkset is in the process of being rebuilt. + // Used to know not the schedule a rebuild in the middle of a rebuild. + // Because of potential update calls that could want to schedule another rebuild. + protected bool Rebuilding { get; set; } + + // Flag saying a linkset rebuild has been scheduled. + // This is turned on when the rebuild is requested and turned off when + // the rebuild is complete. Used to limit modifications to the + // linkset parameters while the linkset is in an intermediate state. + // Protected by a "lock(m_linsetActivityLock)" on the BSLinkset object + public bool RebuildScheduled { get; protected set; } + + // The object is going dynamic (physical). Do any setup necessary + // for a dynamic linkset. + // Only the state of the passed object can be modified. The rest of the linkset + // has not yet been fully constructed. + // Return 'true' if any properties updated on the passed object. + // Called at taint-time! + public abstract bool MakeDynamic(BSPrimLinkable child); + + public virtual bool AllPartsComplete + { + get { + bool ret = true; + this.ForEachMember((member) => + { + if ((!member.IsInitialized) || member.IsIncomplete || member.PrimAssetState == BSPhysObject.PrimAssetCondition.Waiting) + { + ret = false; + return true; // exit loop + } + return false; // continue loop + }); + return ret; + } + } + + // The object is going static (non-physical). Do any setup necessary + // for a static linkset. + // Return 'true' if any properties updated on the passed object. + // Called at taint-time! + public abstract bool MakeStatic(BSPrimLinkable child); + + // Called when a parameter update comes from the physics engine for any object + // of the linkset is received. + // Passed flag is update came from physics engine (true) or the user (false). + // Called at taint-time!! + public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject); + + // Routine used when rebuilding the body of the root of the linkset + // Destroy all the constraints have have been made to root. + // This is called when the root body is changing. + // Returns 'true' of something was actually removed and would need restoring + // Called at taint-time!! + public abstract bool RemoveDependencies(BSPrimLinkable child); + + // ================================================================ + // Some physical setting happen to all members of the linkset + public virtual void SetPhysicalFriction(float friction) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetFriction(member.PhysBody, friction); + return false; // 'false' says to continue looping + } + ); + } + public virtual void SetPhysicalRestitution(float restitution) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetRestitution(member.PhysBody, restitution); + return false; // 'false' says to continue looping + } + ); + } + public virtual void SetPhysicalGravity(OMV.Vector3 gravity) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetGravity(member.PhysBody, gravity); + return false; // 'false' says to continue looping + } + ); + } + public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + { + OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass); + member.Inertia = inertia * inertiaFactor; + m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia); + m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); + DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia); + + } + return false; // 'false' says to continue looping + } + ); + } + public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags); + return false; // 'false' says to continue looping + } + ); + } + public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags); + return false; // 'false' says to continue looping + } + ); + } + public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags); + return false; // 'false' says to continue looping + } + ); + } + // ================================================================ + protected virtual float ComputeLinksetMass() + { + float mass = LinksetRoot.RawMass; + if (HasAnyChildren) + { + lock (m_linksetActivityLock) + { + foreach (BSPrimLinkable bp in m_children.Keys) + { + mass += bp.RawMass; + } + } + } + return mass; + } + + // Computes linkset's center of mass in world coordinates. + protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() + { + OMV.Vector3 com; + lock (m_linksetActivityLock) + { + com = LinksetRoot.Position * LinksetRoot.RawMass; + float totalMass = LinksetRoot.RawMass; + + foreach (BSPrimLinkable bp in m_children.Keys) + { + com += bp.Position * bp.RawMass; + totalMass += bp.RawMass; + } + if (totalMass != 0f) + com /= totalMass; + } + + return com; + } + + protected virtual OMV.Vector3 ComputeLinksetGeometricCenter() + { + OMV.Vector3 com; + lock (m_linksetActivityLock) + { + com = LinksetRoot.Position; + + foreach (BSPrimLinkable bp in m_children.Keys) + { + com += bp.Position; + } + com /= (m_children.Count + 1); + } + + return com; + } + + #region Extension + public virtual object Extension(string pFunct, params object[] pParams) + { + return null; + } + #endregion // Extension + + // Invoke the detailed logger and output something if it's enabled. + protected void DetailLog(string msg, params Object[] args) + { + if (m_physicsScene.PhysicsLogging.Enabled) + m_physicsScene.DetailLog(msg, args); + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs new file mode 100755 index 0000000..953ddee --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs @@ -0,0 +1,477 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; + +using OpenSim.Framework; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + +public sealed class BSLinksetCompound : BSLinkset +{ +#pragma warning disable 414 + private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; +#pragma warning restore 414 + + public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) + : base(scene, parent) + { + LinksetImpl = LinksetImplementation.Compound; + } + + // ================================================================ + // Changing the physical property of the linkset only needs to change the root + public override void SetPhysicalFriction(float friction) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction); + } + public override void SetPhysicalRestitution(float restitution) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution); + } + public override void SetPhysicalGravity(OMV.Vector3 gravity) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity); + } + public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) + { + OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass); + LinksetRoot.Inertia = inertia * inertiaFactor; + m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia); + m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody); + } + public override void SetPhysicalCollisionFlags(CollisionFlags collFlags) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags); + } + public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags); + } + public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags); + } + // ================================================================ + + // When physical properties are changed the linkset needs to recalculate + // its internal properties. + public override void Refresh(BSPrimLinkable requestor) + { + // Something changed so do the rebuilding thing + ScheduleRebuild(requestor); + base.Refresh(requestor); + } + + // Schedule a refresh to happen after all the other taint processing. + private void ScheduleRebuild(BSPrimLinkable requestor) + { + // When rebuilding, it is possible to set properties that would normally require a rebuild. + // If already rebuilding, don't request another rebuild. + // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. + lock (m_linksetActivityLock) + { + if (!RebuildScheduled && !Rebuilding && HasAnyChildren) + { + InternalScheduleRebuild(requestor); + } + } + } + + // Must be called with m_linksetActivityLock or race conditions will haunt you. + private void InternalScheduleRebuild(BSPrimLinkable requestor) + { + DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rebuilding={1},hasChildren={2}", + requestor.LocalID, Rebuilding, HasAnyChildren); + RebuildScheduled = true; + m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() + { + if (HasAnyChildren) + { + if (this.AllPartsComplete) + { + RecomputeLinksetCompound(); + } + else + { + DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rescheduling because not all children complete", + requestor.LocalID); + InternalScheduleRebuild(requestor); + } + } + RebuildScheduled = false; + }); + } + + // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset. + // Only the state of the passed object can be modified. The rest of the linkset + // has not yet been fully constructed. + // Return 'true' if any properties updated on the passed object. + // Called at taint-time! + public override bool MakeDynamic(BSPrimLinkable child) + { + bool ret = false; + DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); + if (IsRoot(child)) + { + // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. + Refresh(LinksetRoot); + } + return ret; + } + + // The object is going static (non-physical). We do not do anything for static linksets. + // Return 'true' if any properties updated on the passed object. + // Called at taint-time! + public override bool MakeStatic(BSPrimLinkable child) + { + bool ret = false; + + DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); + child.ClearDisplacement(); + if (IsRoot(child)) + { + // Schedule a rebuild to verify that the root shape is set to the real shape. + Refresh(LinksetRoot); + } + return ret; + } + + // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then. + // Called at taint-time. + public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) + { + if (!LinksetRoot.IsPhysicallyActive) + { + // No reason to do this physical stuff for static linksets. + DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID); + return; + } + + // The user moving a child around requires the rebuilding of the linkset compound shape + // One problem is this happens when a border is crossed -- the simulator implementation + // stores the position into the group which causes the move of the object + // but it also means all the child positions get updated. + // What would cause an unnecessary rebuild so we make sure the linkset is in a + // region before bothering to do a rebuild. + if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) + { + // If a child of the linkset is updating only the position or rotation, that can be done + // without rebuilding the linkset. + // If a handle for the child can be fetch, we update the child here. If a rebuild was + // scheduled by someone else, the rebuild will just replace this setting. + + bool updatedChild = false; + // Anything other than updating position or orientation usually means a physical update + // and that is caused by us updating the object. + if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) + { + // Find the physical instance of the child + if (!RebuildScheduled // if rebuilding, let the rebuild do it + && !LinksetRoot.IsIncomplete // if waiting for assets or whatever, don't change + && LinksetRoot.PhysShape.HasPhysicalShape // there must be a physical shape assigned + && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) + { + // It is possible that the linkset is still under construction and the child is not yet + // inserted into the compound shape. A rebuild of the linkset in a pre-step action will + // build the whole thing with the new position or rotation. + // The index must be checked because Bullet references the child array but does no validity + // checking of the child index passed. + int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); + if (updated.LinksetChildIndex < numLinksetChildren) + { + BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); + if (linksetChildShape.HasPhysicalShape) + { + // Found the child shape within the compound shape + m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, + updated.RawPosition - LinksetRoot.RawPosition, + updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), + true /* shouldRecalculateLocalAabb */); + updatedChild = true; + DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}", + updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation); + } + else // DEBUG DEBUG + { // DEBUG DEBUG + DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}", + updated.LocalID, linksetChildShape); + } // DEBUG DEBUG + } + else // DEBUG DEBUG + { // DEBUG DEBUG + // the child is not yet in the compound shape. This is non-fatal. + DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}", + updated.LocalID, numLinksetChildren, updated.LinksetChildIndex); + } // DEBUG DEBUG + } + else // DEBUG DEBUG + { // DEBUG DEBUG + DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID); + } // DEBUG DEBUG + + if (!updatedChild) + { + // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info. + // Note: there are several ways through this code that will not update the child if + // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since + // there will already be a rebuild scheduled. + DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", + updated.LocalID, whichUpdated); + Refresh(updated); + } + } + } + } + + // Routine called when rebuilding the body of some member of the linkset. + // If one of the bodies is being changed, the linkset needs rebuilding. + // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated. + // Returns 'true' of something was actually removed and would need restoring + // Called at taint-time!! + public override bool RemoveDependencies(BSPrimLinkable child) + { + bool ret = false; + + DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", + child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); + + Refresh(child); + + return ret; + } + + // ================================================================ + + // Add a new child to the linkset. + // Called while LinkActivity is locked. + protected override void AddChildToLinkset(BSPrimLinkable child) + { + if (!HasChild(child)) + { + m_children.Add(child, new BSLinkInfo(child)); + + DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); + + // Rebuild the compound shape with the new child shape included + Refresh(child); + } + return; + } + + // Remove the specified child from the linkset. + // Safe to call even if the child is not really in the linkset. + protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) + { + child.ClearDisplacement(); + + if (m_children.Remove(child)) + { + DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", + child.LocalID, + LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, + child.LocalID, child.PhysBody.AddrString); + + // Cause the child's body to be rebuilt and thus restored to normal operation + child.ForceBodyShapeRebuild(inTaintTime); + + if (!HasAnyChildren) + { + // The linkset is now empty. The root needs rebuilding. + LinksetRoot.ForceBodyShapeRebuild(inTaintTime); + } + else + { + // Rebuild the compound shape with the child removed + Refresh(LinksetRoot); + } + } + return; + } + + // Called before the simulation step to make sure the compound based linkset + // is all initialized. + // Constraint linksets are rebuilt every time. + // Note that this works for rebuilding just the root after a linkset is taken apart. + // Called at taint time!! + private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape + private void RecomputeLinksetCompound() + { + try + { + Rebuilding = true; + + // No matter what is being done, force the root prim's PhysBody and PhysShape to get set + // to what they should be as if the root was not in a linkset. + // Not that bad since we only get into this routine if there are children in the linkset and + // something has been updated/changed. + // Have to do the rebuild before checking for physical because this might be a linkset + // being destructed and going non-physical. + LinksetRoot.ForceBodyShapeRebuild(true); + + // There is no reason to build all this physical stuff for a non-physical or empty linkset. + if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) + { + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); + return; // Note the 'finally' clause at the botton which will get executed. + } + + // Get a new compound shape to build the linkset shape in. + BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene); + + // Compute a displacement for each component so it is relative to the center-of-mass. + // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass + OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass(); + + OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation)); + OMV.Vector3 origRootPosition = LinksetRoot.RawPosition; + + // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass + OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; + if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass) + { + // Zero everything if center-of-mass displacement is not being done. + centerDisplacementV = OMV.Vector3.Zero; + LinksetRoot.ClearDisplacement(); + } + else + { + // The actual center-of-mass could have been set by the user. + centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV); + } + + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}", + LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV); + + // Add the shapes of all the components of the linkset + int memberIndex = 1; + ForEachMember((cPrim) => + { + if (IsRoot(cPrim)) + { + // Root shape is always index zero. + cPrim.LinksetChildIndex = 0; + } + else + { + cPrim.LinksetChildIndex = memberIndex; + memberIndex++; + } + + // Get a reference to the shape of the child for adding of that shape to the linkset compound shape + BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim); + + // Offset the child shape from the center-of-mass and rotate it to root relative. + OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV; + OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation; + + // Add the child shape to the compound shape being built + if (childShape.physShapeInfo.HasPhysicalShape) + { + m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}", + LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot); + + // Since we are borrowing the shape of the child, disable the origional child body + if (!IsRoot(cPrim)) + { + m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); + m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION); + // We don't want collisions from the old linkset children. + m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + cPrim.PhysBody.collisionType = CollisionType.LinksetChild; + } + } + else + { + // The linkset must be in an intermediate state where all the children have not yet + // been constructed. This sometimes happens on startup when everything is getting + // built and some shapes have to wait for assets to be read in. + // Just skip this linkset for the moment and cause the shape to be rebuilt next tick. + // One problem might be that the shape is broken somehow and it never becomes completely + // available. This might cause the rebuild to happen over and over. + InternalScheduleRebuild(LinksetRoot); + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChildWithNoShape,indx={1},cShape={2},offPos={3},offRot={4}", + LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot); + // Output an annoying warning. It should only happen once but if it keeps coming out, + // the user knows there is something wrong and will report it. + m_physicsScene.Logger.WarnFormat("{0} Linkset rebuild warning. If this happens more than one or two times, please report in Mantis 7191", LogHeader); + m_physicsScene.Logger.WarnFormat("{0} pName={1}, childIdx={2}, shape={3}", + LogHeader, LinksetRoot.Name, cPrim.LinksetChildIndex, childShape); + + // This causes the loop to bail on building the rest of this linkset. + // The rebuild operation will fix it up next tick or declare the object unbuildable. + return true; + } + + return false; // 'false' says to move onto the next child in the list + }); + + // Replace the root shape with the built compound shape. + // Object removed and added to world to get collision cache rebuilt for new shape. + LinksetRoot.PhysShape.Dereference(m_physicsScene); + LinksetRoot.PhysShape = linksetShape; + m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody); + m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo); + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody); + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}", + LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape); + + // With all of the linkset packed into the root prim, it has the mass of everyone. + LinksetMass = ComputeLinksetMass(); + LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); + + if (UseBulletSimRootOffsetHack) + { + // Enable the physical position updator to return the position and rotation of the root shape. + // This enables a feature in the C++ code to return the world coordinates of the first shape in the + // compound shape. This aleviates the need to offset the returned physical position by the + // center-of-mass offset. + // TODO: either debug this feature or remove it. + m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); + } + } + finally + { + Rebuilding = false; + } + + // See that the Aabb surrounds the new shape + m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); + } +} +} \ No newline at end of file diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs new file mode 100755 index 0000000..c4b4c86 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs @@ -0,0 +1,852 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public sealed class BSLinksetConstraints : BSLinkset +{ + // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; + + public class BSLinkInfoConstraint : BSLinkInfo + { + public ConstraintType constraintType; + public BSConstraint constraint; + public OMV.Vector3 linearLimitLow; + public OMV.Vector3 linearLimitHigh; + public OMV.Vector3 angularLimitLow; + public OMV.Vector3 angularLimitHigh; + public bool useFrameOffset; + public bool enableTransMotor; + public float transMotorMaxVel; + public float transMotorMaxForce; + public float cfm; + public float erp; + public float solverIterations; + // + public OMV.Vector3 frameInAloc; + public OMV.Quaternion frameInArot; + public OMV.Vector3 frameInBloc; + public OMV.Quaternion frameInBrot; + public bool useLinearReferenceFrameA; + // Spring + public bool[] springAxisEnable; + public float[] springDamping; + public float[] springStiffness; + public OMV.Vector3 springLinearEquilibriumPoint; + public OMV.Vector3 springAngularEquilibriumPoint; + + public BSLinkInfoConstraint(BSPrimLinkable pMember) + : base(pMember) + { + constraint = null; + ResetLink(); + member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID); + } + + // Set all the parameters for this constraint to a fixed, non-movable constraint. + public override void ResetLink() + { + // constraintType = ConstraintType.D6_CONSTRAINT_TYPE; + constraintType = ConstraintType.BS_FIXED_CONSTRAINT_TYPE; + linearLimitLow = OMV.Vector3.Zero; + linearLimitHigh = OMV.Vector3.Zero; + angularLimitLow = OMV.Vector3.Zero; + angularLimitHigh = OMV.Vector3.Zero; + useFrameOffset = BSParam.LinkConstraintUseFrameOffset; + enableTransMotor = BSParam.LinkConstraintEnableTransMotor; + transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; + transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; + cfm = BSParam.LinkConstraintCFM; + erp = BSParam.LinkConstraintERP; + solverIterations = BSParam.LinkConstraintSolverIterations; + frameInAloc = OMV.Vector3.Zero; + frameInArot = OMV.Quaternion.Identity; + frameInBloc = OMV.Vector3.Zero; + frameInBrot = OMV.Quaternion.Identity; + useLinearReferenceFrameA = true; + springAxisEnable = new bool[6]; + springDamping = new float[6]; + springStiffness = new float[6]; + for (int ii = 0; ii < springAxisEnable.Length; ii++) + { + springAxisEnable[ii] = false; + springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; + springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; + } + springLinearEquilibriumPoint = OMV.Vector3.Zero; + springAngularEquilibriumPoint = OMV.Vector3.Zero; + member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID); + } + + // Given a constraint, apply the current constraint parameters to same. + public override void SetLinkParameters(BSConstraint constrain) + { + member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType); + switch (constraintType) + { + case ConstraintType.BS_FIXED_CONSTRAINT_TYPE: + case ConstraintType.D6_CONSTRAINT_TYPE: + BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof; + if (constrain6dof != null) + { + // NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code. + // zero linear and angular limits makes the objects unable to move in relation to each other + constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh); + constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh); + + // tweek the constraint to increase stability + constrain6dof.UseFrameOffset(useFrameOffset); + constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); + constrain6dof.SetCFMAndERP(cfm, erp); + if (solverIterations != 0f) + { + constrain6dof.SetSolverIterations(solverIterations); + } + } + break; + case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: + BSConstraintSpring constrainSpring = constrain as BSConstraintSpring; + if (constrainSpring != null) + { + // zero linear and angular limits makes the objects unable to move in relation to each other + constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh); + constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh); + + // tweek the constraint to increase stability + constrainSpring.UseFrameOffset(useFrameOffset); + constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); + constrainSpring.SetCFMAndERP(cfm, erp); + if (solverIterations != 0f) + { + constrainSpring.SetSolverIterations(solverIterations); + } + for (int ii = 0; ii < springAxisEnable.Length; ii++) + { + constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]); + if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) + constrainSpring.SetDamping(ii, springDamping[ii]); + if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) + constrainSpring.SetStiffness(ii, springStiffness[ii]); + } + constrainSpring.CalculateTransforms(); + + if (springLinearEquilibriumPoint != OMV.Vector3.Zero) + constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint); + else + constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED); + } + break; + default: + break; + } + } + + // Return 'true' if the property updates from the physics engine should be reported + // to the simulator. + // If the constraint is fixed, we don't need to report as the simulator and viewer will + // report the right things. + public override bool ShouldUpdateChildProperties() + { + bool ret = true; + if (constraintType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE) + ret = false; + + return ret; + } + } + + public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) + { + LinksetImpl = LinksetImplementation.Constraint; + } + + private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]"; + + // When physical properties are changed the linkset needs to recalculate + // its internal properties. + // This is queued in the 'post taint' queue so the + // refresh will happen once after all the other taints are applied. + public override void Refresh(BSPrimLinkable requestor) + { + ScheduleRebuild(requestor); + base.Refresh(requestor); + + } + + private void ScheduleRebuild(BSPrimLinkable requestor) + { + DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", + requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); + + // When rebuilding, it is possible to set properties that would normally require a rebuild. + // If already rebuilding, don't request another rebuild. + // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. + lock (this) + { + if (!RebuildScheduled) + { + if (!Rebuilding && HasAnyChildren) + { + RebuildScheduled = true; + // Queue to happen after all the other taint processing + m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() + { + if (HasAnyChildren) + { + // Constraints that have not been changed are not rebuild but make sure + // the constraint of the requestor is rebuilt. + PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor); + // Rebuild the linkset and all its constraints. + RecomputeLinksetConstraints(); + } + RebuildScheduled = false; + }); + } + } + } + } + + // The object is going dynamic (physical). Do any setup necessary + // for a dynamic linkset. + // Only the state of the passed object can be modified. The rest of the linkset + // has not yet been fully constructed. + // Return 'true' if any properties updated on the passed object. + // Called at taint-time! + public override bool MakeDynamic(BSPrimLinkable child) + { + bool ret = false; + DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); + if (IsRoot(child)) + { + // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. + Refresh(LinksetRoot); + } + return ret; + } + + // The object is going static (non-physical). Do any setup necessary for a static linkset. + // Return 'true' if any properties updated on the passed object. + // This doesn't normally happen -- OpenSim removes the objects from the physical + // world if it is a static linkset. + // Called at taint-time! + public override bool MakeStatic(BSPrimLinkable child) + { + bool ret = false; + + DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); + child.ClearDisplacement(); + if (IsRoot(child)) + { + // Schedule a rebuild to verify that the root shape is set to the real shape. + Refresh(LinksetRoot); + } + return ret; + } + + // Called at taint-time!! + public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj) + { + // Nothing to do for constraints on property updates + } + + // Routine called when rebuilding the body of some member of the linkset. + // Destroy all the constraints have have been made to root and set + // up to rebuild the constraints before the next simulation step. + // Returns 'true' of something was actually removed and would need restoring + // Called at taint-time!! + public override bool RemoveDependencies(BSPrimLinkable child) + { + bool ret = false; + + DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}", + child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); + + lock (m_linksetActivityLock) + { + // Just undo all the constraints for this linkset. Rebuild at the end of the step. + ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); + // Cause the constraints, et al to be rebuilt before the next simulation step. + Refresh(LinksetRoot); + } + return ret; + } + + // ================================================================ + + // Add a new child to the linkset. + // Called while LinkActivity is locked. + protected override void AddChildToLinkset(BSPrimLinkable child) + { + if (!HasChild(child)) + { + m_children.Add(child, new BSLinkInfoConstraint(child)); + + DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); + + // Cause constraints and assorted properties to be recomputed before the next simulation step. + Refresh(LinksetRoot); + } + return; + } + + // Remove the specified child from the linkset. + // Safe to call even if the child is not really in my linkset. + protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) + { + if (m_children.Remove(child)) + { + BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now + BSPrimLinkable childx = child; + + DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", + childx.LocalID, + rootx.LocalID, rootx.PhysBody.AddrString, + childx.LocalID, childx.PhysBody.AddrString); + + m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate() + { + PhysicallyUnlinkAChildFromRoot(rootx, childx); + }); + // See that the linkset parameters are recomputed at the end of the taint time. + Refresh(LinksetRoot); + } + else + { + // Non-fatal occurance. + // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); + } + return; + } + + // Create a constraint between me (root of linkset) and the passed prim (the child). + // Called at taint time! + private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) + { + // Don't build the constraint when asked. Put it off until just before the simulation step. + Refresh(rootPrim); + } + + // Create a static constraint between the two passed objects + private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li) + { + BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint; + if (linkInfo == null) + return null; + + // Zero motion for children so they don't interpolate + li.member.ZeroMotion(true); + + BSConstraint constrain = null; + + switch (linkInfo.constraintType) + { + case ConstraintType.BS_FIXED_CONSTRAINT_TYPE: + case ConstraintType.D6_CONSTRAINT_TYPE: + // Relative position normalized to the root prim + // Essentually a vector pointing from center of rootPrim to center of li.member + OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position; + + // real world coordinate of midpoint between the two objects + OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); + + DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}", + rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody, + rootPrim.Position, linkInfo.member.Position, midPoint); + + // create a constraint that allows no freedom of movement between the two objects + // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 + + constrain = new BSConstraint6Dof( + m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true ); + + /* NOTE: below is an attempt to build constraint with full frame computation, etc. + * Using the midpoint is easier since it lets the Bullet code manipulate the transforms + * of the objects. + * Code left for future programmers. + // ================================================================================== + // relative position normalized to the root prim + OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); + OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation; + + // relative rotation of the child to the parent + OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation; + OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); + + DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID); + constrain = new BS6DofConstraint( + PhysicsScene.World, rootPrim.Body, liConstraint.member.Body, + OMV.Vector3.Zero, + OMV.Quaternion.Inverse(rootPrim.Orientation), + OMV.Vector3.Zero, + OMV.Quaternion.Inverse(liConstraint.member.Orientation), + true, + true + ); + // ================================================================================== + */ + + break; + case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: + constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, + linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot, + linkInfo.useLinearReferenceFrameA, + true /*disableCollisionsBetweenLinkedBodies*/); + DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}", + rootPrim.LocalID, + rootPrim.LocalID, rootPrim.PhysBody.AddrString, + linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString, + rootPrim.Position, linkInfo.member.Position); + + break; + default: + break; + } + + linkInfo.SetLinkParameters(constrain); + + m_physicsScene.Constraints.AddConstraint(constrain); + + return constrain; + } + + // Remove linkage between the linkset root and a particular child + // The root and child bodies are passed in because we need to remove the constraint between + // the bodies that were present at unlink time. + // Called at taint time! + private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) + { + bool ret = false; + DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", + rootPrim.LocalID, + rootPrim.LocalID, rootPrim.PhysBody.AddrString, + childPrim.LocalID, childPrim.PhysBody.AddrString); + + // If asked to unlink root from root, just remove all the constraints + if (rootPrim == childPrim || childPrim == LinksetRoot) + { + PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); + ret = true; + } + else + { + // Find the constraint for this link and get rid of it from the overall collection and from my list + if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) + { + // Make the child refresh its location + m_physicsScene.PE.PushUpdate(childPrim.PhysBody); + ret = true; + } + } + + return ret; + } + + // Remove linkage between myself and any possible children I might have. + // Returns 'true' of any constraints were destroyed. + // Called at taint time! + private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim) + { + DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); + + return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); + } + + // Call each of the constraints that make up this linkset and recompute the + // various transforms and variables. Create constraints of not created yet. + // Called before the simulation step to make sure the constraint based linkset + // is all initialized. + // Called at taint time!! + private void RecomputeLinksetConstraints() + { + float linksetMass = LinksetMass; + LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true); + + DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", + LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); + + try + { + Rebuilding = true; + + // There is no reason to build all this physical stuff for a non-physical linkset. + if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) + { + DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); + return; // Note the 'finally' clause at the botton which will get executed. + } + + ForEachLinkInfo((li) => + { + // A child in the linkset physically shows the mass of the whole linkset. + // This allows Bullet to apply enough force on the child to move the whole linkset. + // (Also do the mass stuff before recomputing the constraint so mass is not zero.) + li.member.UpdatePhysicalMassProperties(linksetMass, true); + + BSConstraint constrain; + if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain)) + { + // If constraint doesn't exist yet, create it. + constrain = BuildConstraint(LinksetRoot, li); + } + li.SetLinkParameters(constrain); + constrain.RecomputeConstraintVariables(linksetMass); + + // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG + return false; // 'false' says to keep processing other members + }); + } + finally + { + Rebuilding = false; + } + } + + #region Extension + public override object Extension(string pFunct, params object[] pParams) + { + object ret = null; + switch (pFunct) + { + // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ] + case ExtendedPhysics.PhysFunctChangeLinkType: + if (pParams.Length > 2) + { + int requestedType = (int)pParams[2]; + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType); + if (requestedType == (int)ConstraintType.BS_FIXED_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE) + { + BSPrimLinkable child = pParams[1] as BSPrimLinkable; + if (child != null) + { + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}", + LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType); + m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate() + { + // Pick up all the constraints currently created. + RemoveDependencies(child); + + BSLinkInfo linkInfo = null; + if (TryGetLinkInfo(child, out linkInfo)) + { + BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; + if (linkInfoC != null) + { + linkInfoC.constraintType = (ConstraintType)requestedType; + ret = (object)true; + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}", + linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); + } + else + { + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID); + } + } + else + { + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID); + } + // Cause the whole linkset to be rebuilt in post-taint time. + Refresh(child); + }); + } + else + { + DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID); + } + } + else + { + DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}", + LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE)); + } + } + break; + // pParams = [ BSPhysObject root, BSPhysObject child ] + case ExtendedPhysics.PhysFunctGetLinkType: + if (pParams.Length > 0) + { + BSPrimLinkable child = pParams[1] as BSPrimLinkable; + if (child != null) + { + BSLinkInfo linkInfo = null; + if (TryGetLinkInfo(child, out linkInfo)) + { + BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; + if (linkInfoC != null) + { + ret = (object)(int)linkInfoC.constraintType; + DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}", + linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); + + } + } + } + } + break; + // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ] + case ExtendedPhysics.PhysFunctChangeLinkParams: + // There should be two parameters: the childActor and a list of parameters to set + if (pParams.Length > 2) + { + BSPrimLinkable child = pParams[1] as BSPrimLinkable; + BSLinkInfo baseLinkInfo = null; + if (TryGetLinkInfo(child, out baseLinkInfo)) + { + BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint; + if (linkInfo != null) + { + int valueInt; + float valueFloat; + bool valueBool; + OMV.Vector3 valueVector; + OMV.Vector3 valueVector2; + OMV.Quaternion valueQuaternion; + int axisLow, axisHigh; + + int opIndex = 2; + while (opIndex < pParams.Length) + { + int thisOp = 0; + string errMsg = ""; + try + { + thisOp = (int)pParams[opIndex]; + DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}", + linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]); + switch (thisOp) + { + case ExtendedPhysics.PHYS_PARAM_LINK_TYPE: + valueInt = (int)pParams[opIndex + 1]; + ConstraintType valueType = (ConstraintType)valueInt; + if (valueType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE + || valueType == ConstraintType.D6_CONSTRAINT_TYPE + || valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE + || valueType == ConstraintType.HINGE_CONSTRAINT_TYPE + || valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE + || valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE) + { + linkInfo.constraintType = valueType; + } + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC: + errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + linkInfo.frameInAloc = valueVector; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT: + errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation"; + valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; + linkInfo.frameInArot = valueQuaternion; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC: + errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + linkInfo.frameInBloc = valueVector; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT: + errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation"; + valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; + linkInfo.frameInBrot = valueQuaternion; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW: + errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + linkInfo.linearLimitLow = valueVector; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH: + errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + linkInfo.linearLimitHigh = valueVector; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW: + errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + linkInfo.angularLimitLow = valueVector; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH: + errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + linkInfo.angularLimitHigh = valueVector; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET: + errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)"; + valueBool = ((int)pParams[opIndex + 1]) != 0; + linkInfo.useFrameOffset = valueBool; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR: + errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)"; + valueBool = ((int)pParams[opIndex + 1]) != 0; + linkInfo.enableTransMotor = valueBool; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL: + errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float"; + valueFloat = (float)pParams[opIndex + 1]; + linkInfo.transMotorMaxVel = valueFloat; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE: + errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float"; + valueFloat = (float)pParams[opIndex + 1]; + linkInfo.transMotorMaxForce = valueFloat; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_CFM: + errMsg = "PHYS_PARAM_CFM takes one parameter of type float"; + valueFloat = (float)pParams[opIndex + 1]; + linkInfo.cfm = valueFloat; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_ERP: + errMsg = "PHYS_PARAM_ERP takes one parameter of type float"; + valueFloat = (float)pParams[opIndex + 1]; + linkInfo.erp = valueFloat; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS: + errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float"; + valueFloat = (float)pParams[opIndex + 1]; + linkInfo.solverIterations = valueFloat; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE: + errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)"; + valueInt = (int)pParams[opIndex + 1]; + valueBool = ((int)pParams[opIndex + 2]) != 0; + GetAxisRange(valueInt, out axisLow, out axisHigh); + for (int ii = axisLow; ii <= axisHigh; ii++) + linkInfo.springAxisEnable[ii] = valueBool; + opIndex += 3; + break; + case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING: + errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float"; + valueInt = (int)pParams[opIndex + 1]; + valueFloat = (float)pParams[opIndex + 2]; + GetAxisRange(valueInt, out axisLow, out axisHigh); + for (int ii = axisLow; ii <= axisHigh; ii++) + linkInfo.springDamping[ii] = valueFloat; + opIndex += 3; + break; + case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS: + errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float"; + valueInt = (int)pParams[opIndex + 1]; + valueFloat = (float)pParams[opIndex + 2]; + GetAxisRange(valueInt, out axisLow, out axisHigh); + for (int ii = axisLow; ii <= axisHigh; ii++) + linkInfo.springStiffness[ii] = valueFloat; + opIndex += 3; + break; + case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT: + errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + valueVector2 = (OMV.Vector3)pParams[opIndex + 2]; + linkInfo.springLinearEquilibriumPoint = valueVector; + linkInfo.springAngularEquilibriumPoint = valueVector2; + opIndex += 3; + break; + case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA: + errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)"; + valueBool = ((int)pParams[opIndex + 1]) != 0; + linkInfo.useLinearReferenceFrameA = valueBool; + opIndex += 2; + break; + default: + break; + } + } + catch (InvalidCastException e) + { + m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}", + LogHeader, errMsg, e); + } + catch (Exception e) + { + m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e); + } + } + } + // Something changed so a rebuild is in order + Refresh(child); + } + } + break; + default: + ret = base.Extension(pFunct, pParams); + break; + } + return ret; + } + + // Bullet constraints keep some limit parameters for each linear and angular axis. + // Setting same is easier if there is an easy way to see all or types. + // This routine returns the array limits for the set of axis. + private void GetAxisRange(int rangeSpec, out int low, out int high) + { + switch (rangeSpec) + { + case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL: + low = 0; + high = 2; + break; + case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL: + low = 3; + high = 5; + break; + case ExtendedPhysics.PHYS_AXIS_ALL: + low = 0; + high = 5; + break; + default: + low = high = rangeSpec; + break; + } + return; + } + #endregion // Extension + +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs new file mode 100755 index 0000000..0e44d03 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs @@ -0,0 +1,203 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using Nini.Config; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + +public struct MaterialAttributes +{ + // Material type values that correspond with definitions for LSL + public enum Material : int + { + Stone = 0, + Metal, + Glass, + Wood, + Flesh, + Plastic, + Rubber, + Light, + // Hereafter are BulletSim additions + Avatar, + NumberOfTypes // the count of types in the enum. + } + + // Names must be in the order of the above enum. + // These names must coorespond to the lower case field names in the MaterialAttributes + // structure as reflection is used to select the field to put the value in. + public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"}; + + public MaterialAttributes(string t, float d, float f, float r) + { + type = t; + density = d; + friction = f; + restitution = r; + } + public string type; + public float density; + public float friction; + public float restitution; +} + +public static class BSMaterials +{ + // Attributes for each material type + private static readonly MaterialAttributes[] Attributes; + + // Map of material name to material type code + public static readonly Dictionary MaterialMap; + + static BSMaterials() + { + // Attribute sets for both the non-physical and physical instances of materials. + Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; + + // Map of name to type code. + MaterialMap = new Dictionary(); + MaterialMap.Add("Stone", MaterialAttributes.Material.Stone); + MaterialMap.Add("Metal", MaterialAttributes.Material.Metal); + MaterialMap.Add("Glass", MaterialAttributes.Material.Glass); + MaterialMap.Add("Wood", MaterialAttributes.Material.Wood); + MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh); + MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic); + MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber); + MaterialMap.Add("Light", MaterialAttributes.Material.Light); + MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar); + } + + // This is where all the default material attributes are defined. + public static void InitializeFromDefaults(ConfigurationParameters parms) + { + // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL + float dDensity = parms.defaultDensity; + float dFriction = parms.defaultFriction; + float dRestitution = parms.defaultRestitution; + Attributes[(int)MaterialAttributes.Material.Stone] = + new MaterialAttributes("stone",dDensity, 0.8f, 0.4f); + Attributes[(int)MaterialAttributes.Material.Metal] = + new MaterialAttributes("metal",dDensity, 0.3f, 0.4f); + Attributes[(int)MaterialAttributes.Material.Glass] = + new MaterialAttributes("glass",dDensity, 0.2f, 0.7f); + Attributes[(int)MaterialAttributes.Material.Wood] = + new MaterialAttributes("wood",dDensity, 0.6f, 0.5f); + Attributes[(int)MaterialAttributes.Material.Flesh] = + new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f); + Attributes[(int)MaterialAttributes.Material.Plastic] = + new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f); + Attributes[(int)MaterialAttributes.Material.Rubber] = + new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f); + Attributes[(int)MaterialAttributes.Material.Light] = + new MaterialAttributes("light",dDensity, dFriction, dRestitution); + Attributes[(int)MaterialAttributes.Material.Avatar] = + new MaterialAttributes("avatar",3.5f, 0.2f, 0f); + + Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f); + Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("metalPhysical",dDensity, 0.3f, 0.4f); + Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f); + Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f); + Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f); + Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f); + Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 0.9f); + Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution); + Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("avatarPhysical",3.5f, 0.2f, 0f); + } + + // Under the [BulletSim] section, one can change the individual material + // attribute values. The format of the configuration parameter is: + // ["Physical"] = floatValue + // For instance: + // [BulletSim] + // StoneFriction = 0.2 + // FleshRestitutionPhysical = 0.8 + // Materials can have different parameters for their static and + // physical instantiations. When setting the non-physical value, + // both values are changed. Setting the physical value only changes + // the physical value. + public static void InitializefromParameters(IConfig pConfig) + { + foreach (KeyValuePair kvp in MaterialMap) + { + string matName = kvp.Key; + foreach (string attribName in MaterialAttributes.MaterialAttribs) + { + string paramName = matName + attribName; + if (pConfig.Contains(paramName)) + { + float paramValue = pConfig.GetFloat(paramName); + SetAttributeValue((int)kvp.Value, attribName, paramValue); + // set the physical value also + SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); + } + paramName += "Physical"; + if (pConfig.Contains(paramName)) + { + float paramValue = pConfig.GetFloat(paramName); + SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); + } + } + } + } + + // Use reflection to set the value in the attribute structure. + private static void SetAttributeValue(int matType, string attribName, float val) + { + // Get the current attribute values for this material + MaterialAttributes thisAttrib = Attributes[matType]; + // Find the field for the passed attribute name (eg, find field named 'friction') + FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); + if (fieldInfo != null) + { + fieldInfo.SetValue(thisAttrib, val); + // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference. + Attributes[matType] = thisAttrib; + } + } + + // Given a material type, return a structure of attributes. + public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) + { + int ind = (int)type; + if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; + return Attributes[ind]; + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs new file mode 100755 index 0000000..2faf2d4 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs @@ -0,0 +1,451 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; +using OpenSim.Framework; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public abstract class BSMotor +{ + // Timescales and other things can be turned off by setting them to 'infinite'. + public const float Infinite = 12345.6f; + public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); + + public BSMotor(string useName) + { + UseName = useName; + PhysicsScene = null; + Enabled = true; + } + public virtual bool Enabled { get; set; } + public virtual void Reset() { } + public virtual void Zero() { } + public virtual void GenerateTestOutput(float timeStep) { } + + // A name passed at motor creation for easily identifyable debugging messages. + public string UseName { get; private set; } + + // Used only for outputting debug information. Might not be set so check for null. + public BSScene PhysicsScene { get; set; } + protected void MDetailLog(string msg, params Object[] parms) + { + if (PhysicsScene != null) + { + PhysicsScene.DetailLog(msg, parms); + } + } +} + +// Motor which moves CurrentValue to TargetValue over TimeScale seconds. +// The TargetValue decays in TargetValueDecayTimeScale. +// This motor will "zero itself" over time in that the targetValue will +// decay to zero and the currentValue will follow it to that zero. +// The overall effect is for the returned correction value to go from large +// values to small and eventually zero values. +// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. + +// For instance, if something is moving at speed X and the desired speed is Y, +// CurrentValue is X and TargetValue is Y. As the motor is stepped, new +// values of CurrentValue are returned that approach the TargetValue. +// The feature of decaying TargetValue is so vehicles will eventually +// come to a stop rather than run forever. This can be disabled by +// setting TargetValueDecayTimescale to 'infinite'. +// The change from CurrentValue to TargetValue is linear over TimeScale seconds. +public class BSVMotor : BSMotor +{ + // public Vector3 FrameOfReference { get; set; } + // public Vector3 Offset { get; set; } + + public virtual float TimeScale { get; set; } + public virtual float TargetValueDecayTimeScale { get; set; } + public virtual float Efficiency { get; set; } + + public virtual float ErrorZeroThreshold { get; set; } + + public virtual Vector3 TargetValue { get; protected set; } + public virtual Vector3 CurrentValue { get; protected set; } + public virtual Vector3 LastError { get; protected set; } + + public virtual bool ErrorIsZero() + { + return ErrorIsZero(LastError); + } + public virtual bool ErrorIsZero(Vector3 err) + { + return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)); + } + + public BSVMotor(string useName) + : base(useName) + { + TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; + Efficiency = 1f; + CurrentValue = TargetValue = Vector3.Zero; + ErrorZeroThreshold = 0.001f; + } + public BSVMotor(string useName, float timeScale, float decayTimeScale, float efficiency) + : this(useName) + { + TimeScale = timeScale; + TargetValueDecayTimeScale = decayTimeScale; + Efficiency = efficiency; + CurrentValue = TargetValue = Vector3.Zero; + } + public void SetCurrent(Vector3 current) + { + CurrentValue = current; + } + public void SetTarget(Vector3 target) + { + TargetValue = target; + } + public override void Zero() + { + base.Zero(); + CurrentValue = TargetValue = Vector3.Zero; + } + + // Compute the next step and return the new current value. + // Returns the correction needed to move 'current' to 'target'. + public virtual Vector3 Step(float timeStep) + { + if (!Enabled) return TargetValue; + + Vector3 origTarget = TargetValue; // DEBUG + Vector3 origCurrVal = CurrentValue; // DEBUG + + Vector3 correction = Vector3.Zero; + Vector3 error = TargetValue - CurrentValue; + if (!ErrorIsZero(error)) + { + correction = StepError(timeStep, error); + + CurrentValue += correction; + + // The desired value reduces to zero which also reduces the difference with current. + // If the decay time is infinite, don't decay at all. + float decayFactor = 0f; + if (TargetValueDecayTimeScale != BSMotor.Infinite) + { + decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; + TargetValue *= (1f - decayFactor); + } + + MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", + BSScene.DetailLogZero, UseName, origCurrVal, origTarget, + timeStep, error, correction); + MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", + BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); + } + else + { + // Difference between what we have and target is small. Motor is done. + if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) + { + // The target can step down to nearly zero but not get there. If close to zero + // it is really zero. + TargetValue = Vector3.Zero; + } + CurrentValue = TargetValue; + MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}", + BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue); + } + LastError = error; + + return correction; + } + // version of step that sets the current value before doing the step + public virtual Vector3 Step(float timeStep, Vector3 current) + { + CurrentValue = current; + return Step(timeStep); + } + // Given and error, computer a correction for this step. + // Simple scaling of the error by the timestep. + public virtual Vector3 StepError(float timeStep, Vector3 error) + { + if (!Enabled) return Vector3.Zero; + + Vector3 returnCorrection = Vector3.Zero; + if (!ErrorIsZero(error)) + { + // correction = error / secondsItShouldTakeToCorrect + Vector3 correctionAmount; + if (TimeScale == 0f || TimeScale == BSMotor.Infinite) + correctionAmount = error * timeStep; + else + correctionAmount = error / TimeScale * timeStep; + + returnCorrection = correctionAmount; + MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", + BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); + } + return returnCorrection; + } + + // The user sets all the parameters and calls this which outputs values until error is zero. + public override void GenerateTestOutput(float timeStep) + { + // maximum number of outputs to generate. + int maxOutput = 50; + MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); + MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}", + BSScene.DetailLogZero, UseName, + TimeScale, TargetValueDecayTimeScale, Efficiency, + CurrentValue, TargetValue); + + LastError = BSMotor.InfiniteVector; + while (maxOutput-- > 0 && !ErrorIsZero()) + { + Vector3 lastStep = Step(timeStep); + MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}", + BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); + } + MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); + + + } + + public override string ToString() + { + return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", + UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); + } +} + +// ============================================================================ +// ============================================================================ +public class BSFMotor : BSMotor +{ + public virtual float TimeScale { get; set; } + public virtual float TargetValueDecayTimeScale { get; set; } + public virtual float Efficiency { get; set; } + + public virtual float ErrorZeroThreshold { get; set; } + + public virtual float TargetValue { get; protected set; } + public virtual float CurrentValue { get; protected set; } + public virtual float LastError { get; protected set; } + + public virtual bool ErrorIsZero() + { + return ErrorIsZero(LastError); + } + public virtual bool ErrorIsZero(float err) + { + return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); + } + + public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency) + : base(useName) + { + TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; + Efficiency = 1f; + CurrentValue = TargetValue = 0f; + ErrorZeroThreshold = 0.01f; + } + public void SetCurrent(float current) + { + CurrentValue = current; + } + public void SetTarget(float target) + { + TargetValue = target; + } + public override void Zero() + { + base.Zero(); + CurrentValue = TargetValue = 0f; + } + + public virtual float Step(float timeStep) + { + if (!Enabled) return TargetValue; + + float origTarget = TargetValue; // DEBUG + float origCurrVal = CurrentValue; // DEBUG + + float correction = 0f; + float error = TargetValue - CurrentValue; + if (!ErrorIsZero(error)) + { + correction = StepError(timeStep, error); + + CurrentValue += correction; + + // The desired value reduces to zero which also reduces the difference with current. + // If the decay time is infinite, don't decay at all. + float decayFactor = 0f; + if (TargetValueDecayTimeScale != BSMotor.Infinite) + { + decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; + TargetValue *= (1f - decayFactor); + } + + MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", + BSScene.DetailLogZero, UseName, origCurrVal, origTarget, + timeStep, error, correction); + MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", + BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); + } + else + { + // Difference between what we have and target is small. Motor is done. + if (Util.InRange(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold)) + { + // The target can step down to nearly zero but not get there. If close to zero + // it is really zero. + TargetValue = 0f; + } + CurrentValue = TargetValue; + MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", + BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); + } + LastError = error; + + return CurrentValue; + } + + public virtual float StepError(float timeStep, float error) + { + if (!Enabled) return 0f; + + float returnCorrection = 0f; + if (!ErrorIsZero(error)) + { + // correction = error / secondsItShouldTakeToCorrect + float correctionAmount; + if (TimeScale == 0f || TimeScale == BSMotor.Infinite) + correctionAmount = error * timeStep; + else + correctionAmount = error / TimeScale * timeStep; + + returnCorrection = correctionAmount; + MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", + BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); + } + return returnCorrection; + } + + public override string ToString() + { + return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", + UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); + } + +} + +// ============================================================================ +// ============================================================================ +// Proportional, Integral, Derivitive ("PID") Motor +// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. +public class BSPIDVMotor : BSVMotor +{ + // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10. + public Vector3 proportionFactor { get; set; } + public Vector3 integralFactor { get; set; } + public Vector3 derivFactor { get; set; } + + // The factors are vectors for the three dimensions. This is the proportional of each + // that is applied. This could be multiplied through the actual factors but it + // is sometimes easier to manipulate the factors and their mix separately. + public Vector3 FactorMix; + + // Arbritrary factor range. + // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. + public float EfficiencyHigh = 0.4f; + public float EfficiencyLow = 4.0f; + + // Running integration of the error + Vector3 RunningIntegration { get; set; } + + public BSPIDVMotor(string useName) + : base(useName) + { + proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); + integralFactor = new Vector3(1.00f, 1.00f, 1.00f); + derivFactor = new Vector3(1.00f, 1.00f, 1.00f); + FactorMix = new Vector3(0.5f, 0.25f, 0.25f); + RunningIntegration = Vector3.Zero; + LastError = Vector3.Zero; + } + + public override void Zero() + { + base.Zero(); + } + + public override float Efficiency + { + get { return base.Efficiency; } + set + { + base.Efficiency = Util.Clamp(value, 0f, 1f); + + // Compute factors based on efficiency. + // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. + // If efficiency is low (0f), use a factor value that overcorrects. + // TODO: might want to vary contribution of different factor depending on efficiency. + // float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; + float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; + + proportionFactor = new Vector3(factor, factor, factor); + integralFactor = new Vector3(factor, factor, factor); + derivFactor = new Vector3(factor, factor, factor); + + MDetailLog("{0}, BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor); + } + } + + // Advance the PID computation on this error. + public override Vector3 StepError(float timeStep, Vector3 error) + { + if (!Enabled) return Vector3.Zero; + + // Add up the error so we can integrate over the accumulated errors + RunningIntegration += error * timeStep; + + // A simple derivitive is the rate of change from the last error. + Vector3 derivitive = (error - LastError) * timeStep; + + // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) + Vector3 ret = error / TimeScale * timeStep * proportionFactor * FactorMix.X + + RunningIntegration / TimeScale * integralFactor * FactorMix.Y + + derivitive / TimeScale * derivFactor * FactorMix.Z + ; + + MDetailLog("{0}, BSPIDVMotor.step,ts={1},err={2},lerr={3},runnInt={4},deriv={5},ret={6}", + BSScene.DetailLogZero, timeStep, error, LastError, RunningIntegration, derivitive, ret); + + return ret; + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs new file mode 100755 index 0000000..c296008 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs @@ -0,0 +1,927 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +using OpenSim.Region.PhysicsModules.SharedBase; + +using OpenMetaverse; +using Nini.Config; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public static class BSParam +{ + private static string LogHeader = "[BULLETSIM PARAMETERS]"; + + // Tuning notes: + // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575 + // Contact points can be added even if the distance is positive. The constraint solver can deal with + // contacts with positive distances as well as negative (penetration). Contact points are discarded + // if the distance exceeds a certain threshold. + // Bullet has a contact processing threshold and a contact breaking threshold. + // If the distance is larger than the contact breaking threshold, it will be removed after one frame. + // If the distance is larger than the contact processing threshold, the constraint solver will ignore it. + + // This is separate/independent from the collision margin. The collision margin increases the object a bit + // to improve collision detection performance and accuracy. + // =================== + // From: + + /// + /// Set whether physics is active or not. + /// + /// + /// Can be enabled and disabled to start and stop physics. + /// + public static bool Active { get; private set; } + + public static bool UseSeparatePhysicsThread { get; private set; } + public static float PhysicsTimeStep { get; private set; } + + // Level of Detail values kept as float because that's what the Meshmerizer wants + public static float MeshLOD { get; private set; } + public static float MeshCircularLOD { get; private set; } + public static float MeshMegaPrimLOD { get; private set; } + public static float MeshMegaPrimThreshold { get; private set; } + public static float SculptLOD { get; private set; } + + public static int CrossingFailuresBeforeOutOfBounds { get; private set; } + public static float UpdateVelocityChangeThreshold { get; private set; } + + public static float MinimumObjectMass { get; private set; } + public static float MaximumObjectMass { get; private set; } + public static float MaxLinearVelocity { get; private set; } + public static float MaxLinearVelocitySquared { get; private set; } + public static float MaxAngularVelocity { get; private set; } + public static float MaxAngularVelocitySquared { get; private set; } + public static float MaxAddForceMagnitude { get; private set; } + public static float MaxAddForceMagnitudeSquared { get; private set; } + public static float DensityScaleFactor { get; private set; } + + public static float LinearDamping { get; private set; } + public static float AngularDamping { get; private set; } + public static float DeactivationTime { get; private set; } + public static float LinearSleepingThreshold { get; private set; } + public static float AngularSleepingThreshold { get; private set; } + public static float CcdMotionThreshold { get; private set; } + public static float CcdSweptSphereRadius { get; private set; } + public static float ContactProcessingThreshold { get; private set; } + + public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed + public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes + public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects + public static bool ShouldRemoveZeroWidthTriangles { get; private set; } + public static bool ShouldUseBulletHACD { get; set; } + public static bool ShouldUseSingleConvexHullForPrims { get; set; } + public static bool ShouldUseGImpactShapeForPrims { get; set; } + public static bool ShouldUseAssetHulls { get; set; } + + public static float TerrainImplementation { get; set; } + public static int TerrainMeshMagnification { get; private set; } + public static float TerrainGroundPlane { get; private set; } + public static float TerrainFriction { get; private set; } + public static float TerrainHitFraction { get; private set; } + public static float TerrainRestitution { get; private set; } + public static float TerrainContactProcessingThreshold { get; private set; } + public static float TerrainCollisionMargin { get; private set; } + + public static float DefaultFriction { get; private set; } + public static float DefaultDensity { get; private set; } + public static float DefaultRestitution { get; private set; } + public static float CollisionMargin { get; private set; } + public static float Gravity { get; private set; } + + // Physics Engine operation + public static float MaxPersistantManifoldPoolSize { get; private set; } + public static float MaxCollisionAlgorithmPoolSize { get; private set; } + public static bool ShouldDisableContactPoolDynamicAllocation { get; private set; } + public static bool ShouldForceUpdateAllAabbs { get; private set; } + public static bool ShouldRandomizeSolverOrder { get; private set; } + public static bool ShouldSplitSimulationIslands { get; private set; } + public static bool ShouldEnableFrictionCaching { get; private set; } + public static float NumberOfSolverIterations { get; private set; } + public static bool UseSingleSidedMeshes { get; private set; } + public static float GlobalContactBreakingThreshold { get; private set; } + public static float PhysicsUnmanLoggingFrames { get; private set; } + + // Avatar parameters + public static bool AvatarToAvatarCollisionsByDefault { get; private set; } + public static float AvatarFriction { get; private set; } + public static float AvatarStandingFriction { get; private set; } + public static float AvatarAlwaysRunFactor { get; private set; } + public static float AvatarDensity { get; private set; } + public static float AvatarRestitution { get; private set; } + public static int AvatarShape { get; private set; } + public static float AvatarCapsuleWidth { get; private set; } + public static float AvatarCapsuleDepth { get; private set; } + public static float AvatarCapsuleHeight { get; private set; } + public static float AvatarHeightLowFudge { get; private set; } + public static float AvatarHeightMidFudge { get; private set; } + public static float AvatarHeightHighFudge { get; private set; } + public static float AvatarFlyingGroundMargin { get; private set; } + public static float AvatarFlyingGroundUpForce { get; private set; } + public static float AvatarTerminalVelocity { get; private set; } + public static float AvatarContactProcessingThreshold { get; private set; } + public static float AvatarStopZeroThreshold { get; private set; } + public static int AvatarJumpFrames { get; private set; } + public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } + public static float AvatarStepHeight { get; private set; } + public static float AvatarStepAngle { get; private set; } + public static float AvatarStepGroundFudge { get; private set; } + public static float AvatarStepApproachFactor { get; private set; } + public static float AvatarStepForceFactor { get; private set; } + public static float AvatarStepUpCorrectionFactor { get; private set; } + public static int AvatarStepSmoothingSteps { get; private set; } + + // Vehicle parameters + public static float VehicleMaxLinearVelocity { get; private set; } + public static float VehicleMaxLinearVelocitySquared { get; private set; } + public static float VehicleMinLinearVelocity { get; private set; } + public static float VehicleMinLinearVelocitySquared { get; private set; } + public static float VehicleMaxAngularVelocity { get; private set; } + public static float VehicleMaxAngularVelocitySq { get; private set; } + public static float VehicleAngularDamping { get; private set; } + public static float VehicleFriction { get; private set; } + public static float VehicleRestitution { get; private set; } + public static Vector3 VehicleLinearFactor { get; private set; } + public static Vector3 VehicleAngularFactor { get; private set; } + public static Vector3 VehicleInertiaFactor { get; private set; } + public static float VehicleGroundGravityFudge { get; private set; } + public static float VehicleAngularBankingTimescaleFudge { get; private set; } + public static bool VehicleEnableLinearDeflection { get; private set; } + public static bool VehicleLinearDeflectionNotCollidingNoZ { get; private set; } + public static bool VehicleEnableAngularVerticalAttraction { get; private set; } + public static int VehicleAngularVerticalAttractionAlgorithm { get; private set; } + public static bool VehicleEnableAngularDeflection { get; private set; } + public static bool VehicleEnableAngularBanking { get; private set; } + + // Convex Hulls + // Parameters for convex hull routine that ships with Bullet + public static int CSHullMaxDepthSplit { get; private set; } + public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; } + public static float CSHullConcavityThresholdPercent { get; private set; } + public static float CSHullVolumeConservationThresholdPercent { get; private set; } + public static int CSHullMaxVertices { get; private set; } + public static float CSHullMaxSkinWidth { get; private set; } + public static float BHullMaxVerticesPerHull { get; private set; } // 100 + public static float BHullMinClusters { get; private set; } // 2 + public static float BHullCompacityWeight { get; private set; } // 0.1 + public static float BHullVolumeWeight { get; private set; } // 0.0 + public static float BHullConcavity { get; private set; } // 100 + public static bool BHullAddExtraDistPoints { get; private set; } // false + public static bool BHullAddNeighboursDistPoints { get; private set; } // false + public static bool BHullAddFacesPoints { get; private set; } // false + public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false + public static float WhichHACD { get; private set; } // zero if Bullet HACD, non-zero says VHACD + // Parameters for VHACD 2.0: http://code.google.com/p/v-hacd + // To enable, set both ShouldUseBulletHACD=true and WhichHACD=1 + // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html + public static float VHACDresolution { get; private set; } // 100,000 max number of voxels generated during voxelization stage + public static float VHACDdepth { get; private set; } // 20 max number of clipping stages + public static float VHACDconcavity { get; private set; } // 0.0025 maximum concavity + public static float VHACDplaneDownsampling { get; private set; } // 4 granularity of search for best clipping plane + public static float VHACDconvexHullDownsampling { get; private set; } // 4 precision of hull gen process + public static float VHACDalpha { get; private set; } // 0.05 bias toward clipping along symmetry planes + public static float VHACDbeta { get; private set; } // 0.05 bias toward clipping along revolution axis + public static float VHACDgamma { get; private set; } // 0.00125 max concavity when merging + public static float VHACDpca { get; private set; } // 0 on/off normalizing mesh before decomp + public static float VHACDmode { get; private set; } // 0 0:voxel based, 1: tetrahedron based + public static float VHACDmaxNumVerticesPerCH { get; private set; } // 64 max triangles per convex hull + public static float VHACDminVolumePerCH { get; private set; } // 0.0001 sampling of generated convex hulls + + // Linkset implementation parameters + public static float LinksetImplementation { get; private set; } + public static bool LinksetOffsetCenterOfMass { get; private set; } + public static bool LinkConstraintUseFrameOffset { get; private set; } + public static bool LinkConstraintEnableTransMotor { get; private set; } + public static float LinkConstraintTransMotorMaxVel { get; private set; } + public static float LinkConstraintTransMotorMaxForce { get; private set; } + public static float LinkConstraintERP { get; private set; } + public static float LinkConstraintCFM { get; private set; } + public static float LinkConstraintSolverIterations { get; private set; } + + public static float PID_D { get; private set; } // derivative + public static float PID_P { get; private set; } // proportional + + // Various constants that come from that other virtual world that shall not be named. + public const float MinGravityZ = -1f; + public const float MaxGravityZ = 28f; + public const float MinFriction = 0f; + public const float MaxFriction = 255f; + public const float MinDensity = 0.01f; + public const float MaxDensity = 22587f; + public const float MinRestitution = 0f; + public const float MaxRestitution = 1f; + + // ===================================================================================== + // ===================================================================================== + + // Base parameter definition that gets and sets parameter values via a string + public abstract class ParameterDefnBase + { + public string name; // string name of the parameter + public string desc; // a short description of what the parameter means + public ParameterDefnBase(string pName, string pDesc) + { + name = pName; + desc = pDesc; + } + // Set the parameter value to the default + public abstract void AssignDefault(BSScene s); + // Get the value as a string + public abstract string GetValue(BSScene s); + // Set the value to this string value + public abstract void SetValue(BSScene s, string valAsString); + // set the value on a particular object (usually sets in physics engine) + public abstract void SetOnObject(BSScene s, BSPhysObject obj); + public abstract bool HasSetOnObject { get; } + } + + // Specific parameter definition for a parameter of a specific type. + public delegate T PGetValue(BSScene s); + public delegate void PSetValue(BSScene s, T val); + public delegate void PSetOnObject(BSScene scene, BSPhysObject obj); + public sealed class ParameterDefn : ParameterDefnBase + { + private T defaultValue; + private PSetValue setter; + private PGetValue getter; + private PSetOnObject objectSet; + public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue pGetter, PSetValue pSetter) + : base(pName, pDesc) + { + defaultValue = pDefault; + setter = pSetter; + getter = pGetter; + objectSet = null; + } + public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue pGetter, PSetValue pSetter, PSetOnObject pObjSetter) + : base(pName, pDesc) + { + defaultValue = pDefault; + setter = pSetter; + getter = pGetter; + objectSet = pObjSetter; + } + // Simple parameter variable where property name is the same as the INI file name + // and the value is only a simple get and set. + public ParameterDefn(string pName, string pDesc, T pDefault) + : base(pName, pDesc) + { + defaultValue = pDefault; + setter = (s, v) => { SetValueByName(s, name, v); }; + getter = (s) => { return GetValueByName(s, name); }; + objectSet = null; + } + // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same. + private void SetValueByName(BSScene s, string pName, T val) + { + PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); + if (prop == null) + { + // This should only be output when someone adds a new INI parameter and misspells the name. + s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName); + } + else + { + prop.SetValue(null, val, null); + } + } + // Use reflection to find the property named 'pName' in BSParam and return the value in same. + private T GetValueByName(BSScene s, string pName) + { + PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); + if (prop == null) + { + // This should only be output when someone adds a new INI parameter and misspells the name. + s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName); + } + return (T)prop.GetValue(null, null); + } + public override void AssignDefault(BSScene s) + { + setter(s, defaultValue); + } + public override string GetValue(BSScene s) + { + return getter(s).ToString(); + } + public override void SetValue(BSScene s, string valAsString) + { + // Get the generic type of the setter + Type genericType = setter.GetType().GetGenericArguments()[0]; + // Find the 'Parse' method on that type + System.Reflection.MethodInfo parser = null; + try + { + parser = genericType.GetMethod("Parse", new Type[] { typeof(String) } ); + } + catch (Exception e) + { + s.Logger.ErrorFormat("{0} Exception getting parser for type '{1}': {2}", LogHeader, genericType, e); + parser = null; + } + if (parser != null) + { + // Parse the input string + try + { + T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString }); + // Store the parsed value + setter(s, setValue); + // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue); + } + catch + { + s.Logger.ErrorFormat("{0} Failed parsing parameter value '{1}' as type '{2}'", LogHeader, valAsString, genericType); + } + } + else + { + s.Logger.ErrorFormat("{0} Could not find parameter parser for type '{1}'", LogHeader, genericType); + } + } + public override bool HasSetOnObject + { + get { return objectSet != null; } + } + public override void SetOnObject(BSScene s, BSPhysObject obj) + { + if (objectSet != null) + objectSet(s, obj); + } + } + + // List of all of the externally visible parameters. + // For each parameter, this table maps a text name to getter and setters. + // To add a new externally referencable/settable parameter, add the paramter storage + // location somewhere in the program and make an entry in this table with the + // getters and setters. + // It is easiest to find an existing definition and copy it. + // + // A ParameterDefn() takes the following parameters: + // -- the text name of the parameter. This is used for console input and ini file. + // -- a short text description of the parameter. This shows up in the console listing. + // -- a default value + // -- a delegate for getting the value + // -- a delegate for setting the value + // -- an optional delegate to update the value in the world. Most often used to + // push the new value to an in-world object. + // + // The single letter parameters for the delegates are: + // s = BSScene + // o = BSPhysObject + // v = value (appropriate type) + private static ParameterDefnBase[] ParameterDefinitions = + { + new ParameterDefn("Active", "If 'true', false then physics is not active", + false ), + new ParameterDefn("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat", + false ), + new ParameterDefn("PhysicsTimeStep", "If separate thread, seconds to simulate each interval", + 0.089f ), + + new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", + true, + (s) => { return ShouldMeshSculptedPrim; }, + (s,v) => { ShouldMeshSculptedPrim = v; } ), + new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", + false, + (s) => { return ShouldForceSimplePrimMeshing; }, + (s,v) => { ShouldForceSimplePrimMeshing = v; } ), + new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", + true, + (s) => { return ShouldUseHullsForPhysicalObjects; }, + (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), + new ParameterDefn("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", + true ), + new ParameterDefn("ShouldUseBulletHACD", "If true, use the Bullet version of HACD", + false ), + new ParameterDefn("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims", + true ), + new ParameterDefn("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", + false ), + new ParameterDefn("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info", + true ), + + new ParameterDefn("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", + 5 ), + new ParameterDefn("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator", + 0.1f ), + + new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", + 32f, + (s) => { return MeshLOD; }, + (s,v) => { MeshLOD = v; } ), + new ParameterDefn("MeshLevelOfDetailCircular", "Level of detail for prims with circular cuts or shapes", + 32f, + (s) => { return MeshCircularLOD; }, + (s,v) => { MeshCircularLOD = v; } ), + new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", + 10f, + (s) => { return MeshMegaPrimThreshold; }, + (s,v) => { MeshMegaPrimThreshold = v; } ), + new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", + 32f, + (s) => { return MeshMegaPrimLOD; }, + (s,v) => { MeshMegaPrimLOD = v; } ), + new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", + 32f, + (s) => { return SculptLOD; }, + (s,v) => { SculptLOD = v; } ), + + new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", + 10, + (s) => { return s.m_maxSubSteps; }, + (s,v) => { s.m_maxSubSteps = (int)v; } ), + new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", + 1f / 60f, + (s) => { return s.m_fixedTimeStep; }, + (s,v) => { s.m_fixedTimeStep = v; } ), + new ParameterDefn("NominalFrameRate", "The base frame rate we claim", + 55f, + (s) => { return s.NominalFrameRate; }, + (s,v) => { s.NominalFrameRate = (int)v; } ), + new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", + 2048, + (s) => { return s.m_maxCollisionsPerFrame; }, + (s,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), + new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame", + 8000, + (s) => { return s.m_maxUpdatesPerFrame; }, + (s,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), + + new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)", + 0.0001f, + (s) => { return MinimumObjectMass; }, + (s,v) => { MinimumObjectMass = v; } ), + new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", + 10000.01f, + (s) => { return MaximumObjectMass; }, + (s,v) => { MaximumObjectMass = v; } ), + new ParameterDefn("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object", + 1000.0f, + (s) => { return MaxLinearVelocity; }, + (s,v) => { MaxLinearVelocity = v; MaxLinearVelocitySquared = v * v; } ), + new ParameterDefn("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object", + 1000.0f, + (s) => { return MaxAngularVelocity; }, + (s,v) => { MaxAngularVelocity = v; MaxAngularVelocitySquared = v * v; } ), + // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject + new ParameterDefn("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)", + 20000.0f, + (s) => { return MaxAddForceMagnitude; }, + (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), + // Density is passed around as 100kg/m3. This scales that to 1kg/m3. + // Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well + new ParameterDefn("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", + 0.01f ), + + new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", + 2200f ), + new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", + 900f ), + + new ParameterDefn("DefaultFriction", "Friction factor used on new objects", + 0.2f, + (s) => { return DefaultFriction; }, + (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ), + // For historical reasons, the viewer and simulator multiply the density by 100 + new ParameterDefn("DefaultDensity", "Density for new objects" , + 1000.0006836f, // Aluminum g/cm3 * 100 + (s) => { return DefaultDensity; }, + (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ), + new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , + 0f, + (s) => { return DefaultRestitution; }, + (s,v) => { DefaultRestitution = v; s.UnmanagedParams[0].defaultRestitution = v; } ), + new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", + 0.04f, + (s) => { return CollisionMargin; }, + (s,v) => { CollisionMargin = v; s.UnmanagedParams[0].collisionMargin = v; } ), + new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)", + -9.80665f, + (s) => { return Gravity; }, + (s,v) => { Gravity = v; s.UnmanagedParams[0].gravity = v; }, + (s,o) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,Gravity)); } ), + + + new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", + 0f, + (s) => { return LinearDamping; }, + (s,v) => { LinearDamping = v; }, + (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ), + new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", + 0f, + (s) => { return AngularDamping; }, + (s,v) => { AngularDamping = v; }, + (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ), + new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", + 0.2f, + (s) => { return DeactivationTime; }, + (s,v) => { DeactivationTime = v; }, + (s,o) => { s.PE.SetDeactivationTime(o.PhysBody, DeactivationTime); } ), + new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", + 0.8f, + (s) => { return LinearSleepingThreshold; }, + (s,v) => { LinearSleepingThreshold = v;}, + (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ), + new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", + 1.0f, + (s) => { return AngularSleepingThreshold; }, + (s,v) => { AngularSleepingThreshold = v;}, + (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ), + new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , + 0.0f, // set to zero to disable + (s) => { return CcdMotionThreshold; }, + (s,v) => { CcdMotionThreshold = v;}, + (s,o) => { s.PE.SetCcdMotionThreshold(o.PhysBody, CcdMotionThreshold); } ), + new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , + 0.2f, + (s) => { return CcdSweptSphereRadius; }, + (s,v) => { CcdSweptSphereRadius = v;}, + (s,o) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, CcdSweptSphereRadius); } ), + new ParameterDefn("ContactProcessingThreshold", "Distance above which contacts can be discarded (0 means no discard)" , + 0.0f, + (s) => { return ContactProcessingThreshold; }, + (s,v) => { ContactProcessingThreshold = v;}, + (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), + + new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", + (float)BSTerrainPhys.TerrainImplementation.Heightmap ), + new ParameterDefn("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , + 2 ), + new ParameterDefn("TerrainGroundPlane", "Altitude of ground plane used to keep things from falling to infinity" , + -500.0f ), + new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , + 0.3f ), + new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , + 0.8f ), + new ParameterDefn("TerrainRestitution", "Bouncyness" , + 0f ), + new ParameterDefn("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" , + 0.0f ), + new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , + 0.04f ), + + new ParameterDefn("AvatarToAvatarCollisionsByDefault", "Should avatars collide with other avatars by default?", + true), + new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", + 0.2f ), + new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", + 0.95f ), + new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", + 1.3f ), + // For historical reasons, density is reported * 100 + new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation. Scaled times 100.", + 3500f) , // 3.5 * 100 + new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", + 0f ), + new ParameterDefn("AvatarShape", "Code for avatar physical shape: 0:capsule, 1:cube, 2:ovoid, 2:mesh", + BSShapeCollection.AvatarShapeCube ) , + new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", + 0.6f ) , + new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", + 0.45f ), + new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", + 1.5f ), + new ParameterDefn("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground", + 0f ), + new ParameterDefn("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground", + 0f ), + new ParameterDefn("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground", + 0f ), + new ParameterDefn("AvatarFlyingGroundMargin", "Meters avatar is kept above the ground when flying", + 5f ), + new ParameterDefn("AvatarFlyingGroundUpForce", "Upward force applied to the avatar to keep it at flying ground margin", + 2.0f ), + new ParameterDefn("AvatarTerminalVelocity", "Terminal Velocity of falling avatar", + -54.0f ), + new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", + 0.1f ), + new ParameterDefn("AvatarStopZeroThreshold", "Movement velocity below which avatar is assumed to be stopped", + 0.1f ), + new ParameterDefn("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", + 1.0f ), + new ParameterDefn("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.", + 4 ), + new ParameterDefn("AvatarStepHeight", "Height of a step obstacle to consider step correction", + 0.999f ) , + new ParameterDefn("AvatarStepAngle", "The angle (in radians) for a vertical surface to be considered a step", + 0.3f ) , + new ParameterDefn("AvatarStepGroundFudge", "Fudge factor subtracted from avatar base when comparing collision height", + 0.1f ) , + new ParameterDefn("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", + 2f ), + new ParameterDefn("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", + 0f ), + new ParameterDefn("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step", + 0.8f ), + new ParameterDefn("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs", + 1 ), + + new ParameterDefn("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", + 1000.0f, + (s) => { return (float)VehicleMaxLinearVelocity; }, + (s,v) => { VehicleMaxLinearVelocity = v; VehicleMaxLinearVelocitySquared = v * v; } ), + new ParameterDefn("VehicleMinLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", + 0.001f, + (s) => { return (float)VehicleMinLinearVelocity; }, + (s,v) => { VehicleMinLinearVelocity = v; VehicleMinLinearVelocitySquared = v * v; } ), + new ParameterDefn("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle", + 12.0f, + (s) => { return (float)VehicleMaxAngularVelocity; }, + (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), + new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", + 0.0f ), + new ParameterDefn("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)", + new Vector3(1f, 1f, 1f) ), + new ParameterDefn("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)", + new Vector3(1f, 1f, 1f) ), + new ParameterDefn("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)", + new Vector3(1f, 1f, 1f) ), + new ParameterDefn("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", + 0.0f ), + new ParameterDefn("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", + 0.0f ), + new ParameterDefn("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", + 0.2f ), + new ParameterDefn("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", + 60.0f ), + new ParameterDefn("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect", + true ), + new ParameterDefn("VehicleLinearDeflectionNotCollidingNoZ", "Turn on/off linear deflection Z effect on non-colliding vehicles", + true ), + new ParameterDefn("VehicleEnableAngularVerticalAttraction", "Turn on/off vehicle angular vertical attraction effect", + true ), + new ParameterDefn("VehicleAngularVerticalAttractionAlgorithm", "Select vertical attraction algo. You need to look at the source.", + 0 ), + new ParameterDefn("VehicleEnableAngularDeflection", "Turn on/off vehicle angular deflection effect", + true ), + new ParameterDefn("VehicleEnableAngularBanking", "Turn on/off vehicle angular banking effect", + true ), + + new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", + 0f, + (s) => { return MaxPersistantManifoldPoolSize; }, + (s,v) => { MaxPersistantManifoldPoolSize = v; s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ), + new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", + 0f, + (s) => { return MaxCollisionAlgorithmPoolSize; }, + (s,v) => { MaxCollisionAlgorithmPoolSize = v; s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ), + new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", + false, + (s) => { return ShouldDisableContactPoolDynamicAllocation; }, + (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; + s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), + new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", + false, + (s) => { return ShouldForceUpdateAllAabbs; }, + (s,v) => { ShouldForceUpdateAllAabbs = v; s.UnmanagedParams[0].shouldForceUpdateAllAabbs = NumericBool(v); } ), + new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", + true, + (s) => { return ShouldRandomizeSolverOrder; }, + (s,v) => { ShouldRandomizeSolverOrder = v; s.UnmanagedParams[0].shouldRandomizeSolverOrder = NumericBool(v); } ), + new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", + true, + (s) => { return ShouldSplitSimulationIslands; }, + (s,v) => { ShouldSplitSimulationIslands = v; s.UnmanagedParams[0].shouldSplitSimulationIslands = NumericBool(v); } ), + new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", + true, + (s) => { return ShouldEnableFrictionCaching; }, + (s,v) => { ShouldEnableFrictionCaching = v; s.UnmanagedParams[0].shouldEnableFrictionCaching = NumericBool(v); } ), + new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)", + 0f, // zero says use Bullet default + (s) => { return NumberOfSolverIterations; }, + (s,v) => { NumberOfSolverIterations = v; s.UnmanagedParams[0].numberOfSolverIterations = v; } ), + new ParameterDefn("UseSingleSidedMeshes", "Whether to compute collisions based on single sided meshes.", + true, + (s) => { return UseSingleSidedMeshes; }, + (s,v) => { UseSingleSidedMeshes = v; s.UnmanagedParams[0].useSingleSidedMeshes = NumericBool(v); } ), + new ParameterDefn("GlobalContactBreakingThreshold", "Amount of shape radius before breaking a collision contact (0 says Bullet default (0.2))", + 0f, + (s) => { return GlobalContactBreakingThreshold; }, + (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), + new ParameterDefn("PhysicsUnmanLoggingFrames", "If non-zero, frames between output of detailed unmanaged physics statistics", + 0f, + (s) => { return PhysicsUnmanLoggingFrames; }, + (s,v) => { PhysicsUnmanLoggingFrames = v; s.UnmanagedParams[0].physicsLoggingFrames = v; } ), + + new ParameterDefn("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", + 7 ), + new ParameterDefn("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", + 2 ), + new ParameterDefn("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", + 5f ), + new ParameterDefn("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", + 5f ), + new ParameterDefn("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.", + 32 ), + new ParameterDefn("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", + 0f ), + + new ParameterDefn("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull", + 200f ), + new ParameterDefn("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh", + 10f ), + new ParameterDefn("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls", + 20f ), + new ParameterDefn("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull", + 0.1f ), + new ParameterDefn("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be", + 10f ), + new ParameterDefn("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors", + true ), + new ParameterDefn("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls", + true ), + new ParameterDefn("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces", + true ), + new ParameterDefn("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin", + false ), + + new ParameterDefn("WhichHACD", "zero if Bullet HACD, non-zero says VHACD", + 0f ), + new ParameterDefn("VHACDresolution", "max number of voxels generated during voxelization stage", + 100000f ), + new ParameterDefn("VHACDdepth", "max number of clipping stages", + 20f ), + new ParameterDefn("VHACDconcavity", "maximum concavity", + 0.0025f ), + new ParameterDefn("VHACDplaneDownsampling", "granularity of search for best clipping plane", + 4f ), + new ParameterDefn("VHACDconvexHullDownsampling", "precision of hull gen process", + 4f ), + new ParameterDefn("VHACDalpha", "bias toward clipping along symmetry planes", + 0.05f ), + new ParameterDefn("VHACDbeta", "bias toward clipping along revolution axis", + 0.05f ), + new ParameterDefn("VHACDgamma", "max concavity when merging", + 0.00125f ), + new ParameterDefn("VHACDpca", "on/off normalizing mesh before decomp", + 0f ), + new ParameterDefn("VHACDmode", "0:voxel based, 1: tetrahedron based", + 0f ), + new ParameterDefn("VHACDmaxNumVerticesPerCH", "max triangles per convex hull", + 64f ), + new ParameterDefn("VHACDminVolumePerCH", "sampling of generated convex hulls", + 0.0001f ), + + new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", + (float)BSLinkset.LinksetImplementation.Compound ), + new ParameterDefn("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same", + true ), + new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", + false ), + new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", + true ), + new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", + 5.0f ), + new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", + 0.1f ), + new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", + 0.1f ), + new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", + 0.1f ), + new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", + 40 ), + + new ParameterDefn("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", + 0, + (s) => { return s.PhysicsMetricDumpFrames; }, + (s,v) => { s.PhysicsMetricDumpFrames = v; } ), + new ParameterDefn("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool", + 0f, + (s) => { return 0f; }, + (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v, false /* inTaintTime */); } ), + new ParameterDefn("ResetConstraintSolver", "Setting this is any value resets the constraint solver", + 0f, + (s) => { return 0f; }, + (s,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ), + }; + + // Convert a boolean to our numeric true and false values + public static float NumericBool(bool b) + { + return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); + } + + // Convert numeric true and false values to a boolean + public static bool BoolNumeric(float b) + { + return (b == ConfigurationParameters.numericTrue ? true : false); + } + + // Search through the parameter definitions and return the matching + // ParameterDefn structure. + // Case does not matter as names are compared after converting to lower case. + // Returns 'false' if the parameter is not found. + internal static bool TryGetParameter(string paramName, out ParameterDefnBase defn) + { + bool ret = false; + ParameterDefnBase foundDefn = null; + string pName = paramName.ToLower(); + + foreach (ParameterDefnBase parm in ParameterDefinitions) + { + if (pName == parm.name.ToLower()) + { + foundDefn = parm; + ret = true; + break; + } + } + defn = foundDefn; + return ret; + } + + // Pass through the settable parameters and set the default values + internal static void SetParameterDefaultValues(BSScene physicsScene) + { + foreach (ParameterDefnBase parm in ParameterDefinitions) + { + parm.AssignDefault(physicsScene); + } + } + + // Get user set values out of the ini file. + internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg) + { + foreach (ParameterDefnBase parm in ParameterDefinitions) + { + parm.SetValue(physicsScene, cfg.GetString(parm.name, parm.GetValue(physicsScene))); + } + } + + internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; + + // This creates an array in the correct format for returning the list of + // parameters. This is used by the 'list' option of the 'physics' command. + internal static void BuildParameterTable() + { + if (SettableParameters.Length < ParameterDefinitions.Length) + { + List entries = new List(); + for (int ii = 0; ii < ParameterDefinitions.Length; ii++) + { + ParameterDefnBase pd = ParameterDefinitions[ii]; + entries.Add(new PhysParameterEntry(pd.name, pd.desc)); + } + + // make the list alphabetical for ease of finding anything + entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); }); + + SettableParameters = entries.ToArray(); + } + } + + // ===================================================================== + // ===================================================================== + // There are parameters that, when set, cause things to happen in the physics engine. + // This causes the broadphase collision cache to be cleared. + private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v, bool inTaintTime) + { + BSScene physScene = pPhysScene; + physScene.TaintedObject(inTaintTime, "BSParam.ResetBroadphasePoolTainted", delegate() + { + physScene.PE.ResetBroadphasePool(physScene.World); + }); + } + + // This causes the constraint solver cache to be cleared and reset. + private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v) + { + BSScene physScene = pPhysScene; + physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetConstraintSolver", delegate() + { + physScene.PE.ResetConstraintSolver(physScene.World); + }); + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs new file mode 100755 index 0000000..da3fc18 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs @@ -0,0 +1,620 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; + +using OMV = OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +/* + * Class to wrap all objects. + * The rest of BulletSim doesn't need to keep checking for avatars or prims + * unless the difference is significant. + * + * Variables in the physicsl objects are in three forms: + * VariableName: used by the simulator and performs taint operations, etc + * RawVariableName: direct reference to the BulletSim storage for the variable value + * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. + * The last one should only be referenced in taint-time. + */ + +/* + * As of 20121221, the following are the call sequences (going down) for different script physical functions: + * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce + * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce + * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse + * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v + * BS.ApplyCentralForce BS.ApplyTorque + */ + +// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc. +public enum UpdatedProperties : uint +{ + Position = 1 << 0, + Orientation = 1 << 1, + Velocity = 1 << 2, + Acceleration = 1 << 3, + RotationalVelocity = 1 << 4, + EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity, +} +public abstract class BSPhysObject : PhysicsActor +{ + protected BSPhysObject() + { + } + protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) + { + IsInitialized = false; + + PhysScene = parentScene; + LocalID = localID; + PhysObjectName = name; + Name = name; // PhysicsActor also has the name of the object. Someday consolidate. + TypeName = typeName; + + // Oddity if object is destroyed and recreated very quickly it could still have the old body. + if (!PhysBody.HasPhysicalBody) + PhysBody = new BulletBody(localID); + + // Clean out anything that might be in the physical actor list. + // Again, a workaround for destroying and recreating an object very quickly. + PhysicalActors.Dispose(); + + UserSetCenterOfMassDisplacement = null; + + PrimAssetState = PrimAssetCondition.Unknown; + + // Initialize variables kept in base. + // Beware that these cause taints to be queued whch can cause race conditions on startup. + GravModifier = 1.0f; + Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); + HoverActive = false; + + // Default material type. Also sets Friction, Restitution and Density. + SetMaterial((int)MaterialAttributes.Material.Wood); + + CollisionsLastTickStep = -1; + + SubscribedEventsMs = 0; + // Crazy values that will never be true + CollidingStep = BSScene.NotASimulationStep; + CollidingGroundStep = BSScene.NotASimulationStep; + CollisionAccumulation = BSScene.NotASimulationStep; + ColliderIsMoving = false; + CollisionScore = 0; + + // All axis free. + LockedLinearAxis = LockedAxisFree; + LockedAngularAxis = LockedAxisFree; + } + + // Tell the object to clean up. + public virtual void Destroy() + { + PhysicalActors.Enable(false); + PhysScene.TaintedObject(LocalID, "BSPhysObject.Destroy", delegate() + { + PhysicalActors.Dispose(); + }); + } + + public BSScene PhysScene { get; protected set; } + // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor + public string PhysObjectName { get; protected set; } + public string TypeName { get; protected set; } + + // Set to 'true' when the object is completely initialized. + // This mostly prevents property updates and collisions until the object is completely here. + public bool IsInitialized { get; protected set; } + + // Set to 'true' if an object (mesh/linkset/sculpty) is not completely constructed. + // This test is used to prevent some updates to the object when it only partially exists. + // There are several reasons and object might be incomplete: + // Its underlying mesh/sculpty is an asset which must be fetched from the asset store + // It is a linkset who is being added to or removed from + // It is changing state (static to physical, for instance) which requires rebuilding + // This is a computed value based on the underlying physical object construction + abstract public bool IsIncomplete { get; } + + // Return the object mass without calculating it or having side effects + public abstract float RawMass { get; } + // Set the raw mass but also update physical mass properties (inertia, ...) + // 'inWorld' true if the object has already been added to the dynamic world. + public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld); + + // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy. + public virtual OMV.Vector3 Gravity { get; set; } + // The last value calculated for the prim's inertia + public OMV.Vector3 Inertia { get; set; } + + // Reference to the physical body (btCollisionObject) of this object + public BulletBody PhysBody = new BulletBody(0); + // Reference to the physical shape (btCollisionShape) of this object + public BSShape PhysShape = new BSShapeNull(); + + // The physical representation of the prim might require an asset fetch. + // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. + public enum PrimAssetCondition + { + Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched + } + public PrimAssetCondition PrimAssetState { get; set; } + public virtual bool AssetFailed() + { + return ( (this.PrimAssetState == PrimAssetCondition.FailedAssetFetch) + || (this.PrimAssetState == PrimAssetCondition.FailedMeshing) ); + } + + // The objects base shape information. Null if not a prim type shape. + public PrimitiveBaseShape BaseShape { get; protected set; } + + // When the physical properties are updated, an EntityProperty holds the update values. + // Keep the current and last EntityProperties to enable computation of differences + // between the current update and the previous values. + public EntityProperties CurrentEntityProperties { get; set; } + public EntityProperties LastEntityProperties { get; set; } + + public virtual OMV.Vector3 Scale { get; set; } + + // It can be confusing for an actor to know if it should move or update an object + // depeneding on the setting of 'selected', 'physical, ... + // This flag is the true test -- if true, the object is being acted on in the physical world + public abstract bool IsPhysicallyActive { get; } + + // Detailed state of the object. + public abstract bool IsSolid { get; } + public abstract bool IsStatic { get; } + public abstract bool IsSelected { get; } + public abstract bool IsVolumeDetect { get; } + + // Materialness + public MaterialAttributes.Material Material { get; private set; } + public override void SetMaterial(int material) + { + Material = (MaterialAttributes.Material)material; + + // Setting the material sets the material attributes also. + // TODO: decide if this is necessary -- the simulator does this. + MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); + Friction = matAttrib.friction; + Restitution = matAttrib.restitution; + Density = matAttrib.density; + // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); + } + + public override float Density + { + get + { + return base.Density; + } + set + { + DetailLog("{0},BSPhysObject.Density,set,den={1}", LocalID, value); + base.Density = value; + } + } + + // Stop all physical motion. + public abstract void ZeroMotion(bool inTaintTime); + public abstract void ZeroAngularMotion(bool inTaintTime); + + // Update the physical location and motion of the object. Called with data from Bullet. + public abstract void UpdateProperties(EntityProperties entprop); + + public virtual OMV.Vector3 RawPosition { get; set; } + public abstract OMV.Vector3 ForcePosition { get; set; } + + public virtual OMV.Quaternion RawOrientation { get; set; } + public abstract OMV.Quaternion ForceOrientation { get; set; } + + public virtual OMV.Vector3 RawVelocity { get; set; } + public abstract OMV.Vector3 ForceVelocity { get; set; } + + public OMV.Vector3 RawForce { get; set; } + public OMV.Vector3 RawTorque { get; set; } + public override void AddAngularForce(OMV.Vector3 force, bool pushforce) + { + AddAngularForce(force, pushforce, false); + } + public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime); + public abstract void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime); + + public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } + + public abstract float ForceBuoyancy { get; set; } + + public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } + + public override bool PIDActive + { + get { return MoveToTargetActive; } + set { MoveToTargetActive = value; } + } + + public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } } + public override float PIDTau { set { MoveToTargetTau = value; } } + + public bool MoveToTargetActive { get; set; } + public OMV.Vector3 MoveToTargetTarget { get; set; } + public float MoveToTargetTau { get; set; } + + // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z + public override bool PIDHoverActive { set { HoverActive = value; } } + public override float PIDHoverHeight { set { HoverHeight = value; } } + public override PIDHoverType PIDHoverType { set { HoverType = value; } } + public override float PIDHoverTau { set { HoverTau = value; } } + + public bool HoverActive { get; set; } + public float HoverHeight { get; set; } + public PIDHoverType HoverType { get; set; } + public float HoverTau { get; set; } + + // For RotLookAt + public override OMV.Quaternion APIDTarget { set { return; } } + public override bool APIDActive { set { return; } } + public override float APIDStrength { set { return; } } + public override float APIDDamping { set { return; } } + + // The current velocity forward + public virtual float ForwardSpeed + { + get + { + OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation)); + return characterOrientedVelocity.X; + } + } + // The forward speed we are trying to achieve (TargetVelocity) + public virtual float TargetVelocitySpeed + { + get + { + OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation)); + return characterOrientedVelocity.X; + } + } + + // The user can optionally set the center of mass. The user's setting will override any + // computed center-of-mass (like in linksets). + // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass. + public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; } + + public OMV.Vector3 LockedLinearAxis; // zero means locked. one means free. + public OMV.Vector3 LockedAngularAxis; // zero means locked. one means free. + public const float FreeAxis = 1f; + public const float LockedAxis = 0f; + public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free + + // If an axis is locked (flagged above) then the limits of that axis are specified here. + // Linear axis limits are relative to the object's starting coordinates. + // Angular limits are limited to -PI to +PI + public OMV.Vector3 LockedLinearAxisLow; + public OMV.Vector3 LockedLinearAxisHigh; + public OMV.Vector3 LockedAngularAxisLow; + public OMV.Vector3 LockedAngularAxisHigh; + + // Enable physical actions. Bullet will keep sleeping non-moving physical objects so + // they need waking up when parameters are changed. + // Called in taint-time!! + public void ActivateIfPhysical(bool forceIt) + { + if (PhysBody.HasPhysicalBody) + { + if (IsPhysical) + { + // Physical objects might need activating + PhysScene.PE.Activate(PhysBody, forceIt); + } + else + { + // Clear the collision cache since we've changed some properties. + PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody); + } + } + } + + // 'actors' act on the physical object to change or constrain its motion. These can range from + // hovering to complex vehicle motion. + // May be called at non-taint time as this just adds the actor to the action list and the real + // work is done during the simulation step. + // Note that, if the actor is already in the list and we are disabling same, the actor is just left + // in the list disabled. + public delegate BSActor CreateActor(); + public void EnableActor(bool enableActor, string actorName, CreateActor creator) + { + lock (PhysicalActors) + { + BSActor theActor; + if (PhysicalActors.TryGetActor(actorName, out theActor)) + { + // The actor already exists so just turn it on or off + DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor); + theActor.Enabled = enableActor; + } + else + { + // The actor does not exist. If it should, create it. + if (enableActor) + { + DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName); + theActor = creator(); + PhysicalActors.Add(actorName, theActor); + theActor.Enabled = true; + } + else + { + DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName); + } + } + } + } + + #region Collisions + + // Requested number of milliseconds between collision events. Zero means disabled. + protected int SubscribedEventsMs { get; set; } + // Given subscription, the time that a collision may be passed up + protected int NextCollisionOkTime { get; set; } + // The simulation step that last had a collision + protected long CollidingStep { get; set; } + // The simulation step that last had a collision with the ground + protected long CollidingGroundStep { get; set; } + // The simulation step that last collided with an object + protected long CollidingObjectStep { get; set; } + // The collision flags we think are set in Bullet + protected CollisionFlags CurrentCollisionFlags { get; set; } + // On a collision, check the collider and remember if the last collider was moving + // Used to modify the standing of avatars (avatars on stationary things stand still) + public bool ColliderIsMoving; + // 'true' if the last collider was a volume detect object + public bool ColliderIsVolumeDetect; + // Used by BSCharacter to manage standing (and not slipping) + public bool IsStationary; + + // Count of collisions for this object + protected long CollisionAccumulation { get; set; } + + public override bool IsColliding { + get { return (CollidingStep == PhysScene.SimulationStep); } + set { + if (value) + CollidingStep = PhysScene.SimulationStep; + else + CollidingStep = BSScene.NotASimulationStep; + } + } + // Complex objects (like linksets) need to know if there is a collision on any part of + // their shape. 'IsColliding' has an existing definition of reporting a collision on + // only this specific prim or component of linksets. + // 'HasSomeCollision' is defined as reporting if there is a collision on any part of + // the complex body that this prim is the root of. + public virtual bool HasSomeCollision + { + get { return IsColliding; } + set { IsColliding = value; } + } + public override bool CollidingGround { + get { return (CollidingGroundStep == PhysScene.SimulationStep); } + set + { + if (value) + CollidingGroundStep = PhysScene.SimulationStep; + else + CollidingGroundStep = BSScene.NotASimulationStep; + } + } + public override bool CollidingObj { + get { return (CollidingObjectStep == PhysScene.SimulationStep); } + set { + if (value) + CollidingObjectStep = PhysScene.SimulationStep; + else + CollidingObjectStep = BSScene.NotASimulationStep; + } + } + + // The collisions that have been collected for the next collision reporting (throttled by subscription) + protected CollisionEventUpdate CollisionCollection = new CollisionEventUpdate(); + // This is the collision collection last reported to the Simulator. + public CollisionEventUpdate CollisionsLastReported = new CollisionEventUpdate(); + // Remember the collisions recorded in the last tick for fancy collision checking + // (like a BSCharacter walking up stairs). + public CollisionEventUpdate CollisionsLastTick = new CollisionEventUpdate(); + private long CollisionsLastTickStep = -1; + + // The simulation step is telling this object about a collision. + // Return 'true' if a collision was processed and should be sent up. + // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. + // Called at taint time from within the Step() function + public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth); + public virtual bool Collide(uint collidingWith, BSPhysObject collidee, + OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) + { + bool ret = false; + + // The following lines make IsColliding(), CollidingGround() and CollidingObj work + CollidingStep = PhysScene.SimulationStep; + if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID) + { + CollidingGroundStep = PhysScene.SimulationStep; + } + else + { + CollidingObjectStep = PhysScene.SimulationStep; + } + + CollisionAccumulation++; + + // For movement tests, remember if we are colliding with an object that is moving. + ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; + ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false; + + // Make a collection of the collisions that happened the last simulation tick. + // This is different than the collection created for sending up to the simulator as it is cleared every tick. + if (CollisionsLastTickStep != PhysScene.SimulationStep) + { + CollisionsLastTick = new CollisionEventUpdate(); + CollisionsLastTickStep = PhysScene.SimulationStep; + } + CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); + + // If someone has subscribed for collision events log the collision so it will be reported up + if (SubscribedEvents()) { + lock (PhysScene.CollisionLock) + { + CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); + } + DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}", + LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving); + + ret = true; + } + return ret; + } + + // Send the collected collisions into the simulator. + // Called at taint time from within the Step() function thus no locking problems + // with CollisionCollection and ObjectsWithNoMoreCollisions. + // Called with BSScene.CollisionLock locked to protect the collision lists. + // Return 'true' if there were some actual collisions passed up + public virtual bool SendCollisions() + { + bool ret = true; + + // If no collisions this call but there were collisions last call, force the collision + // event to be happen right now so quick collision_end. + bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0); + + // throttle the collisions to the number of milliseconds specified in the subscription + if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime)) + { + NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs; + + // We are called if we previously had collisions. If there are no collisions + // this time, send up one last empty event so OpenSim can sense collision end. + if (CollisionCollection.Count == 0) + { + // If I have no collisions this time, remove me from the list of objects with collisions. + ret = false; + } + + DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); + base.SendCollisionUpdate(CollisionCollection); + + // Remember the collisions from this tick for some collision specific processing. + CollisionsLastReported = CollisionCollection; + + // The CollisionCollection instance is passed around in the simulator. + // Make sure we don't have a handle to that one and that a new one is used for next time. + // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, + // a race condition is created for the other users of this instance. + CollisionCollection = new CollisionEventUpdate(); + } + return ret; + } + + // Subscribe for collision events. + // Parameter is the millisecond rate the caller wishes collision events to occur. + public override void SubscribeEvents(int ms) { + // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms); + SubscribedEventsMs = ms; + if (ms > 0) + { + // make sure first collision happens + NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); + + PhysScene.TaintedObject(LocalID, TypeName+".SubscribeEvents", delegate() + { + if (PhysBody.HasPhysicalBody) + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + }); + } + else + { + // Subscribing for zero or less is the same as unsubscribing + UnSubscribeEvents(); + } + } + public override void UnSubscribeEvents() { + // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); + SubscribedEventsMs = 0; + PhysScene.TaintedObject(LocalID, TypeName+".UnSubscribeEvents", delegate() + { + // Make sure there is a body there because sometimes destruction happens in an un-ideal order. + if (PhysBody.HasPhysicalBody) + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + }); + } + // Return 'true' if the simulator wants collision events + public override bool SubscribedEvents() { + return (SubscribedEventsMs > 0); + } + // Because 'CollisionScore' is called many times while sorting, it should not be recomputed + // each time called. So this is built to be light weight for each collision and to do + // all the processing when the user asks for the info. + public void ComputeCollisionScore() + { + // Scale the collision count by the time since the last collision. + // The "+1" prevents dividing by zero. + long timeAgo = PhysScene.SimulationStep - CollidingStep + 1; + CollisionScore = CollisionAccumulation / timeAgo; + } + public override float CollisionScore { get; set; } + + #endregion // Collisions + + #region Per Simulation Step actions + + public BSActorCollection PhysicalActors = new BSActorCollection(); + + // When an update to the physical properties happens, this event is fired to let + // different actors to modify the update before it is passed around + public delegate void PreUpdatePropertyAction(ref EntityProperties entprop); + public event PreUpdatePropertyAction OnPreUpdateProperty; + protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop) + { + PreUpdatePropertyAction actions = OnPreUpdateProperty; + if (actions != null) + actions(ref entprop); + } + + #endregion // Per Simulation Step actions + + // High performance detailed logging routine used by the physical objects. + protected void DetailLog(string msg, params Object[] args) + { + if (PhysScene.PhysicsLogging.Enabled) + PhysScene.DetailLog(msg, args); + } + +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs new file mode 100644 index 0000000..6f27ac7 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs @@ -0,0 +1,1895 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Xml; +using log4net; +using OMV = OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + + [Serializable] +public class BSPrim : BSPhysObject +{ + protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly string LogHeader = "[BULLETS PRIM]"; + + // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. + private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user + + private bool _grabbed; + private bool _isSelected; + private bool _isVolumeDetect; + + private float _mass; // the mass of this object + private OMV.Vector3 _acceleration; + private int _physicsActorType; + private bool _isPhysical; + private bool _flying; + private bool _setAlwaysRun; + private bool _throttleUpdates; + private bool _floatOnWater; + private OMV.Vector3 _rotationalVelocity; + private bool _kinematic; + private float _buoyancy; + + private int CrossingFailures { get; set; } + + // Keep a handle to the vehicle actor so it is easy to set parameters on same. + public const string VehicleActorName = "BasicVehicle"; + + // Parameters for the hover actor + public const string HoverActorName = "BSPrim.HoverActor"; + // Parameters for the axis lock actor + public const String LockedAxisActorName = "BSPrim.LockedAxis"; + // Parameters for the move to target actor + public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor"; + // Parameters for the setForce and setTorque actors + public const string SetForceActorName = "BSPrim.SetForceActor"; + public const string SetTorqueActorName = "BSPrim.SetTorqueActor"; + + public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, + OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) + : base(parent_scene, localID, primName, "BSPrim") + { + // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); + _physicsActorType = (int)ActorTypes.Prim; + RawPosition = pos; + _size = size; + Scale = size; // prims are the size the user wants them to be (different for BSCharactes). + RawOrientation = rotation; + _buoyancy = 0f; + RawVelocity = OMV.Vector3.Zero; + _rotationalVelocity = OMV.Vector3.Zero; + BaseShape = pbs; + _isPhysical = pisPhysical; + _isVolumeDetect = false; + + _mass = CalculateMass(); + + DetailLog("{0},BSPrim.constructor,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(pbs)); + // DetailLog("{0},BSPrim.constructor,call", LocalID); + // do the actual object creation at taint time + PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate() + { + // Make sure the object is being created with some sanity. + ExtremeSanityCheck(true /* inTaintTime */); + + CreateGeomAndObject(true); + + CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody); + + IsInitialized = true; + }); + } + + // called when this prim is being destroyed and we should free all the resources + public override void Destroy() + { + // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); + IsInitialized = false; + + base.Destroy(); + + // Undo any vehicle properties + this.VehicleType = (int)Vehicle.TYPE_NONE; + + PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate() + { + DetailLog("{0},BSPrim.Destroy,taint,", LocalID); + // If there are physical body and shape, release my use of same. + PhysScene.Shapes.DereferenceBody(PhysBody, null); + PhysBody.Clear(); + PhysShape.Dereference(PhysScene); + PhysShape = new BSShapeNull(); + }); + } + + // No one uses this property. + public override bool Stopped { + get { return false; } + } + + public override bool IsIncomplete { + get { + return ShapeRebuildScheduled; + } + } + + // 'true' if this object's shape is in need of a rebuild and a rebuild has been queued. + // The prim is still available but its underlying shape will change soon. + // This is protected by a 'lock(this)'. + public bool ShapeRebuildScheduled { get; protected set; } + + public override OMV.Vector3 Size { + get { return _size; } + set { + // We presume the scale and size are the same. If scale must be changed for + // the physical shape, that is done when the geometry is built. + _size = value; + Scale = _size; + ForceBodyShapeRebuild(false); + } + } + + public override PrimitiveBaseShape Shape { + set { + BaseShape = value; + DetailLog("{0},BSPrim.changeShape,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(BaseShape)); + PrimAssetState = PrimAssetCondition.Unknown; + ForceBodyShapeRebuild(false); + } + } + // Cause the body and shape of the prim to be rebuilt if necessary. + // If there are no changes required, this is quick and does not make changes to the prim. + // If rebuilding is necessary (like changing from static to physical), that will happen. + // The 'ShapeRebuildScheduled' tells any checker that the body/shape may change shortly. + // The return parameter is not used by anyone. + public override bool ForceBodyShapeRebuild(bool inTaintTime) + { + if (inTaintTime) + { + // If called in taint time, do the operation immediately + _mass = CalculateMass(); // changing the shape changes the mass + CreateGeomAndObject(true); + } + else + { + lock (this) + { + // If a rebuild is not already in the queue + if (!ShapeRebuildScheduled) + { + // Remember that a rebuild is queued -- this is used to flag an incomplete object + ShapeRebuildScheduled = true; + PhysScene.TaintedObject(LocalID, "BSPrim.ForceBodyShapeRebuild", delegate() + { + _mass = CalculateMass(); // changing the shape changes the mass + CreateGeomAndObject(true); + ShapeRebuildScheduled = false; + }); + } + } + } + return true; + } + public override bool Grabbed { + set { _grabbed = value; + } + } + public override bool Selected { + set + { + if (value != _isSelected) + { + _isSelected = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate() + { + DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); + SetObjectDynamic(false); + }); + } + } + } + public override bool IsSelected + { + get { return _isSelected; } + } + + public override void CrossingFailure() + { + CrossingFailures++; + if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds) + { + base.RaiseOutOfBounds(RawPosition); + } + else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds) + { + m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name); + } + return; + } + + // link me to the specified parent + public override void link(PhysicsActor obj) { + } + + // delink me from my linkset + public override void delink() { + } + + // Set motion values to zero. + // Do it to the properties so the values get set in the physics engine. + // Push the setting of the values to the viewer. + // Called at taint time! + public override void ZeroMotion(bool inTaintTime) + { + RawVelocity = OMV.Vector3.Zero; + _acceleration = OMV.Vector3.Zero; + _rotationalVelocity = OMV.Vector3.Zero; + + // Zero some other properties in the physics engine + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate() + { + if (PhysBody.HasPhysicalBody) + PhysScene.PE.ClearAllForces(PhysBody); + }); + } + public override void ZeroAngularMotion(bool inTaintTime) + { + _rotationalVelocity = OMV.Vector3.Zero; + // Zero some other properties in the physics engine + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate() + { + // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); + PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); + } + }); + } + + public override void LockAngularMotion(OMV.Vector3 axis) + { + DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); + + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f); + if (axis.X != 1) + { + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X, 0f, 0f); + } + if (axis.Y != 1) + { + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y, 0f, 0f); + } + if (axis.Z != 1) + { + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z, 0f, 0f); + } + + InitializeAxisActor(); + + return; + } + + public override OMV.Vector3 Position { + get { + // don't do the GetObjectPosition for root elements because this function is called a zillion times. + // RawPosition = ForcePosition; + return RawPosition; + } + set { + // If the position must be forced into the physics engine, use ForcePosition. + // All positions are given in world positions. + if (RawPosition == value) + { + DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); + return; + } + RawPosition = value; + PositionSanityCheck(false); + + PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate() + { + DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); + ForcePosition = RawPosition; + }); + } + } + + // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity. + public override OMV.Vector3 ForcePosition { + get { + RawPosition = PhysScene.PE.GetPosition(PhysBody); + return RawPosition; + } + set { + RawPosition = value; + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); + ActivateIfPhysical(false); + } + } + } + + // Check that the current position is sane and, if not, modify the position to make it so. + // Check for being below terrain and being out of bounds. + // Returns 'true' of the position was made sane by some action. + private bool PositionSanityCheck(bool inTaintTime) + { + bool ret = false; + + // We don't care where non-physical items are placed + if (!IsPhysicallyActive) + return ret; + + if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) + { + // The physical object is out of the known/simulated area. + // Upper levels of code will handle the transition to other areas so, for + // the time, we just ignore the position. + return ret; + } + + float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); + OMV.Vector3 upForce = OMV.Vector3.Zero; + float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); + if ((RawPosition.Z + approxSize / 2f) < terrainHeight) + { + DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); + float targetHeight = terrainHeight + (Size.Z / 2f); + // If the object is below ground it just has to be moved up because pushing will + // not get it through the terrain + RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight); + if (inTaintTime) + { + ForcePosition = RawPosition; + } + // If we are throwing the object around, zero its other forces + ZeroMotion(inTaintTime); + ret = true; + } + + if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) + { + float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); + // TODO: a floating motor so object will bob in the water + if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) + { + // Upforce proportional to the distance away from the water. Correct the error in 1 sec. + upForce.Z = (waterHeight - RawPosition.Z) * 1f; + + // Apply upforce and overcome gravity. + OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity; + DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce); + AddForce(correctionForce, false, inTaintTime); + ret = true; + } + } + + return ret; + } + + // Occasionally things will fly off and really get lost. + // Find the wanderers and bring them back. + // Return 'true' if some parameter need some sanity. + private bool ExtremeSanityCheck(bool inTaintTime) + { + bool ret = false; + + int wayOverThere = -1000; + int wayOutThere = 10000; + // There have been instances of objects getting thrown way out of bounds and crashing + // the border crossing code. + if ( RawPosition.X < wayOverThere || RawPosition.X > wayOutThere + || RawPosition.Y < wayOverThere || RawPosition.X > wayOutThere + || RawPosition.Z < wayOverThere || RawPosition.X > wayOutThere) + { + RawPosition = new OMV.Vector3(10, 10, 50); + ZeroMotion(inTaintTime); + ret = true; + } + if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocitySquared) + { + RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity); + ret = true; + } + if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) + { + _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); + ret = true; + } + + return ret; + } + + // Return the effective mass of the object. + // The definition of this call is to return the mass of the prim. + // If the simulator cares about the mass of the linkset, it will sum it itself. + public override float Mass + { + get { return _mass; } + } + // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code) + public virtual float TotalMass + { + get { return _mass; } + } + // used when we only want this prim's mass and not the linkset thing + public override float RawMass { + get { return _mass; } + } + // Set the physical mass to the passed mass. + // Note that this does not change _mass! + public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) + { + if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) + { + if (IsStatic) + { + PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity); + Inertia = OMV.Vector3.Zero; + PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia); + PhysScene.PE.UpdateInertiaTensor(PhysBody); + } + else + { + if (inWorld) + { + // Changing interesting properties doesn't change proxy and collision cache + // information. The Bullet solution is to re-add the object to the world + // after parameters are changed. + PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); + } + + // The computation of mass props requires gravity to be set on the object. + Gravity = ComputeGravity(Buoyancy); + PhysScene.PE.SetGravity(PhysBody, Gravity); + + // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG + // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG + + Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); + PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia); + PhysScene.PE.UpdateInertiaTensor(PhysBody); + + DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", + LocalID, physMass, Inertia, Gravity, inWorld); + + if (inWorld) + { + AddObjectToPhysicalWorld(); + } + } + } + } + + // Return what gravity should be set to this very moment + public OMV.Vector3 ComputeGravity(float buoyancy) + { + OMV.Vector3 ret = PhysScene.DefaultGravity; + + if (!IsStatic) + { + ret *= (1f - buoyancy); + ret *= GravModifier; + } + + return ret; + } + + // Is this used? + public override OMV.Vector3 CenterOfMass + { + get { return RawPosition; } + } + + // Is this used? + public override OMV.Vector3 GeometricCenter + { + get { return RawPosition; } + } + + public override OMV.Vector3 Force { + get { return RawForce; } + set { + RawForce = value; + EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate() + { + return new BSActorSetForce(PhysScene, this, SetForceActorName); + }); + + // Call update so actor Refresh() is called to start things off + PhysScene.TaintedObject(LocalID, "BSPrim.setForce", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + + // Find and return a handle to the current vehicle actor. + // Return 'null' if there is no vehicle actor. + public BSDynamics GetVehicleActor(bool createIfNone) + { + BSDynamics ret = null; + BSActor actor; + if (PhysicalActors.TryGetActor(VehicleActorName, out actor)) + { + ret = actor as BSDynamics; + } + else + { + if (createIfNone) + { + ret = new BSDynamics(PhysScene, this, VehicleActorName); + PhysicalActors.Add(ret.ActorName, ret); + } + } + return ret; + } + + public override int VehicleType { + get { + int ret = (int)Vehicle.TYPE_NONE; + BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); + if (vehicleActor != null) + ret = (int)vehicleActor.Type; + return ret; + } + set { + Vehicle type = (Vehicle)value; + + PhysScene.TaintedObject(LocalID, "setVehicleType", delegate() + { + // Some vehicle scripts change vehicle type on the fly as an easy way to + // change all the parameters. Like a plane changing to CAR when on the + // ground. In this case, don't want to zero motion. + // ZeroMotion(true /* inTaintTime */); + if (type == Vehicle.TYPE_NONE) + { + // Vehicle type is 'none' so get rid of any actor that may have been allocated. + BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); + if (vehicleActor != null) + { + PhysicalActors.RemoveAndRelease(vehicleActor.ActorName); + } + } + else + { + // Vehicle type is not 'none' so create an actor and set it running. + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessTypeChange(type); + ActivateIfPhysical(false); + } + } + }); + } + } + public override void VehicleFloatParam(int param, float value) + { + PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate() + { + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); + ActivateIfPhysical(false); + } + }); + } + public override void VehicleVectorParam(int param, OMV.Vector3 value) + { + PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate() + { + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); + ActivateIfPhysical(false); + } + }); + } + public override void VehicleRotationParam(int param, OMV.Quaternion rotation) + { + PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate() + { + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); + ActivateIfPhysical(false); + } + }); + } + public override void VehicleFlags(int param, bool remove) + { + PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate() + { + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessVehicleFlags(param, remove); + } + }); + } + + // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more + public override void SetVolumeDetect(int param) { + bool newValue = (param != 0); + if (_isVolumeDetect != newValue) + { + _isVolumeDetect = newValue; + PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate() + { + // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); + SetObjectDynamic(true); + }); + } + return; + } + public override bool IsVolumeDetect + { + get { return _isVolumeDetect; } + } + public override void SetMaterial(int material) + { + base.SetMaterial(material); + PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate() + { + UpdatePhysicalParameters(); + }); + } + public override float Friction + { + get { return base.Friction; } + set + { + if (base.Friction != value) + { + base.Friction = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + } + public override float Restitution + { + get { return base.Restitution; } + set + { + if (base.Restitution != value) + { + base.Restitution = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + } + // The simulator/viewer keep density as 100kg/m3. + // Remember to use BSParam.DensityScaleFactor to create the physical density. + public override float Density + { + get { return base.Density; } + set + { + if (base.Density != value) + { + base.Density = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + } + public override float GravModifier + { + get { return base.GravModifier; } + set + { + if (base.GravModifier != value) + { + base.GravModifier = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + } + public override OMV.Vector3 Velocity { + get { return RawVelocity; } + set { + RawVelocity = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate() + { + // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); + ForceVelocity = RawVelocity; + }); + } + } + public override OMV.Vector3 ForceVelocity { + get { return RawVelocity; } + set { + PhysScene.AssertInTaintTime("BSPrim.ForceVelocity"); + + RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); + if (PhysBody.HasPhysicalBody) + { + DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity); + PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); + ActivateIfPhysical(false); + } + } + } + public override OMV.Vector3 Torque { + get { return RawTorque; } + set { + RawTorque = value; + EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate() + { + return new BSActorSetTorque(PhysScene, this, SetTorqueActorName); + }); + DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); + + // Call update so actor Refresh() is called to start things off + PhysScene.TaintedObject(LocalID, "BSPrim.setTorque", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + public override OMV.Vector3 Acceleration { + get { return _acceleration; } + set { _acceleration = value; } + } + + public override OMV.Quaternion Orientation { + get { + return RawOrientation; + } + set { + if (RawOrientation == value) + return; + RawOrientation = value; + + PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate() + { + ForceOrientation = RawOrientation; + }); + } + } + // Go directly to Bullet to get/set the value. + public override OMV.Quaternion ForceOrientation + { + get + { + RawOrientation = PhysScene.PE.GetOrientation(PhysBody); + return RawOrientation; + } + set + { + RawOrientation = value; + if (PhysBody.HasPhysicalBody) + PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); + } + } + public override int PhysicsActorType { + get { return _physicsActorType; } + set { _physicsActorType = value; } + } + public override bool IsPhysical { + get { return _isPhysical; } + set { + if (_isPhysical != value) + { + _isPhysical = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate() + { + DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); + SetObjectDynamic(true); + // whether phys-to-static or static-to-phys, the object is not moving. + ZeroMotion(true); + + }); + } + } + } + + // An object is static (does not move) if selected or not physical + public override bool IsStatic + { + get { return _isSelected || !IsPhysical; } + } + + // An object is solid if it's not phantom and if it's not doing VolumeDetect + public override bool IsSolid + { + get { return !IsPhantom && !_isVolumeDetect; } + } + + // The object is moving and is actively being dynamic in the physical world + public override bool IsPhysicallyActive + { + get { return !_isSelected && IsPhysical; } + } + + // Make gravity work if the object is physical and not selected + // Called at taint-time!! + private void SetObjectDynamic(bool forceRebuild) + { + // Recreate the physical object if necessary + CreateGeomAndObject(forceRebuild); + } + + // Convert the simulator's physical properties into settings on BulletSim objects. + // There are four flags we're interested in: + // IsStatic: Object does not move, otherwise the object has mass and moves + // isSolid: other objects bounce off of this object + // isVolumeDetect: other objects pass through but can generate collisions + // collisionEvents: whether this object returns collision events + // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters. + public virtual void UpdatePhysicalParameters() + { + if (!PhysBody.HasPhysicalBody) + { + // This would only happen if updates are called for during initialization when the body is not set up yet. + // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); + return; + } + + // Mangling all the physical properties requires the object not be in the physical world. + // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). + PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); + + // Set up the object physicalness (does gravity and collisions move this object) + MakeDynamic(IsStatic); + + // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) + PhysicalActors.Refresh(); + + // Arrange for collision events if the simulator wants them + EnableCollisions(SubscribedEvents()); + + // Make solid or not (do things bounce off or pass through this object). + MakeSolid(IsSolid); + + AddObjectToPhysicalWorld(); + + // Rebuild its shape + PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); + + DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", + LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), + CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); + } + + // "Making dynamic" means changing to and from static. + // When static, gravity does not effect the object and it is fixed in space. + // When dynamic, the object can fall and be pushed by others. + // This is independent of its 'solidness' which controls what passes through + // this object and what interacts with it. + protected virtual void MakeDynamic(bool makeStatic) + { + if (makeStatic) + { + // Become a Bullet 'static' object type + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); + // Stop all movement + ZeroMotion(true); + + // Set various physical properties so other object interact properly + PhysScene.PE.SetFriction(PhysBody, Friction); + PhysScene.PE.SetRestitution(PhysBody, Restitution); + PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); + + // Mass is zero which disables a bunch of physics stuff in Bullet + UpdatePhysicalMassProperties(0f, false); + // Set collision detection parameters + if (BSParam.CcdMotionThreshold > 0f) + { + PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); + PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); + } + + // The activation state is 'disabled' so Bullet will not try to act on it. + // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); + // Start it out sleeping and physical actions could wake it up. + PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); + + // This collides like a static object + PhysBody.collisionType = CollisionType.Static; + } + else + { + // Not a Bullet static object + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); + + // Set various physical properties so other object interact properly + PhysScene.PE.SetFriction(PhysBody, Friction); + PhysScene.PE.SetRestitution(PhysBody, Restitution); + // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); + + // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 + // Since this can be called multiple times, only zero forces when becoming physical + // PhysicsScene.PE.ClearAllForces(BSBody); + + // For good measure, make sure the transform is set through to the motion state + ForcePosition = RawPosition; + ForceVelocity = RawVelocity; + ForceRotationalVelocity = _rotationalVelocity; + + // A dynamic object has mass + UpdatePhysicalMassProperties(RawMass, false); + + // Set collision detection parameters + if (BSParam.CcdMotionThreshold > 0f) + { + PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); + PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); + } + + // Various values for simulation limits + PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); + PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); + PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); + PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); + + // This collides like an object. + PhysBody.collisionType = CollisionType.Dynamic; + + // Force activation of the object so Bullet will act on it. + // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. + PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); + } + } + + // "Making solid" means that other object will not pass through this object. + // To make transparent, we create a Bullet ghost object. + // Note: This expects to be called from the UpdatePhysicalParameters() routine as + // the functions after this one set up the state of a possibly newly created collision body. + private void MakeSolid(bool makeSolid) + { + CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody); + if (makeSolid) + { + // Verify the previous code created the correct shape for this type of thing. + if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0) + { + m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); + } + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); + } + else + { + if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0) + { + m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); + } + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); + + // Change collision info from a static object to a ghosty collision object + PhysBody.collisionType = CollisionType.VolumeDetect; + } + } + + // Turn on or off the flag controlling whether collision events are returned to the simulator. + private void EnableCollisions(bool wantsCollisionEvents) + { + if (wantsCollisionEvents) + { + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + } + else + { + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + } + } + + // Add me to the physical world. + // Object MUST NOT already be in the world. + // This routine exists because some assorted properties get mangled by adding to the world. + internal void AddObjectToPhysicalWorld() + { + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); + } + else + { + m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID); + DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType); + } + } + + // prims don't fly + public override bool Flying { + get { return _flying; } + set { + _flying = value; + } + } + public override bool SetAlwaysRun { + get { return _setAlwaysRun; } + set { _setAlwaysRun = value; } + } + public override bool ThrottleUpdates { + get { return _throttleUpdates; } + set { _throttleUpdates = value; } + } + public bool IsPhantom { + get { + // SceneObjectPart removes phantom objects from the physics scene + // so, although we could implement touching and such, we never + // are invoked as a phantom object + return false; + } + } + public override bool FloatOnWater { + set { + _floatOnWater = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate() + { + if (_floatOnWater) + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); + else + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); + }); + } + } + public override OMV.Vector3 RotationalVelocity { + get { + return _rotationalVelocity; + } + set { + _rotationalVelocity = value; + Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); + // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); + PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate() + { + ForceRotationalVelocity = _rotationalVelocity; + }); + } + } + public override OMV.Vector3 ForceRotationalVelocity { + get { + return _rotationalVelocity; + } + set { + _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity); + if (PhysBody.HasPhysicalBody) + { + DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); + PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); + // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); + ActivateIfPhysical(false); + } + } + } + public override bool Kinematic { + get { return _kinematic; } + set { _kinematic = value; + // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); + } + } + public override float Buoyancy { + get { return _buoyancy; } + set { + _buoyancy = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate() + { + ForceBuoyancy = _buoyancy; + }); + } + } + public override float ForceBuoyancy { + get { return _buoyancy; } + set { + _buoyancy = value; + // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); + // Force the recalculation of the various inertia,etc variables in the object + UpdatePhysicalMassProperties(RawMass, true); + DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity); + ActivateIfPhysical(false); + } + } + + public override bool PIDActive + { + get + { + return MoveToTargetActive; + } + + set + { + MoveToTargetActive = value; + + EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate() + { + return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName); + }); + + // Call update so actor Refresh() is called to start things off + PhysScene.TaintedObject(LocalID, "BSPrim.PIDActive", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + + public override OMV.Vector3 PIDTarget + { + set + { + base.PIDTarget = value; + BSActor actor; + if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor)) + { + // if the actor exists, tell it to refresh its values. + actor.Refresh(); + } + + } + } + // Used for llSetHoverHeight and maybe vehicle height + // Hover Height will override MoveTo target's Z + public override bool PIDHoverActive { + set { + base.HoverActive = value; + EnableActor(HoverActive, HoverActorName, delegate() + { + return new BSActorHover(PhysScene, this, HoverActorName); + }); + + // Call update so actor Refresh() is called to start things off + PhysScene.TaintedObject(LocalID, "BSPrim.PIDHoverActive", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + + public override void AddForce(OMV.Vector3 force, bool pushforce) { + // Per documentation, max force is limited. + OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); + + // Since this force is being applied in only one step, make this a force per second. + addForce /= PhysScene.LastTimeStep; + AddForce(addForce, pushforce, false /* inTaintTime */); + } + + // Applying a force just adds this to the total force on the object. + // This added force will only last the next simulation tick. + public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { + // for an object, doesn't matter if force is a pushforce or not + if (IsPhysicallyActive) + { + if (force.IsFinite()) + { + // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); + + OMV.Vector3 addForce = force; + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate() + { + // Bullet adds this central force to the total force for this tick. + // Deep down in Bullet: + // linearVelocity += totalForce / mass * timeStep; + DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.ApplyCentralForce(PhysBody, addForce); + ActivateIfPhysical(false); + } + }); + } + else + { + m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); + return; + } + } + } + + public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) { + // for an object, doesn't matter if force is a pushforce or not + if (!IsPhysicallyActive) + { + if (impulse.IsFinite()) + { + OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); + // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); + + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate() + { + // Bullet adds this impulse immediately to the velocity + DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); + ActivateIfPhysical(false); + } + }); + } + else + { + m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID); + return; + } + } + } + + // BSPhysObject.AddAngularForce() + public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) + { + if (force.IsFinite()) + { + OMV.Vector3 angForce = force; + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate() + { + if (PhysBody.HasPhysicalBody) + { + DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); + PhysScene.PE.ApplyTorque(PhysBody, angForce); + ActivateIfPhysical(false); + } + }); + } + else + { + m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); + return; + } + } + + // A torque impulse. + // ApplyTorqueImpulse adds torque directly to the angularVelocity. + // AddAngularForce accumulates the force and applied it to the angular velocity all at once. + // Computed as: angularVelocity += impulse * inertia; + public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) + { + OMV.Vector3 applyImpulse = impulse; + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate() + { + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); + ActivateIfPhysical(false); + } + }); + } + + public override void SetMomentum(OMV.Vector3 momentum) { + // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); + } + #region Mass Calculation + + private float CalculateMass() + { + float volume = _size.X * _size.Y * _size.Z; // default + float tmp; + + float returnMass = 0; + float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f; + float hollowVolume = hollowAmount * hollowAmount; + + switch (BaseShape.ProfileShape) + { + case ProfileShape.Square: + // default box + + if (BaseShape.PathCurve == (byte)Extrusion.Straight) + { + if (hollowAmount > 0.0) + { + switch (BaseShape.HollowShape) + { + case HollowShape.Square: + case HollowShape.Same: + break; + + case HollowShape.Circle: + + hollowVolume *= 0.78539816339f; + break; + + case HollowShape.Triangle: + + hollowVolume *= (0.5f * .5f); + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + + else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) + { + //a tube + + volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX); + tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY); + volume -= volume*tmp*tmp; + + if (hollowAmount > 0.0) + { + hollowVolume *= hollowAmount; + + switch (BaseShape.HollowShape) + { + case HollowShape.Square: + case HollowShape.Same: + break; + + case HollowShape.Circle: + hollowVolume *= 0.78539816339f;; + break; + + case HollowShape.Triangle: + hollowVolume *= 0.5f * 0.5f; + break; + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + + break; + + case ProfileShape.Circle: + + if (BaseShape.PathCurve == (byte)Extrusion.Straight) + { + volume *= 0.78539816339f; // elipse base + + if (hollowAmount > 0.0) + { + switch (BaseShape.HollowShape) + { + case HollowShape.Same: + case HollowShape.Circle: + break; + + case HollowShape.Square: + hollowVolume *= 0.5f * 2.5984480504799f; + break; + + case HollowShape.Triangle: + hollowVolume *= .5f * 1.27323954473516f; + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + + else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) + { + volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX); + tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); + volume *= (1.0f - tmp * tmp); + + if (hollowAmount > 0.0) + { + + // calculate the hollow volume by it's shape compared to the prim shape + hollowVolume *= hollowAmount; + + switch (BaseShape.HollowShape) + { + case HollowShape.Same: + case HollowShape.Circle: + break; + + case HollowShape.Square: + hollowVolume *= 0.5f * 2.5984480504799f; + break; + + case HollowShape.Triangle: + hollowVolume *= .5f * 1.27323954473516f; + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + break; + + case ProfileShape.HalfCircle: + if (BaseShape.PathCurve == (byte)Extrusion.Curve1) + { + volume *= 0.52359877559829887307710723054658f; + } + break; + + case ProfileShape.EquilateralTriangle: + + if (BaseShape.PathCurve == (byte)Extrusion.Straight) + { + volume *= 0.32475953f; + + if (hollowAmount > 0.0) + { + + // calculate the hollow volume by it's shape compared to the prim shape + switch (BaseShape.HollowShape) + { + case HollowShape.Same: + case HollowShape.Triangle: + hollowVolume *= .25f; + break; + + case HollowShape.Square: + hollowVolume *= 0.499849f * 3.07920140172638f; + break; + + case HollowShape.Circle: + // Hollow shape is a perfect cyllinder in respect to the cube's scale + // Cyllinder hollow volume calculation + + hollowVolume *= 0.1963495f * 3.07920140172638f; + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) + { + volume *= 0.32475953f; + volume *= 0.01f * (float)(200 - BaseShape.PathScaleX); + tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); + volume *= (1.0f - tmp * tmp); + + if (hollowAmount > 0.0) + { + + hollowVolume *= hollowAmount; + + switch (BaseShape.HollowShape) + { + case HollowShape.Same: + case HollowShape.Triangle: + hollowVolume *= .25f; + break; + + case HollowShape.Square: + hollowVolume *= 0.499849f * 3.07920140172638f; + break; + + case HollowShape.Circle: + + hollowVolume *= 0.1963495f * 3.07920140172638f; + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + break; + + default: + break; + } + + + + float taperX1; + float taperY1; + float taperX; + float taperY; + float pathBegin; + float pathEnd; + float profileBegin; + float profileEnd; + + if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible) + { + taperX1 = BaseShape.PathScaleX * 0.01f; + if (taperX1 > 1.0f) + taperX1 = 2.0f - taperX1; + taperX = 1.0f - taperX1; + + taperY1 = BaseShape.PathScaleY * 0.01f; + if (taperY1 > 1.0f) + taperY1 = 2.0f - taperY1; + taperY = 1.0f - taperY1; + } + else + { + taperX = BaseShape.PathTaperX * 0.01f; + if (taperX < 0.0f) + taperX = -taperX; + taperX1 = 1.0f - taperX; + + taperY = BaseShape.PathTaperY * 0.01f; + if (taperY < 0.0f) + taperY = -taperY; + taperY1 = 1.0f - taperY; + + } + + + volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); + + pathBegin = (float)BaseShape.PathBegin * 2.0e-5f; + pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f; + volume *= (pathEnd - pathBegin); + + // this is crude aproximation + profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f; + profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; + volume *= (profileEnd - profileBegin); + + returnMass = Density * BSParam.DensityScaleFactor * volume; + + returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); + // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); + DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}", + LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size); + + return returnMass; + }// end CalculateMass + #endregion Mass Calculation + + // Rebuild the geometry and object. + // This is called when the shape changes so we need to recreate the mesh/hull. + // Called at taint-time!!! + public void CreateGeomAndObject(bool forceRebuild) + { + // Create the correct physical representation for this type of object. + // Updates base.PhysBody and base.PhysShape with the new information. + // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. + PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape) + { + // Called if the current prim body is about to be destroyed. + // Remove all the physical dependencies on the old body. + // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) + // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints. + RemoveDependencies(); + }); + + // Make sure the properties are set on the new object + UpdatePhysicalParameters(); + return; + } + + // Called at taint-time + protected virtual void RemoveDependencies() + { + PhysicalActors.RemoveDependencies(); + } + + #region Extension + public override object Extension(string pFunct, params object[] pParams) + { + DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct); + object ret = null; + switch (pFunct) + { + case ExtendedPhysics.PhysFunctAxisLockLimits: + ret = SetAxisLockLimitsExtension(pParams); + break; + default: + ret = base.Extension(pFunct, pParams); + break; + } + return ret; + } + + private void InitializeAxisActor() + { + EnableActor(LockedAngularAxis != LockedAxisFree || LockedLinearAxis != LockedAxisFree, + LockedAxisActorName, delegate() + { + return new BSActorLockAxis(PhysScene, this, LockedAxisActorName); + }); + + // Update parameters so the new actor's Refresh() action is called at the right time. + PhysScene.TaintedObject(LocalID, "BSPrim.LockAxis", delegate() + { + UpdatePhysicalParameters(); + }); + } + + // Passed an array of an array of parameters, set the axis locking. + // This expects an int (PHYS_AXIS_*) followed by none or two limit floats + // followed by another int and floats, etc. + private object SetAxisLockLimitsExtension(object[] pParams) + { + DetailLog("{0} SetAxisLockLimitsExtension. parmlen={1}", LocalID, pParams.GetLength(0)); + object ret = null; + try + { + if (pParams.GetLength(0) > 1) + { + int index = 2; + while (index < pParams.GetLength(0)) + { + var funct = pParams[index]; + DetailLog("{0} SetAxisLockLimitsExtension. op={1}, index={2}", LocalID, funct, index); + if (funct is Int32 || funct is Int64) + { + switch ((int)funct) + { + // Those that take no parameters + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR: + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X: + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y: + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z: + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR: + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X: + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y: + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z: + case ExtendedPhysics.PHYS_AXIS_UNLOCK: + ApplyAxisLimits((int)funct, 0f, 0f); + index += 1; + break; + // Those that take two parameters (the limits) + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X: + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y: + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z: + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X: + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y: + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z: + ApplyAxisLimits((int)funct, (float)pParams[index + 1], (float)pParams[index + 2]); + index += 3; + break; + default: + m_log.WarnFormat("{0} SetSxisLockLimitsExtension. Unknown op={1}", LogHeader, funct); + index += 1; + break; + } + } + } + InitializeAxisActor(); + ret = (object)index; + } + } + catch (Exception e) + { + m_log.WarnFormat("{0} SetSxisLockLimitsExtension exception in object {1}: {2}", LogHeader, this.Name, e); + ret = null; + } + return ret; // not implemented yet + } + + // Set the locking parameters. + // If an axis is locked, the limits for the axis are set to zero, + // If the axis is being constrained, the high and low value are passed and set. + // When done here, LockedXXXAxis flags are set and LockedXXXAxixLow/High are set to the range. + protected void ApplyAxisLimits(int funct, float low, float high) + { + DetailLog("{0} ApplyAxisLimits. op={1}, low={2}, high={3}", LocalID, funct, low, high); + float linearMax = 23000f; + float angularMax = (float)Math.PI; + + switch (funct) + { + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR: + this.LockedLinearAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis); + this.LockedLinearAxisLow = OMV.Vector3.Zero; + this.LockedLinearAxisHigh = OMV.Vector3.Zero; + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X: + this.LockedLinearAxis.X = LockedAxis; + this.LockedLinearAxisLow.X = 0f; + this.LockedLinearAxisHigh.X = 0f; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X: + this.LockedLinearAxis.X = LockedAxis; + this.LockedLinearAxisLow.X = Util.Clip(low, -linearMax, linearMax); + this.LockedLinearAxisHigh.X = Util.Clip(high, -linearMax, linearMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y: + this.LockedLinearAxis.Y = LockedAxis; + this.LockedLinearAxisLow.Y = 0f; + this.LockedLinearAxisHigh.Y = 0f; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y: + this.LockedLinearAxis.Y = LockedAxis; + this.LockedLinearAxisLow.Y = Util.Clip(low, -linearMax, linearMax); + this.LockedLinearAxisHigh.Y = Util.Clip(high, -linearMax, linearMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z: + this.LockedLinearAxis.Z = LockedAxis; + this.LockedLinearAxisLow.Z = 0f; + this.LockedLinearAxisHigh.Z = 0f; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z: + this.LockedLinearAxis.Z = LockedAxis; + this.LockedLinearAxisLow.Z = Util.Clip(low, -linearMax, linearMax); + this.LockedLinearAxisHigh.Z = Util.Clip(high, -linearMax, linearMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR: + this.LockedAngularAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis); + this.LockedAngularAxisLow = OMV.Vector3.Zero; + this.LockedAngularAxisHigh = OMV.Vector3.Zero; + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X: + this.LockedAngularAxis.X = LockedAxis; + this.LockedAngularAxisLow.X = 0; + this.LockedAngularAxisHigh.X = 0; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X: + this.LockedAngularAxis.X = LockedAxis; + this.LockedAngularAxisLow.X = Util.Clip(low, -angularMax, angularMax); + this.LockedAngularAxisHigh.X = Util.Clip(high, -angularMax, angularMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y: + this.LockedAngularAxis.Y = LockedAxis; + this.LockedAngularAxisLow.Y = 0; + this.LockedAngularAxisHigh.Y = 0; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y: + this.LockedAngularAxis.Y = LockedAxis; + this.LockedAngularAxisLow.Y = Util.Clip(low, -angularMax, angularMax); + this.LockedAngularAxisHigh.Y = Util.Clip(high, -angularMax, angularMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z: + this.LockedAngularAxis.Z = LockedAxis; + this.LockedAngularAxisLow.Z = 0; + this.LockedAngularAxisHigh.Z = 0; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z: + this.LockedAngularAxis.Z = LockedAxis; + this.LockedAngularAxisLow.Z = Util.Clip(low, -angularMax, angularMax); + this.LockedAngularAxisHigh.Z = Util.Clip(high, -angularMax, angularMax); + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR: + this.LockedLinearAxis = LockedAxisFree; + this.LockedLinearAxisLow = new OMV.Vector3(-linearMax, -linearMax, -linearMax); + this.LockedLinearAxisHigh = new OMV.Vector3(linearMax, linearMax, linearMax); + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X: + this.LockedLinearAxis.X = FreeAxis; + this.LockedLinearAxisLow.X = -linearMax; + this.LockedLinearAxisHigh.X = linearMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y: + this.LockedLinearAxis.Y = FreeAxis; + this.LockedLinearAxisLow.Y = -linearMax; + this.LockedLinearAxisHigh.Y = linearMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z: + this.LockedLinearAxis.Z = FreeAxis; + this.LockedLinearAxisLow.Z = -linearMax; + this.LockedLinearAxisHigh.Z = linearMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR: + this.LockedAngularAxis = LockedAxisFree; + this.LockedAngularAxisLow = new OMV.Vector3(-angularMax, -angularMax, -angularMax); + this.LockedAngularAxisHigh = new OMV.Vector3(angularMax, angularMax, angularMax); + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X: + this.LockedAngularAxis.X = FreeAxis; + this.LockedAngularAxisLow.X = -angularMax; + this.LockedAngularAxisHigh.X = angularMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y: + this.LockedAngularAxis.Y = FreeAxis; + this.LockedAngularAxisLow.Y = -angularMax; + this.LockedAngularAxisHigh.Y = angularMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z: + this.LockedAngularAxis.Z = FreeAxis; + this.LockedAngularAxisLow.Z = -angularMax; + this.LockedAngularAxisHigh.Z = angularMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR, 0f, 0f); + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f); + break; + default: + break; + } + return; + } + #endregion // Extension + + // The physics engine says that properties have updated. Update same and inform + // the world that things have changed. + // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims. + // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position. + public override void UpdateProperties(EntityProperties entprop) + { + // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. + TriggerPreUpdatePropertyAction(ref entprop); + + // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG + + // Assign directly to the local variables so the normal set actions do not happen + RawPosition = entprop.Position; + RawOrientation = entprop.Rotation; + // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be + // very sensitive to velocity changes. + if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold)) + RawVelocity = entprop.Velocity; + _acceleration = entprop.Acceleration; + _rotationalVelocity = entprop.RotationalVelocity; + + // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG + + // The sanity check can change the velocity and/or position. + if (PositionSanityCheck(true /* inTaintTime */ )) + { + entprop.Position = RawPosition; + entprop.Velocity = RawVelocity; + entprop.RotationalVelocity = _rotationalVelocity; + entprop.Acceleration = _acceleration; + } + + OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG + DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction); + + // remember the current and last set values + LastEntityProperties = CurrentEntityProperties; + CurrentEntityProperties = entprop; + + PhysScene.PostUpdate(this); + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs new file mode 100755 index 0000000..d8ed56b --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs @@ -0,0 +1,182 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public class BSPrimDisplaced : BSPrim +{ + // The purpose of this subclass is to do any mapping between what the simulator thinks + // the prim position and orientation is and what the physical position/orientation. + // This difference happens because Bullet assumes the center-of-mass is the <0,0,0> + // of the prim/linkset. The simulator, on the other hand, tracks the location of + // the prim/linkset by the location of the root prim. So, if center-of-mass is anywhere + // but the origin of the root prim, the physical origin is displaced from the simulator origin. + // + // This routine works by capturing ForcePosition and + // adjusting the simulator values (being set) into the physical values. + // The conversion is also done in the opposite direction (physical origin -> simulator origin). + // + // The updateParameter call is also captured and the values from the physics engine + // are converted into simulator origin values before being passed to the base + // class. + + // PositionDisplacement is the vehicle relative distance from the root prim position to the center-of-mass. + public virtual OMV.Vector3 PositionDisplacement { get; set; } + + public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, + OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) + : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) + { + ClearDisplacement(); + } + + // Clears any center-of-mass displacement introduced by linksets, etc. + // Does not clear the displacement set by the user. + public void ClearDisplacement() + { + if (UserSetCenterOfMassDisplacement.HasValue) + PositionDisplacement = (OMV.Vector3)UserSetCenterOfMassDisplacement; + else + PositionDisplacement = OMV.Vector3.Zero; + } + + // Set this sets and computes the displacement from the passed prim to the center-of-mass. + // A user set value for center-of-mass overrides whatever might be passed in here. + // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). + // Returns the relative offset from the root position to the center-of-mass. + // Called at taint time. + public virtual Vector3 SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement) + { + PhysScene.AssertInTaintTime("BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement"); + Vector3 comDisp; + if (UserSetCenterOfMassDisplacement.HasValue) + comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement; + else + comDisp = centerOfMassDisplacement; + + // Eliminate any jitter caused be very slight differences in masses and positions + if (comDisp.ApproxEquals(Vector3.Zero, 0.01f) ) + comDisp = Vector3.Zero; + + DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}", + LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp); + if ( !comDisp.ApproxEquals(PositionDisplacement, 0.01f) ) + { + // Displacement setting is changing. + // The relationship between the physical object and simulated object must be aligned. + PositionDisplacement = comDisp; + this.ForcePosition = RawPosition; + } + + return PositionDisplacement; + } + + // 'ForcePosition' is the one way to set the physical position of the body in the physics engine. + // Displace the simulator idea of position (center of root prim) to the physical position. + public override Vector3 ForcePosition + { + get { + OMV.Vector3 physPosition = PhysScene.PE.GetPosition(PhysBody); + if (PositionDisplacement != OMV.Vector3.Zero) + { + // If there is some displacement, return the physical position (center-of-mass) + // location minus the displacement to give the center of the root prim. + OMV.Vector3 displacement = PositionDisplacement * ForceOrientation; + DetailLog("{0},BSPrimDisplaced.ForcePosition,get,physPos={1},disp={2},simPos={3}", + LocalID, physPosition, displacement, physPosition - displacement); + physPosition -= displacement; + } + RawPosition = physPosition; + return physPosition; + } + set + { + if (PositionDisplacement != OMV.Vector3.Zero) + { + // This value is the simulator's idea of where the prim is: the center of the root prim + RawPosition = value; + + // Move the passed root prim postion to the center-of-mass position and set in the physics engine. + OMV.Vector3 displacement = PositionDisplacement * RawOrientation; + OMV.Vector3 displacedPos = RawPosition + displacement; + DetailLog("{0},BSPrimDisplaced.ForcePosition,set,simPos={1},disp={2},physPos={3}", + LocalID, RawPosition, displacement, displacedPos); + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.SetTranslation(PhysBody, displacedPos, RawOrientation); + ActivateIfPhysical(false); + } + } + else + { + base.ForcePosition = value; + } + } + } + + // These are also overridden by BSPrimLinkable if the prim can be part of a linkset + public override OMV.Vector3 CenterOfMass + { + get { return RawPosition; } + } + + public override OMV.Vector3 GeometricCenter + { + get { return RawPosition; } + } + + public override void UpdateProperties(EntityProperties entprop) + { + // Undo any center-of-mass displacement that might have been done. + if (PositionDisplacement != OMV.Vector3.Zero) + { + // The origional shape was offset from 'zero' by PositionDisplacement. + // These physical location must be back converted to be centered around the displaced + // root shape. + + // Move the returned center-of-mass location to the root prim location. + OMV.Vector3 displacement = PositionDisplacement * entprop.Rotation; + OMV.Vector3 displacedPos = entprop.Position - displacement; + DetailLog("{0},BSPrimDisplaced.UpdateProperties,physPos={1},disp={2},simPos={3}", + LocalID, entprop.Position, displacement, displacedPos); + entprop.Position = displacedPos; + } + + base.UpdateProperties(entprop); + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs new file mode 100755 index 0000000..55b5da0 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs @@ -0,0 +1,349 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenSim.Framework; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public class BSPrimLinkable : BSPrimDisplaced +{ + // The purpose of this subclass is to add linkset functionality to the prim. This overrides + // operations necessary for keeping the linkset created and, additionally, this + // calls the linkset implementation for its creation and management. + +#pragma warning disable 414 + private static readonly string LogHeader = "[BULLETS PRIMLINKABLE]"; +#pragma warning restore 414 + + // This adds the overrides for link() and delink() so the prim is linkable. + + public BSLinkset Linkset { get; set; } + // The index of this child prim. + public int LinksetChildIndex { get; set; } + + public BSLinkset.LinksetImplementation LinksetType { get; set; } + + public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, + OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) + : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) + { + // Default linkset implementation for this prim + LinksetType = (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation; + + Linkset = BSLinkset.Factory(PhysScene, this); + + Linkset.Refresh(this); + } + + public override void Destroy() + { + Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime */); + base.Destroy(); + } + + public override void link(OpenSim.Region.PhysicsModules.SharedBase.PhysicsActor obj) + { + BSPrimLinkable parent = obj as BSPrimLinkable; + if (parent != null) + { + BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG + int childrenBefore = Linkset.NumberOfChildren; // DEBUG + + Linkset = parent.Linkset.AddMeToLinkset(this); + + DetailLog("{0},BSPrimLinkable.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", + LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); + } + return; + } + + public override void delink() + { + // TODO: decide if this parent checking needs to happen at taint time + // Race condition here: if link() and delink() in same simulation tick, the delink will not happen + + BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG + int childrenBefore = Linkset.NumberOfChildren; // DEBUG + + Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime*/); + + DetailLog("{0},BSPrimLinkable.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", + LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); + return; + } + + // When simulator changes position, this might be moving a child of the linkset. + public override OMV.Vector3 Position + { + get { return base.Position; } + set + { + base.Position = value; + PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setPosition", delegate() + { + Linkset.UpdateProperties(UpdatedProperties.Position, this); + }); + } + } + + // When simulator changes orientation, this might be moving a child of the linkset. + public override OMV.Quaternion Orientation + { + get { return base.Orientation; } + set + { + base.Orientation = value; + PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setOrientation", delegate() + { + Linkset.UpdateProperties(UpdatedProperties.Orientation, this); + }); + } + } + + public override float TotalMass + { + get { return Linkset.LinksetMass; } + } + + public override OMV.Vector3 CenterOfMass + { + get { return Linkset.CenterOfMass; } + } + + public override OMV.Vector3 GeometricCenter + { + get { return Linkset.GeometricCenter; } + } + + // Refresh the linkset structure and parameters when the prim's physical parameters are changed. + public override void UpdatePhysicalParameters() + { + base.UpdatePhysicalParameters(); + // Recompute any linkset parameters. + // When going from non-physical to physical, this re-enables the constraints that + // had been automatically disabled when the mass was set to zero. + // For compound based linksets, this enables and disables interactions of the children. + if (Linkset != null) // null can happen during initialization + Linkset.Refresh(this); + } + + // When the prim is made dynamic or static, the linkset needs to change. + protected override void MakeDynamic(bool makeStatic) + { + base.MakeDynamic(makeStatic); + if (Linkset != null) // null can happen during initialization + { + if (makeStatic) + Linkset.MakeStatic(this); + else + Linkset.MakeDynamic(this); + } + } + + // Body is being taken apart. Remove physical dependencies and schedule a rebuild. + protected override void RemoveDependencies() + { + Linkset.RemoveDependencies(this); + base.RemoveDependencies(); + } + + // Called after a simulation step for the changes in physical object properties. + // Do any filtering/modification needed for linksets. + public override void UpdateProperties(EntityProperties entprop) + { + if (Linkset.IsRoot(this) || Linkset.ShouldReportPropertyUpdates(this)) + { + // Properties are only updated for the roots of a linkset. + // TODO: this will have to change when linksets are articulated. + base.UpdateProperties(entprop); + } + /* + else + { + // For debugging, report the movement of children + DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", + LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, + entprop.Acceleration, entprop.RotationalVelocity); + } + */ + // The linkset might like to know about changing locations + Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); + } + + // Called after a simulation step to post a collision with this object. + // This returns 'true' if the collision has been queued and the SendCollisions call must + // be made at the end of the simulation step. + public override bool Collide(uint collidingWith, BSPhysObject collidee, + OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) + { + bool ret = false; + // Ask the linkset if it wants to handle the collision + if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth)) + { + // The linkset didn't handle it so pass the collision through normal processing + ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); + } + return ret; + } + + // A linkset reports any collision on any part of the linkset. + public long SomeCollisionSimulationStep = 0; + public override bool HasSomeCollision + { + get + { + return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding; + } + set + { + if (value) + SomeCollisionSimulationStep = PhysScene.SimulationStep; + else + SomeCollisionSimulationStep = 0; + + base.HasSomeCollision = value; + } + } + + // Convert the existing linkset of this prim into a new type. + public bool ConvertLinkset(BSLinkset.LinksetImplementation newType) + { + bool ret = false; + if (LinksetType != newType) + { + DetailLog("{0},BSPrimLinkable.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType); + + // Set the implementation type first so the call to BSLinkset.Factory gets the new type. + this.LinksetType = newType; + + BSLinkset oldLinkset = this.Linkset; + BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this); + + this.Linkset = newLinkset; + + // Pick up any physical dependencies this linkset might have in the physics engine. + oldLinkset.RemoveDependencies(this); + + // Create a list of the children (mainly because can't interate through a list that's changing) + List children = new List(); + oldLinkset.ForEachMember((child) => + { + if (!oldLinkset.IsRoot(child)) + children.Add(child); + return false; // 'false' says to continue to next member + }); + + // Remove the children from the old linkset and add to the new (will be a new instance from the factory) + foreach (BSPrimLinkable child in children) + { + oldLinkset.RemoveMeFromLinkset(child, true /*inTaintTime*/); + } + foreach (BSPrimLinkable child in children) + { + newLinkset.AddMeToLinkset(child); + child.Linkset = newLinkset; + } + + // Force the shape and linkset to get reconstructed + newLinkset.Refresh(this); + this.ForceBodyShapeRebuild(true /* inTaintTime */); + } + return ret; + } + + #region Extension + public override object Extension(string pFunct, params object[] pParams) + { + DetailLog("{0} BSPrimLinkable.Extension,op={1},nParam={2}", LocalID, pFunct, pParams.Length); + object ret = null; + switch (pFunct) + { + // physGetLinksetType(); + // pParams = [ BSPhysObject root, null ] + case ExtendedPhysics.PhysFunctGetLinksetType: + { + ret = (object)LinksetType; + DetailLog("{0},BSPrimLinkable.Extension.physGetLinksetType,type={1}", LocalID, ret); + break; + } + // physSetLinksetType(type); + // pParams = [ BSPhysObject root, null, integer type ] + case ExtendedPhysics.PhysFunctSetLinksetType: + { + if (pParams.Length > 2) + { + BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[2]; + if (Linkset.IsRoot(this)) + { + PhysScene.TaintedObject(LocalID, "BSPrim.PhysFunctSetLinksetType", delegate() + { + // Cause the linkset type to change + DetailLog("{0},BSPrimLinkable.Extension.physSetLinksetType, oldType={1},newType={2}", + LocalID, Linkset.LinksetImpl, linksetType); + ConvertLinkset(linksetType); + }); + } + ret = (object)(int)linksetType; + } + break; + } + // physChangeLinkType(linknum, typeCode); + // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ] + case ExtendedPhysics.PhysFunctChangeLinkType: + { + ret = Linkset.Extension(pFunct, pParams); + break; + } + // physGetLinkType(linknum); + // pParams = [ BSPhysObject root, BSPhysObject child ] + case ExtendedPhysics.PhysFunctGetLinkType: + { + ret = Linkset.Extension(pFunct, pParams); + break; + } + // physChangeLinkParams(linknum, [code, value, code, value, ...]); + // pParams = [ BSPhysObject root, BSPhysObject child, object[] [ string op, object opParam, string op, object opParam, ... ] ] + case ExtendedPhysics.PhysFunctChangeLinkParams: + { + ret = Linkset.Extension(pFunct, pParams); + break; + } + default: + ret = base.Extension(pFunct, pParams); + break; + } + return ret; + } + #endregion // Extension +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs new file mode 100644 index 0000000..452ce55 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs @@ -0,0 +1,1333 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using OpenSim.Framework; +using OpenSim.Framework.Monitoring; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.PhysicsModules.SharedBase; +using Nini.Config; +using log4net; +using OpenMetaverse; +using Mono.Addins; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BulletSPhysicsScene")] + public sealed class BSScene : PhysicsScene, IPhysicsParameters, INonSharedRegionModule + { + internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + internal static readonly string LogHeader = "[BULLETS SCENE]"; + + private bool m_Enabled = false; + private IConfigSource m_Config; + + // The name of the region we're working for. + public string RegionName { get; private set; } + + public string BulletSimVersion = "?"; + + // The handle to the underlying managed or unmanaged version of Bullet being used. + public string BulletEngineName { get; private set; } + public BSAPITemplate PE; + + // If the physics engine is running on a separate thread + public Thread m_physicsThread; + + public Dictionary PhysObjects; + public BSShapeCollection Shapes; + + // Keeping track of the objects with collisions so we can report begin and end of a collision + public HashSet ObjectsWithCollisions = new HashSet(); + public HashSet ObjectsWithNoMoreCollisions = new HashSet(); + + // All the collision processing is protected with this lock object + public Object CollisionLock = new Object(); + + // Properties are updated here + public Object UpdateLock = new Object(); + public HashSet ObjectsWithUpdates = new HashSet(); + + // Keep track of all the avatars so we can send them a collision event + // every tick so OpenSim will update its animation. + private HashSet AvatarsInScene = new HashSet(); + private Object AvatarsInSceneLock = new Object(); + + // let my minuions use my logger + public ILog Logger { get { return m_log; } } + + public IMesher mesher; + public uint WorldID { get; private set; } + public BulletWorld World { get; private set; } + + // All the constraints that have been allocated in this instance. + public BSConstraintCollection Constraints { get; private set; } + + // Simulation parameters + //internal float m_physicsStepTime; // if running independently, the interval simulated by default + + internal int m_maxSubSteps; + internal float m_fixedTimeStep; + + internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc. + + internal long m_simulationStep = 0; // The current simulation step. + public long SimulationStep { get { return m_simulationStep; } } + // A number to use for SimulationStep that is probably not any step value + // Used by the collision code (which remembers the step when a collision happens) to remember not any simulation step. + public static long NotASimulationStep = -1234; + + internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate() + + internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to + + // Physical objects can register for prestep or poststep events + public delegate void PreStepAction(float timeStep); + public delegate void PostStepAction(float timeStep); + public event PreStepAction BeforeStep; + public event PostStepAction AfterStep; + + // A value of the time 'now' so all the collision and update routines do not have to get their own + // Set to 'now' just before all the prims and actors are called for collisions and updates + public int SimulationNowTime { get; private set; } + + // True if initialized and ready to do simulation steps + private bool m_initialized = false; + + // Flag which is true when processing taints. + // Not guaranteed to be correct all the time (don't depend on this) but good for debugging. + public bool InTaintTime { get; private set; } + + // Pinned memory used to pass step information between managed and unmanaged + internal int m_maxCollisionsPerFrame; + internal CollisionDesc[] m_collisionArray; + + internal int m_maxUpdatesPerFrame; + internal EntityProperties[] m_updateArray; + + /// + /// Used to control physics simulation timing if Bullet is running on its own thread. + /// + private ManualResetEvent m_updateWaitEvent; + + public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero + public const uint GROUNDPLANE_ID = 1; + public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here + + public float SimpleWaterLevel { get; set; } + public BSTerrainManager TerrainManager { get; private set; } + + public ConfigurationParameters Params + { + get { return UnmanagedParams[0]; } + } + public Vector3 DefaultGravity + { + get { return new Vector3(0f, 0f, Params.gravity); } + } + // Just the Z value of the gravity + public float DefaultGravityZ + { + get { return Params.gravity; } + } + + // When functions in the unmanaged code must be called, it is only + // done at a known time just before the simulation step. The taint + // system saves all these function calls and executes them in + // order before the simulation. + public delegate void TaintCallback(); + private struct TaintCallbackEntry + { + public String originator; + public String ident; + public TaintCallback callback; + public TaintCallbackEntry(string pIdent, TaintCallback pCallBack) + { + originator = BSScene.DetailLogZero; + ident = pIdent; + callback = pCallBack; + } + public TaintCallbackEntry(string pOrigin, string pIdent, TaintCallback pCallBack) + { + originator = pOrigin; + ident = pIdent; + callback = pCallBack; + } + } + private Object _taintLock = new Object(); // lock for using the next object + private List _taintOperations; + private Dictionary _postTaintOperations; + private List _postStepOperations; + + // A pointer to an instance if this structure is passed to the C++ code + // Used to pass basic configuration values to the unmanaged code. + internal ConfigurationParameters[] UnmanagedParams; + + // Sometimes you just have to log everything. + public LogWriter PhysicsLogging; + private bool m_physicsLoggingEnabled; + private string m_physicsLoggingDir; + private string m_physicsLoggingPrefix; + private int m_physicsLoggingFileMinutes; + private bool m_physicsLoggingDoFlush; + private bool m_physicsPhysicalDumpEnabled; + public int PhysicsMetricDumpFrames { get; set; } + // 'true' of the vehicle code is to log lots of details + public bool VehicleLoggingEnabled { get; private set; } + public bool VehiclePhysicalLoggingEnabled { get; private set; } + + #region INonSharedRegionModule + public string Name + { + get { return "BulletSim"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Initialise(IConfigSource source) + { + // TODO: Move this out of Startup + IConfig config = source.Configs["Startup"]; + if (config != null) + { + string physics = config.GetString("physics", string.Empty); + if (physics == Name) + { + m_Enabled = true; + m_Config = source; + } + } + + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + EngineType = Name; + RegionName = scene.RegionInfo.RegionName; + PhysicsSceneName = EngineType + "/" + RegionName; + + scene.RegisterModuleInterface(this); + Vector3 extent = new Vector3(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, scene.RegionInfo.RegionSizeZ); + Initialise(m_Config, extent); + + base.Initialise(scene.PhysicsRequestAsset, + (scene.Heightmap != null ? scene.Heightmap.GetFloatsSerialised() : new float[scene.RegionInfo.RegionSizeX * scene.RegionInfo.RegionSizeY]), + (float)scene.RegionInfo.RegionSettings.WaterHeight); + + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + + mesher = scene.RequestModuleInterface(); + if (mesher == null) + m_log.WarnFormat("{0} No mesher. Things will not work well.", LogHeader); + + scene.PhysicsEnabled = true; + } + #endregion + + #region Initialization + + private void Initialise(IConfigSource config, Vector3 regionExtent) + { + _taintOperations = new List(); + _postTaintOperations = new Dictionary(); + _postStepOperations = new List(); + PhysObjects = new Dictionary(); + Shapes = new BSShapeCollection(this); + + m_simulatedTime = 0f; + LastTimeStep = 0.1f; + + // Allocate pinned memory to pass parameters. + UnmanagedParams = new ConfigurationParameters[1]; + + // Set default values for physics parameters plus any overrides from the ini file + GetInitialParameterValues(config); + + // Force some parameters to values depending on other configurations + // Only use heightmap terrain implementation if terrain larger than legacy size + if ((uint)regionExtent.X > Constants.RegionSize || (uint)regionExtent.Y > Constants.RegionSize) + { + m_log.WarnFormat("{0} Forcing terrain implementation to heightmap for large region", LogHeader); + BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap; + } + + // Get the connection to the physics engine (could be native or one of many DLLs) + PE = SelectUnderlyingBulletEngine(BulletEngineName); + + // Enable very detailed logging. + // By creating an empty logger when not logging, the log message invocation code + // can be left in and every call doesn't have to check for null. + if (m_physicsLoggingEnabled) + { + PhysicsLogging = new LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes, m_physicsLoggingDoFlush); + PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output its own error messages. + } + else + { + PhysicsLogging = new LogWriter(); + } + + // Allocate memory for returning of the updates and collisions from the physics engine + m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; + m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; + + // The bounding box for the simulated world. The origin is 0,0,0 unless we're + // a child in a mega-region. + // Bullet actually doesn't care about the extents of the simulated + // area. It tracks active objects no matter where they are. + Vector3 worldExtent = regionExtent; + + World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray); + + Constraints = new BSConstraintCollection(World); + + TerrainManager = new BSTerrainManager(this, worldExtent); + TerrainManager.CreateInitialGroundPlaneAndTerrain(); + + // Put some informational messages into the log file. + m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); + + InTaintTime = false; + m_initialized = true; + + // If the physics engine runs on its own thread, start same. + if (BSParam.UseSeparatePhysicsThread) + { + // The physics simulation should happen independently of the heartbeat loop + m_physicsThread + = WorkManager.StartThread( + BulletSPluginPhysicsThread, + string.Format("{0} ({1})", BulletEngineName, RegionName), + ThreadPriority.Normal, + true, + true); + } + } + + // All default parameter values are set here. There should be no values set in the + // variable definitions. + private void GetInitialParameterValues(IConfigSource config) + { + ConfigurationParameters parms = new ConfigurationParameters(); + UnmanagedParams[0] = parms; + + BSParam.SetParameterDefaultValues(this); + + if (config != null) + { + // If there are specifications in the ini file, use those values + IConfig pConfig = config.Configs["BulletSim"]; + if (pConfig != null) + { + BSParam.SetParameterConfigurationValues(this, pConfig); + + // There are two Bullet implementations to choose from + BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged"); + + // Very detailed logging for physics debugging + // TODO: the boolean values can be moved to the normal parameter processing. + m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); + m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); + m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); + m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); + m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false); + m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false); + // Very detailed logging for vehicle debugging + VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); + VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false); + + // Do any replacements in the parameters + m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); + } + else + { + // Nothing in the configuration INI file so assume unmanaged and other defaults. + BulletEngineName = "BulletUnmanaged"; + m_physicsLoggingEnabled = false; + VehicleLoggingEnabled = false; + } + + // The material characteristics. + BSMaterials.InitializeFromDefaults(Params); + if (pConfig != null) + { + // Let the user add new and interesting material property values. + BSMaterials.InitializefromParameters(pConfig); + } + } + } + + // A helper function that handles a true/false parameter and returns the proper float number encoding + float ParamBoolean(IConfig config, string parmName, float deflt) + { + float ret = deflt; + if (config.Contains(parmName)) + { + ret = ConfigurationParameters.numericFalse; + if (config.GetBoolean(parmName, false)) + { + ret = ConfigurationParameters.numericTrue; + } + } + return ret; + } + + // Select the connection to the actual Bullet implementation. + // The main engine selection is the engineName up to the first hypen. + // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name + // is passed to the engine to do its special selection, etc. + private BSAPITemplate SelectUnderlyingBulletEngine(string engineName) + { + // For the moment, do a simple switch statement. + // Someday do fancyness with looking up the interfaces in the assembly. + BSAPITemplate ret = null; + + string selectionName = engineName.ToLower(); + int hyphenIndex = engineName.IndexOf("-"); + if (hyphenIndex > 0) + selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1); + + switch (selectionName) + { + case "bullet": + case "bulletunmanaged": + ret = new BSAPIUnman(engineName, this); + break; + case "bulletxna": + ret = new BSAPIXNA(engineName, this); + // Disable some features that are not implemented in BulletXNA + m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader); + m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader); + BSParam.ShouldUseBulletHACD = false; + m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader); + BSParam.ShouldUseSingleConvexHullForPrims = false; + m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader); + BSParam.ShouldUseGImpactShapeForPrims = false; + m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader); + BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap; + break; + } + + if (ret == null) + { + m_log.ErrorFormat("{0} COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader); + } + else + { + m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); + } + + return ret; + } + + public override void Dispose() + { + // m_log.DebugFormat("{0}: Dispose()", LogHeader); + + // make sure no stepping happens while we're deleting stuff + m_initialized = false; + + lock (PhysObjects) + { + foreach (KeyValuePair kvp in PhysObjects) + { + kvp.Value.Destroy(); + } + PhysObjects.Clear(); + } + + // Now that the prims are all cleaned up, there should be no constraints left + if (Constraints != null) + { + Constraints.Dispose(); + Constraints = null; + } + + if (Shapes != null) + { + Shapes.Dispose(); + Shapes = null; + } + + if (TerrainManager != null) + { + TerrainManager.ReleaseGroundPlaneAndTerrain(); + TerrainManager.Dispose(); + TerrainManager = null; + } + + // Anything left in the unmanaged code should be cleaned out + PE.Shutdown(World); + + // Not logging any more + PhysicsLogging.Close(); + } + #endregion // Construction and Initialization + + #region Prim and Avatar addition and removal + + public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) + { + m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); + return null; + } + + public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) + { + // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName); + + if (!m_initialized) return null; + + BSCharacter actor = new BSCharacter(localID, avName, this, position, velocity, size, isFlying); + lock (PhysObjects) + PhysObjects.Add(localID, actor); + + // TODO: Remove kludge someday. + // We must generate a collision for avatars whether they collide or not. + // This is required by OpenSim to update avatar animations, etc. + lock (AvatarsInSceneLock) + AvatarsInScene.Add(actor); + + return actor; + } + + public override void RemoveAvatar(PhysicsActor actor) + { + // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); + + if (!m_initialized) return; + + BSCharacter bsactor = actor as BSCharacter; + if (bsactor != null) + { + try + { + lock (PhysObjects) + PhysObjects.Remove(bsactor.LocalID); + // Remove kludge someday + lock (AvatarsInSceneLock) + AvatarsInScene.Remove(bsactor); + } + catch (Exception e) + { + m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); + } + bsactor.Destroy(); + // bsactor.dispose(); + } + else + { + m_log.ErrorFormat("{0}: Requested to remove avatar that is not a BSCharacter. ID={1}, type={2}", + LogHeader, actor.LocalID, actor.GetType().Name); + } + } + + public override void RemovePrim(PhysicsActor prim) + { + if (!m_initialized) return; + + BSPhysObject bsprim = prim as BSPhysObject; + if (bsprim != null) + { + DetailLog("{0},RemovePrim,call", bsprim.LocalID); + // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); + try + { + lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID); + } + catch (Exception e) + { + m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); + } + bsprim.Destroy(); + // bsprim.dispose(); + } + else + { + m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader); + } + } + + public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, + Vector3 size, Quaternion rotation, bool isPhysical, uint localID) + { + // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName); + + if (!m_initialized) return null; + + // DetailLog("{0},BSScene.AddPrimShape,call", localID); + + BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical); + lock (PhysObjects) PhysObjects.Add(localID, prim); + return prim; + } + + // This is a call from the simulator saying that some physical property has been updated. + // The BulletSim driver senses the changing of relevant properties so this taint + // information call is not needed. + public override void AddPhysicsActorTaint(PhysicsActor prim) { } + + #endregion // Prim and Avatar addition and removal + + #region Simulation + + // Call from the simulator to send physics information to the simulator objects. + // This pushes all the collision and property update events into the objects in + // the simulator and, since it is on the heartbeat thread, there is an implicit + // locking of those data structures from other heartbeat events. + // If the physics engine is running on a separate thread, the update information + // will be in the ObjectsWithCollions and ObjectsWithUpdates structures. + public override float Simulate(float timeStep) + { + if (!BSParam.UseSeparatePhysicsThread) + { + DoPhysicsStep(timeStep); + } + return SendUpdatesToSimulator(timeStep); + } + + // Call the physics engine to do one 'timeStep' and collect collisions and updates + // into ObjectsWithCollisions and ObjectsWithUpdates data structures. + private void DoPhysicsStep(float timeStep) + { + // prevent simulation until we've been initialized + if (!m_initialized) return; + + LastTimeStep = timeStep; + + int updatedEntityCount = 0; + int collidersCount = 0; + + int beforeTime = Util.EnvironmentTickCount(); + int simTime = 0; + + int numTaints = _taintOperations.Count; + InTaintTime = true; // Only used for debugging so locking is not necessary. + + // update the prim states while we know the physics engine is not busy + ProcessTaints(); + + // Some of the physical objects requre individual, pre-step calls + // (vehicles and avatar movement, in particular) + TriggerPreStepEvent(timeStep); + + // the prestep actions might have added taints + numTaints += _taintOperations.Count; + ProcessTaints(); + + InTaintTime = false; // Only used for debugging so locking is not necessary. + + // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. + // Only enable this in a limited test world with few objects. + if (m_physicsPhysicalDumpEnabled) + PE.DumpAllInfo(World); + + // step the physical world one interval + m_simulationStep++; + int numSubSteps = 0; + try + { + numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); + + } + catch (Exception e) + { + m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}", + LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e); + DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}", + DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); + updatedEntityCount = 0; + collidersCount = 0; + } + + // Make the physics engine dump useful statistics periodically + if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) + PE.DumpPhysicsStatistics(World); + + // Get a value for 'now' so all the collision and update routines don't have to get their own. + SimulationNowTime = Util.EnvironmentTickCount(); + + // Send collision information to the colliding objects. The objects decide if the collision + // is 'real' (like linksets don't collide with themselves) and the individual objects + // know if the simulator has subscribed to collisions. + lock (CollisionLock) + { + if (collidersCount > 0) + { + lock (PhysObjects) + { + for (int ii = 0; ii < collidersCount; ii++) + { + uint cA = m_collisionArray[ii].aID; + uint cB = m_collisionArray[ii].bID; + Vector3 point = m_collisionArray[ii].point; + Vector3 normal = m_collisionArray[ii].normal; + float penetration = m_collisionArray[ii].penetration; + SendCollision(cA, cB, point, normal, penetration); + SendCollision(cB, cA, point, -normal, penetration); + } + } + } + } + + // If any of the objects had updated properties, tell the managed objects about the update + // and remember that there was a change so it will be passed to the simulator. + lock (UpdateLock) + { + if (updatedEntityCount > 0) + { + lock (PhysObjects) + { + for (int ii = 0; ii < updatedEntityCount; ii++) + { + EntityProperties entprop = m_updateArray[ii]; + BSPhysObject pobj; + if (PhysObjects.TryGetValue(entprop.ID, out pobj)) + { + if (pobj.IsInitialized) + pobj.UpdateProperties(entprop); + } + } + } + } + } + + // Some actors want to know when the simulation step is complete. + TriggerPostStepEvent(timeStep); + + simTime = Util.EnvironmentTickCountSubtract(beforeTime); + if (PhysicsLogging.Enabled) + { + DetailLog("{0},DoPhysicsStep,complete,frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", + DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, + updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); + } + + // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. + // Only enable this in a limited test world with few objects. + if (m_physicsPhysicalDumpEnabled) + PE.DumpAllInfo(World); + + // The physics engine returns the number of milliseconds it simulated this call. + // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. + // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). + m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; + } + + // Called by a BSPhysObject to note that it has changed properties and this information + // should be passed up to the simulator at the proper time. + // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so + // this is is under UpdateLock. + public void PostUpdate(BSPhysObject updatee) + { + lock (UpdateLock) + { + ObjectsWithUpdates.Add(updatee); + } + } + + // The simulator thinks it is physics time so return all the collisions and position + // updates that were collected in actual physics simulation. + private float SendUpdatesToSimulator(float timeStep) + { + if (!m_initialized) return 5.0f; + + DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}", + BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime); + // Push the collisions into the simulator. + lock (CollisionLock) + { + if (ObjectsWithCollisions.Count > 0) + { + foreach (BSPhysObject bsp in ObjectsWithCollisions) + if (!bsp.SendCollisions()) + { + // If the object is done colliding, see that it's removed from the colliding list + ObjectsWithNoMoreCollisions.Add(bsp); + } + } + + // This is a kludge to get avatar movement updates. + // The simulator expects collisions for avatars even if there are have been no collisions. + // The event updates avatar animations and stuff. + // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. + // Note that we get a copy of the list to search because SendCollision() can take a while. + HashSet tempAvatarsInScene; + lock (AvatarsInSceneLock) + { + tempAvatarsInScene = new HashSet(AvatarsInScene); + } + foreach (BSPhysObject actor in tempAvatarsInScene) + { + if (!ObjectsWithCollisions.Contains(actor)) // don't call avatars twice + actor.SendCollisions(); + } + tempAvatarsInScene = null; + + // Objects that are done colliding are removed from the ObjectsWithCollisions list. + // Not done above because it is inside an iteration of ObjectWithCollisions. + // This complex collision processing is required to create an empty collision + // event call after all real collisions have happened on an object. This allows + // the simulator to generate the 'collision end' event. + if (ObjectsWithNoMoreCollisions.Count > 0) + { + foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) + ObjectsWithCollisions.Remove(po); + ObjectsWithNoMoreCollisions.Clear(); + } + } + + // Call the simulator for each object that has physics property updates. + HashSet updatedObjects = null; + lock (UpdateLock) + { + if (ObjectsWithUpdates.Count > 0) + { + updatedObjects = ObjectsWithUpdates; + ObjectsWithUpdates = new HashSet(); + } + } + if (updatedObjects != null) + { + foreach (BSPhysObject obj in updatedObjects) + { + obj.RequestPhysicsterseUpdate(); + } + updatedObjects.Clear(); + } + + // Return the framerate simulated to give the above returned results. + // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock). + float simTime = m_simulatedTime; + m_simulatedTime = 0f; + return simTime; + } + + // Something has collided + private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration) + { + if (localID <= TerrainManager.HighestTerrainID) + { + return; // don't send collisions to the terrain + } + + BSPhysObject collider; + // NOTE that PhysObjects was locked before the call to SendCollision(). + if (!PhysObjects.TryGetValue(localID, out collider)) + { + // If the object that is colliding cannot be found, just ignore the collision. + DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith); + return; + } + + // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called. + BSPhysObject collidee = null; + PhysObjects.TryGetValue(collidingWith, out collidee); + + // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); + + if (collider.IsInitialized) + { + if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) + { + // If a collision was 'good', remember to send it to the simulator + lock (CollisionLock) + { + ObjectsWithCollisions.Add(collider); + } + } + } + + return; + } + + public void BulletSPluginPhysicsThread() + { + Thread.CurrentThread.Priority = ThreadPriority.Highest; + m_updateWaitEvent = new ManualResetEvent(false); + + while (m_initialized) + { + int beginSimulationRealtimeMS = Util.EnvironmentTickCount(); + + if (BSParam.Active) + DoPhysicsStep(BSParam.PhysicsTimeStep); + + int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS); + int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS; + + if (simulationTimeVsRealtimeDifferenceMS > 0) + { + // The simulation of the time interval took less than realtime. + // Do a wait for the rest of realtime. + m_updateWaitEvent.WaitOne(simulationTimeVsRealtimeDifferenceMS); + //Thread.Sleep(simulationTimeVsRealtimeDifferenceMS); + } + else + { + // The simulation took longer than realtime. + // Do some scaling of simulation time. + // TODO. + DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); + } + + Watchdog.UpdateThread(); + } + + Watchdog.RemoveThread(); + } + + #endregion // Simulation + + public override void GetResults() { } + + #region Terrain + + public override void SetTerrain(float[] heightMap) { + TerrainManager.SetTerrain(heightMap); + } + + public override void SetWaterLevel(float baseheight) + { + SimpleWaterLevel = baseheight; + } + + public override void DeleteTerrain() + { + // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); + } + + // Although no one seems to check this, I do support combining. + public override bool SupportsCombining() + { + return TerrainManager.SupportsCombining(); + } + // This call says I am a child to region zero in a mega-region. 'pScene' is that + // of region zero, 'offset' is my offset from regions zero's origin, and + // 'extents' is the largest XY that is handled in my region. + public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) + { + TerrainManager.Combine(pScene, offset, extents); + } + + // Unhook all the combining that I know about. + public override void UnCombine(PhysicsScene pScene) + { + TerrainManager.UnCombine(pScene); + } + + #endregion // Terrain + + public override Dictionary GetTopColliders() + { + Dictionary topColliders; + + lock (PhysObjects) + { + foreach (KeyValuePair kvp in PhysObjects) + { + kvp.Value.ComputeCollisionScore(); + } + + List orderedPrims = new List(PhysObjects.Values); + orderedPrims.OrderByDescending(p => p.CollisionScore); + topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore); + } + + return topColliders; + } + + public override bool IsThreaded { get { return false; } } + + #region Extensions + public override object Extension(string pFunct, params object[] pParams) + { + DetailLog("{0} BSScene.Extension,op={1}", DetailLogZero, pFunct); + return base.Extension(pFunct, pParams); + } + #endregion // Extensions + + public static string PrimitiveBaseShapeToString(PrimitiveBaseShape pbs) + { + float pathShearX = pbs.PathShearX < 128 ? (float)pbs.PathShearX * 0.01f : (float)(pbs.PathShearX - 256) * 0.01f; + float pathShearY = pbs.PathShearY < 128 ? (float)pbs.PathShearY * 0.01f : (float)(pbs.PathShearY - 256) * 0.01f; + float pathBegin = (float)pbs.PathBegin * 2.0e-5f; + float pathEnd = 1.0f - (float)pbs.PathEnd * 2.0e-5f; + float pathScaleX = (float)(200 - pbs.PathScaleX) * 0.01f; + float pathScaleY = (float)(200 - pbs.PathScaleY) * 0.01f; + float pathTaperX = pbs.PathTaperX * 0.01f; + float pathTaperY = pbs.PathTaperY * 0.01f; + + float profileBegin = (float)pbs.ProfileBegin * 2.0e-5f; + float profileEnd = 1.0f - (float)pbs.ProfileEnd * 2.0e-5f; + float profileHollow = (float)pbs.ProfileHollow * 2.0e-5f; + if (profileHollow > 0.95f) + profileHollow = 0.95f; + + StringBuilder buff = new StringBuilder(); + buff.Append("shape="); + buff.Append(((ProfileShape)pbs.ProfileShape).ToString()); + buff.Append(","); + buff.Append("hollow="); + buff.Append(((HollowShape)pbs.HollowShape).ToString()); + buff.Append(","); + buff.Append("pathCurve="); + buff.Append(((Extrusion)pbs.PathCurve).ToString()); + buff.Append(","); + buff.Append("profCurve="); + buff.Append(((Extrusion)pbs.ProfileCurve).ToString()); + buff.Append(","); + buff.Append("profHollow="); + buff.Append(profileHollow.ToString()); + buff.Append(","); + buff.Append("pathBegEnd="); + buff.Append(pathBegin.ToString()); + buff.Append("/"); + buff.Append(pathEnd.ToString()); + buff.Append(","); + buff.Append("profileBegEnd="); + buff.Append(profileBegin.ToString()); + buff.Append("/"); + buff.Append(profileEnd.ToString()); + buff.Append(","); + buff.Append("scaleXY="); + buff.Append(pathScaleX.ToString()); + buff.Append("/"); + buff.Append(pathScaleY.ToString()); + buff.Append(","); + buff.Append("shearXY="); + buff.Append(pathShearX.ToString()); + buff.Append("/"); + buff.Append(pathShearY.ToString()); + buff.Append(","); + buff.Append("taperXY="); + buff.Append(pbs.PathTaperX.ToString()); + buff.Append("/"); + buff.Append(pbs.PathTaperY.ToString()); + buff.Append(","); + buff.Append("skew="); + buff.Append(pbs.PathSkew.ToString()); + buff.Append(","); + buff.Append("twist/Beg="); + buff.Append(pbs.PathTwist.ToString()); + buff.Append("/"); + buff.Append(pbs.PathTwistBegin.ToString()); + + return buff.ToString(); + } + + #region Taints + // The simulation execution order is: + // Simulate() + // DoOneTimeTaints + // TriggerPreStepEvent + // DoOneTimeTaints + // Step() + // ProcessAndSendToSimulatorCollisions + // ProcessAndSendToSimulatorPropertyUpdates + // TriggerPostStepEvent + + // Calls to the PhysicsActors can't directly call into the physics engine + // because it might be busy. We delay changes to a known time. + // We rely on C#'s closure to save and restore the context for the delegate. + public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback) + { + TaintedObject(false /*inTaintTime*/, pOriginator, pIdent, pCallback); + } + public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback) + { + TaintedObject(false /*inTaintTime*/, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback); + } + public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback) + { + TaintedObject(inTaintTime, BSScene.DetailLogZero, pIdent, pCallback); + } + public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback) + { + TaintedObject(inTaintTime, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback); + } + // Sometimes a potentially tainted operation can be used in and out of taint time. + // This routine executes the command immediately if in taint-time otherwise it is queued. + public void TaintedObject(bool inTaintTime, string pOriginator, string pIdent, TaintCallback pCallback) + { + if (!m_initialized) return; + + if (inTaintTime) + pCallback(); + else + { + lock (_taintLock) + { + _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback)); + } + } + } + + private void TriggerPreStepEvent(float timeStep) + { + PreStepAction actions = BeforeStep; + if (actions != null) + actions(timeStep); + + } + + private void TriggerPostStepEvent(float timeStep) + { + PostStepAction actions = AfterStep; + if (actions != null) + actions(timeStep); + + } + + // When someone tries to change a property on a BSPrim or BSCharacter, the object queues + // a callback into itself to do the actual property change. That callback is called + // here just before the physics engine is called to step the simulation. + public void ProcessTaints() + { + ProcessRegularTaints(); + ProcessPostTaintTaints(); + } + + private void ProcessRegularTaints() + { + if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process + { + // swizzle a new list into the list location so we can process what's there + List oldList; + lock (_taintLock) + { + oldList = _taintOperations; + _taintOperations = new List(); + } + + foreach (TaintCallbackEntry tcbe in oldList) + { + try + { + DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG + tcbe.callback(); + } + catch (Exception e) + { + m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); + } + } + oldList.Clear(); + } + } + + // Schedule an update to happen after all the regular taints are processed. + // Note that new requests for the same operation ("ident") for the same object ("ID") + // will replace any previous operation by the same object. + public void PostTaintObject(String ident, uint ID, TaintCallback callback) + { + string IDAsString = ID.ToString(); + string uniqueIdent = ident + "-" + IDAsString; + lock (_taintLock) + { + _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(IDAsString, uniqueIdent, callback); + } + + return; + } + + // Taints that happen after the normal taint processing but before the simulation step. + private void ProcessPostTaintTaints() + { + if (m_initialized && _postTaintOperations.Count > 0) + { + Dictionary oldList; + lock (_taintLock) + { + oldList = _postTaintOperations; + _postTaintOperations = new Dictionary(); + } + + foreach (KeyValuePair kvp in oldList) + { + try + { + DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG + kvp.Value.callback(); + } + catch (Exception e) + { + m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e); + } + } + oldList.Clear(); + } + } + + // Only used for debugging. Does not change state of anything so locking is not necessary. + public bool AssertInTaintTime(string whereFrom) + { + if (!InTaintTime) + { + DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); + m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); + // Util.PrintCallStack(DetailLog); + } + return InTaintTime; + } + + #endregion // Taints + + #region IPhysicsParameters + // Get the list of parameters this physics engine supports + public PhysParameterEntry[] GetParameterList() + { + BSParam.BuildParameterTable(); + return BSParam.SettableParameters; + } + + // Set parameter on a specific or all instances. + // Return 'false' if not able to set the parameter. + // Setting the value in the m_params block will change the value the physics engine + // will use the next time since it's pinned and shared memory. + // Some of the values require calling into the physics engine to get the new + // value activated ('terrainFriction' for instance). + public bool SetPhysicsParameter(string parm, string val, uint localID) + { + bool ret = false; + + BSParam.ParameterDefnBase theParam; + if (BSParam.TryGetParameter(parm, out theParam)) + { + // Set the value in the C# code + theParam.SetValue(this, val); + + // Optionally set the parameter in the unmanaged code + if (theParam.HasSetOnObject) + { + // update all the localIDs specified + // If the local ID is APPLY_TO_NONE, just change the default value + // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs + // If the localID is a specific object, apply the parameter change to only that object + List objectIDs = new List(); + switch (localID) + { + case PhysParameterEntry.APPLY_TO_NONE: + // This will cause a call into the physical world if some operation is specified (SetOnObject). + objectIDs.Add(TERRAIN_ID); + TaintedUpdateParameter(parm, objectIDs, val); + break; + case PhysParameterEntry.APPLY_TO_ALL: + lock (PhysObjects) objectIDs = new List(PhysObjects.Keys); + TaintedUpdateParameter(parm, objectIDs, val); + break; + default: + // setting only one localID + objectIDs.Add(localID); + TaintedUpdateParameter(parm, objectIDs, val); + break; + } + } + + ret = true; + } + return ret; + } + + // schedule the actual updating of the paramter to when the phys engine is not busy + private void TaintedUpdateParameter(string parm, List lIDs, string val) + { + string xval = val; + List xlIDs = lIDs; + string xparm = parm; + TaintedObject(DetailLogZero, "BSScene.UpdateParameterSet", delegate() { + BSParam.ParameterDefnBase thisParam; + if (BSParam.TryGetParameter(xparm, out thisParam)) + { + if (thisParam.HasSetOnObject) + { + foreach (uint lID in xlIDs) + { + BSPhysObject theObject = null; + if (PhysObjects.TryGetValue(lID, out theObject)) + thisParam.SetOnObject(this, theObject); + } + } + } + }); + } + + // Get parameter. + // Return 'false' if not able to get the parameter. + public bool GetPhysicsParameter(string parm, out string value) + { + string val = String.Empty; + bool ret = false; + BSParam.ParameterDefnBase theParam; + if (BSParam.TryGetParameter(parm, out theParam)) + { + val = theParam.GetValue(this); + ret = true; + } + value = val; + return ret; + } + + #endregion IPhysicsParameters + + // Invoke the detailed logger and output something if it's enabled. + public void DetailLog(string msg, params Object[] args) + { + PhysicsLogging.Write(msg, args); + } + // Used to fill in the LocalID when there isn't one. It's the correct number of characters. + public const string DetailLogZero = "0000000000"; + + } +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs new file mode 100755 index 0000000..b100273 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs @@ -0,0 +1,425 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; +using OMV = OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public sealed class BSShapeCollection : IDisposable +{ +#pragma warning disable 414 + private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; +#pragma warning restore 414 + + private BSScene m_physicsScene { get; set; } + + private Object m_collectionActivityLock = new Object(); + + private bool DDetail = false; + + public BSShapeCollection(BSScene physScene) + { + m_physicsScene = physScene; + // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) + // While detailed debugging is still active, this is better than commenting out all the + // DetailLog statements. When debugging slows down, this and the protected logging + // statements can be commented/removed. + DDetail = true; + } + + public void Dispose() + { + // TODO!!!!!!!!! + } + + // Callbacks called just before either the body or shape is destroyed. + // Mostly used for changing bodies out from under Linksets. + // Useful for other cases where parameters need saving. + // Passing 'null' says no callback. + public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape); + + // Called to update/change the body and shape for an object. + // The object has some shape and body on it. Here we decide if that is the correct shape + // for the current state of the object (static/dynamic/...). + // If bodyCallback is not null, it is called if either the body or the shape are changed + // so dependencies (like constraints) can be removed before the physical object is dereferenced. + // Return 'true' if either the body or the shape changed. + // Called at taint-time. + public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback) + { + m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); + + bool ret = false; + + // This lock could probably be pushed down lower but building shouldn't take long + lock (m_collectionActivityLock) + { + // Do we have the correct geometry for this type of object? + // Updates prim.BSShape with information/pointers to shape. + // Returns 'true' of BSShape is changed to a new shape. + bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback); + // If we had to select a new shape geometry for the object, + // rebuild the body around it. + // Updates prim.BSBody with information/pointers to requested body + // Returns 'true' if BSBody was changed. + bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback); + ret = newGeom || newBody; + } + DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", + prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape); + + return ret; + } + + public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) + { + return GetBodyAndShape(forceRebuild, sim, prim, null); + } + + // If the existing prim's shape is to be replaced, remove the tie to the existing shape + // before replacing it. + private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) + { + if (prim.PhysShape.HasPhysicalShape) + { + if (shapeCallback != null) + shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo); + prim.PhysShape.Dereference(m_physicsScene); + } + prim.PhysShape = new BSShapeNull(); + } + + // Create the geometry information in Bullet for later use. + // The objects needs a hull if it's physical otherwise a mesh is enough. + // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls, + // shared geometries will be used. If the parameters of the existing shape are the same + // as this request, the shape is not rebuilt. + // Info in prim.BSShape is updated to the new shape. + // Returns 'true' if the geometry was rebuilt. + // Called at taint-time! + public const int AvatarShapeCapsule = 0; + public const int AvatarShapeCube = 1; + public const int AvatarShapeOvoid = 2; + public const int AvatarShapeMesh = 3; + private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback) + { + bool ret = false; + bool haveShape = false; + bool nativeShapePossible = true; + PrimitiveBaseShape pbs = prim.BaseShape; + + // Kludge to create the capsule for the avatar. + // TDOD: Remove/redo this when BSShapeAvatar is working!! + BSCharacter theChar = prim as BSCharacter; + if (theChar != null) + { + DereferenceExistingShape(prim, shapeCallback); + switch (BSParam.AvatarShape) + { + case AvatarShapeCapsule: + prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, + BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE); + ret = true; + haveShape = true; + break; + case AvatarShapeCube: + prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, + BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_CAPSULE); + ret = true; + haveShape = true; + break; + case AvatarShapeOvoid: + // Saddly, Bullet doesn't scale spheres so this doesn't work as an avatar shape + prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, + BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_CAPSULE); + ret = true; + haveShape = true; + break; + case AvatarShapeMesh: + break; + default: + break; + } + } + + // If the prim attributes are simple, this could be a simple Bullet native shape + // Native shapes work whether to object is static or physical. + if (!haveShape + && nativeShapePossible + && pbs != null + && PrimHasNoCuts(pbs) + && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) ) + ) + { + // Get the scale of any existing shape so we can see if the new shape is same native type and same size. + OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; + if (prim.PhysShape.HasPhysicalShape) + scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo); + + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", + prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType); + + // It doesn't look like Bullet scales native spheres so make sure the scales are all equal + if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) + && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) + { + haveShape = true; + if (forceRebuild + || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE + ) + { + DereferenceExistingShape(prim, shapeCallback); + prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, + BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE); + ret = true; + } + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", + prim.LocalID, forceRebuild, ret, prim.PhysShape); + } + // If we didn't make a sphere, maybe a box will work. + if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) + { + haveShape = true; + if (forceRebuild + || prim.Scale != scaleOfExistingShape + || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX + ) + { + DereferenceExistingShape(prim, shapeCallback); + prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, + BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + ret = true; + } + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", + prim.LocalID, forceRebuild, ret, prim.PhysShape); + } + } + + // If a simple shape is not happening, create a mesh and possibly a hull. + if (!haveShape && pbs != null) + { + ret = CreateGeomMeshOrHull(prim, shapeCallback); + } + + return ret; + } + + // return 'true' if this shape description does not include any cutting or twisting. + public static bool PrimHasNoCuts(PrimitiveBaseShape pbs) + { + return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 + && pbs.ProfileHollow == 0 + && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 + && pbs.PathBegin == 0 && pbs.PathEnd == 0 + && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 + && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 + && pbs.PathShearX == 0 && pbs.PathShearY == 0; + } + + // return 'true' if the prim's shape was changed. + private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) + { + + bool ret = false; + // Note that if it's a native shape, the check for physical/non-physical is not + // made. Native shapes work in either case. + if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) + { + // Use a simple, single mesh convex hull shape if the object is simple enough + BSShape potentialHull = null; + + PrimitiveBaseShape pbs = prim.BaseShape; + // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists) + if (BSParam.ShouldUseSingleConvexHullForPrims + && pbs != null + && !pbs.SculptEntry + && PrimHasNoCuts(pbs) + ) + { + potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim); + } + // Use the GImpact shape if it is a prim that has some concaveness + if (potentialHull == null + && BSParam.ShouldUseGImpactShapeForPrims + && pbs != null + && !pbs.SculptEntry + ) + { + potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim); + } + // If not any of the simple cases, just make a hull + if (potentialHull == null) + { + potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); + } + + // If the current shape is not what is on the prim at the moment, time to change. + if (!prim.PhysShape.HasPhysicalShape + || potentialHull.ShapeType != prim.PhysShape.ShapeType + || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) + { + DereferenceExistingShape(prim, shapeCallback); + prim.PhysShape = potentialHull; + ret = true; + } + else + { + // The current shape on the prim is the correct one. We don't need the potential reference. + potentialHull.Dereference(m_physicsScene); + } + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape); + } + else + { + // Non-physical objects should be just meshes. + BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim); + // If the current shape is not what is on the prim at the moment, time to change. + if (!prim.PhysShape.HasPhysicalShape + || potentialMesh.ShapeType != prim.PhysShape.ShapeType + || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) + { + DereferenceExistingShape(prim, shapeCallback); + prim.PhysShape = potentialMesh; + ret = true; + } + else + { + // We don't need this reference to the mesh that is already being using. + potentialMesh.Dereference(m_physicsScene); + } + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape); + } + return ret; + } + + // Track another user of a body. + // We presume the caller has allocated the body. + // Bodies only have one user so the body is just put into the world if not already there. + private void ReferenceBody(BulletBody body) + { + lock (m_collectionActivityLock) + { + if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); + if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body)) + { + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body); + if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); + } + } + } + + // Release the usage of a body. + // Called when releasing use of a BSBody. BSShape is handled separately. + // Called in taint time. + public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback ) + { + if (!body.HasPhysicalBody) + return; + + m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody"); + + lock (m_collectionActivityLock) + { + if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body); + // If the caller needs to know the old body is going away, pass the event up. + if (bodyCallback != null) + bodyCallback(body, null); + + // Removing an object not in the world is a NOOP + m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body); + + // Zero any reference to the shape so it is not freed when the body is deleted. + m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null); + + m_physicsScene.PE.DestroyObject(m_physicsScene.World, body); + } + } + + // Create a body object in Bullet. + // Updates prim.BSBody with the information about the new body if one is created. + // Returns 'true' if an object was actually created. + // Called at taint-time. + private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback) + { + bool ret = false; + + // the mesh, hull or native shape must have already been created in Bullet + bool mustRebuild = !prim.PhysBody.HasPhysicalBody; + + // If there is an existing body, verify it's of an acceptable type. + // If not a solid object, body is a GhostObject. Otherwise a RigidBody. + if (!mustRebuild) + { + CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody); + if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY + || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) + { + // If the collisionObject is not the correct type for solidness, rebuild what's there + mustRebuild = true; + if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType); + } + } + + if (mustRebuild || forceRebuild) + { + // Free any old body + DereferenceBody(prim.PhysBody, bodyCallback); + + BulletBody aBody; + if (prim.IsSolid) + { + aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); + if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody); + } + else + { + aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); + if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); + } + + ReferenceBody(aBody); + + prim.PhysBody = aBody; + + ret = true; + } + + return ret; + } + + private void DetailLog(string msg, params Object[] args) + { + if (m_physicsScene.PhysicsLogging.Enabled) + m_physicsScene.DetailLog(msg, args); + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs new file mode 100755 index 0000000..086a412 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs @@ -0,0 +1,1463 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; + +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Region.PhysicsModules.Meshing; +using OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +// Information class that holds stats for the shape. Which values mean +// something depends on the type of shape. +// This information is used for debugging and stats and is not used +// for operational things. +public class ShapeInfoInfo +{ + public int Vertices { get; set; } + private int m_hullCount; + private int[] m_verticesPerHull; + public ShapeInfoInfo() + { + Vertices = 0; + m_hullCount = 0; + m_verticesPerHull = null; + } + public int HullCount + { + set + { + m_hullCount = value; + m_verticesPerHull = new int[m_hullCount]; + Array.Clear(m_verticesPerHull, 0, m_hullCount); + } + get { return m_hullCount; } + } + public void SetVerticesPerHull(int hullNum, int vertices) + { + if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length) + { + m_verticesPerHull[hullNum] = vertices; + } + } + public int GetVerticesPerHull(int hullNum) + { + if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length) + { + return m_verticesPerHull[hullNum]; + } + return 0; + } + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + // buff.Append("ShapeInfo=<"); + buff.Append("<"); + if (Vertices > 0) + { + buff.Append("verts="); + buff.Append(Vertices.ToString()); + } + + if (Vertices > 0 && HullCount > 0) buff.Append(","); + + if (HullCount > 0) + { + buff.Append("nHulls="); + buff.Append(HullCount.ToString()); + buff.Append(","); + buff.Append("hullVerts="); + for (int ii = 0; ii < HullCount; ii++) + { + if (ii != 0) buff.Append(","); + buff.Append(GetVerticesPerHull(ii).ToString()); + } + } + buff.Append(">"); + return buff.ToString(); + } +} + +public abstract class BSShape +{ + private static string LogHeader = "[BULLETSIM SHAPE]"; + + public int referenceCount { get; set; } + public DateTime lastReferenced { get; set; } + public BulletShape physShapeInfo { get; set; } + public ShapeInfoInfo shapeInfo { get; private set; } + + public BSShape() + { + referenceCount = 1; + lastReferenced = DateTime.Now; + physShapeInfo = new BulletShape(); + shapeInfo = new ShapeInfoInfo(); + } + public BSShape(BulletShape pShape) + { + referenceCount = 1; + lastReferenced = DateTime.Now; + physShapeInfo = pShape; + shapeInfo = new ShapeInfoInfo(); + } + + // Get another reference to this shape. + public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim); + + // Called when this shape is being used again. + // Used internally. External callers should call instance.GetReference() to properly copy/reference + // the shape. + protected virtual void IncrementReference() + { + referenceCount++; + lastReferenced = DateTime.Now; + } + + // Called when this shape is done being used. + protected virtual void DecrementReference() + { + referenceCount--; + lastReferenced = DateTime.Now; + } + + // Release the use of a physical shape. + public abstract void Dereference(BSScene physicsScene); + + // Return 'true' if there is an allocated physics physical shape under this class instance. + public virtual bool HasPhysicalShape + { + get + { + if (physShapeInfo != null) + return physShapeInfo.HasPhysicalShape; + return false; + } + } + public virtual BSPhysicsShapeType ShapeType + { + get + { + BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + if (physShapeInfo != null && physShapeInfo.HasPhysicalShape) + ret = physShapeInfo.shapeType; + return ret; + } + } + + // Returns a string for debugging that uniquily identifies the memory used by this instance + public virtual string AddrString + { + get + { + if (physShapeInfo != null) + return physShapeInfo.AddrString; + return "unknown"; + } + } + + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + if (physShapeInfo == null) + { + buff.Append(""); + return buff.ToString(); + } + + #region Common shape routines + // Create a hash of all the shape parameters to be used as a key for this particular shape. + public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) + { + // level of detail based on size and type of the object + float lod = BSParam.MeshLOD; + if (pbs.SculptEntry) + lod = BSParam.SculptLOD; + + // Mega prims usually get more detail because one can interact with shape approximations at this size. + float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); + if (maxAxis > BSParam.MeshMegaPrimThreshold) + lod = BSParam.MeshMegaPrimLOD; + + retLod = lod; + return pbs.GetMeshKey(size, lod); + } + + // The creation of a mesh or hull can fail if an underlying asset is not available. + // There are two cases: 1) the asset is not in the cache and it needs to be fetched; + // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). + // The first case causes the asset to be fetched. The second case requires + // us to not loop forever. + // Called after creating a physical mesh or hull. If the physical shape was created, + // just return. + public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim) + { + // If the shape was successfully created, nothing more to do + if (newShape.HasPhysicalShape) + return newShape; + + // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been + // fetched but we end up here again, the meshing of the asset must have failed. + // Prevent trying to keep fetching the mesh by declaring failure. + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) + { + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; + physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}", + LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}", + prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + } + else + { + // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset + if (prim.BaseShape.SculptEntry + && !prim.AssetFailed() + && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting + && prim.BaseShape.SculptTexture != OMV.UUID.Zero + ) + { + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}", + prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); + // Multiple requestors will know we're waiting for this asset + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; + + BSPhysObject xprim = prim; + RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod; + if (assetProvider != null) + { + BSPhysObject yprim = xprim; // probably not necessary, but, just in case. + assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) + { + // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID); + bool assetFound = false; + string mismatchIDs = String.Empty; // DEBUG DEBUG + if (asset != null && yprim.BaseShape.SculptEntry) + { + if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) + { + yprim.BaseShape.SculptData = asset.Data; + // This will cause the prim to see that the filler shape is not the right + // one and try again to build the object. + // No race condition with the normal shape setting since the rebuild is at taint time. + yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; + yprim.ForceBodyShapeRebuild(false /* inTaintTime */); + assetFound = true; + } + else + { + mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; + } + } + if (!assetFound) + { + yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; + } + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}", + yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); + }); + } + else + { + xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; + physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", + LogHeader, physicsScene.PhysicsSceneName); + } + } + else + { + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) + { + physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}", + LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}", + prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + } + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing) + { + physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}", + LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}", + prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + } + } + } + + // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. + BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID); + + return fillShape.physShapeInfo; + } + + public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim) + { + StringBuilder buff = new StringBuilder(prim.PhysObjectName); + buff.Append("/pos="); + buff.Append(prim.RawPosition.ToString()); + if (pScene != null) + { + buff.Append("/rgn="); + buff.Append(pScene.PhysicsSceneName); + } + return buff.ToString(); + } + + #endregion // Common shape routines +} + +// ============================================================================================================ +public class BSShapeNull : BSShape +{ + public BSShapeNull() : base() + { + } + public static BSShape GetReference() { return new BSShapeNull(); } + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); } + public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } +} + +// ============================================================================================================ +// BSShapeNative is a wrapper for a Bullet 'native' shape -- cube and sphere. +// They are odd in that they don't allocate meshes but are computated/procedural. +// This means allocation and freeing is different than meshes. +public class BSShapeNative : BSShape +{ + private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; + public BSShapeNative(BulletShape pShape) : base(pShape) + { + } + + public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, + BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) + { + // Native shapes are not shared and are always built anew. + return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); + } + + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) + { + // Native shapes are not shared so we return a new shape. + BSShape ret = null; + lock (physShapeInfo) + { + ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim, + physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey)); + } + return ret; + } + + // Make this reference to the physical shape go away since native shapes are not shared. + public override void Dereference(BSScene physicsScene) + { + // Native shapes are not tracked and are released immediately + lock (physShapeInfo) + { + if (physShapeInfo.HasPhysicalShape) + { + physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); + physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); + } + physShapeInfo.Clear(); + // Garbage collection will free up this instance. + } + } + + private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim, + BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) + { + BulletShape newShape; + + ShapeData nativeShapeData = new ShapeData(); + nativeShapeData.Type = shapeType; + nativeShapeData.ID = prim.LocalID; + nativeShapeData.Scale = prim.Scale; + nativeShapeData.Size = prim.Scale; + nativeShapeData.MeshKey = (ulong)shapeKey; + nativeShapeData.HullKey = (ulong)shapeKey; + + if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) + { + newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); + physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale); + } + else + { + newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); + } + if (!newShape.HasPhysicalShape) + { + physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", + LogHeader, prim.LocalID, shapeType); + } + newShape.shapeType = shapeType; + newShape.isNativeShape = true; + newShape.shapeKey = (UInt64)shapeKey; + return newShape; + } + +} + +// ============================================================================================================ +// BSShapeMesh is a simple mesh. +public class BSShapeMesh : BSShape +{ + private static string LogHeader = "[BULLETSIM SHAPE MESH]"; + public static Dictionary Meshes = new Dictionary(); + + public BSShapeMesh(BulletShape pShape) : base(pShape) + { + } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + float lod; + System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + + BSShapeMesh retMesh = null; + lock (Meshes) + { + if (Meshes.TryGetValue(newMeshKey, out retMesh)) + { + // The mesh has already been created. Return a new reference to same. + retMesh.IncrementReference(); + } + else + { + retMesh = new BSShapeMesh(new BulletShape()); + // An instance of this mesh has not been created. Build and remember same. + BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); + + // Check to see if mesh was created (might require an asset). + newShape = VerifyMeshCreated(physicsScene, newShape, prim); + if (!newShape.isNativeShape || prim.AssetFailed() ) + { + // If a mesh was what was created, remember the built shape for later sharing. + // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh. + Meshes.Add(newMeshKey, retMesh); + } + + retMesh.physShapeInfo = newShape; + } + } + physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod); + return retMesh; + } + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) + { + BSShape ret = null; + // If the underlying shape is native, the actual shape has not been build (waiting for asset) + // and we must create a copy of the native shape since they are never shared. + if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) + { + // TODO: decide when the native shapes should be freed. Check in Dereference? + ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + } + else + { + // Another reference to this shape is just counted. + IncrementReference(); + ret = this; + } + return ret; + } + public override void Dereference(BSScene physicsScene) + { + lock (Meshes) + { + this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this); + // TODO: schedule aging and destruction of unused meshes. + } + } + // Loop through all the known meshes and return the description based on the physical address. + public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh) + { + bool ret = false; + BSShapeMesh foundDesc = null; + lock (Meshes) + { + foreach (BSShapeMesh sm in Meshes.Values) + { + if (sm.physShapeInfo.ReferenceSame(pShape)) + { + foundDesc = sm; + ret = true; + break; + } + + } + } + outMesh = foundDesc; + return ret; + } + + public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices ); + private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, + PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) + { + return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, + (w, iC, i, vC, v) => + { + shapeInfo.Vertices = vC; + return physicsScene.PE.CreateMeshShape(w, iC, i, vC, v); + }); + } + + // Code that uses the mesher to create the index/vertices info for a trimesh shape. + // This is used by the passed 'makeShape' call to create the Bullet mesh shape. + // The actual build call is passed so this logic can be used by several of the shapes that use a + // simple mesh as their base shape. + public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, + PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape) + { + BulletShape newShape = new BulletShape(); + + IMesh meshData = null; + lock (physicsScene.mesher) + { + meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, + false, // say it is not physical so a bounding box is not built + false // do not cache the mesh and do not use previously built versions + ); + } + + if (meshData != null) + { + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) + { + // Release the fetched asset data once it has been used. + pbs.SculptData = new byte[0]; + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; + } + + int[] indices = meshData.getIndexListAsInt(); + int realIndicesIndex = indices.Length; + float[] verticesAsFloats = meshData.getVertexListAsFloat(); + + if (BSParam.ShouldRemoveZeroWidthTriangles) + { + // Remove degenerate triangles. These are triangles with two of the vertices + // are the same. This is complicated by the problem that vertices are not + // made unique in sculpties so we have to compare the values in the vertex. + realIndicesIndex = 0; + for (int tri = 0; tri < indices.Length; tri += 3) + { + // Compute displacements into vertex array for each vertex of the triangle + int v1 = indices[tri + 0] * 3; + int v2 = indices[tri + 1] * 3; + int v3 = indices[tri + 2] * 3; + // Check to see if any two of the vertices are the same + if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] + && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] + && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) + || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] + && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] + && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) + || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] + && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] + && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) ) + ) + { + // None of the vertices of the triangles are the same. This is a good triangle; + indices[realIndicesIndex + 0] = indices[tri + 0]; + indices[realIndicesIndex + 1] = indices[tri + 1]; + indices[realIndicesIndex + 2] = indices[tri + 2]; + realIndicesIndex += 3; + } + } + } + physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}", + BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); + + if (realIndicesIndex != 0) + { + newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); + } + else + { + // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh. + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; + physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) ); + physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey); + } + } + newShape.shapeKey = newMeshKey; + + return newShape; + } +} + +// ============================================================================================================ +// BSShapeHull is a physical shape representation htat is made up of many convex hulls. +// The convex hulls are either supplied with the asset or are approximated by one of the +// convex hull creation routines (in OpenSim or in Bullet). +public class BSShapeHull : BSShape +{ +#pragma warning disable 414 + private static string LogHeader = "[BULLETSIM SHAPE HULL]"; +#pragma warning restore 414 + + public static Dictionary Hulls = new Dictionary(); + + + public BSShapeHull(BulletShape pShape) : base(pShape) + { + } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + float lod; + System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + + BSShapeHull retHull = null; + lock (Hulls) + { + if (Hulls.TryGetValue(newHullKey, out retHull)) + { + // The mesh has already been created. Return a new reference to same. + retHull.IncrementReference(); + } + else + { + retHull = new BSShapeHull(new BulletShape()); + // An instance of this mesh has not been created. Build and remember same. + BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod); + + // Check to see if hull was created (might require an asset). + newShape = VerifyMeshCreated(physicsScene, newShape, prim); + if (!newShape.isNativeShape || prim.AssetFailed()) + { + // If a mesh was what was created, remember the built shape for later sharing. + Hulls.Add(newHullKey, retHull); + } + retHull.physShapeInfo = newShape; + } + } + physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod); + return retHull; + } + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) + { + BSShape ret = null; + // If the underlying shape is native, the actual shape has not been build (waiting for asset) + // and we must create a copy of the native shape since they are never shared. + if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) + { + // TODO: decide when the native shapes should be freed. Check in Dereference? + ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + } + else + { + // Another reference to this shape is just counted. + IncrementReference(); + ret = this; + } + return ret; + } + public override void Dereference(BSScene physicsScene) + { + lock (Hulls) + { + this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this); + // TODO: schedule aging and destruction of unused meshes. + } + } + + List m_hulls; + private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey, + PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) + { + BulletShape newShape = new BulletShape(); + + IMesh meshData = null; + List> allHulls = null; + lock (physicsScene.mesher) + { + // Pass true for physicalness as this prevents the creation of bounding box which is not needed + meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); + + // If we should use the asset's hull info, fetch it out of the locked mesher + if (meshData != null && BSParam.ShouldUseAssetHulls) + { + Meshmerizer realMesher = physicsScene.mesher as Meshmerizer; + if (realMesher != null) + { + allHulls = realMesher.GetConvexHulls(size); + } + if (allHulls == null) + { + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID); + } + } + } + + // If there is hull data in the mesh asset, build the hull from that + if (allHulls != null && BSParam.ShouldUseAssetHulls) + { + int hullCount = allHulls.Count; + shapeInfo.HullCount = hullCount; + int totalVertices = 1; // include one for the count of the hulls + // Using the structure described for HACD hulls, create the memory sturcture + // to pass the hull data to the creater. + foreach (List hullVerts in allHulls) + { + totalVertices += 4; // add four for the vertex count and centroid + totalVertices += hullVerts.Count * 3; // one vertex is three dimensions + } + float[] convHulls = new float[totalVertices]; + + convHulls[0] = (float)hullCount; + int jj = 1; + int hullIndex = 0; + foreach (List hullVerts in allHulls) + { + convHulls[jj + 0] = hullVerts.Count; + convHulls[jj + 1] = 0f; // centroid x,y,z + convHulls[jj + 2] = 0f; + convHulls[jj + 3] = 0f; + jj += 4; + foreach (OMV.Vector3 oneVert in hullVerts) + { + convHulls[jj + 0] = oneVert.X; + convHulls[jj + 1] = oneVert.Y; + convHulls[jj + 2] = oneVert.Z; + jj += 3; + } + shapeInfo.SetVerticesPerHull(hullIndex, hullVerts.Count); + hullIndex++; + } + + // create the hull data structure in Bullet + newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); + + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}", + prim.LocalID, hullCount, totalVertices, newShape); + } + + // If no hull specified in the asset and we should use Bullet's HACD approximation... + if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD) + { + // Build the hull shape from an existing mesh shape. + // The mesh should have already been created in Bullet. + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID); + BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim); + + if (meshShape.physShapeInfo.HasPhysicalShape) + { + HACDParams parms = new HACDParams(); + parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull; + parms.minClusters = BSParam.BHullMinClusters; + parms.compacityWeight = BSParam.BHullCompacityWeight; + parms.volumeWeight = BSParam.BHullVolumeWeight; + parms.concavity = BSParam.BHullConcavity; + parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints); + parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints); + parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints); + parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin); + parms.whichHACD = 0; // Use the HACD routine that comes with Bullet + + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); + newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms); + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape); + + // Now done with the mesh shape. + shapeInfo.HullCount = 1; + BSShapeMesh maybeMesh = meshShape as BSShapeMesh; + if (maybeMesh != null) + shapeInfo.SetVerticesPerHull(0, maybeMesh.shapeInfo.Vertices); + meshShape.Dereference(physicsScene); + } + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); + } + + // If no other hull specifications, use our HACD hull approximation. + if (!newShape.HasPhysicalShape && meshData != null) + { + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) + { + // Release the fetched asset data once it has been used. + pbs.SculptData = new byte[0]; + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; + } + + int[] indices = meshData.getIndexListAsInt(); + List vertices = meshData.getVertexList(); + + //format conversion from IMesh format to DecompDesc format + List convIndices = new List(); + List convVertices = new List(); + for (int ii = 0; ii < indices.GetLength(0); ii++) + { + convIndices.Add(indices[ii]); + } + foreach (OMV.Vector3 vv in vertices) + { + convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); + } + + uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; + if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) + { + // Simple primitive shapes we know are convex so they are better implemented with + // fewer hulls. + // Check for simple shape (prim without cuts) and reduce split parameter if so. + if (BSShapeCollection.PrimHasNoCuts(pbs)) + { + maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; + } + } + + // setup and do convex hull conversion + m_hulls = new List(); + DecompDesc dcomp = new DecompDesc(); + dcomp.mIndices = convIndices; + dcomp.mVertices = convVertices; + dcomp.mDepth = maxDepthSplit; + dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; + dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; + dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; + dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; + ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); + // create the hull into the _hulls variable + convexBuilder.process(dcomp); + + physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", + BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); + + // Convert the vertices and indices for passing to unmanaged. + // The hull information is passed as a large floating point array. + // The format is: + // convHulls[0] = number of hulls + // convHulls[1] = number of vertices in first hull + // convHulls[2] = hull centroid X coordinate + // convHulls[3] = hull centroid Y coordinate + // convHulls[4] = hull centroid Z coordinate + // convHulls[5] = first hull vertex X + // convHulls[6] = first hull vertex Y + // convHulls[7] = first hull vertex Z + // convHulls[8] = second hull vertex X + // ... + // convHulls[n] = number of vertices in second hull + // convHulls[n+1] = second hull centroid X coordinate + // ... + // + // TODO: is is very inefficient. Someday change the convex hull generator to return + // data structures that do not need to be converted in order to pass to Bullet. + // And maybe put the values directly into pinned memory rather than marshaling. + int hullCount = m_hulls.Count; + int totalVertices = 1; // include one for the count of the hulls + foreach (ConvexResult cr in m_hulls) + { + totalVertices += 4; // add four for the vertex count and centroid + totalVertices += cr.HullIndices.Count * 3; // we pass just triangles + } + float[] convHulls = new float[totalVertices]; + + convHulls[0] = (float)hullCount; + int jj = 1; + foreach (ConvexResult cr in m_hulls) + { + // copy vertices for index access + float3[] verts = new float3[cr.HullVertices.Count]; + int kk = 0; + foreach (float3 ff in cr.HullVertices) + { + verts[kk++] = ff; + } + + // add to the array one hull's worth of data + convHulls[jj++] = cr.HullIndices.Count; + convHulls[jj++] = 0f; // centroid x,y,z + convHulls[jj++] = 0f; + convHulls[jj++] = 0f; + foreach (int ind in cr.HullIndices) + { + convHulls[jj++] = verts[ind].x; + convHulls[jj++] = verts[ind].y; + convHulls[jj++] = verts[ind].z; + } + } + // create the hull data structure in Bullet + newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); + } + newShape.shapeKey = newHullKey; + return newShape; + } + // Callback from convex hull creater with a newly created hull. + // Just add it to our collection of hulls for this shape. + private void HullReturn(ConvexResult result) + { + m_hulls.Add(result); + return; + } + // Loop through all the known hulls and return the description based on the physical address. + public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull) + { + bool ret = false; + BSShapeHull foundDesc = null; + lock (Hulls) + { + foreach (BSShapeHull sh in Hulls.Values) + { + if (sh.physShapeInfo.ReferenceSame(pShape)) + { + foundDesc = sh; + ret = true; + break; + } + + } + } + outHull = foundDesc; + return ret; + } +} + +// ============================================================================================================ +// BSShapeCompound is a wrapper for the Bullet compound shape which is built from multiple, separate +// meshes. Used by BulletSim for complex shapes like linksets. +public class BSShapeCompound : BSShape +{ + private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; + public static Dictionary CompoundShapes = new Dictionary(); + + public BSShapeCompound(BulletShape pShape) : base(pShape) + { + } + public static BSShape GetReference(BSScene physicsScene) + { + // Base compound shapes are not shared so this returns a raw shape. + // A built compound shape can be reused in linksets. + BSShapeCompound ret = new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene)); + CompoundShapes.Add(ret.AddrString, ret); + return ret; + } + public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) + { + // Calling this reference means we want another handle to an existing compound shape + // (usually linksets) so return this copy. + IncrementReference(); + return this; + } + // Dereferencing a compound shape releases the hold on all the child shapes. + public override void Dereference(BSScene physicsScene) + { + lock (physShapeInfo) + { + this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this); + if (referenceCount <= 0) + { + if (!physicsScene.PE.IsCompound(physShapeInfo)) + { + // Failed the sanity check!! + physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", + LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString); + physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", + BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString); + return; + } + + int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo); + physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", + BSScene.DetailLogZero, physShapeInfo, numChildren); + + // Loop through all the children dereferencing each. + for (int ii = numChildren - 1; ii >= 0; ii--) + { + BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii); + DereferenceAnonCollisionShape(physicsScene, childShape); + } + + lock (CompoundShapes) + CompoundShapes.Remove(physShapeInfo.AddrString); + physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); + } + } + } + public static bool TryGetCompoundByPtr(BulletShape pShape, out BSShapeCompound outCompound) + { + lock (CompoundShapes) + { + string addr = pShape.AddrString; + return CompoundShapes.TryGetValue(addr, out outCompound); + } + } + private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene) + { + BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false); + return cShape; + } + // Sometimes we have a pointer to a collision shape but don't know what type it is. + // Figure out type and call the correct dereference routine. + // Called at taint-time. + private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape) + { + // TODO: figure a better way to go through all the shape types and find a possible instance. + physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,shape={1}", + BSScene.DetailLogZero, pShape); + BSShapeMesh meshDesc; + if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc)) + { + meshDesc.Dereference(physicsScene); + // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundMesh,shape={1}", BSScene.DetailLogZero, pShape); + } + else + { + BSShapeHull hullDesc; + if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc)) + { + hullDesc.Dereference(physicsScene); + // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundHull,shape={1}", BSScene.DetailLogZero, pShape); + } + else + { + BSShapeConvexHull chullDesc; + if (BSShapeConvexHull.TryGetConvexHullByPtr(pShape, out chullDesc)) + { + chullDesc.Dereference(physicsScene); + // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundConvexHull,shape={1}", BSScene.DetailLogZero, pShape); + } + else + { + BSShapeGImpact gImpactDesc; + if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc)) + { + gImpactDesc.Dereference(physicsScene); + // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundgImpact,shape={1}", BSScene.DetailLogZero, pShape); + } + else + { + // Didn't find it in the lists of specific types. It could be compound. + BSShapeCompound compoundDesc; + if (BSShapeCompound.TryGetCompoundByPtr(pShape, out compoundDesc)) + { + compoundDesc.Dereference(physicsScene); + // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,recursiveCompoundShape,shape={1}", BSScene.DetailLogZero, pShape); + } + else + { + // If none of the above, maybe it is a simple native shape. + if (physicsScene.PE.IsNativeShape(pShape)) + { + // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,assumingNative,shape={1}", BSScene.DetailLogZero, pShape); + BSShapeNative nativeShape = new BSShapeNative(pShape); + nativeShape.Dereference(physicsScene); + } + else + { + physicsScene.Logger.WarnFormat("{0} DereferenceAnonCollisionShape. Did not find shape. {1}", + LogHeader, pShape); + } + } + } + } + } + } + } +} + +// ============================================================================================================ +// BSShapeConvexHull is a wrapper for a Bullet single convex hull. A BSShapeHull contains multiple convex +// hull shapes. This is used for simple prims that are convex and thus can be made into a simple +// collision shape (a single hull). More complex physical shapes will be BSShapeHull's. +public class BSShapeConvexHull : BSShape +{ +#pragma warning disable 414 + private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]"; +#pragma warning restore 414 + + public static Dictionary ConvexHulls = new Dictionary(); + + public BSShapeConvexHull(BulletShape pShape) : base(pShape) + { + } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + float lod; + System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + + physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}", + prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); + + BSShapeConvexHull retConvexHull = null; + lock (ConvexHulls) + { + if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull)) + { + // The mesh has already been created. Return a new reference to same. + retConvexHull.IncrementReference(); + } + else + { + retConvexHull = new BSShapeConvexHull(new BulletShape()); + BulletShape convexShape = null; + + // Get a handle to a mesh to build the hull from + BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim); + if (baseMesh.physShapeInfo.isNativeShape) + { + // We get here if the mesh was not creatable. Could be waiting for an asset from the disk. + // In the short term, we return the native shape and a later ForceBodyShapeRebuild should + // get back to this code with a buildable mesh. + // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed? + convexShape = baseMesh.physShapeInfo; + } + else + { + convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo); + convexShape.shapeKey = newMeshKey; + ConvexHulls.Add(convexShape.shapeKey, retConvexHull); + physicsScene.DetailLog("{0},BSShapeConvexHull.GetReference,addingNewlyCreatedShape,shape={1}", + BSScene.DetailLogZero, convexShape); + } + + // Done with the base mesh + baseMesh.Dereference(physicsScene); + + retConvexHull.physShapeInfo = convexShape; + } + } + return retConvexHull; + } + public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) + { + // Calling this reference means we want another handle to an existing shape + // (usually linksets) so return this copy. + IncrementReference(); + return this; + } + // Dereferencing a compound shape releases the hold on all the child shapes. + public override void Dereference(BSScene physicsScene) + { + lock (ConvexHulls) + { + this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this); + // TODO: schedule aging and destruction of unused meshes. + } + } + // Loop through all the known hulls and return the description based on the physical address. + public static bool TryGetConvexHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull) + { + bool ret = false; + BSShapeConvexHull foundDesc = null; + lock (ConvexHulls) + { + foreach (BSShapeConvexHull sh in ConvexHulls.Values) + { + if (sh.physShapeInfo.ReferenceSame(pShape)) + { + foundDesc = sh; + ret = true; + break; + } + + } + } + outHull = foundDesc; + return ret; + } +} +// ============================================================================================================ +// BSShapeGImpact is a wrapper for the Bullet GImpact shape which is a collision mesh shape that +// can handle concave as well as convex shapes. Much slower computationally but creates smoother +// shapes than multiple convex hull approximations. +public class BSShapeGImpact : BSShape +{ +#pragma warning disable 414 + private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]"; +#pragma warning restore 414 + + public static Dictionary GImpacts = new Dictionary(); + + public BSShapeGImpact(BulletShape pShape) : base(pShape) + { + } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + float lod; + System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + + physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}", + prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); + + BSShapeGImpact retGImpact = null; + lock (GImpacts) + { + if (GImpacts.TryGetValue(newMeshKey, out retGImpact)) + { + // The mesh has already been created. Return a new reference to same. + retGImpact.IncrementReference(); + } + else + { + retGImpact = new BSShapeGImpact(new BulletShape()); + BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); + + // Check to see if mesh was created (might require an asset). + newShape = VerifyMeshCreated(physicsScene, newShape, prim); + newShape.shapeKey = newMeshKey; + if (!newShape.isNativeShape || prim.AssetFailed()) + { + // If a mesh was what was created, remember the built shape for later sharing. + // Also note that if meshing failed we put it in the mesh list as there is nothing + // else to do about the mesh. + GImpacts.Add(newMeshKey, retGImpact); + } + + retGImpact.physShapeInfo = newShape; + } + } + return retGImpact; + } + + private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, + PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) + { + return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, + (w, iC, i, vC, v) => + { + shapeInfo.Vertices = vC; + return physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v); + }); + } + + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) + { + BSShape ret = null; + // If the underlying shape is native, the actual shape has not been build (waiting for asset) + // and we must create a copy of the native shape since they are never shared. + if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) + { + // TODO: decide when the native shapes should be freed. Check in Dereference? + ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + } + else + { + // Another reference to this shape is just counted. + IncrementReference(); + ret = this; + } + return ret; + } + // Dereferencing a compound shape releases the hold on all the child shapes. + public override void Dereference(BSScene physicsScene) + { + lock (GImpacts) + { + this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this); + // TODO: schedule aging and destruction of unused meshes. + } + } + // Loop through all the known hulls and return the description based on the physical address. + public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull) + { + bool ret = false; + BSShapeGImpact foundDesc = null; + lock (GImpacts) + { + foreach (BSShapeGImpact sh in GImpacts.Values) + { + if (sh.physShapeInfo.ReferenceSame(pShape)) + { + foundDesc = sh; + ret = true; + break; + } + + } + } + outHull = foundDesc; + return ret; + } +} + +// ============================================================================================================ +// BSShapeAvatar is a specialized mesh shape for avatars. +public class BSShapeAvatar : BSShape +{ +#pragma warning disable 414 + private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; +#pragma warning restore 414 + + public BSShapeAvatar() + : base() + { + } + public static BSShape GetReference(BSPhysObject prim) + { + return new BSShapeNull(); + } + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) + { + return new BSShapeNull(); + } + public override void Dereference(BSScene physicsScene) { } + + // From the front: + // A---A + // / \ + // B-------B + // / \ +Z + // C-----------C | + // \ / -Y --+-- +Y + // \ / | + // \ / -Z + // D-----D + // \ / + // E-E + + // From the top A and E are just lines. + // B, C and D are hexagons: + // + // C1--C2 +X + // / \ | + // C0 C3 -Y --+-- +Y + // \ / | + // C5--C4 -X + + // Zero goes directly through the middle so the offsets are from that middle axis + // and up and down from a middle horizon (A and E are the same distance from the zero). + // The height, width and depth is one. All scaling is done by the simulator. + + // Z component -- how far the level is from the middle zero + private const float Aup = 0.5f; + private const float Bup = 0.4f; + private const float Cup = 0.3f; + private const float Dup = -0.4f; + private const float Eup = -0.5f; + + // Y component -- distance from center to x0 and x3 + private const float Awid = 0.25f; + private const float Bwid = 0.3f; + private const float Cwid = 0.5f; + private const float Dwid = 0.3f; + private const float Ewid = 0.2f; + + // Y component -- distance from center to x1, x2, x4 and x5 + private const float Afwid = 0.0f; + private const float Bfwid = 0.2f; + private const float Cfwid = 0.4f; + private const float Dfwid = 0.2f; + private const float Efwid = 0.0f; + + // X component -- distance from zero to the front or back of a level + private const float Adep = 0f; + private const float Bdep = 0.3f; + private const float Cdep = 0.5f; + private const float Ddep = 0.2f; + private const float Edep = 0f; + + private OMV.Vector3[] avatarVertices = { + new OMV.Vector3( 0.0f, -Awid, Aup), // A0 + new OMV.Vector3( 0.0f, +Awid, Aup), // A3 + + new OMV.Vector3( 0.0f, -Bwid, Bup), // B0 + new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1 + new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2 + new OMV.Vector3( 0.0f, +Bwid, Bup), // B3 + new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4 + new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5 + + new OMV.Vector3( 0.0f, -Cwid, Cup), // C0 + new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1 + new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2 + new OMV.Vector3( 0.0f, +Cwid, Cup), // C3 + new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4 + new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5 + + new OMV.Vector3( 0.0f, -Dwid, Dup), // D0 + new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1 + new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2 + new OMV.Vector3( 0.0f, +Dwid, Dup), // D3 + new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4 + new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5 + + new OMV.Vector3( 0.0f, -Ewid, Eup), // E0 + new OMV.Vector3( 0.0f, +Ewid, Eup), // E3 + }; + + // Offsets of the vertices in the vertices array + private enum Ind : int + { + A0, A3, + B0, B1, B2, B3, B4, B5, + C0, C1, C2, C3, C4, C5, + D0, D1, D2, D3, D4, D5, + E0, E3 + } + + // Comments specify trianges and quads in clockwise direction + private Ind[] avatarIndices = { + Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1 + Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3 + Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3 + Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4 + Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0 + Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0 + + Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1 + Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2 + Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3 + Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4 + Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5 + Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0 + + Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1 + Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2 + Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3 + Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4 + Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5 + Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0 + + Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1 + Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3 + Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3 + Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4 + Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0 + Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0 + + }; + +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs new file mode 100755 index 0000000..42fc11b --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs @@ -0,0 +1,169 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; + +using OpenSim.Framework; +using OpenSim.Region.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +using Nini.Config; +using log4net; + +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public sealed class BSTerrainHeightmap : BSTerrainPhys +{ + static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; + + BulletHMapInfo m_mapInfo = null; + + // Constructor to build a default, flat heightmap terrain. + public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) + : base(physicsScene, regionBase, id) + { + Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE); + Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION); + int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; + float[] initialMap = new float[totalHeights]; + for (int ii = 0; ii < totalHeights; ii++) + { + initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; + } + m_mapInfo = new BulletHMapInfo(id, initialMap, regionSize.X, regionSize.Y); + m_mapInfo.minCoords = minTerrainCoords; + m_mapInfo.maxCoords = maxTerrainCoords; + m_mapInfo.terrainRegionBase = TerrainBase; + // Don't have to free any previous since we just got here. + BuildHeightmapTerrain(); + } + + // This minCoords and maxCoords passed in give the size of the terrain (min and max Z + // are the high and low points of the heightmap). + public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, + Vector3 minCoords, Vector3 maxCoords) + : base(physicsScene, regionBase, id) + { + m_mapInfo = new BulletHMapInfo(id, initialMap, maxCoords.X - minCoords.X, maxCoords.Y - minCoords.Y); + m_mapInfo.minCoords = minCoords; + m_mapInfo.maxCoords = maxCoords; + m_mapInfo.minZ = minCoords.Z; + m_mapInfo.maxZ = maxCoords.Z; + m_mapInfo.terrainRegionBase = TerrainBase; + + // Don't have to free any previous since we just got here. + BuildHeightmapTerrain(); + } + + public override void Dispose() + { + ReleaseHeightMapTerrain(); + } + + // Using the information in m_mapInfo, create the physical representation of the heightmap. + private void BuildHeightmapTerrain() + { + // Create the terrain shape from the mapInfo + m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID, + new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, + m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); + + + // The terrain object initial position is at the center of the object + Vector3 centerPos; + centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f); + centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); + centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); + + m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, + m_mapInfo.ID, centerPos, Quaternion.Identity); + + // Set current terrain attributes + m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); + m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); + m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); + m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); + + m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; + + // Return the new terrain to the world of physical objects + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody); + + // redo its bounding box now that it is in the world + m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody); + + // Make it so the terrain will not move or be considered for movement. + m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); + + return; + } + + // If there is information in m_mapInfo pointing to physical structures, release same. + private void ReleaseHeightMapTerrain() + { + if (m_mapInfo != null) + { + if (m_mapInfo.terrainBody.HasPhysicalBody) + { + m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody); + // Frees both the body and the shape. + m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody); + } + } + m_mapInfo = null; + } + + // The passed position is relative to the base of the region. + public override float GetTerrainHeightAtXYZ(Vector3 pos) + { + float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; + + int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X; + try + { + ret = m_mapInfo.heightMap[mapIndex]; + } + catch + { + // Sometimes they give us wonky values of X and Y. Give a warning and return something. + m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", + LogHeader, m_mapInfo.terrainRegionBase, pos); + ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; + } + return ret; + } + + // The passed position is relative to the base of the region. + public override float GetWaterLevelAtXYZ(Vector3 pos) + { + return m_physicsScene.SimpleWaterLevel; + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs new file mode 100755 index 0000000..d11baa6 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs @@ -0,0 +1,584 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; + +using OpenSim.Framework; +using OpenSim.Region.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +using Nini.Config; +using log4net; + +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + +// The physical implementation of the terrain is wrapped in this class. +public abstract class BSTerrainPhys : IDisposable +{ + public enum TerrainImplementation + { + Heightmap = 0, + Mesh = 1 + } + + protected BSScene m_physicsScene { get; private set; } + // Base of the region in world coordinates. Coordinates inside the region are relative to this. + public Vector3 TerrainBase { get; private set; } + public uint ID { get; private set; } + + public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) + { + m_physicsScene = physicsScene; + TerrainBase = regionBase; + ID = id; + } + public abstract void Dispose(); + public abstract float GetTerrainHeightAtXYZ(Vector3 pos); + public abstract float GetWaterLevelAtXYZ(Vector3 pos); +} + +// ========================================================================================== +public sealed class BSTerrainManager : IDisposable +{ + static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; + + // These height values are fractional so the odd values will be + // noticable when debugging. + public const float HEIGHT_INITIALIZATION = 24.987f; + public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; + public const float HEIGHT_GETHEIGHT_RET = 24.765f; + public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f; + + // If the min and max height are equal, we reduce the min by this + // amount to make sure that a bounding box is built for the terrain. + public const float HEIGHT_EQUAL_FUDGE = 0.2f; + + // Until the whole simulator is changed to pass us the region size, we rely on constants. + public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); + + // The scene that I am part of + private BSScene m_physicsScene { get; set; } + + // The ground plane created to keep thing from falling to infinity. + private BulletBody m_groundPlane; + + // If doing mega-regions, if we're region zero we will be managing multiple + // region terrains since region zero does the physics for the whole mega-region. + private Dictionary m_terrains; + + // Flags used to know when to recalculate the height. + private bool m_terrainModified = false; + + // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. + // This is incremented before assigning to new region so it is the last ID allocated. + private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1; + public uint HighestTerrainID { get {return m_terrainCount; } } + + // If doing mega-regions, this holds our offset from region zero of + // the mega-regions. "parentScene" points to the PhysicsScene of region zero. + private Vector3 m_worldOffset; + // If the parent region (region 0), this is the extent of the combined regions + // relative to the origin of region zero + private Vector3 m_worldMax; + private PhysicsScene MegaRegionParentPhysicsScene { get; set; } + + public BSTerrainManager(BSScene physicsScene, Vector3 regionSize) + { + m_physicsScene = physicsScene; + DefaultRegionSize = regionSize; + + m_terrains = new Dictionary(); + + // Assume one region of default size + m_worldOffset = Vector3.Zero; + m_worldMax = new Vector3(DefaultRegionSize); + MegaRegionParentPhysicsScene = null; + } + + public void Dispose() + { + ReleaseGroundPlaneAndTerrain(); + } + + // Create the initial instance of terrain and the underlying ground plane. + // This is called from the initialization routine so we presume it is + // safe to call Bullet in real time. We hope no one is moving prims around yet. + public void CreateInitialGroundPlaneAndTerrain() + { + DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); + // The ground plane is here to catch things that are trying to drop to negative infinity + BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); + Vector3 groundPlaneAltitude = new Vector3(0f, 0f, BSParam.TerrainGroundPlane); + m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, + BSScene.GROUNDPLANE_ID, groundPlaneAltitude, Quaternion.Identity); + + // Everything collides with the ground plane. + m_groundPlane.collisionType = CollisionType.Groundplane; + + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane); + m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane); + + // Ground plane does not move + m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); + + BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); + lock (m_terrains) + { + // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. + m_terrains.Add(Vector3.Zero, initialTerrain); + } + } + + // Release all the terrain structures we might have allocated + public void ReleaseGroundPlaneAndTerrain() + { + DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); + if (m_groundPlane.HasPhysicalBody) + { + if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane)) + { + m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane); + } + m_groundPlane.Clear(); + } + + ReleaseTerrain(); + } + + // Release all the terrain we have allocated + public void ReleaseTerrain() + { + lock (m_terrains) + { + foreach (KeyValuePair kvp in m_terrains) + { + kvp.Value.Dispose(); + } + m_terrains.Clear(); + } + } + + // The simulator wants to set a new heightmap for the terrain. + public void SetTerrain(float[] heightMap) { + float[] localHeightMap = heightMap; + // If there are multiple requests for changes to the same terrain between ticks, + // only do that last one. + m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() + { + if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) + { + // If a child of a mega-region, we shouldn't have any terrain allocated for us + ReleaseGroundPlaneAndTerrain(); + // If doing the mega-prim stuff and we are the child of the zero region, + // the terrain is added to our parent + if (MegaRegionParentPhysicsScene is BSScene) + { + DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax); + ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain( + BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); + } + } + else + { + // If not doing the mega-prim thing, just change the terrain + DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); + + UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); + } + }); + } + + // Another region is calling this region and passing a terrain. + // A region that is not the mega-region root will pass its terrain to the root region so the root region + // physics engine will have all the terrains. + private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) + { + // Since we are called by another region's thread, the action must be rescheduled onto our processing thread. + m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate() + { + UpdateTerrain(id, heightMap, minCoords, maxCoords); + }); + } + + // If called for terrain has has not been previously allocated, a new terrain will be built + // based on the passed information. The 'id' should be either the terrain id or + // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. + // The latter feature is for creating child terrains for mega-regions. + // If there is an existing terrain body, a new + // terrain shape is created and added to the body. + // This call is most often used to update the heightMap and parameters of the terrain. + // (The above does suggest that some simplification/refactoring is in order.) + // Called during taint-time. + private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) + { + // Find high and low points of passed heightmap. + // The min and max passed in is usually the area objects can be in (maximum + // object height, for instance). The terrain wants the bounding box for the + // terrain so replace passed min and max Z with the actual terrain min/max Z. + float minZ = float.MaxValue; + float maxZ = float.MinValue; + foreach (float height in heightMap) + { + if (height < minZ) minZ = height; + if (height > maxZ) maxZ = height; + } + if (minZ == maxZ) + { + // If min and max are the same, reduce min a little bit so a good bounding box is created. + minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE; + } + minCoords.Z = minZ; + maxCoords.Z = maxZ; + + DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}", + BSScene.DetailLogZero, id, minCoords, maxCoords); + + Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); + + lock (m_terrains) + { + BSTerrainPhys terrainPhys; + if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) + { + // There is already a terrain in this spot. Free the old and build the new. + DetailLog("{0},BSTerrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", + BSScene.DetailLogZero, id, terrainRegionBase, minCoords, maxCoords); + + // Remove old terrain from the collection + m_terrains.Remove(terrainRegionBase); + // Release any physical memory it may be using. + terrainPhys.Dispose(); + + if (MegaRegionParentPhysicsScene == null) + { + // This terrain is not part of the mega-region scheme. Create vanilla terrain. + BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); + m_terrains.Add(terrainRegionBase, newTerrainPhys); + + m_terrainModified = true; + } + else + { + // It's possible that Combine() was called after this code was queued. + // If we are a child of combined regions, we don't create any terrain for us. + DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero); + + // Get rid of any terrain that may have been allocated for us. + ReleaseGroundPlaneAndTerrain(); + + // I hate doing this, but just bail + return; + } + } + else + { + // We don't know about this terrain so either we are creating a new terrain or + // our mega-prim child is giving us a new terrain to add to the phys world + + // if this is a child terrain, calculate a unique terrain id + uint newTerrainID = id; + if (newTerrainID >= BSScene.CHILDTERRAIN_ID) + newTerrainID = ++m_terrainCount; + + DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", + BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords); + BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); + m_terrains.Add(terrainRegionBase, newTerrainPhys); + + m_terrainModified = true; + } + } + } + + // TODO: redo terrain implementation selection to allow other base types than heightMap. + private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) + { + m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", + LogHeader, m_physicsScene.RegionName, terrainRegionBase, + (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); + BSTerrainPhys newTerrainPhys = null; + switch ((int)BSParam.TerrainImplementation) + { + case (int)BSTerrainPhys.TerrainImplementation.Heightmap: + newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id, + heightMap, minCoords, maxCoords); + break; + case (int)BSTerrainPhys.TerrainImplementation.Mesh: + newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id, + heightMap, minCoords, maxCoords); + break; + default: + m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", + LogHeader, + (int)BSParam.TerrainImplementation, + BSParam.TerrainImplementation, + m_physicsScene.RegionName, terrainRegionBase); + break; + } + return newTerrainPhys; + } + + // Return 'true' of this position is somewhere in known physical terrain space + public bool IsWithinKnownTerrain(Vector3 pos) + { + Vector3 terrainBaseXYZ; + BSTerrainPhys physTerrain; + return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); + } + + // Return a new position that is over known terrain if the position is outside our terrain. + public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos) + { + float edgeEpsilon = 0.1f; + + Vector3 ret = pPos; + + // First, base addresses are never negative so correct for that possible problem. + if (ret.X < 0f || ret.Y < 0f) + { + ret.X = Util.Clamp(ret.X, 0f, 1000000f); + ret.Y = Util.Clamp(ret.Y, 0f, 1000000f); + DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}", + BSScene.DetailLogZero, pPos, ret); + } + + // Can't do this function if we don't know about any terrain. + if (m_terrains.Count == 0) + return ret; + + int loopPrevention = 10; + Vector3 terrainBaseXYZ; + BSTerrainPhys physTerrain; + while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ)) + { + // The passed position is not within a known terrain area. + // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region. + + // Must be off the top of a region. Find an adjacent region to move into. + // The returned terrain is always 'lower'. That is, closer to <0,0>. + Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ); + + if (adjacentTerrainBase.X < terrainBaseXYZ.X) + { + // moving down into a new region in the X dimension. New position will be the max in the new base. + ret.X = adjacentTerrainBase.X + DefaultRegionSize.X - edgeEpsilon; + } + if (adjacentTerrainBase.Y < terrainBaseXYZ.Y) + { + // moving down into a new region in the X dimension. New position will be the max in the new base. + ret.Y = adjacentTerrainBase.Y + DefaultRegionSize.Y - edgeEpsilon; + } + DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}", + BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret); + + if (loopPrevention-- < 0f) + { + // The 'while' is a little dangerous so this prevents looping forever if the + // mapping of the terrains ever gets messed up (like nothing at <0,0>) or + // the list of terrains is in transition. + DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero); + break; + } + } + + return ret; + } + + // Given an X and Y, find the height of the terrain. + // Since we could be handling multiple terrains for a mega-region, + // the base of the region is calcuated assuming all regions are + // the same size and that is the default. + // Once the heightMapInfo is found, we have all the information to + // compute the offset into the array. + private float lastHeightTX = 999999f; + private float lastHeightTY = 999999f; + private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; + public float GetTerrainHeightAtXYZ(Vector3 pos) + { + float tX = pos.X; + float tY = pos.Y; + // You'd be surprized at the number of times this routine is called + // with the same parameters as last time. + if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY)) + return lastHeight; + m_terrainModified = false; + + lastHeightTX = tX; + lastHeightTY = tY; + float ret = HEIGHT_GETHEIGHT_RET; + + Vector3 terrainBaseXYZ; + BSTerrainPhys physTerrain; + if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) + { + ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ); + } + else + { + m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", + LogHeader, m_physicsScene.RegionName, tX, tY); + DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", + BSScene.DetailLogZero, pos, terrainBaseXYZ); + } + + lastHeight = ret; + return ret; + } + + public float GetWaterLevelAtXYZ(Vector3 pos) + { + float ret = WATER_HEIGHT_GETHEIGHT_RET; + + Vector3 terrainBaseXYZ; + BSTerrainPhys physTerrain; + if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) + { + ret = physTerrain.GetWaterLevelAtXYZ(pos); + } + else + { + m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", + LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret); + } + return ret; + } + + // Given an address, return 'true' of there is a description of that terrain and output + // the descriptor class and the 'base' fo the addresses therein. + private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) + { + bool ret = false; + + Vector3 terrainBaseXYZ = Vector3.Zero; + if (pos.X < 0f || pos.Y < 0f) + { + // We don't handle negative addresses so just make up a base that will not be found. + terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f); + } + else + { + int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; + int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; + terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); + } + + BSTerrainPhys physTerrain = null; + lock (m_terrains) + { + ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); + } + outTerrainBase = terrainBaseXYZ; + outPhysTerrain = physTerrain; + return ret; + } + + // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than + // this one. Usually used to return an out of bounds object to a known place. + private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase) + { + Vector3 ret = pTerrainBase; + + // Can't do this function if we don't know about any terrain. + if (m_terrains.Count == 0) + return ret; + + // Just some sanity + ret.X = Util.Clamp(ret.X, 0f, 1000000f); + ret.Y = Util.Clamp(ret.Y, 0f, 1000000f); + ret.Z = 0f; + + lock (m_terrains) + { + // Once down to the <0,0> region, we have to be done. + while (ret.X > 0f || ret.Y > 0f) + { + if (ret.X > 0f) + { + ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X); + DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret); + if (m_terrains.ContainsKey(ret)) + break; + } + if (ret.Y > 0f) + { + ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y); + DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret); + if (m_terrains.ContainsKey(ret)) + break; + } + } + } + + return ret; + } + + // Although no one seems to check this, I do support combining. + public bool SupportsCombining() + { + return true; + } + + // This routine is called two ways: + // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum + // extent of the combined regions. This is to inform the parent of the size + // of the combined regions. + // and one with 'offset' as the offset of the child region to the base region, + // 'pScene' pointing to the parent and 'extents' of zero. This informs the + // child of its relative base and new parent. + public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) + { + m_worldOffset = offset; + m_worldMax = extents; + MegaRegionParentPhysicsScene = pScene; + if (pScene != null) + { + // We are a child. + // We want m_worldMax to be the highest coordinate of our piece of terrain. + m_worldMax = offset + DefaultRegionSize; + } + DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}", + BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax); + } + + // Unhook all the combining that I know about. + public void UnCombine(PhysicsScene pScene) + { + // Just like ODE, we don't do anything yet. + DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero); + } + + + private void DetailLog(string msg, params Object[] args) + { + m_physicsScene.PhysicsLogging.Write(msg, args); + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs new file mode 100755 index 0000000..cd59b65 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs @@ -0,0 +1,440 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; + +using OpenSim.Framework; +using OpenSim.Region.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +using Nini.Config; +using log4net; + +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +public sealed class BSTerrainMesh : BSTerrainPhys +{ + static string LogHeader = "[BULLETSIM TERRAIN MESH]"; + + private float[] m_savedHeightMap; + int m_sizeX; + int m_sizeY; + + BulletShape m_terrainShape; + BulletBody m_terrainBody; + + public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) + : base(physicsScene, regionBase, id) + { + } + + public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */) + : base(physicsScene, regionBase, id) + { + } + + // Create terrain mesh from a heightmap. + public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, + Vector3 minCoords, Vector3 maxCoords) + : base(physicsScene, regionBase, id) + { + int indicesCount; + int[] indices; + int verticesCount; + float[] vertices; + + m_savedHeightMap = initialMap; + + m_sizeX = (int)(maxCoords.X - minCoords.X); + m_sizeY = (int)(maxCoords.Y - minCoords.Y); + + bool meshCreationSuccess = false; + if (BSParam.TerrainMeshMagnification == 1) + { + // If a magnification of one, use the old routine that is tried and true. + meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene, + initialMap, m_sizeX, m_sizeY, // input size + Vector3.Zero, // base for mesh + out indicesCount, out indices, out verticesCount, out vertices); + } + else + { + // Other magnifications use the newer routine + meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene, + initialMap, m_sizeX, m_sizeY, // input size + BSParam.TerrainMeshMagnification, + physicsScene.TerrainManager.DefaultRegionSize, + Vector3.Zero, // base for mesh + out indicesCount, out indices, out verticesCount, out vertices); + } + if (!meshCreationSuccess) + { + // DISASTER!! + m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); + m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); + // Something is very messed up and a crash is in our future. + return; + } + + m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", + BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length); + + m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices); + if (!m_terrainShape.HasPhysicalShape) + { + // DISASTER!! + m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); + m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); + // Something is very messed up and a crash is in our future. + return; + } + + Vector3 pos = regionBase; + Quaternion rot = Quaternion.Identity; + + m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); + if (!m_terrainBody.HasPhysicalBody) + { + // DISASTER!! + m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); + // Something is very messed up and a crash is in our future. + return; + } + physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin); + + // Set current terrain attributes + m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); + m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); + m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); + m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold); + m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); + + // Static objects are not very massive. + m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); + + // Put the new terrain to the world of physical objects + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody); + + // Redo its bounding box now that it is in the world + m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody); + + m_terrainBody.collisionType = CollisionType.Terrain; + m_terrainBody.ApplyCollisionMask(m_physicsScene); + + if (BSParam.UseSingleSidedMeshes) + { + m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); + m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); + } + + // Make it so the terrain will not move or be considered for movement. + m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); + } + + public override void Dispose() + { + if (m_terrainBody.HasPhysicalBody) + { + m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody); + // Frees both the body and the shape. + m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody); + m_terrainBody.Clear(); + m_terrainShape.Clear(); + } + } + + public override float GetTerrainHeightAtXYZ(Vector3 pos) + { + // For the moment use the saved heightmap to get the terrain height. + // TODO: raycast downward to find the true terrain below the position. + float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; + + int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X; + try + { + ret = m_savedHeightMap[mapIndex]; + } + catch + { + // Sometimes they give us wonky values of X and Y. Give a warning and return something. + m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", + LogHeader, TerrainBase, pos); + ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; + } + return ret; + } + + // The passed position is relative to the base of the region. + public override float GetWaterLevelAtXYZ(Vector3 pos) + { + return m_physicsScene.SimpleWaterLevel; + } + + // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). + // Return 'true' if successfully created. + public static bool ConvertHeightmapToMesh( BSScene physicsScene, + float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap + Vector3 extentBase, // base to be added to all vertices + out int indicesCountO, out int[] indicesO, + out int verticesCountO, out float[] verticesO) + { + bool ret = false; + + int indicesCount = 0; + int verticesCount = 0; + int[] indices = new int[0]; + float[] vertices = new float[0]; + + // Simple mesh creation which assumes magnification == 1. + // TODO: do a more general solution that scales, adds new vertices and smoothes the result. + + // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop + // from zero to <= sizeX). The triangle indices are then generated as two triangles + // per heightmap point. There are sizeX by sizeY of these squares. The extra row and + // column of vertices are used to complete the triangles of the last row and column + // of the heightmap. + try + { + // One vertice per heightmap value plus the vertices off the side and bottom edge. + int totalVertices = (sizeX + 1) * (sizeY + 1); + vertices = new float[totalVertices * 3]; + int totalIndices = sizeX * sizeY * 6; + indices = new int[totalIndices]; + + if (physicsScene != null) + physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}", + BSScene.DetailLogZero, totalVertices, totalIndices, extentBase); + float minHeight = float.MaxValue; + // Note that sizeX+1 vertices are created since there is land between this and the next region. + for (int yy = 0; yy <= sizeY; yy++) + { + for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times + { + int offset = yy * sizeX + xx; + // Extend the height with the height from the last row or column + if (yy == sizeY) offset -= sizeX; + if (xx == sizeX) offset -= 1; + float height = heightMap[offset]; + minHeight = Math.Min(minHeight, height); + vertices[verticesCount + 0] = (float)xx + extentBase.X; + vertices[verticesCount + 1] = (float)yy + extentBase.Y; + vertices[verticesCount + 2] = height + extentBase.Z; + verticesCount += 3; + } + } + verticesCount = verticesCount / 3; + + for (int yy = 0; yy < sizeY; yy++) + { + for (int xx = 0; xx < sizeX; xx++) + { + int offset = yy * (sizeX + 1) + xx; + // Each vertices is presumed to be the upper left corner of a box of two triangles + indices[indicesCount + 0] = offset; + indices[indicesCount + 1] = offset + 1; + indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column + indices[indicesCount + 3] = offset + 1; + indices[indicesCount + 4] = offset + sizeX + 2; + indices[indicesCount + 5] = offset + sizeX + 1; + indicesCount += 6; + } + } + + ret = true; + } + catch (Exception e) + { + if (physicsScene != null) + physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", + LogHeader, physicsScene.RegionName, extentBase, e); + } + + indicesCountO = indicesCount; + indicesO = indices; + verticesCountO = verticesCount; + verticesO = vertices; + + return ret; + } + + private class HeightMapGetter + { + private float[] m_heightMap; + private int m_sizeX; + private int m_sizeY; + public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY) + { + m_heightMap = pHeightMap; + m_sizeX = pSizeX; + m_sizeY = pSizeY; + } + // The heightmap is extended as an infinite plane at the last height + public float GetHeight(int xx, int yy) + { + int offset = 0; + // Extend the height with the height from the last row or column + if (yy >= m_sizeY) + if (xx >= m_sizeX) + offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1); + else + offset = (m_sizeY - 1) * m_sizeX + xx; + else + if (xx >= m_sizeX) + offset = yy * m_sizeX + (m_sizeX - 1); + else + offset = yy * m_sizeX + xx; + + return m_heightMap[offset]; + } + } + + // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). + // Version that handles magnification. + // Return 'true' if successfully created. + public static bool ConvertHeightmapToMesh2( BSScene physicsScene, + float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap + int magnification, // number of vertices per heighmap step + Vector3 extent, // dimensions of the output mesh + Vector3 extentBase, // base to be added to all vertices + out int indicesCountO, out int[] indicesO, + out int verticesCountO, out float[] verticesO) + { + bool ret = false; + + int indicesCount = 0; + int verticesCount = 0; + int[] indices = new int[0]; + float[] vertices = new float[0]; + + HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY); + + // The vertices dimension of the output mesh + int meshX = sizeX * magnification; + int meshY = sizeY * magnification; + // The output size of one mesh step + float meshXStep = extent.X / meshX; + float meshYStep = extent.Y / meshY; + + // Create an array of vertices that is meshX+1 by meshY+1 (note the loop + // from zero to <= meshX). The triangle indices are then generated as two triangles + // per heightmap point. There are meshX by meshY of these squares. The extra row and + // column of vertices are used to complete the triangles of the last row and column + // of the heightmap. + try + { + // Vertices for the output heightmap plus one on the side and bottom to complete triangles + int totalVertices = (meshX + 1) * (meshY + 1); + vertices = new float[totalVertices * 3]; + int totalIndices = meshX * meshY * 6; + indices = new int[totalIndices]; + + if (physicsScene != null) + physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}", + BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY), + totalVertices, totalIndices, extentBase); + + float minHeight = float.MaxValue; + // Note that sizeX+1 vertices are created since there is land between this and the next region. + // Loop through the output vertices and compute the mediun height in between the input vertices + for (int yy = 0; yy <= meshY; yy++) + { + for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times + { + float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point + int stepY = (int)offsetY; + float fractionalY = offsetY - (float)stepY; + float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point + int stepX = (int)offsetX; + float fractionalX = offsetX - (float)stepX; + + // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}", + // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY); + + // get the four corners of the heightmap square the mesh point is in + float heightUL = hmap.GetHeight(stepX , stepY ); + float heightUR = hmap.GetHeight(stepX + 1, stepY ); + float heightLL = hmap.GetHeight(stepX , stepY + 1); + float heightLR = hmap.GetHeight(stepX + 1, stepY + 1); + + // bilinear interplolation + float height = heightUL * (1 - fractionalX) * (1 - fractionalY) + + heightUR * fractionalX * (1 - fractionalY) + + heightLL * (1 - fractionalX) * fractionalY + + heightLR * fractionalX * fractionalY; + + // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}", + // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height); + + minHeight = Math.Min(minHeight, height); + + vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X; + vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y; + vertices[verticesCount + 2] = height + extentBase.Z; + verticesCount += 3; + } + } + // The number of vertices generated + verticesCount /= 3; + + // Loop through all the heightmap squares and create indices for the two triangles for that square + for (int yy = 0; yy < meshY; yy++) + { + for (int xx = 0; xx < meshX; xx++) + { + int offset = yy * (meshX + 1) + xx; + // Each vertices is presumed to be the upper left corner of a box of two triangles + indices[indicesCount + 0] = offset; + indices[indicesCount + 1] = offset + 1; + indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column + indices[indicesCount + 3] = offset + 1; + indices[indicesCount + 4] = offset + meshX + 2; + indices[indicesCount + 5] = offset + meshX + 1; + indicesCount += 6; + } + } + + ret = true; + } + catch (Exception e) + { + if (physicsScene != null) + physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", + LogHeader, physicsScene.RegionName, extentBase, e); + } + + indicesCountO = indicesCount; + indicesO = indices; + verticesCountO = verticesCount; + verticesO = vertices; + + return ret; + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs new file mode 100755 index 0000000..3329395 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs @@ -0,0 +1,277 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; +using OMV = OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ +// Classes to allow some type checking for the API +// These hold pointers to allocated objects in the unmanaged space. +// These classes are subclassed by the various physical implementations of +// objects. In particular, there is a version for physical instances in +// unmanaged memory ("unman") and one for in managed memory ("XNA"). + +// Currently, the instances of these classes are a reference to a +// physical representation and this has no releationship to other +// instances. Someday, refarb the usage of these classes so each instance +// refers to a particular physical instance and this class controls reference +// counts and such. This should be done along with adding BSShapes. + +public class BulletWorld +{ + public BulletWorld(uint worldId, BSScene bss) + { + worldID = worldId; + physicsScene = bss; + } + public uint worldID; + // The scene is only in here so very low level routines have a handle to print debug/error messages + public BSScene physicsScene; +} + +// An allocated Bullet btRigidBody +public class BulletBody +{ + public BulletBody(uint id) + { + ID = id; + collisionType = CollisionType.Static; + } + public uint ID; + public CollisionType collisionType; + + public virtual void Clear() { } + public virtual bool HasPhysicalBody { get { return false; } } + + // Apply the specificed collision mask into the physical world + public virtual bool ApplyCollisionMask(BSScene physicsScene) + { + // Should assert the body has been added to the physical world. + // (The collision masks are stored in the collision proxy cache which only exists for + // a collision body that is in the world.) + return physicsScene.PE.SetCollisionGroupMask(this, + BulletSimData.CollisionTypeMasks[collisionType].group, + BulletSimData.CollisionTypeMasks[collisionType].mask); + } + + // Used for log messages for a unique display of the memory/object allocated to this instance + public virtual string AddrString + { + get { return "unknown"; } + } + + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + buff.Append(""); + return buff.ToString(); + } +} + +public class BulletShape +{ + public BulletShape() + { + shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN; + shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; + isNativeShape = false; + } + public BSPhysicsShapeType shapeType; + public System.UInt64 shapeKey; + public bool isNativeShape; + + public virtual void Clear() { } + public virtual bool HasPhysicalShape { get { return false; } } + + // Make another reference to this physical object. + public virtual BulletShape Clone() { return new BulletShape(); } + + // Return 'true' if this and other refer to the same physical object + public virtual bool ReferenceSame(BulletShape xx) { return false; } + + // Used for log messages for a unique display of the memory/object allocated to this instance + public virtual string AddrString + { + get { return "unknown"; } + } + + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + buff.Append(""); + return buff.ToString(); + } +} + +// An allocated Bullet btConstraint +public class BulletConstraint +{ + public BulletConstraint() + { + } + public virtual void Clear() { } + public virtual bool HasPhysicalConstraint { get { return false; } } + + // Used for log messages for a unique display of the memory/object allocated to this instance + public virtual string AddrString + { + get { return "unknown"; } + } +} + +// An allocated HeightMapThing which holds various heightmap info. +// Made a class rather than a struct so there would be only one +// instance of this and C# will pass around pointers rather +// than making copies. +public class BulletHMapInfo +{ + public BulletHMapInfo(uint id, float[] hm, float pSizeX, float pSizeY) { + ID = id; + heightMap = hm; + terrainRegionBase = OMV.Vector3.Zero; + minCoords = new OMV.Vector3(100f, 100f, 25f); + maxCoords = new OMV.Vector3(101f, 101f, 26f); + minZ = maxZ = 0f; + sizeX = pSizeX; + sizeY = pSizeY; + } + public uint ID; + public float[] heightMap; + public OMV.Vector3 terrainRegionBase; + public OMV.Vector3 minCoords; + public OMV.Vector3 maxCoords; + public float sizeX, sizeY; + public float minZ, maxZ; + public BulletShape terrainShape; + public BulletBody terrainBody; +} + +// The general class of collsion object. +public enum CollisionType +{ + Avatar, + PhantomToOthersAvatar, // An avatar that it phantom to other avatars but not to anything else + Groundplane, + Terrain, + Static, + Dynamic, + VolumeDetect, + // Linkset, // A linkset should be either Static or Dynamic + LinksetChild, + Unknown +}; + +// Hold specification of group and mask collision flags for a CollisionType +public struct CollisionTypeFilterGroup +{ + public CollisionTypeFilterGroup(CollisionType t, uint g, uint m) + { + type = t; + group = g; + mask = m; + } + public CollisionType type; + public uint group; + public uint mask; +}; + +public static class BulletSimData +{ + +// Map of collisionTypes to flags for collision groups and masks. +// An object's 'group' is the collison groups this object belongs to +// An object's 'filter' is the groups another object has to belong to in order to collide with me +// A collision happens if ((obj1.group & obj2.filter) != 0) || ((obj2.group & obj1.filter) != 0) +// +// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code +// but, instead, use references to this dictionary. Finding and debugging +// collision flag problems will be made easier. +public static Dictionary CollisionTypeMasks + = new Dictionary() +{ + { CollisionType.Avatar, + new CollisionTypeFilterGroup(CollisionType.Avatar, + (uint)CollisionFilterGroups.BCharacterGroup, + (uint)(CollisionFilterGroups.BAllGroup)) + }, + { CollisionType.PhantomToOthersAvatar, + new CollisionTypeFilterGroup(CollisionType.PhantomToOthersAvatar, + (uint)CollisionFilterGroups.BCharacterGroup, + (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BCharacterGroup)) + }, + { CollisionType.Groundplane, + new CollisionTypeFilterGroup(CollisionType.Groundplane, + (uint)CollisionFilterGroups.BGroundPlaneGroup, + // (uint)CollisionFilterGroups.BAllGroup) + (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) + }, + { CollisionType.Terrain, + new CollisionTypeFilterGroup(CollisionType.Terrain, + (uint)CollisionFilterGroups.BTerrainGroup, + (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) + }, + { CollisionType.Static, + new CollisionTypeFilterGroup(CollisionType.Static, + (uint)CollisionFilterGroups.BStaticGroup, + (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) + }, + { CollisionType.Dynamic, + new CollisionTypeFilterGroup(CollisionType.Dynamic, + (uint)CollisionFilterGroups.BSolidGroup, + (uint)(CollisionFilterGroups.BAllGroup)) + }, + { CollisionType.VolumeDetect, + new CollisionTypeFilterGroup(CollisionType.VolumeDetect, + (uint)CollisionFilterGroups.BSensorTrigger, + (uint)(~CollisionFilterGroups.BSensorTrigger)) + }, + { CollisionType.LinksetChild, + new CollisionTypeFilterGroup(CollisionType.LinksetChild, + (uint)CollisionFilterGroups.BLinksetChildGroup, + (uint)(CollisionFilterGroups.BNoneGroup)) + // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) + }, +}; + +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt b/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt new file mode 100755 index 0000000..0453376 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt @@ -0,0 +1,379 @@ +CURRENT PROBLEMS TO FIX AND/OR LOOK AT +================================================= +Vehicle buoyancy. Computed correctly? Possibly creating very large effective mass. + Interaction of llSetBuoyancy and vehicle buoyancy. Should be additive? + Negative buoyancy computed correctly +Center-of-gravity +Computation of mesh mass. How done? How should it be done? +Enable vehicle border crossings (at least as poorly as ODE) + Terrain skirts + Avatar created in previous region and not new region when crossing border + Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) +User settable terrain mesh + Allow specifying as convex or concave and use different getHeight functions depending +Boats, when turning nose down into the water + Acts like rotation around Z is also effecting rotation around X and Y +Deleting a linkset while standing on the root will leave the physical shape of the root behind. + Not sure if it is because standing on it. Done with large prim linksets. +Linkset child rotations. + Nebadon spiral tube has middle sections which are rotated wrong. + Select linked spiral tube. Delink and note where the middle section ends up. +Teravus llMoveToTarget script debug + Mixing of hover, buoyancy/gravity, moveToTarget, into one force + Setting hover height to zero disables hover even if hover flags are on (from SL wiki) +limitMotorUp calibration (more down?) +llRotLookAt +llLookAt +Convert to avatar mesh capsule. Include rotation of capsule. +Vehicle script tuning/debugging + Avanti speed script + Weapon shooter script +Move material definitions (friction, ...) into simulator. +osGetPhysicsEngineVerion() and create a version code for the C++ DLL +One sided meshes? Should terrain be built into a closed shape? + When meshes get partially wedged into the terrain, they cannot push themselves out. + It is possible that Bullet processes collisions whether entering or leaving a mesh. + Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869 +Small physical objects do not interact correctly + Create chain of .5x.5x.1 torui and make all but top physical so to hang. + The chain will fall apart and pairs will dance around on ground + Chains of 1x1x.2 will stay connected but will dance. + Chains above 2x2x.4 are more stable and get stablier as torui get larger. + +VEHICLES TODO LIST: +================================================= +LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers. + What are the limits in SL? + Same for other velocity settings. +UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims: + https://github.com/UbitUmarov/Ubit-opensim +Some vehicles should not be able to turn if no speed or off ground. +Cannot edit/move a vehicle being ridden: it jumps back to the origional position. +Neb car jiggling left and right + Happens on terrain and any other mesh object. Flat cubes are much smoother. + This has been reduced but not eliminated. +Implement referenceFrame for all the motion routines. +Verify llGetVel() is returning a smooth and good value for vehicle movement. +llGetVel() should return the root's velocity if requested in a child prim. +Implement function efficiency for lineaar and angular motion. +Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) +Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). + A kludge that isn't fixing the real problem of Bullet adding extra motion. +Incorporate inter-relationship of angular corrections. For instance, angularDeflection + and angularMotorUp will compute same X or Y correction. When added together + creates over-correction and over-shoot and wabbling. +Vehicle attributes are not restored when a vehicle is rezzed on region creation + Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized. +What to do if vehicle and prim buoyancy differ? + +GENERAL TODO LIST: +================================================= +Resitution of a prim works on another prim but not on terrain. + The dropped prim doesn't bounce properly on the terrain. +Add a sanity check for PIDTarget location. +Level-of-detail for mesh creation. Prims with circular interiors require lod of 32. + Is much saved with lower LODs? At the moment, all set to 32. +Collisions are inconsistant: arrows are supposed to hit and report collision. Often don't. + If arrow show at prim, collision reported about 1/3 of time. If collision reported, + both arrow and prim report it. The arrow bounces off the prim 9 out of 10 times. + Shooting 5m sphere "arrows" at 60m/s. +llMoveToTarget objects are not effected by gravity until target is removed. +Compute CCD parameters based on body size +Can solver iterations be changed per body/shape? Can be for constraints but what + about regular vehicles? +Implement llSetPhysicalMaterial. + extend it with Center-of-mass, rolling friction, density +Implement llSetForceAndTorque. +Change BSPrim.moveToTarget to used forces rather than changing position + Changing position allows one to move through walls +Implement an avatar mesh shape. The Bullet capsule is way too limited. + Consider just hand creating a vertex/index array in a new BSShapeAvatar. +Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain. +Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. +Duplicating a physical prim causes old prim to jump away + Dup a phys prim and the original become unselected and thus interacts w/ selected prim. +Scenes with hundred of thousands of static objects take a lot of physics CPU time. +Gun sending shooter flying. +Collision margin (gap between physical objects lying on each other) +Boundry checking (crashes related to crossing boundry) + Add check for border edge position for avatars and objects. + Verify the events are created for border crossings. +Implement ShapeCollection.Dispose() +Implement water as a plain or mesh so raycasting and collisions can happen with same. +Add collision penetration return + Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance() +Linkset.Position and Linkset.Orientation requre rewrite to properly return + child position. LinksetConstraint acts like it's at taint time!! +Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F) +Should the different PID factors have non-equal contributions for different + values of Efficiency? +Selecting and deselecting physical objects causes CPU processing time to jump + http://www.youtube.com/watch?v=Hjg57fWg8yI&hd=1 + put thousand physical objects, select and deselect same. CPU time will be large. +Re-implement buoyancy as a separate force on the object rather than diddling gravity. + Register a pre-step event to add the force. +More efficient memory usage when passing hull information from BSPrim to BulletSim +Physical and phantom will drop through the terrain + + +LINKSETS +====================================================== +Child prims do not report collisions +Allow children of a linkset to be phantom: + http://opensim-dev.2196679.n2.nabble.com/Setting-a-single-child-prim-to-Phantom-tp7578513.html + Add OS_STATUS_PHANTOM_PRIM to llSetLinkPrimitaveParamsFast. +Editing a child of a linkset causes the child to go phantom + Move a child prim once when it is physical and can never move it again without it going phantom +Offset the center of the linkset to be the geometric center of all the prims + Not quite the same as the center-of-gravity +Linksets should allow collisions to individual children + Add LocalID to children shapes in LinksetCompound and create events for individuals +LinksetCompound: when one of the children changes orientation (like tires + turning on a vehicle, the whole compound object is rebuilt. Optimize this + so orientation/position of individual children can change without a rebuild. +Verify/think through scripts in children of linksets. What do they reference + and return when getting position, velocity, ... +Confirm constraint linksets still work after making all the changes for compound linksets. +Use PostTaint callback to do rebuilds for constraint linksets to reduce rebuilding +Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt. + For compound linksets, add ability to remove or reposition individual child shapes. +Speed up creation of large physical linksets + For instance, sitting in Neb's car (130 prims) takes several seconds to become physical. + REALLY bad for very large physical linksets (freezes the sim for many seconds). +Eliminate collisions between objects in a linkset. (LinksetConstraint) + Have UserPointer point to struct with localID and linksetID? + Objects in original linkset still collide with each other? + +MORE +====================================================== +Compute avatar size and scale correctly. Now it is a bit off from the capsule size. +Create tests for different interface components + Have test objects/scripts measure themselves and turn color if correct/bad + Test functions in SL and calibrate correctness there + Create auto rezzer and tracker to run through the tests +Do we need to do convex hulls all the time? Can complex meshes be left meshes? + There is some problem with meshes and collisions + Hulls are not as detailed as meshes. Hulled vehicles insides are different shape. +Debounce avatar contact so legs don't keep folding up when standing. +Add border extensions to terrain to help region crossings and objects leaving region. +Use a different capsule shape for avatar when sitting + LL uses a pyrimidal shape scaled by the avatar's bounding box + http://wiki.secondlife.com/wiki/File:Avmeshforms.png +Performance test with lots of avatars. Can BulletSim support a thousand? +Optimize collisions in C++: only send up to the object subscribed to collisions. + Use collision subscription and remove the collsion(A,B) and collision(B,A) +Check whether SimMotionState needs large if statement (see TODO). +Implement 'top colliders' info. +Avatar jump +Performance measurement and changes to make quicker. +Implement detailed physics stats (GetStats()). +Measure performance improvement from hulls +Test not using ghost objects for volume detect implementation. +Performance of closures and delegates for taint processing + Are there faster ways? + Is any slowdown introduced by the existing implementation significant? +Is there are more efficient method of implementing pre and post step actions? + See http://www.codeproject.com/Articles/29922/Weak-Events-in-C +Physics Arena central pyramid: why is one side permiable? +In SL, perfect spheres don't seem to have rolling friction. Add special case. +Enforce physical parameter min/max: + Gravity: [-1, 28] + Friction: [0, 255] + Density: [1, 22587] + Restitution [0, 1] + http://wiki.secondlife.com/wiki/Physics_Material_Settings_test +Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html +Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale.html + +INTERNAL IMPROVEMENT/CLEANUP +================================================= +Create the physical wrapper classes (BulletBody, BulletShape) by methods on + BSAPITemplate and make their actual implementation Bullet engine specific. + For the short term, just call the existing functions in ShapeCollection. +Consider moving prim/character body and shape destruction in destroy() + to postTimeTime rather than protecting all the potential sets that + might have been queued up. +Remove unused fields from ShapeData (not used in API2) +Remove unused fields from pinned memory shared parameter block + Create parameter variables in BSScene to replace same. +Breakout code for mesh/hull/compound/native into separate BSShape* classes + Standardize access to building and reference code. + The skeleton classes are in the sources but are not complete or linked in. +Make BSBody and BSShape real classes to centralize creation/changin/destruction + Convert state and parameter calls from BulletSimAPI direct calls to + calls on BSBody and BSShape +Generalize Dynamics and PID with standardized motors. +Generalize Linkset and vehicles into PropertyManagers + Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies + Potentially add events for shape destruction, etc. +Better mechanism for resetting linkset set and vehicle parameters when body rebuilt. + BSPrim.CreateGeomAndObject is kludgy with the callbacks, etc. +Implement linkset by setting position of children when root updated. (LinksetManual) + Linkset implementation using manual prim movement. +LinkablePrim class? Would that simplify/centralize the linkset logic? +BSScene.UpdateParameterSet() is broken. How to set params on objects? +Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will + bob at the water level. BSPrim.PositionSanityCheck() +Should taints check for existance or activeness of target? + When destroying linksets/etc, taints can be generated for objects that are + actually gone when the taint happens. Crashes don't happen because the taint closure + keeps the object from being freed, but that is just an accident. + Possibly have an 'active' flag that is checked by the taint processor? +Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones) +Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'? +There are TOO MANY interfaces from BulletSim core to Bullet itself + Think of something to eliminate one or more of the layers + +THREADING +================================================= +Do taint action immediately if not actually executing Bullet. + Add lock around Bullet execution and just do taint actions if simulation is not happening. + +DONE DONE DONE DONE +================================================= +Cleanup code in BSDynamics by using motors. (Resolution: started) +Consider implementing terrain with a mesh rather than heightmap. (Resolution: done) + Would have better and adjustable resolution. +Build terrain mesh so heighmap is height of the center of the square meter. + Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional. +Terrain as mesh. (Resolution: done) +How are static linksets seen by the physics engine? + Resolution: they are not linked in physics. When moved, all the children are repositioned. +Convert BSCharacter to use all API2 (Resolution: done) +Avatar pushing difficult (too heavy?) +Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done) +Remove old code in DLL (all non-API2 stuff). (Resolution: done) +Measurements of mega-physical prim performance (with graph) (Resolution: done, email) +Debug Bullet internal stats output (why is timing all wrong?) + Resolution: Bullet stats logging only works with a single instance of Bullet (one region). +Implement meshes or just verify that they work. (Resolution: they do!) +Do prim hash codes work for sculpties and meshes? (Resolution: yes) +Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound) + Compound shapes will need the LocalID in the shapes and collision + processing to get it from there. +Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.) +Package Bullet source mods for Bullet internal stats output + (Resolution: move code into WorldData.h rather than relying on patches) +Single prim vehicles don't seem to properly vehiclize. + (Resolution: mass was not getting set properly for single prim linksets) +Add material type linkage and input all the material property definitions. + Skeleton classes and table are in the sources but are not filled or used. + (Resolution: +Neb vehicle taking > 25ms of physics time!! + (Resolution: compound linksets were being rebuild WAY too often) +Avatar height off after unsitting (floats off ground) + Editting appearance then moving restores. + Must not be initializing height when recreating capsule after unsit. + (Resolution: confusion of scale vs size for native objects removed) +Light cycle falling over when driving (Resolution: implemented angularMotorUp) +Should vehicle angular/linear movement friction happen after all the components + or does it only apply to the basic movement? + (Resolution: friction added before returning newly computed motor value. + What is expected by some vehicles (turning up friction to moderate speed)) +Tune terrain/object friction to be closer to SL. + (Resolution: added material type with friction and resolution) +Smooth avatar movement with motor (DONE) + Should motor update be all at taint-time? (Yes, DONE) + Fix avatar slowly sliding when standing (zero motion when stopped) (DONE) + (Resolution: added BSVMotor for avatar starting and stopping) +llApplyImpulse() + Compare mass/movement in OS and SL. Calibrate actions. (DONE) + (Resolution: tested on SL and OS. AddForce scales the force for timestep) +llSetBuoyancy() (DONE) + (Resolution: Bullet resets object gravity when added to world. Moved set gravity) +Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE) + (Resolution: set default density to 3.5 (from 60) which is closer to SL) +Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE) + (Resolution: added BSAPITemplate and then interfaces for C++ Bullet and C# BulletXNA +Meshes rendering as bounding boxes (DONE) + (Resolution: Added test for mesh/sculpties in native shapes so it didn't think it was a box) +llMoveToTarget (Resolution: added simple motor to update the position.) +Angular motor direction is global coordinates rather than local coordinates (DONE) +Add vehicle collisions so IsColliding is properly reported. (DONE) + Needed for banking, limitMotorUp, movementLimiting, ... + (Resolution: added CollisionFlags.BS_VEHICLE_COLLISION and code to use it) +VehicleAddForce is not scaled by the simulation step but it is only + applied for one step. Should it be scaled? (DONE) + (Resolution: use force for timed things, Impulse for immediate, non-timed things) +Complete implemention of preStepActions (DONE) + Replace vehicle step call with prestep event. + Is there a need for postStepActions? postStepTaints? +Disable activity of passive linkset children. (DONE) + Since the linkset is a compound object, the old prims are left lying + around and need to be phantomized so they don't collide, ... +Remove HeightmapInfo from terrain specification (DONE) + Since C++ code does not need terrain height, this structure et al are not needed. +Surfboard go wonky when turning (DONE) + Angular motor direction is global coordinates rather than local coordinates? + (Resolution: made angular motor direction correct coordinate system) +Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 (DONE) + Msg Kayaker on OSGrid when working + (Resolution: LINEAR_DIRECTION is in vehicle coords. Test script does the + same in SL as in OS/BulletSim) +Boats float low in the water (DONE) +Boats floating at proper level (DONE) +When is force introduced by SetForce removed? The prestep action could go forever. (DONE) + (Resolution: setForce registers a prestep action which keeps applying the force) +Child movement in linkset (don't rebuild linkset) (DONE 20130122)) +Avatar standing on a moving object should start to move with the object. (DONE 20130125) +Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. + Verify that angular motion specified around Z moves in the vehicle coordinates. + DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. +Nebadon vehicles turning funny in arena (DONE) +Lock axis (DONE 20130401) +Terrain detail: double terrain mesh detail (DONE) +Use the HACD convex hull routine in Bullet rather than the C# version. + Speed up hullifying large meshes. (DONE) +Vehicle ride, get up, ride again. Second time vehicle does not act correctly. + Have to rez new vehicle and delete the old to fix situation. + (DONE 20130520: normalize rotations) +Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd + position state where it will not settle onto ground properly, etc + (DONE 20130520: normalize rotations) +Two of Nebadon vehicles in a sim max the CPU. This is new. + (DONE 20130520: two problems: if asset failed to mesh, constantly refetched + asset; vehicle was sending too many messages to all linkset members) +Add material densities to the material types. (WILL NOT BE DONE: not how it is done) +Avatars walking up stairs (DONE) +Avatar movement + flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) + walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE) + avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) +After getting off a vehicle, the root prim is phantom (can be walked through) + Need to force a position update for the root prim after compound shape destruction + (DONE) +Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects. + Regular triangle meshes don't do physical collisions. + (DONE: discovered GImpact is VERY CPU intensive) +Script changing rotation of child prim while vehicle moving (eg turning wheel) causes + the wheel to appear to jump back. Looks like sending position from previous update. + (DONE: redo of compound linksets fixed problem) +Refarb compound linkset creation to create a pseudo-root for center-of-mass + Let children change their shape to physical indendently and just add shapes to compound + (DONE: redo of compound linkset fixed problem) +Vehicle angular vertical attraction (DONE: vegaslon code) +vehicle angular banking (DONE: vegaslon code) +Vehicle angular deflection (DONE: vegaslon code) + Preferred orientation angular correction fix +Vehicles (Move smoothly) +For limitMotorUp, use raycast down to find if vehicle is in the air. + (WILL NOT BE DONE: gravity does the job well enough) +BSPrim.Force should set a continious force on the prim. The force should be + applied each tick. Some limits? + (DONE: added physical actors. Implemented SetForce, SetTorque, ...) +Implement LSL physics controls. Like STATUS_ROTATE_X. (DONE) +Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE +Avatar rotation (check out changes to ScenePresence for physical rotation) (DONE) +Avatar running (what does phys engine need to do?) (DONE: multiplies run factor by walking force) +setForce should set a constant force. Different than AddImpulse. (DONE) +Add PID motor for avatar movement (slow to stop, ...) (WNBD: current works ok) +Avatar movement motor check for zero or small movement. Somehow suppress small movements + when avatar has stopped and is just standing. Simple test for near zero has + the problem of preventing starting up (increase from zero) especially when falling. + (DONE: avatar movement actor knows if standing on stationary object and zeros motion) +Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to + BSScene.TaintedObject() could immediately execute the callback if already in taint time. + (DONE) + + + diff --git a/OpenSim/Region/PhysicsModules/BulletS/ExtendedPhysics.cs b/OpenSim/Region/PhysicsModules/BulletS/ExtendedPhysics.cs new file mode 100755 index 0000000..2ba3c5a --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/ExtendedPhysics.cs @@ -0,0 +1,622 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; + +using OpenSim.Framework; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.PhysicsModules.SharedBase; + +using Mono.Addins; +using Nini.Config; +using log4net; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] + public class ExtendedPhysics : INonSharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static string LogHeader = "[EXTENDED PHYSICS]"; + + // ============================================================= + // Since BulletSim is a plugin, this these values aren't defined easily in one place. + // This table must correspond to an identical table in BSScene. + + // Per scene functions. See BSScene. + + // Per avatar functions. See BSCharacter. + + // Per prim functions. See BSPrim. + public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType"; + public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType"; + public const string PhysFunctChangeLinkFixed = "BulletSim.ChangeLinkFixed"; + public const string PhysFunctChangeLinkType = "BulletSim.ChangeLinkType"; + public const string PhysFunctGetLinkType = "BulletSim.GetLinkType"; + public const string PhysFunctChangeLinkParams = "BulletSim.ChangeLinkParams"; + public const string PhysFunctAxisLockLimits = "BulletSim.AxisLockLimits"; + + // ============================================================= + + private IConfig Configuration { get; set; } + private bool Enabled { get; set; } + private Scene BaseScene { get; set; } + private IScriptModuleComms Comms { get; set; } + + #region INonSharedRegionModule + + public string Name { get { return this.GetType().Name; } } + + public void Initialise(IConfigSource config) + { + BaseScene = null; + Enabled = false; + Configuration = null; + Comms = null; + + try + { + if ((Configuration = config.Configs["ExtendedPhysics"]) != null) + { + Enabled = Configuration.GetBoolean("Enabled", Enabled); + } + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Initialization error: {0}", LogHeader, e); + } + + m_log.InfoFormat("{0} module {1} enabled", LogHeader, (Enabled ? "is" : "is not")); + } + + public void Close() + { + if (BaseScene != null) + { + BaseScene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; + BaseScene.EventManager.OnSceneObjectPartUpdated -= EventManager_OnSceneObjectPartUpdated; + BaseScene = null; + } + } + + public void AddRegion(Scene scene) + { + } + + public void RemoveRegion(Scene scene) + { + if (BaseScene != null && BaseScene == scene) + { + Close(); + } + } + + public void RegionLoaded(Scene scene) + { + if (!Enabled) return; + + BaseScene = scene; + + Comms = BaseScene.RequestModuleInterface(); + if (Comms == null) + { + m_log.WarnFormat("{0} ScriptModuleComms interface not defined", LogHeader); + Enabled = false; + + return; + } + + // Register as LSL functions all the [ScriptInvocation] marked methods. + Comms.RegisterScriptInvocations(this); + Comms.RegisterConstants(this); + + // When an object is modified, we might need to update its extended physics parameters + BaseScene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene; + BaseScene.EventManager.OnSceneObjectPartUpdated += EventManager_OnSceneObjectPartUpdated; + + } + + public Type ReplaceableInterface { get { return null; } } + + #endregion // INonSharedRegionModule + + private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) + { + } + + // Event generated when some property of a prim changes. + private void EventManager_OnSceneObjectPartUpdated(SceneObjectPart sop, bool isFullUpdate) + { + } + + [ScriptConstant] + public const int PHYS_CENTER_OF_MASS = 1 << 0; + + [ScriptInvocation] + public string physGetEngineType(UUID hostID, UUID scriptID) + { + string ret = string.Empty; + + if (BaseScene.PhysicsScene != null) + { + ret = BaseScene.PhysicsScene.EngineType; + } + + return ret; + } + + // Code for specifying params. + // The choice if 14700 is arbitrary and only serves to catch parameter code misuse. + [ScriptConstant] + public const int PHYS_AXIS_LOCK_LINEAR = 14700; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_LINEAR_X = 14701; + [ScriptConstant] + public const int PHYS_AXIS_LIMIT_LINEAR_X = 14702; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_LINEAR_Y = 14703; + [ScriptConstant] + public const int PHYS_AXIS_LIMIT_LINEAR_Y = 14704; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_LINEAR_Z = 14705; + [ScriptConstant] + public const int PHYS_AXIS_LIMIT_LINEAR_Z = 14706; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_ANGULAR = 14707; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_ANGULAR_X = 14708; + [ScriptConstant] + public const int PHYS_AXIS_LIMIT_ANGULAR_X = 14709; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_ANGULAR_Y = 14710; + [ScriptConstant] + public const int PHYS_AXIS_LIMIT_ANGULAR_Y = 14711; + [ScriptConstant] + public const int PHYS_AXIS_LOCK_ANGULAR_Z = 14712; + [ScriptConstant] + public const int PHYS_AXIS_LIMIT_ANGULAR_Z = 14713; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_LINEAR = 14714; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_LINEAR_X = 14715; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_LINEAR_Y = 14716; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_LINEAR_Z = 14717; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_ANGULAR = 14718; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_ANGULAR_X = 14719; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_ANGULAR_Y = 14720; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK_ANGULAR_Z = 14721; + [ScriptConstant] + public const int PHYS_AXIS_UNLOCK = 14722; + // physAxisLockLimits() + [ScriptInvocation] + public int physAxisLock(UUID hostID, UUID scriptID, object[] parms) + { + int ret = -1; + if (!Enabled) return ret; + + PhysicsActor rootPhysActor; + if (GetRootPhysActor(hostID, out rootPhysActor)) + { + object[] parms2 = AddToBeginningOfArray(rootPhysActor, null, parms); + ret = MakeIntError(rootPhysActor.Extension(PhysFunctAxisLockLimits, parms2)); + } + + return ret; + } + + [ScriptConstant] + public const int PHYS_LINKSET_TYPE_CONSTRAINT = 0; + [ScriptConstant] + public const int PHYS_LINKSET_TYPE_COMPOUND = 1; + [ScriptConstant] + public const int PHYS_LINKSET_TYPE_MANUAL = 2; + + [ScriptInvocation] + public int physSetLinksetType(UUID hostID, UUID scriptID, int linksetType) + { + int ret = -1; + if (!Enabled) return ret; + + // The part that is requesting the change. + SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID); + + if (requestingPart != null) + { + // The change is always made to the root of a linkset. + SceneObjectGroup containingGroup = requestingPart.ParentGroup; + SceneObjectPart rootPart = containingGroup.RootPart; + + if (rootPart != null) + { + PhysicsActor rootPhysActor = rootPart.PhysActor; + if (rootPhysActor != null) + { + if (rootPhysActor.IsPhysical) + { + // Change a physical linkset by making non-physical, waiting for one heartbeat so all + // the prim and linkset state is updated, changing the type and making the + // linkset physical again. + containingGroup.ScriptSetPhysicsStatus(false); + Thread.Sleep(150); // longer than one heartbeat tick + + // A kludge for the moment. + // Since compound linksets move the children but don't generate position updates to the + // simulator, it is possible for compound linkset children to have out-of-sync simulator + // and physical positions. The following causes the simulator to push the real child positions + // down into the physics engine to get everything synced. + containingGroup.UpdateGroupPosition(containingGroup.AbsolutePosition); + containingGroup.UpdateGroupRotationR(containingGroup.GroupRotation); + + object[] parms2 = { rootPhysActor, null, linksetType }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, parms2)); + Thread.Sleep(150); // longer than one heartbeat tick + + containingGroup.ScriptSetPhysicsStatus(true); + } + else + { + // Non-physical linksets don't have a physical instantiation so there is no state to + // worry about being updated. + object[] parms2 = { rootPhysActor, null, linksetType }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, parms2)); + } + } + else + { + m_log.WarnFormat("{0} physSetLinksetType: root part does not have a physics actor. rootName={1}, hostID={2}", + LogHeader, rootPart.Name, hostID); + } + } + else + { + m_log.WarnFormat("{0} physSetLinksetType: root part does not exist. RequestingPartName={1}, hostID={2}", + LogHeader, requestingPart.Name, hostID); + } + } + else + { + m_log.WarnFormat("{0} physSetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID); + } + return ret; + } + + [ScriptInvocation] + public int physGetLinksetType(UUID hostID, UUID scriptID) + { + int ret = -1; + if (!Enabled) return ret; + + PhysicsActor rootPhysActor; + if (GetRootPhysActor(hostID, out rootPhysActor)) + { + object[] parms2 = { rootPhysActor, null }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinksetType, parms2)); + } + else + { + m_log.WarnFormat("{0} physGetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID); + } + return ret; + } + + [ScriptConstant] + public const int PHYS_LINK_TYPE_FIXED = 1234; + [ScriptConstant] + public const int PHYS_LINK_TYPE_HINGE = 4; + [ScriptConstant] + public const int PHYS_LINK_TYPE_SPRING = 9; + [ScriptConstant] + public const int PHYS_LINK_TYPE_6DOF = 6; + [ScriptConstant] + public const int PHYS_LINK_TYPE_SLIDER = 7; + + // physChangeLinkType(integer linkNum, integer typeCode) + [ScriptInvocation] + public int physChangeLinkType(UUID hostID, UUID scriptID, int linkNum, int typeCode) + { + int ret = -1; + if (!Enabled) return ret; + + PhysicsActor rootPhysActor; + PhysicsActor childPhysActor; + + if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) + { + object[] parms2 = { rootPhysActor, childPhysActor, typeCode }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms2)); + } + + return ret; + } + + // physGetLinkType(integer linkNum) + [ScriptInvocation] + public int physGetLinkType(UUID hostID, UUID scriptID, int linkNum) + { + int ret = -1; + if (!Enabled) return ret; + + PhysicsActor rootPhysActor; + PhysicsActor childPhysActor; + + if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) + { + object[] parms2 = { rootPhysActor, childPhysActor }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinkType, parms2)); + } + + return ret; + } + + // physChangeLinkFixed(integer linkNum) + // Change the link between the root and the linkNum into a fixed, static physical connection. + [ScriptInvocation] + public int physChangeLinkFixed(UUID hostID, UUID scriptID, int linkNum) + { + int ret = -1; + if (!Enabled) return ret; + + PhysicsActor rootPhysActor; + PhysicsActor childPhysActor; + + if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) + { + object[] parms2 = { rootPhysActor, childPhysActor , PHYS_LINK_TYPE_FIXED }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms2)); + } + + return ret; + } + + // Code for specifying params. + // The choice if 14400 is arbitrary and only serves to catch parameter code misuse. + public const int PHYS_PARAM_MIN = 14401; + + [ScriptConstant] + public const int PHYS_PARAM_FRAMEINA_LOC = 14401; + [ScriptConstant] + public const int PHYS_PARAM_FRAMEINA_ROT = 14402; + [ScriptConstant] + public const int PHYS_PARAM_FRAMEINB_LOC = 14403; + [ScriptConstant] + public const int PHYS_PARAM_FRAMEINB_ROT = 14404; + [ScriptConstant] + public const int PHYS_PARAM_LINEAR_LIMIT_LOW = 14405; + [ScriptConstant] + public const int PHYS_PARAM_LINEAR_LIMIT_HIGH = 14406; + [ScriptConstant] + public const int PHYS_PARAM_ANGULAR_LIMIT_LOW = 14407; + [ScriptConstant] + public const int PHYS_PARAM_ANGULAR_LIMIT_HIGH = 14408; + [ScriptConstant] + public const int PHYS_PARAM_USE_FRAME_OFFSET = 14409; + [ScriptConstant] + public const int PHYS_PARAM_ENABLE_TRANSMOTOR = 14410; + [ScriptConstant] + public const int PHYS_PARAM_TRANSMOTOR_MAXVEL = 14411; + [ScriptConstant] + public const int PHYS_PARAM_TRANSMOTOR_MAXFORCE = 14412; + [ScriptConstant] + public const int PHYS_PARAM_CFM = 14413; + [ScriptConstant] + public const int PHYS_PARAM_ERP = 14414; + [ScriptConstant] + public const int PHYS_PARAM_SOLVER_ITERATIONS = 14415; + [ScriptConstant] + public const int PHYS_PARAM_SPRING_AXIS_ENABLE = 14416; + [ScriptConstant] + public const int PHYS_PARAM_SPRING_DAMPING = 14417; + [ScriptConstant] + public const int PHYS_PARAM_SPRING_STIFFNESS = 14418; + [ScriptConstant] + public const int PHYS_PARAM_LINK_TYPE = 14419; + [ScriptConstant] + public const int PHYS_PARAM_USE_LINEAR_FRAMEA = 14420; + [ScriptConstant] + public const int PHYS_PARAM_SPRING_EQUILIBRIUM_POINT = 14421; + + public const int PHYS_PARAM_MAX = 14421; + + // Used when specifying a parameter that has settings for the three linear and three angular axis + [ScriptConstant] + public const int PHYS_AXIS_ALL = -1; + [ScriptConstant] + public const int PHYS_AXIS_LINEAR_ALL = -2; + [ScriptConstant] + public const int PHYS_AXIS_ANGULAR_ALL = -3; + [ScriptConstant] + public const int PHYS_AXIS_LINEAR_X = 0; + [ScriptConstant] + public const int PHYS_AXIS_LINEAR_Y = 1; + [ScriptConstant] + public const int PHYS_AXIS_LINEAR_Z = 2; + [ScriptConstant] + public const int PHYS_AXIS_ANGULAR_X = 3; + [ScriptConstant] + public const int PHYS_AXIS_ANGULAR_Y = 4; + [ScriptConstant] + public const int PHYS_AXIS_ANGULAR_Z = 5; + + // physChangeLinkParams(integer linkNum, [ PHYS_PARAM_*, value, PHYS_PARAM_*, value, ...]) + [ScriptInvocation] + public int physChangeLinkParams(UUID hostID, UUID scriptID, int linkNum, object[] parms) + { + int ret = -1; + if (!Enabled) return ret; + + PhysicsActor rootPhysActor; + PhysicsActor childPhysActor; + + if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) + { + object[] parms2 = AddToBeginningOfArray(rootPhysActor, childPhysActor, parms); + ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkParams, parms2)); + } + + return ret; + } + + private bool GetRootPhysActor(UUID hostID, out PhysicsActor rootPhysActor) + { + SceneObjectGroup containingGroup; + SceneObjectPart rootPart; + return GetRootPhysActor(hostID, out containingGroup, out rootPart, out rootPhysActor); + } + + private bool GetRootPhysActor(UUID hostID, out SceneObjectGroup containingGroup, out SceneObjectPart rootPart, out PhysicsActor rootPhysActor) + { + bool ret = false; + rootPhysActor = null; + containingGroup = null; + rootPart = null; + + SceneObjectPart requestingPart; + + requestingPart = BaseScene.GetSceneObjectPart(hostID); + if (requestingPart != null) + { + // The type is is always on the root of a linkset. + containingGroup = requestingPart.ParentGroup; + if (containingGroup != null && !containingGroup.IsDeleted) + { + rootPart = containingGroup.RootPart; + if (rootPart != null) + { + rootPhysActor = rootPart.PhysActor; + if (rootPhysActor != null) + { + ret = true; + } + else + { + m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not have a physics actor. rootName={1}, hostID={2}", + LogHeader, rootPart.Name, hostID); + } + } + else + { + m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not exist. RequestingPartName={1}, hostID={2}", + LogHeader, requestingPart.Name, hostID); + } + } + else + { + m_log.WarnFormat("{0} GetRootAndChildPhysActors: Containing group missing or deleted. hostID={1}", LogHeader, hostID); + } + } + else + { + m_log.WarnFormat("{0} GetRootAndChildPhysActors: cannot find script object in scene. hostID={1}", LogHeader, hostID); + } + + return ret; + } + + // Find the root and child PhysActors based on the linkNum. + // Return 'true' if both are found and returned. + private bool GetRootAndChildPhysActors(UUID hostID, int linkNum, out PhysicsActor rootPhysActor, out PhysicsActor childPhysActor) + { + bool ret = false; + rootPhysActor = null; + childPhysActor = null; + + SceneObjectGroup containingGroup; + SceneObjectPart rootPart; + + if (GetRootPhysActor(hostID, out containingGroup, out rootPart, out rootPhysActor)) + { + SceneObjectPart linkPart = containingGroup.GetLinkNumPart(linkNum); + if (linkPart != null) + { + childPhysActor = linkPart.PhysActor; + if (childPhysActor != null) + { + ret = true; + } + else + { + m_log.WarnFormat("{0} GetRootAndChildPhysActors: Link part has no physical actor. rootName={1}, hostID={2}, linknum={3}", + LogHeader, rootPart.Name, hostID, linkNum); + } + } + else + { + m_log.WarnFormat("{0} GetRootAndChildPhysActors: Could not find linknum part. rootName={1}, hostID={2}, linknum={3}", + LogHeader, rootPart.Name, hostID, linkNum); + } + } + else + { + m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not have a physics actor. rootName={1}, hostID={2}", + LogHeader, rootPart.Name, hostID); + } + + return ret; + } + + // Return an array of objects with the passed object as the first object of a new array + private object[] AddToBeginningOfArray(object firstOne, object secondOne, object[] prevArray) + { + object[] newArray = new object[2 + prevArray.Length]; + newArray[0] = firstOne; + newArray[1] = secondOne; + prevArray.CopyTo(newArray, 2); + return newArray; + } + + // Extension() returns an object. Convert that object into the integer error we expect to return. + private int MakeIntError(object extensionRet) + { + int ret = -1; + if (extensionRet != null) + { + try + { + ret = (int)extensionRet; + } + catch + { + ret = -1; + } + } + return ret; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..698be39 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Mono.Addins; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.Region.Physics.BulletSPlugin")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("http://opensimulator.org")] +[assembly: AssemblyProduct("OpenSim")] +[assembly: AssemblyCopyright("OpenSimulator developers")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("520ea11b-20cb-449d-ba05-c01015fed841")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("0.8.3.*")] + +[assembly: Addin("OpenSim.Region.PhysicsModule.BulletS", OpenSim.VersionInfo.VersionNumber)] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs new file mode 100755 index 0000000..35eba29 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs @@ -0,0 +1,156 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using log4net; + +using OpenSim.Framework; +using OpenSim.Region.PhysicsModule.BulletS; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Tests.Common; + +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS.Tests +{ +[TestFixture] +public class BasicVehicles : OpenSimTestCase +{ + // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 + // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 + + BSScene PhysicsScene { get; set; } + BSPrim TestVehicle { get; set; } + Vector3 TestVehicleInitPosition { get; set; } + float simulationTimeStep = 0.089f; + + [TestFixtureSetUp] + public void Init() + { + Dictionary engineParams = new Dictionary(); + engineParams.Add("VehicleEnableAngularVerticalAttraction", "true"); + engineParams.Add("VehicleAngularVerticalAttractionAlgorithm", "1"); + PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams); + + PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere(); + Vector3 pos = new Vector3(100.0f, 100.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2f; + TestVehicleInitPosition = pos; + Vector3 size = new Vector3(1f, 1f, 1f); + pbs.Scale = size; + Quaternion rot = Quaternion.Identity; + bool isPhys = false; + uint localID = 123; + + PhysicsScene.AddPrimShape("testPrim", pbs, pos, size, rot, isPhys, localID); + TestVehicle = (BSPrim)PhysicsScene.PhysObjects[localID]; + // The actual prim shape creation happens at taint time + PhysicsScene.ProcessTaints(); + + } + + [TestFixtureTearDown] + public void TearDown() + { + if (PhysicsScene != null) + { + // The Dispose() will also free any physical objects in the scene + PhysicsScene.Dispose(); + PhysicsScene = null; + } + } + + [TestCase(2f, 0.2f, 0.25f, 0.25f, 0.25f)] + [TestCase(2f, 0.2f, -0.25f, 0.25f, 0.25f)] + [TestCase(2f, 0.2f, 0.25f, -0.25f, 0.25f)] + [TestCase(2f, 0.2f, -0.25f, -0.25f, 0.25f)] + // [TestCase(2f, 0.2f, 0.785f, 0.0f, 0.25f) /*, "Leaning 45 degrees to the side" */] + // [TestCase(2f, 0.2f, 1.650f, 0.0f, 0.25f) /*, "Leaning more than 90 degrees to the side" */] + // [TestCase(2f, 0.2f, 2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped right" */] + // [TestCase(2f, 0.2f,-2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped left" */] + // [TestCase(2f, 0.2f, 0.0f, 0.785f, 0.25f) /*, "Tipped back 45 degrees" */] + // [TestCase(2f, 0.2f, 0.0f, 1.650f, 0.25f) /*, "Tipped back more than 90 degrees" */] + // [TestCase(2f, 0.2f, 0.0f, 2.750f, 0.25f) /*, "Almost upside down, tipped back" */] + // [TestCase(2f, 0.2f, 0.0f,-2.750f, 0.25f) /*, "Almost upside down, tipped forward" */] + public void AngularVerticalAttraction(float timeScale, float efficiency, float initRoll, float initPitch, float initYaw) + { + // Enough simulation steps to cover the timescale the operation should take + int simSteps = (int)(timeScale / simulationTimeStep) + 1; + + // Tip the vehicle + Quaternion initOrientation = Quaternion.CreateFromEulers(initRoll, initPitch, initYaw); + TestVehicle.Orientation = initOrientation; + + TestVehicle.Position = TestVehicleInitPosition; + + // The vehicle controller is not enabled directly (by setting a vehicle type). + // Instead the appropriate values are set and calls are made just the parts of the + // controller we want to exercise. Stepping the physics engine then applies + // the actions of that one feature. + BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); + vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); + // vehicleActor.enableAngularVerticalAttraction = true; + + TestVehicle.IsPhysical = true; + PhysicsScene.ProcessTaints(); + + // Step the simulator a bunch of times and vertical attraction should orient the vehicle up + for (int ii = 0; ii < simSteps; ii++) + { + vehicleActor.ForgetKnownVehicleProperties(); + vehicleActor.ComputeAngularVerticalAttraction(); + vehicleActor.PushKnownChanged(); + + PhysicsScene.Simulate(simulationTimeStep); + } + } + + TestVehicle.IsPhysical = false; + PhysicsScene.ProcessTaints(); + + // After these steps, the vehicle should be upright + /* + float finalRoll, finalPitch, finalYaw; + TestVehicle.Orientation.GetEulerAngles(out finalRoll, out finalPitch, out finalYaw); + Assert.That(finalRoll, Is.InRange(-0.01f, 0.01f)); + Assert.That(finalPitch, Is.InRange(-0.01f, 0.01f)); + Assert.That(finalYaw, Is.InRange(initYaw - 0.1f, initYaw + 0.1f)); + */ + + Vector3 upPointer = Vector3.UnitZ * TestVehicle.Orientation; + Assert.That(upPointer.Z, Is.GreaterThan(0.99f)); + } +} +} \ No newline at end of file diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs new file mode 100755 index 0000000..0be1f4c --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs @@ -0,0 +1,56 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using log4net; + +using OpenSim.Tests.Common; + +namespace OpenSim.Region.PhysicsModule.BulletS.Tests +{ +[TestFixture] +public class BulletSimTests : OpenSimTestCase +{ + // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 + // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 + + [TestFixtureSetUp] + public void Init() + { + } + + [TestFixtureTearDown] + public void TearDown() + { + } +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs new file mode 100755 index 0000000..4eeea4d --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs @@ -0,0 +1,109 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; + +using Nini.Config; + +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Region.PhysicsModules.Meshing; +using OpenSim.Region.Framework.Interfaces; + +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS.Tests +{ +// Utility functions for building up and tearing down the sample physics environments +public static class BulletSimTestsUtil +{ + // 'engineName' is the Bullet engine to use. Either null (for unmanaged), "BulletUnmanaged" or "BulletXNA" + // 'params' is a set of keyValue pairs to set in the engine's configuration file (override defaults) + // May be 'null' if there are no overrides. + public static BSScene CreateBasicPhysicsEngine(Dictionary paramOverrides) + { + IConfigSource openSimINI = new IniConfigSource(); + IConfig startupConfig = openSimINI.AddConfig("Startup"); + startupConfig.Set("physics", "BulletSim"); + startupConfig.Set("meshing", "Meshmerizer"); + startupConfig.Set("cacheSculptMaps", "false"); // meshmerizer shouldn't save maps + + IConfig bulletSimConfig = openSimINI.AddConfig("BulletSim"); + // If the caller cares, specify the bullet engine otherwise it will default to "BulletUnmanaged". + // bulletSimConfig.Set("BulletEngine", "BulletUnmanaged"); + // bulletSimConfig.Set("BulletEngine", "BulletXNA"); + bulletSimConfig.Set("MeshSculptedPrim", "false"); + bulletSimConfig.Set("ForceSimplePrimMeshing", "true"); + if (paramOverrides != null) + { + foreach (KeyValuePair kvp in paramOverrides) + { + bulletSimConfig.Set(kvp.Key, kvp.Value); + } + } + + // If a special directory exists, put detailed logging therein. + // This allows local testing/debugging without having to worry that the build engine will output logs. + if (Directory.Exists("physlogs")) + { + bulletSimConfig.Set("PhysicsLoggingDir","./physlogs"); + bulletSimConfig.Set("PhysicsLoggingEnabled","True"); + bulletSimConfig.Set("PhysicsLoggingDoFlush","True"); + bulletSimConfig.Set("VehicleLoggingEnabled","True"); + } + + Vector3 regionExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); + + RegionInfo info = new RegionInfo(); + info.RegionName = "BSTestRegion"; + info.RegionSizeX = info.RegionSizeY = info.RegionSizeZ = Constants.RegionSize; + OpenSim.Region.Framework.Scenes.Scene scene = new OpenSim.Region.Framework.Scenes.Scene(info); + + IMesher mesher = new OpenSim.Region.PhysicsModules.Meshing.Meshmerizer(); + INonSharedRegionModule mod = mesher as INonSharedRegionModule; + mod.Initialise(openSimINI); + mod.AddRegion(scene); + mod.RegionLoaded(scene); + + BSScene pScene = new BSScene(); + mod = (pScene as INonSharedRegionModule); + mod.Initialise(openSimINI); + mod.AddRegion(scene); + mod.RegionLoaded(scene); + + // Since the asset requestor is not initialized, any mesh or sculptie will be a cube. + // In the future, add a fake asset fetcher to get meshes and sculpts. + // bsScene.RequestAssetMethod = ???; + + return pScene; + } + +} +} diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs new file mode 100644 index 0000000..c0cf19a --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs @@ -0,0 +1,205 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; +using log4net; + +using OpenSim.Framework; +using OpenSim.Region.PhysicsModule.BulletS; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Tests.Common; + +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModule.BulletS.Tests +{ +[TestFixture] +public class HullCreation : OpenSimTestCase +{ + // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 + // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 + + BSScene PhysicsScene { get; set; } + Vector3 ObjectInitPosition; + + [TestFixtureSetUp] + public void Init() + { + + } + + [TestFixtureTearDown] + public void TearDown() + { + if (PhysicsScene != null) + { + // The Dispose() will also free any physical objects in the scene + PhysicsScene.Dispose(); + PhysicsScene = null; + } + } + + [TestCase(7, 2, 5f, 5f, 32, 0f)] /* default hull parameters */ + public void GeomHullConvexDecomp( int maxDepthSplit, + int maxDepthSplitForSimpleShapes, + float concavityThresholdPercent, + float volumeConservationThresholdPercent, + int maxVertices, + float maxSkinWidth) + { + // Setup the physics engine to use the C# version of convex decomp + Dictionary engineParams = new Dictionary(); + engineParams.Add("MeshSculptedPrim", "true"); // ShouldMeshSculptedPrim + engineParams.Add("ForceSimplePrimMeshing", "false"); // ShouldForceSimplePrimMeshing + engineParams.Add("UseHullsForPhysicalObjects", "true"); // ShouldUseHullsForPhysicalObjects + engineParams.Add("ShouldRemoveZeroWidthTriangles", "true"); + engineParams.Add("ShouldUseBulletHACD", "false"); + engineParams.Add("ShouldUseSingleConvexHullForPrims", "true"); + engineParams.Add("ShouldUseGImpactShapeForPrims", "false"); + engineParams.Add("ShouldUseAssetHulls", "true"); + + engineParams.Add("CSHullMaxDepthSplit", maxDepthSplit.ToString()); + engineParams.Add("CSHullMaxDepthSplitForSimpleShapes", maxDepthSplitForSimpleShapes.ToString()); + engineParams.Add("CSHullConcavityThresholdPercent", concavityThresholdPercent.ToString()); + engineParams.Add("CSHullVolumeConservationThresholdPercent", volumeConservationThresholdPercent.ToString()); + engineParams.Add("CSHullMaxVertices", maxVertices.ToString()); + engineParams.Add("CSHullMaxSkinWidth", maxSkinWidth.ToString()); + + PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams); + + PrimitiveBaseShape pbs; + Vector3 pos; + Vector3 size; + Quaternion rot; + bool isPhys; + + // Cylinder + pbs = PrimitiveBaseShape.CreateCylinder(); + pos = new Vector3(100.0f, 100.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; + ObjectInitPosition = pos; + size = new Vector3(2f, 2f, 2f); + pbs.Scale = size; + rot = Quaternion.Identity; + isPhys = true; + uint cylinderLocalID = 123; + PhysicsScene.AddPrimShape("testCylinder", pbs, pos, size, rot, isPhys, cylinderLocalID); + BSPrim primTypeCylinder = (BSPrim)PhysicsScene.PhysObjects[cylinderLocalID]; + + // Hollow Cylinder + pbs = PrimitiveBaseShape.CreateCylinder(); + pbs.ProfileHollow = (ushort)(0.70f * 50000); + pos = new Vector3(110.0f, 110.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; + ObjectInitPosition = pos; + size = new Vector3(2f, 2f, 2f); + pbs.Scale = size; + rot = Quaternion.Identity; + isPhys = true; + uint hollowCylinderLocalID = 124; + PhysicsScene.AddPrimShape("testHollowCylinder", pbs, pos, size, rot, isPhys, hollowCylinderLocalID); + BSPrim primTypeHollowCylinder = (BSPrim)PhysicsScene.PhysObjects[hollowCylinderLocalID]; + + // Torus + // ProfileCurve = Circle, PathCurve = Curve1 + pbs = PrimitiveBaseShape.CreateSphere(); + pbs.ProfileShape = (byte)ProfileShape.Circle; + pbs.PathCurve = (byte)Extrusion.Curve1; + pbs.PathScaleX = 100; // default hollow info as set in the viewer + pbs.PathScaleY = (int)(.25f / 0.01f) + 200; + pos = new Vector3(120.0f, 120.0f, 0f); + pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f; + ObjectInitPosition = pos; + size = new Vector3(2f, 4f, 4f); + pbs.Scale = size; + rot = Quaternion.Identity; + isPhys = true; + uint torusLocalID = 125; + PhysicsScene.AddPrimShape("testTorus", pbs, pos, size, rot, isPhys, torusLocalID); + BSPrim primTypeTorus = (BSPrim)PhysicsScene.PhysObjects[torusLocalID]; + + // The actual prim shape creation happens at taint time + PhysicsScene.ProcessTaints(); + + // Check out the created hull shapes and report their characteristics + ReportShapeGeom(primTypeCylinder); + ReportShapeGeom(primTypeHollowCylinder); + ReportShapeGeom(primTypeTorus); + } + + [TestCase] + public void GeomHullBulletHACD() + { + // Cylinder + // Hollow Cylinder + // Torus + } + + private void ReportShapeGeom(BSPrim prim) + { + if (prim != null) + { + if (prim.PhysShape.HasPhysicalShape) + { + BSShape physShape = prim.PhysShape; + string shapeType = physShape.GetType().ToString(); + switch (shapeType) + { + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeNative": + BSShapeNative nShape = physShape as BSShapeNative; + prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeMesh": + BSShapeMesh mShape = physShape as BSShapeMesh; + prim.PhysScene.DetailLog("{0}, mesh, shapeInfo={1}", prim.Name, mShape.shapeInfo); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeHull": + // BSShapeHull hShape = physShape as BSShapeHull; + // prim.PhysScene.DetailLog("{0}, hull, shapeInfo={1}", prim.Name, hShape.shapeInfo); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeConvexHull": + BSShapeConvexHull chShape = physShape as BSShapeConvexHull; + prim.PhysScene.DetailLog("{0}, convexHull, shapeInfo={1}", prim.Name, chShape.shapeInfo); + break; + case "OpenSim.Region.Physics.BulletSPlugin.BSShapeCompound": + BSShapeCompound cShape = physShape as BSShapeCompound; + prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); + break; + default: + prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType); + break; + } + } + } + } +} +} \ No newline at end of file diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/CTri.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/CTri.cs new file mode 100644 index 0000000..7ad689e --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/CTri.cs @@ -0,0 +1,341 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class Wpoint + { + public float3 mPoint; + public float mWeight; + + public Wpoint(float3 p, float w) + { + mPoint = p; + mWeight = w; + } + } + + public class CTri + { + private const int WSCALE = 4; + + public float3 mP1; + public float3 mP2; + public float3 mP3; + public float3 mNear1; + public float3 mNear2; + public float3 mNear3; + public float3 mNormal; + public float mPlaneD; + public float mConcavity; + public float mC1; + public float mC2; + public float mC3; + public int mI1; + public int mI2; + public int mI3; + public int mProcessed; // already been added... + + public CTri(float3 p1, float3 p2, float3 p3, int i1, int i2, int i3) + { + mProcessed = 0; + mI1 = i1; + mI2 = i2; + mI3 = i3; + + mP1 = new float3(p1); + mP2 = new float3(p2); + mP3 = new float3(p3); + + mNear1 = new float3(); + mNear2 = new float3(); + mNear3 = new float3(); + + mNormal = new float3(); + mPlaneD = mNormal.ComputePlane(mP1, mP2, mP3); + } + + public float Facing(CTri t) + { + return float3.dot(mNormal, t.mNormal); + } + + public bool clip(float3 start, ref float3 end) + { + float3 sect = new float3(); + bool hit = lineIntersectsTriangle(start, end, mP1, mP2, mP3, ref sect); + + if (hit) + end = sect; + return hit; + } + + public bool Concave(float3 p, ref float distance, ref float3 n) + { + n.NearestPointInTriangle(p, mP1, mP2, mP3); + distance = p.Distance(n); + return true; + } + + public void addTri(int[] indices, int i1, int i2, int i3, ref int tcount) + { + indices[tcount * 3 + 0] = i1; + indices[tcount * 3 + 1] = i2; + indices[tcount * 3 + 2] = i3; + tcount++; + } + + public float getVolume() + { + int[] indices = new int[8 * 3]; + + int tcount = 0; + + addTri(indices, 0, 1, 2, ref tcount); + addTri(indices, 3, 4, 5, ref tcount); + + addTri(indices, 0, 3, 4, ref tcount); + addTri(indices, 0, 4, 1, ref tcount); + + addTri(indices, 1, 4, 5, ref tcount); + addTri(indices, 1, 5, 2, ref tcount); + + addTri(indices, 0, 3, 5, ref tcount); + addTri(indices, 0, 5, 2, ref tcount); + + List vertices = new List { mP1, mP2, mP3, mNear1, mNear2, mNear3 }; + List indexList = new List(indices); + + float v = Concavity.computeMeshVolume(vertices, indexList); + return v; + } + + public float raySect(float3 p, float3 dir, ref float3 sect) + { + float4 plane = new float4(); + + plane.x = mNormal.x; + plane.y = mNormal.y; + plane.z = mNormal.z; + plane.w = mPlaneD; + + float3 dest = p + dir * 100000f; + + intersect(p, dest, ref sect, plane); + + return sect.Distance(p); // return the intersection distance + } + + public float planeDistance(float3 p) + { + float4 plane = new float4(); + + plane.x = mNormal.x; + plane.y = mNormal.y; + plane.z = mNormal.z; + plane.w = mPlaneD; + + return DistToPt(p, plane); + } + + public bool samePlane(CTri t) + { + const float THRESH = 0.001f; + float dd = Math.Abs(t.mPlaneD - mPlaneD); + if (dd > THRESH) + return false; + dd = Math.Abs(t.mNormal.x - mNormal.x); + if (dd > THRESH) + return false; + dd = Math.Abs(t.mNormal.y - mNormal.y); + if (dd > THRESH) + return false; + dd = Math.Abs(t.mNormal.z - mNormal.z); + if (dd > THRESH) + return false; + return true; + } + + public bool hasIndex(int i) + { + if (i == mI1 || i == mI2 || i == mI3) + return true; + return false; + } + + public bool sharesEdge(CTri t) + { + bool ret = false; + uint count = 0; + + if (t.hasIndex(mI1)) + count++; + if (t.hasIndex(mI2)) + count++; + if (t.hasIndex(mI3)) + count++; + + if (count >= 2) + ret = true; + + return ret; + } + + public float area() + { + float a = mConcavity * mP1.Area(mP2, mP3); + return a; + } + + public void addWeighted(List list) + { + Wpoint p1 = new Wpoint(mP1, mC1); + Wpoint p2 = new Wpoint(mP2, mC2); + Wpoint p3 = new Wpoint(mP3, mC3); + + float3 d1 = mNear1 - mP1; + float3 d2 = mNear2 - mP2; + float3 d3 = mNear3 - mP3; + + d1 *= WSCALE; + d2 *= WSCALE; + d3 *= WSCALE; + + d1 = d1 + mP1; + d2 = d2 + mP2; + d3 = d3 + mP3; + + Wpoint p4 = new Wpoint(d1, mC1); + Wpoint p5 = new Wpoint(d2, mC2); + Wpoint p6 = new Wpoint(d3, mC3); + + list.Add(p1); + list.Add(p2); + list.Add(p3); + + list.Add(p4); + list.Add(p5); + list.Add(p6); + } + + private static float DistToPt(float3 p, float4 plane) + { + float x = p.x; + float y = p.y; + float z = p.z; + float d = x*plane.x + y*plane.y + z*plane.z + plane.w; + return d; + } + + private static void intersect(float3 p1, float3 p2, ref float3 split, float4 plane) + { + float dp1 = DistToPt(p1, plane); + + float3 dir = new float3(); + dir.x = p2[0] - p1[0]; + dir.y = p2[1] - p1[1]; + dir.z = p2[2] - p1[2]; + + float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2]; + float dot2 = dp1 - plane[3]; + + float t = -(plane[3] + dot2) / dot1; + + split.x = (dir[0] * t) + p1[0]; + split.y = (dir[1] * t) + p1[1]; + split.z = (dir[2] * t) + p1[2]; + } + + private static bool rayIntersectsTriangle(float3 p, float3 d, float3 v0, float3 v1, float3 v2, out float t) + { + t = 0f; + + float3 e1, e2, h, s, q; + float a, f, u, v; + + e1 = v1 - v0; + e2 = v2 - v0; + h = float3.cross(d, e2); + a = float3.dot(e1, h); + + if (a > -0.00001f && a < 0.00001f) + return false; + + f = 1f / a; + s = p - v0; + u = f * float3.dot(s, h); + + if (u < 0.0f || u > 1.0f) + return false; + + q = float3.cross(s, e1); + v = f * float3.dot(d, q); + if (v < 0.0f || u + v > 1.0f) + return false; + + // at this stage we can compute t to find out where + // the intersection point is on the line + t = f * float3.dot(e2, q); + if (t > 0f) // ray intersection + return true; + else // this means that there is a line intersection but not a ray intersection + return false; + } + + private static bool lineIntersectsTriangle(float3 rayStart, float3 rayEnd, float3 p1, float3 p2, float3 p3, ref float3 sect) + { + float3 dir = rayEnd - rayStart; + + float d = (float)Math.Sqrt(dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]); + float r = 1.0f / d; + + dir *= r; + + float t; + bool ret = rayIntersectsTriangle(rayStart, dir, p1, p2, p3, out t); + + if (ret) + { + if (t > d) + { + sect.x = rayStart.x + dir.x * t; + sect.y = rayStart.y + dir.y * t; + sect.z = rayStart.z + dir.z * t; + } + else + { + ret = false; + } + } + + return ret; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Concavity.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Concavity.cs new file mode 100644 index 0000000..4140d25 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Concavity.cs @@ -0,0 +1,233 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public static class Concavity + { + // compute's how 'concave' this object is and returns the total volume of the + // convex hull as well as the volume of the 'concavity' which was found. + public static float computeConcavity(List vertices, List indices, ref float4 plane, ref float volume) + { + float cret = 0f; + volume = 1f; + + HullResult result = new HullResult(); + HullDesc desc = new HullDesc(); + + desc.MaxFaces = 256; + desc.MaxVertices = 256; + desc.SetHullFlag(HullFlag.QF_TRIANGLES); + desc.Vertices = vertices; + + HullError ret = HullUtils.CreateConvexHull(desc, ref result); + + if (ret == HullError.QE_OK) + { + volume = computeMeshVolume2(result.OutputVertices, result.Indices); + + // ok..now..for each triangle on the original mesh.. + // we extrude the points to the nearest point on the hull. + List tris = new List(); + + for (int i = 0; i < result.Indices.Count / 3; i++) + { + int i1 = result.Indices[i * 3 + 0]; + int i2 = result.Indices[i * 3 + 1]; + int i3 = result.Indices[i * 3 + 2]; + + float3 p1 = result.OutputVertices[i1]; + float3 p2 = result.OutputVertices[i2]; + float3 p3 = result.OutputVertices[i3]; + + CTri t = new CTri(p1, p2, p3, i1, i2, i3); + tris.Add(t); + } + + // we have not pre-computed the plane equation for each triangle in the convex hull.. + float totalVolume = 0; + + List ftris = new List(); // 'feature' triangles. + List input_mesh = new List(); + + for (int i = 0; i < indices.Count / 3; i++) + { + int i1 = indices[i * 3 + 0]; + int i2 = indices[i * 3 + 1]; + int i3 = indices[i * 3 + 2]; + + float3 p1 = vertices[i1]; + float3 p2 = vertices[i2]; + float3 p3 = vertices[i3]; + + CTri t = new CTri(p1, p2, p3, i1, i2, i3); + input_mesh.Add(t); + } + + for (int i = 0; i < indices.Count / 3; i++) + { + int i1 = indices[i * 3 + 0]; + int i2 = indices[i * 3 + 1]; + int i3 = indices[i * 3 + 2]; + + float3 p1 = vertices[i1]; + float3 p2 = vertices[i2]; + float3 p3 = vertices[i3]; + + CTri t = new CTri(p1, p2, p3, i1, i2, i3); + + featureMatch(t, tris, input_mesh); + + if (t.mConcavity > 0.05f) + { + float v = t.getVolume(); + totalVolume += v; + ftris.Add(t); + } + } + + SplitPlane.computeSplitPlane(vertices, indices, ref plane); + cret = totalVolume; + } + + return cret; + } + + public static bool featureMatch(CTri m, List tris, List input_mesh) + { + bool ret = false; + float neardot = 0.707f; + m.mConcavity = 0; + + for (int i = 0; i < tris.Count; i++) + { + CTri t = tris[i]; + + if (t.samePlane(m)) + { + ret = false; + break; + } + + float dot = float3.dot(t.mNormal, m.mNormal); + + if (dot > neardot) + { + float d1 = t.planeDistance(m.mP1); + float d2 = t.planeDistance(m.mP2); + float d3 = t.planeDistance(m.mP3); + + if (d1 > 0.001f || d2 > 0.001f || d3 > 0.001f) // can't be near coplaner! + { + neardot = dot; + + t.raySect(m.mP1, m.mNormal, ref m.mNear1); + t.raySect(m.mP2, m.mNormal, ref m.mNear2); + t.raySect(m.mP3, m.mNormal, ref m.mNear3); + + ret = true; + } + } + } + + if (ret) + { + m.mC1 = m.mP1.Distance(m.mNear1); + m.mC2 = m.mP2.Distance(m.mNear2); + m.mC3 = m.mP3.Distance(m.mNear3); + + m.mConcavity = m.mC1; + + if (m.mC2 > m.mConcavity) + m.mConcavity = m.mC2; + if (m.mC3 > m.mConcavity) + m.mConcavity = m.mC3; + } + + return ret; + } + + private static float det(float3 p1, float3 p2, float3 p3) + { + return p1.x * p2.y * p3.z + p2.x * p3.y * p1.z + p3.x * p1.y * p2.z - p1.x * p3.y * p2.z - p2.x * p1.y * p3.z - p3.x * p2.y * p1.z; + } + + public static float computeMeshVolume(List vertices, List indices) + { + float volume = 0f; + + for (int i = 0; i < indices.Count / 3; i++) + { + float3 p1 = vertices[indices[i * 3 + 0]]; + float3 p2 = vertices[indices[i * 3 + 1]]; + float3 p3 = vertices[indices[i * 3 + 2]]; + + volume += det(p1, p2, p3); // compute the volume of the tetrahedran relative to the origin. + } + + volume *= (1.0f / 6.0f); + if (volume < 0f) + return -volume; + return volume; + } + + public static float computeMeshVolume2(List vertices, List indices) + { + float volume = 0f; + + float3 p0 = vertices[0]; + for (int i = 0; i < indices.Count / 3; i++) + { + float3 p1 = vertices[indices[i * 3 + 0]]; + float3 p2 = vertices[indices[i * 3 + 1]]; + float3 p3 = vertices[indices[i * 3 + 2]]; + + volume += tetVolume(p0, p1, p2, p3); // compute the volume of the tetrahedron relative to the root vertice + } + + return volume * (1.0f / 6.0f); + } + + private static float tetVolume(float3 p0, float3 p1, float3 p2, float3 p3) + { + float3 a = p1 - p0; + float3 b = p2 - p0; + float3 c = p3 - p0; + + float3 cross = float3.cross(b, c); + float volume = float3.dot(a, cross); + + if (volume < 0f) + return -volume; + return volume; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexBuilder.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexBuilder.cs new file mode 100644 index 0000000..70c3a2b --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexBuilder.cs @@ -0,0 +1,411 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class DecompDesc + { + public List mVertices; + public List mIndices; + + // options + public uint mDepth; // depth to split, a maximum of 10, generally not over 7. + public float mCpercent; // the concavity threshold percentage. 0=20 is reasonable. + public float mPpercent; // the percentage volume conservation threshold to collapse hulls. 0-30 is reasonable. + + // hull output limits. + public uint mMaxVertices; // maximum number of vertices in the output hull. Recommended 32 or less. + public float mSkinWidth; // a skin width to apply to the output hulls. + + public ConvexDecompositionCallback mCallback; // the interface to receive back the results. + + public DecompDesc() + { + mDepth = 5; + mCpercent = 5; + mPpercent = 5; + mMaxVertices = 32; + } + } + + public class CHull + { + public float[] mMin = new float[3]; + public float[] mMax = new float[3]; + public float mVolume; + public float mDiagonal; + public ConvexResult mResult; + + public CHull(ConvexResult result) + { + mResult = new ConvexResult(result); + mVolume = Concavity.computeMeshVolume(result.HullVertices, result.HullIndices); + + mDiagonal = getBoundingRegion(result.HullVertices, mMin, mMax); + + float dx = mMax[0] - mMin[0]; + float dy = mMax[1] - mMin[1]; + float dz = mMax[2] - mMin[2]; + + dx *= 0.1f; // inflate 1/10th on each edge + dy *= 0.1f; // inflate 1/10th on each edge + dz *= 0.1f; // inflate 1/10th on each edge + + mMin[0] -= dx; + mMin[1] -= dy; + mMin[2] -= dz; + + mMax[0] += dx; + mMax[1] += dy; + mMax[2] += dz; + } + + public void Dispose() + { + mResult = null; + } + + public bool overlap(CHull h) + { + return overlapAABB(mMin, mMax, h.mMin, h.mMax); + } + + // returns the d1Giagonal distance + private static float getBoundingRegion(List points, float[] bmin, float[] bmax) + { + float3 first = points[0]; + + bmin[0] = first.x; + bmin[1] = first.y; + bmin[2] = first.z; + + bmax[0] = first.x; + bmax[1] = first.y; + bmax[2] = first.z; + + for (int i = 1; i < points.Count; i++) + { + float3 p = points[i]; + + if (p[0] < bmin[0]) bmin[0] = p[0]; + if (p[1] < bmin[1]) bmin[1] = p[1]; + if (p[2] < bmin[2]) bmin[2] = p[2]; + + if (p[0] > bmax[0]) bmax[0] = p[0]; + if (p[1] > bmax[1]) bmax[1] = p[1]; + if (p[2] > bmax[2]) bmax[2] = p[2]; + } + + float dx = bmax[0] - bmin[0]; + float dy = bmax[1] - bmin[1]; + float dz = bmax[2] - bmin[2]; + + return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz); + } + + // return true if the two AABB's overlap. + private static bool overlapAABB(float[] bmin1, float[] bmax1, float[] bmin2, float[] bmax2) + { + if (bmax2[0] < bmin1[0]) return false; // if the maximum is less than our minimum on any axis + if (bmax2[1] < bmin1[1]) return false; + if (bmax2[2] < bmin1[2]) return false; + + if (bmin2[0] > bmax1[0]) return false; // if the minimum is greater than our maximum on any axis + if (bmin2[1] > bmax1[1]) return false; // if the minimum is greater than our maximum on any axis + if (bmin2[2] > bmax1[2]) return false; // if the minimum is greater than our maximum on any axis + + return true; // the extents overlap + } + } + + public class ConvexBuilder + { + public List mChulls = new List(); + private ConvexDecompositionCallback mCallback; + + private int MAXDEPTH = 8; + private float CONCAVE_PERCENT = 1f; + private float MERGE_PERCENT = 2f; + + public ConvexBuilder(ConvexDecompositionCallback callback) + { + mCallback = callback; + } + + public void Dispose() + { + int i; + for (i = 0; i < mChulls.Count; i++) + { + CHull cr = mChulls[i]; + cr.Dispose(); + } + } + + public bool isDuplicate(uint i1, uint i2, uint i3, uint ci1, uint ci2, uint ci3) + { + uint dcount = 0; + + Debug.Assert(i1 != i2 && i1 != i3 && i2 != i3); + Debug.Assert(ci1 != ci2 && ci1 != ci3 && ci2 != ci3); + + if (i1 == ci1 || i1 == ci2 || i1 == ci3) + dcount++; + if (i2 == ci1 || i2 == ci2 || i2 == ci3) + dcount++; + if (i3 == ci1 || i3 == ci2 || i3 == ci3) + dcount++; + + return dcount == 3; + } + + public void getMesh(ConvexResult cr, VertexPool vc, List indices) + { + List src = cr.HullIndices; + + for (int i = 0; i < src.Count / 3; i++) + { + int i1 = src[i * 3 + 0]; + int i2 = src[i * 3 + 1]; + int i3 = src[i * 3 + 2]; + + float3 p1 = cr.HullVertices[i1]; + float3 p2 = cr.HullVertices[i2]; + float3 p3 = cr.HullVertices[i3]; + + i1 = vc.getIndex(p1); + i2 = vc.getIndex(p2); + i3 = vc.getIndex(p3); + } + } + + public CHull canMerge(CHull a, CHull b) + { + if (!a.overlap(b)) // if their AABB's (with a little slop) don't overlap, then return. + return null; + + CHull ret = null; + + // ok..we are going to combine both meshes into a single mesh + // and then we are going to compute the concavity... + + VertexPool vc = new VertexPool(); + + List indices = new List(); + + getMesh(a.mResult, vc, indices); + getMesh(b.mResult, vc, indices); + + int vcount = vc.GetSize(); + List vertices = vc.GetVertices(); + int tcount = indices.Count / 3; + + //don't do anything if hull is empty + if (tcount == 0) + { + vc.Clear(); + return null; + } + + HullResult hresult = new HullResult(); + HullDesc desc = new HullDesc(); + + desc.SetHullFlag(HullFlag.QF_TRIANGLES); + desc.Vertices = vertices; + + HullError hret = HullUtils.CreateConvexHull(desc, ref hresult); + + if (hret == HullError.QE_OK) + { + float combineVolume = Concavity.computeMeshVolume(hresult.OutputVertices, hresult.Indices); + float sumVolume = a.mVolume + b.mVolume; + + float percent = (sumVolume * 100) / combineVolume; + if (percent >= (100.0f - MERGE_PERCENT)) + { + ConvexResult cr = new ConvexResult(hresult.OutputVertices, hresult.Indices); + ret = new CHull(cr); + } + } + + vc.Clear(); + return ret; + } + + public bool combineHulls() + { + bool combine = false; + + sortChulls(mChulls); // sort the convex hulls, largest volume to least... + + List output = new List(); // the output hulls... + + int i; + for (i = 0; i < mChulls.Count && !combine; ++i) + { + CHull cr = mChulls[i]; + + int j; + for (j = 0; j < mChulls.Count; j++) + { + CHull match = mChulls[j]; + + if (cr != match) // don't try to merge a hull with itself, that be stoopid + { + + CHull merge = canMerge(cr, match); // if we can merge these two.... + + if (merge != null) + { + output.Add(merge); + + ++i; + while (i != mChulls.Count) + { + CHull cr2 = mChulls[i]; + if (cr2 != match) + { + output.Add(cr2); + } + i++; + } + + cr.Dispose(); + match.Dispose(); + combine = true; + break; + } + } + } + + if (combine) + { + break; + } + else + { + output.Add(cr); + } + } + + if (combine) + { + mChulls.Clear(); + mChulls = output; + output.Clear(); + } + + return combine; + } + + public int process(DecompDesc desc) + { + int ret = 0; + + MAXDEPTH = (int)desc.mDepth; + CONCAVE_PERCENT = desc.mCpercent; + MERGE_PERCENT = desc.mPpercent; + + ConvexDecomposition.calcConvexDecomposition(desc.mVertices, desc.mIndices, ConvexDecompResult, 0f, 0, MAXDEPTH, CONCAVE_PERCENT, MERGE_PERCENT); + + while (combineHulls()) // keep combinging hulls until I can't combine any more... + ; + + int i; + for (i = 0; i < mChulls.Count; i++) + { + CHull cr = mChulls[i]; + + // before we hand it back to the application, we need to regenerate the hull based on the + // limits given by the user. + + ConvexResult c = cr.mResult; // the high resolution hull... + + HullResult result = new HullResult(); + HullDesc hdesc = new HullDesc(); + + hdesc.SetHullFlag(HullFlag.QF_TRIANGLES); + + hdesc.Vertices = c.HullVertices; + hdesc.MaxVertices = desc.mMaxVertices; // maximum number of vertices allowed in the output + + if (desc.mSkinWidth != 0f) + { + hdesc.SkinWidth = desc.mSkinWidth; + hdesc.SetHullFlag(HullFlag.QF_SKIN_WIDTH); // do skin width computation. + } + + HullError ret2 = HullUtils.CreateConvexHull(hdesc, ref result); + + if (ret2 == HullError.QE_OK) + { + ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices); + + r.mHullVolume = Concavity.computeMeshVolume(result.OutputVertices, result.Indices); // the volume of the hull. + + // compute the best fit OBB + //computeBestFitOBB(result.mNumOutputVertices, result.mOutputVertices, sizeof(float) * 3, r.mOBBSides, r.mOBBTransform); + + //r.mOBBVolume = r.mOBBSides[0] * r.mOBBSides[1] * r.mOBBSides[2]; // compute the OBB volume. + + //fm_getTranslation(r.mOBBTransform, r.mOBBCenter); // get the translation component of the 4x4 matrix. + + //fm_matrixToQuat(r.mOBBTransform, r.mOBBOrientation); // extract the orientation as a quaternion. + + //r.mSphereRadius = computeBoundingSphere(result.mNumOutputVertices, result.mOutputVertices, r.mSphereCenter); + //r.mSphereVolume = fm_sphereVolume(r.mSphereRadius); + + mCallback(r); + } + + result = null; + cr.Dispose(); + } + + ret = mChulls.Count; + + mChulls.Clear(); + + return ret; + } + + public void ConvexDecompResult(ConvexResult result) + { + CHull ch = new CHull(result); + mChulls.Add(ch); + } + + public void sortChulls(List hulls) + { + hulls.Sort(delegate(CHull a, CHull b) { return a.mVolume.CompareTo(b.mVolume); }); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexDecomposition.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexDecomposition.cs new file mode 100644 index 0000000..5046bce --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexDecomposition.cs @@ -0,0 +1,200 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public delegate void ConvexDecompositionCallback(ConvexResult result); + + public class FaceTri + { + public float3 P1; + public float3 P2; + public float3 P3; + + public FaceTri() { } + + public FaceTri(List vertices, int i1, int i2, int i3) + { + P1 = new float3(vertices[i1]); + P2 = new float3(vertices[i2]); + P3 = new float3(vertices[i3]); + } + } + + public static class ConvexDecomposition + { + private static void addTri(VertexPool vl, List list, float3 p1, float3 p2, float3 p3) + { + int i1 = vl.getIndex(p1); + int i2 = vl.getIndex(p2); + int i3 = vl.getIndex(p3); + + // do *not* process degenerate triangles! + if ( i1 != i2 && i1 != i3 && i2 != i3 ) + { + list.Add(i1); + list.Add(i2); + list.Add(i3); + } + } + + public static void calcConvexDecomposition(List vertices, List indices, ConvexDecompositionCallback callback, float masterVolume, int depth, + int maxDepth, float concavePercent, float mergePercent) + { + float4 plane = new float4(); + bool split = false; + + if (depth < maxDepth) + { + float volume = 0f; + float c = Concavity.computeConcavity(vertices, indices, ref plane, ref volume); + + if (depth == 0) + { + masterVolume = volume; + } + + float percent = (c * 100.0f) / masterVolume; + + if (percent > concavePercent) // if great than 5% of the total volume is concave, go ahead and keep splitting. + { + split = true; + } + } + + if (depth >= maxDepth || !split) + { + HullResult result = new HullResult(); + HullDesc desc = new HullDesc(); + + desc.SetHullFlag(HullFlag.QF_TRIANGLES); + + desc.Vertices = vertices; + + HullError ret = HullUtils.CreateConvexHull(desc, ref result); + + if (ret == HullError.QE_OK) + { + ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices); + callback(r); + } + + return; + } + + List ifront = new List(); + List iback = new List(); + + VertexPool vfront = new VertexPool(); + VertexPool vback = new VertexPool(); + + // ok..now we are going to 'split' all of the input triangles against this plane! + for (int i = 0; i < indices.Count / 3; i++) + { + int i1 = indices[i * 3 + 0]; + int i2 = indices[i * 3 + 1]; + int i3 = indices[i * 3 + 2]; + + FaceTri t = new FaceTri(vertices, i1, i2, i3); + + float3[] front = new float3[4]; + float3[] back = new float3[4]; + + int fcount = 0; + int bcount = 0; + + PlaneTriResult result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount); + + if (fcount > 4 || bcount > 4) + { + result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount); + } + + switch (result) + { + case PlaneTriResult.PTR_FRONT: + Debug.Assert(fcount == 3); + addTri(vfront, ifront, front[0], front[1], front[2]); + break; + case PlaneTriResult.PTR_BACK: + Debug.Assert(bcount == 3); + addTri(vback, iback, back[0], back[1], back[2]); + break; + case PlaneTriResult.PTR_SPLIT: + Debug.Assert(fcount >= 3 && fcount <= 4); + Debug.Assert(bcount >= 3 && bcount <= 4); + + addTri(vfront, ifront, front[0], front[1], front[2]); + addTri(vback, iback, back[0], back[1], back[2]); + + if (fcount == 4) + { + addTri(vfront, ifront, front[0], front[2], front[3]); + } + + if (bcount == 4) + { + addTri(vback, iback, back[0], back[2], back[3]); + } + + break; + } + } + + // ok... here we recursively call + if (ifront.Count > 0) + { + int vcount = vfront.GetSize(); + List vertices2 = vfront.GetVertices(); + for (int i = 0; i < vertices2.Count; i++) + vertices2[i] = new float3(vertices2[i]); + int tcount = ifront.Count / 3; + + calcConvexDecomposition(vertices2, ifront, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent); + } + + ifront.Clear(); + vfront.Clear(); + + if (iback.Count > 0) + { + int vcount = vback.GetSize(); + List vertices2 = vback.GetVertices(); + int tcount = iback.Count / 3; + + calcConvexDecomposition(vertices2, iback, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent); + } + + iback.Clear(); + vback.Clear(); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexResult.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexResult.cs new file mode 100644 index 0000000..44e3e50 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexResult.cs @@ -0,0 +1,74 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class ConvexResult + { + public List HullVertices; + public List HullIndices; + + public float mHullVolume; // the volume of the convex hull. + + //public float[] OBBSides = new float[3]; // the width, height and breadth of the best fit OBB + //public float[] OBBCenter = new float[3]; // the center of the OBB + //public float[] OBBOrientation = new float[4]; // the quaternion rotation of the OBB. + //public float[] OBBTransform = new float[16]; // the 4x4 transform of the OBB. + //public float OBBVolume; // the volume of the OBB + + //public float SphereRadius; // radius and center of best fit sphere + //public float[] SphereCenter = new float[3]; + //public float SphereVolume; // volume of the best fit sphere + + public ConvexResult() + { + HullVertices = new List(); + HullIndices = new List(); + } + + public ConvexResult(List hvertices, List hindices) + { + HullVertices = hvertices; + HullIndices = hindices; + } + + public ConvexResult(ConvexResult r) + { + HullVertices = new List(r.HullVertices); + HullIndices = new List(r.HullIndices); + } + + public void Dispose() + { + HullVertices = null; + HullIndices = null; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullClasses.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullClasses.cs new file mode 100644 index 0000000..8a0164e --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullClasses.cs @@ -0,0 +1,171 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class HullResult + { + public bool Polygons = true; // true if indices represents polygons, false indices are triangles + public List OutputVertices = new List(); + public List Indices; + + // If triangles, then indices are array indexes into the vertex list. + // If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc.. + } + + public class PHullResult + { + public List Vertices = new List(); + public List Indices = new List(); + } + + [Flags] + public enum HullFlag : int + { + QF_DEFAULT = 0, + QF_TRIANGLES = (1 << 0), // report results as triangles, not polygons. + QF_SKIN_WIDTH = (1 << 2) // extrude hull based on this skin width + } + + public enum HullError : int + { + QE_OK, // success! + QE_FAIL // failed. + } + + public class HullDesc + { + public HullFlag Flags; // flags to use when generating the convex hull. + public List Vertices; + public float NormalEpsilon; // the epsilon for removing duplicates. This is a normalized value, if normalized bit is on. + public float SkinWidth; + public uint MaxVertices; // maximum number of vertices to be considered for the hull! + public uint MaxFaces; + + public HullDesc() + { + Flags = HullFlag.QF_DEFAULT; + Vertices = new List(); + NormalEpsilon = 0.001f; + MaxVertices = 4096; + MaxFaces = 4096; + SkinWidth = 0.01f; + } + + public HullDesc(HullFlag flags, List vertices) + { + Flags = flags; + Vertices = new List(vertices); + NormalEpsilon = 0.001f; + MaxVertices = 4096; + MaxFaces = 4096; + SkinWidth = 0.01f; + } + + public bool HasHullFlag(HullFlag flag) + { + return (Flags & flag) != 0; + } + + public void SetHullFlag(HullFlag flag) + { + Flags |= flag; + } + + public void ClearHullFlag(HullFlag flag) + { + Flags &= ~flag; + } + } + + public class ConvexH + { + public struct HalfEdge + { + public short ea; // the other half of the edge (index into edges list) + public byte v; // the vertex at the start of this edge (index into vertices list) + public byte p; // the facet on which this edge lies (index into facets list) + + public HalfEdge(short _ea, byte _v, byte _p) + { + ea = _ea; + v = _v; + p = _p; + } + + public HalfEdge(HalfEdge e) + { + ea = e.ea; + v = e.v; + p = e.p; + } + } + + public List vertices = new List(); + public List edges = new List(); + public List facets = new List(); + + public ConvexH(int vertices_size, int edges_size, int facets_size) + { + vertices = new List(vertices_size); + edges = new List(edges_size); + facets = new List(facets_size); + } + } + + public class VertFlag + { + public byte planetest; + public byte junk; + public byte undermap; + public byte overmap; + } + + public class EdgeFlag + { + public byte planetest; + public byte fixes; + public short undermap; + public short overmap; + } + + public class PlaneFlag + { + public byte undermap; + public byte overmap; + } + + public class Coplanar + { + public ushort ea; + public byte v0; + public byte v1; + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullTriangle.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullTriangle.cs new file mode 100644 index 0000000..d3f0052 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullTriangle.cs @@ -0,0 +1,99 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class HullTriangle : int3 + { + public int3 n = new int3(); + public int id; + public int vmax; + public float rise; + private List tris; + + public HullTriangle(int a, int b, int c, List tris) + : base(a, b, c) + { + this.tris = tris; + + n = new int3(-1, -1, -1); + id = tris.Count; + tris.Add(this); + vmax = -1; + rise = 0.0f; + } + + public void Dispose() + { + Debug.Assert(tris[id] == this); + tris[id] = null; + } + + public int neib(int a, int b) + { + int i; + + for (i = 0; i < 3; i++) + { + int i1 = (i + 1) % 3; + int i2 = (i + 2) % 3; + if ((this)[i] == a && (this)[i1] == b) + return n[i2]; + if ((this)[i] == b && (this)[i1] == a) + return n[i2]; + } + + Debug.Assert(false); + return -1; + } + + public void setneib(int a, int b, int value) + { + int i; + + for (i = 0; i < 3; i++) + { + int i1 = (i + 1) % 3; + int i2 = (i + 2) % 3; + if ((this)[i] == a && (this)[i1] == b) + { + n[i2] = value; + return; + } + if ((this)[i] == b && (this)[i1] == a) + { + n[i2] = value; + return; + } + } + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs new file mode 100644 index 0000000..3903254 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs @@ -0,0 +1,1868 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public static class HullUtils + { + public static int argmin(float[] a, int n) + { + int r = 0; + for (int i = 1; i < n; i++) + { + if (a[i] < a[r]) + { + r = i; + } + } + return r; + } + + public static float clampf(float a) + { + return Math.Min(1.0f, Math.Max(0.0f, a)); + } + + public static float Round(float a, float precision) + { + return (float)Math.Floor(0.5f + a / precision) * precision; + } + + public static float Interpolate(float f0, float f1, float alpha) + { + return f0 * (1 - alpha) + f1 * alpha; + } + + public static void Swap(ref T a, ref T b) + { + T tmp = a; + a = b; + b = tmp; + } + + public static bool above(List vertices, int3 t, float3 p, float epsilon) + { + float3 vtx = vertices[t.x]; + float3 n = TriNormal(vtx, vertices[t.y], vertices[t.z]); + return (float3.dot(n, p - vtx) > epsilon); // EPSILON??? + } + + public static int hasedge(int3 t, int a, int b) + { + for (int i = 0; i < 3; i++) + { + int i1 = (i + 1) % 3; + if (t[i] == a && t[i1] == b) + return 1; + } + return 0; + } + + public static bool hasvert(int3 t, int v) + { + return (t[0] == v || t[1] == v || t[2] == v); + } + + public static int shareedge(int3 a, int3 b) + { + int i; + for (i = 0; i < 3; i++) + { + int i1 = (i + 1) % 3; + if (hasedge(a, b[i1], b[i]) != 0) + return 1; + } + return 0; + } + + public static void b2bfix(HullTriangle s, HullTriangle t, List tris) + { + int i; + for (i = 0; i < 3; i++) + { + int i1 = (i + 1) % 3; + int i2 = (i + 2) % 3; + int a = (s)[i1]; + int b = (s)[i2]; + Debug.Assert(tris[s.neib(a, b)].neib(b, a) == s.id); + Debug.Assert(tris[t.neib(a, b)].neib(b, a) == t.id); + tris[s.neib(a, b)].setneib(b, a, t.neib(b, a)); + tris[t.neib(b, a)].setneib(a, b, s.neib(a, b)); + } + } + + public static void removeb2b(HullTriangle s, HullTriangle t, List tris) + { + b2bfix(s, t, tris); + s.Dispose(); + t.Dispose(); + } + + public static void checkit(HullTriangle t, List tris) + { + int i; + Debug.Assert(tris[t.id] == t); + for (i = 0; i < 3; i++) + { + int i1 = (i + 1) % 3; + int i2 = (i + 2) % 3; + int a = (t)[i1]; + int b = (t)[i2]; + Debug.Assert(a != b); + Debug.Assert(tris[t.n[i]].neib(b, a) == t.id); + } + } + + public static void extrude(HullTriangle t0, int v, List tris) + { + int3 t = t0; + int n = tris.Count; + HullTriangle ta = new HullTriangle(v, t[1], t[2], tris); + ta.n = new int3(t0.n[0], n + 1, n + 2); + tris[t0.n[0]].setneib(t[1], t[2], n + 0); + HullTriangle tb = new HullTriangle(v, t[2], t[0], tris); + tb.n = new int3(t0.n[1], n + 2, n + 0); + tris[t0.n[1]].setneib(t[2], t[0], n + 1); + HullTriangle tc = new HullTriangle(v, t[0], t[1], tris); + tc.n = new int3(t0.n[2], n + 0, n + 1); + tris[t0.n[2]].setneib(t[0], t[1], n + 2); + checkit(ta, tris); + checkit(tb, tris); + checkit(tc, tris); + if (hasvert(tris[ta.n[0]], v)) + removeb2b(ta, tris[ta.n[0]], tris); + if (hasvert(tris[tb.n[0]], v)) + removeb2b(tb, tris[tb.n[0]], tris); + if (hasvert(tris[tc.n[0]], v)) + removeb2b(tc, tris[tc.n[0]], tris); + t0.Dispose(); + } + + public static HullTriangle extrudable(float epsilon, List tris) + { + int i; + HullTriangle t = null; + for (i = 0; i < tris.Count; i++) + { + if (t == null || (tris.Count > i && (object)tris[i] != null && t.rise < tris[i].rise)) + { + t = tris[i]; + } + } + return (t.rise > epsilon) ? t : null; + } + + public static Quaternion RotationArc(float3 v0, float3 v1) + { + Quaternion q = new Quaternion(); + v0 = float3.normalize(v0); // Comment these two lines out if you know its not needed. + v1 = float3.normalize(v1); // If vector is already unit length then why do it again? + float3 c = float3.cross(v0, v1); + float d = float3.dot(v0, v1); + if (d <= -1.0f) // 180 about x axis + { + return new Quaternion(1f, 0f, 0f, 0f); + } + float s = (float)Math.Sqrt((1 + d) * 2f); + q.x = c.x / s; + q.y = c.y / s; + q.z = c.z / s; + q.w = s / 2.0f; + return q; + } + + public static float3 PlaneLineIntersection(Plane plane, float3 p0, float3 p1) + { + // returns the point where the line p0-p1 intersects the plane n&d + float3 dif = p1 - p0; + float dn = float3.dot(plane.normal, dif); + float t = -(plane.dist + float3.dot(plane.normal, p0)) / dn; + return p0 + (dif * t); + } + + public static float3 LineProject(float3 p0, float3 p1, float3 a) + { + float3 w = new float3(); + w = p1 - p0; + float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z); + return p0 + w * t; + } + + public static float3 PlaneProject(Plane plane, float3 point) + { + return point - plane.normal * (float3.dot(point, plane.normal) + plane.dist); + } + + public static float LineProjectTime(float3 p0, float3 p1, float3 a) + { + float3 w = new float3(); + w = p1 - p0; + float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z); + return t; + } + + public static float3 ThreePlaneIntersection(Plane p0, Plane p1, Plane p2) + { + float3x3 mp = float3x3.Transpose(new float3x3(p0.normal, p1.normal, p2.normal)); + float3x3 mi = float3x3.Inverse(mp); + float3 b = new float3(p0.dist, p1.dist, p2.dist); + return -b * mi; + } + + public static bool PolyHit(List vert, float3 v0, float3 v1) + { + float3 impact = new float3(); + float3 normal = new float3(); + return PolyHit(vert, v0, v1, out impact, out normal); + } + + public static bool PolyHit(List vert, float3 v0, float3 v1, out float3 impact) + { + float3 normal = new float3(); + return PolyHit(vert, v0, v1, out impact, out normal); + } + + public static bool PolyHit(List vert, float3 v0, float3 v1, out float3 impact, out float3 normal) + { + float3 the_point = new float3(); + + impact = null; + normal = null; + + int i; + float3 nrml = new float3(0, 0, 0); + for (i = 0; i < vert.Count; i++) + { + int i1 = (i + 1) % vert.Count; + int i2 = (i + 2) % vert.Count; + nrml = nrml + float3.cross(vert[i1] - vert[i], vert[i2] - vert[i1]); + } + + float m = float3.magnitude(nrml); + if (m == 0.0) + { + return false; + } + nrml = nrml * (1.0f / m); + float dist = -float3.dot(nrml, vert[0]); + float d0; + float d1; + if ((d0 = float3.dot(v0, nrml) + dist) < 0 || (d1 = float3.dot(v1, nrml) + dist) > 0) + { + return false; + } + + // By using the cached plane distances d0 and d1 + // we can optimize the following: + // the_point = planelineintersection(nrml,dist,v0,v1); + float a = d0 / (d0 - d1); + the_point = v0 * (1 - a) + v1 * a; + + + bool inside = true; + for (int j = 0; inside && j < vert.Count; j++) + { + // let inside = 0 if outside + float3 pp1 = new float3(); + float3 pp2 = new float3(); + float3 side = new float3(); + pp1 = vert[j]; + pp2 = vert[(j + 1) % vert.Count]; + side = float3.cross((pp2 - pp1), (the_point - pp1)); + inside = (float3.dot(nrml, side) >= 0.0); + } + if (inside) + { + if (normal != null) + { + normal = nrml; + } + if (impact != null) + { + impact = the_point; + } + } + return inside; + } + + public static bool BoxInside(float3 p, float3 bmin, float3 bmax) + { + return (p.x >= bmin.x && p.x <= bmax.x && p.y >= bmin.y && p.y <= bmax.y && p.z >= bmin.z && p.z <= bmax.z); + } + + public static bool BoxIntersect(float3 v0, float3 v1, float3 bmin, float3 bmax, float3 impact) + { + if (BoxInside(v0, bmin, bmax)) + { + impact = v0; + return true; + } + if (v0.x <= bmin.x && v1.x >= bmin.x) + { + float a = (bmin.x - v0.x) / (v1.x - v0.x); + //v.x = bmin.x; + float vy = (1 - a) * v0.y + a * v1.y; + float vz = (1 - a) * v0.z + a * v1.z; + if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z) + { + impact.x = bmin.x; + impact.y = vy; + impact.z = vz; + return true; + } + } + else if (v0.x >= bmax.x && v1.x <= bmax.x) + { + float a = (bmax.x - v0.x) / (v1.x - v0.x); + //v.x = bmax.x; + float vy = (1 - a) * v0.y + a * v1.y; + float vz = (1 - a) * v0.z + a * v1.z; + if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z) + { + impact.x = bmax.x; + impact.y = vy; + impact.z = vz; + return true; + } + } + if (v0.y <= bmin.y && v1.y >= bmin.y) + { + float a = (bmin.y - v0.y) / (v1.y - v0.y); + float vx = (1 - a) * v0.x + a * v1.x; + //v.y = bmin.y; + float vz = (1 - a) * v0.z + a * v1.z; + if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z) + { + impact.x = vx; + impact.y = bmin.y; + impact.z = vz; + return true; + } + } + else if (v0.y >= bmax.y && v1.y <= bmax.y) + { + float a = (bmax.y - v0.y) / (v1.y - v0.y); + float vx = (1 - a) * v0.x + a * v1.x; + // vy = bmax.y; + float vz = (1 - a) * v0.z + a * v1.z; + if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z) + { + impact.x = vx; + impact.y = bmax.y; + impact.z = vz; + return true; + } + } + if (v0.z <= bmin.z && v1.z >= bmin.z) + { + float a = (bmin.z - v0.z) / (v1.z - v0.z); + float vx = (1 - a) * v0.x + a * v1.x; + float vy = (1 - a) * v0.y + a * v1.y; + // v.z = bmin.z; + if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x) + { + impact.x = vx; + impact.y = vy; + impact.z = bmin.z; + return true; + } + } + else if (v0.z >= bmax.z && v1.z <= bmax.z) + { + float a = (bmax.z - v0.z) / (v1.z - v0.z); + float vx = (1 - a) * v0.x + a * v1.x; + float vy = (1 - a) * v0.y + a * v1.y; + // v.z = bmax.z; + if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x) + { + impact.x = vx; + impact.y = vy; + impact.z = bmax.z; + return true; + } + } + return false; + } + + public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint) + { + return DistanceBetweenLines(ustart, udir, vstart, vdir, upoint, null); + } + + public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir) + { + return DistanceBetweenLines(ustart, udir, vstart, vdir, null, null); + } + + public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint, float3 vpoint) + { + float3 cp = float3.normalize(float3.cross(udir, vdir)); + + float distu = -float3.dot(cp, ustart); + float distv = -float3.dot(cp, vstart); + float dist = (float)Math.Abs(distu - distv); + if (upoint != null) + { + Plane plane = new Plane(); + plane.normal = float3.normalize(float3.cross(vdir, cp)); + plane.dist = -float3.dot(plane.normal, vstart); + upoint = PlaneLineIntersection(plane, ustart, ustart + udir); + } + if (vpoint != null) + { + Plane plane = new Plane(); + plane.normal = float3.normalize(float3.cross(udir, cp)); + plane.dist = -float3.dot(plane.normal, ustart); + vpoint = PlaneLineIntersection(plane, vstart, vstart + vdir); + } + return dist; + } + + public static float3 TriNormal(float3 v0, float3 v1, float3 v2) + { + // return the normal of the triangle + // inscribed by v0, v1, and v2 + float3 cp = float3.cross(v1 - v0, v2 - v1); + float m = float3.magnitude(cp); + if (m == 0) + return new float3(1, 0, 0); + return cp * (1.0f / m); + } + + public static int PlaneTest(Plane p, float3 v, float planetestepsilon) + { + float a = float3.dot(v, p.normal) + p.dist; + int flag = (a > planetestepsilon) ? (2) : ((a < -planetestepsilon) ? (1) : (0)); + return flag; + } + + public static int SplitTest(ref ConvexH convex, Plane plane, float planetestepsilon) + { + int flag = 0; + for (int i = 0; i < convex.vertices.Count; i++) + { + flag |= PlaneTest(plane, convex.vertices[i], planetestepsilon); + } + return flag; + } + + public static Quaternion VirtualTrackBall(float3 cop, float3 cor, float3 dir1, float3 dir2) + { + // routine taken from game programming gems. + // Implement track ball functionality to spin stuf on the screen + // cop center of projection + // cor center of rotation + // dir1 old mouse direction + // dir2 new mouse direction + // pretend there is a sphere around cor. Then find the points + // where dir1 and dir2 intersect that sphere. Find the + // rotation that takes the first point to the second. + float m; + // compute plane + float3 nrml = cor - cop; + float fudgefactor = 1.0f / (float3.magnitude(nrml) * 0.25f); // since trackball proportional to distance from cop + nrml = float3.normalize(nrml); + float dist = -float3.dot(nrml, cor); + float3 u = PlaneLineIntersection(new Plane(nrml, dist), cop, cop + dir1); + u = u - cor; + u = u * fudgefactor; + m = float3.magnitude(u); + if (m > 1) + { + u /= m; + } + else + { + u = u - (nrml * (float)Math.Sqrt(1 - m * m)); + } + float3 v = PlaneLineIntersection(new Plane(nrml, dist), cop, cop + dir2); + v = v - cor; + v = v * fudgefactor; + m = float3.magnitude(v); + if (m > 1) + { + v /= m; + } + else + { + v = v - (nrml * (float)Math.Sqrt(1 - m * m)); + } + return RotationArc(u, v); + } + + public static bool AssertIntact(ConvexH convex, float planetestepsilon) + { + int i; + int estart = 0; + for (i = 0; i < convex.edges.Count; i++) + { + if (convex.edges[estart].p != convex.edges[i].p) + { + estart = i; + } + int inext = i + 1; + if (inext >= convex.edges.Count || convex.edges[inext].p != convex.edges[i].p) + { + inext = estart; + } + Debug.Assert(convex.edges[inext].p == convex.edges[i].p); + int nb = convex.edges[i].ea; + Debug.Assert(nb != 255); + if (nb == 255 || nb == -1) + return false; + Debug.Assert(nb != -1); + Debug.Assert(i == convex.edges[nb].ea); + } + for (i = 0; i < convex.edges.Count; i++) + { + Debug.Assert((0) == PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon)); + if ((0) != PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon)) + return false; + if (convex.edges[estart].p != convex.edges[i].p) + { + estart = i; + } + int i1 = i + 1; + if (i1 >= convex.edges.Count || convex.edges[i1].p != convex.edges[i].p) + { + i1 = estart; + } + int i2 = i1 + 1; + if (i2 >= convex.edges.Count || convex.edges[i2].p != convex.edges[i].p) + { + i2 = estart; + } + if (i == i2) // i sliced tangent to an edge and created 2 meaningless edges + continue; + float3 localnormal = TriNormal(convex.vertices[convex.edges[i].v], convex.vertices[convex.edges[i1].v], convex.vertices[convex.edges[i2].v]); + Debug.Assert(float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) > 0); + if (float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) <= 0) + return false; + } + return true; + } + + public static ConvexH test_btbq(float planetestepsilon) + { + // back to back quads + ConvexH convex = new ConvexH(4, 8, 2); + convex.vertices[0] = new float3(0, 0, 0); + convex.vertices[1] = new float3(1, 0, 0); + convex.vertices[2] = new float3(1, 1, 0); + convex.vertices[3] = new float3(0, 1, 0); + convex.facets[0] = new Plane(new float3(0, 0, 1), 0); + convex.facets[1] = new Plane(new float3(0, 0, -1), 0); + convex.edges[0] = new ConvexH.HalfEdge(7, 0, 0); + convex.edges[1] = new ConvexH.HalfEdge(6, 1, 0); + convex.edges[2] = new ConvexH.HalfEdge(5, 2, 0); + convex.edges[3] = new ConvexH.HalfEdge(4, 3, 0); + + convex.edges[4] = new ConvexH.HalfEdge(3, 0, 1); + convex.edges[5] = new ConvexH.HalfEdge(2, 3, 1); + convex.edges[6] = new ConvexH.HalfEdge(1, 2, 1); + convex.edges[7] = new ConvexH.HalfEdge(0, 1, 1); + AssertIntact(convex, planetestepsilon); + return convex; + } + + public static ConvexH test_cube() + { + ConvexH convex = new ConvexH(8, 24, 6); + convex.vertices[0] = new float3(0, 0, 0); + convex.vertices[1] = new float3(0, 0, 1); + convex.vertices[2] = new float3(0, 1, 0); + convex.vertices[3] = new float3(0, 1, 1); + convex.vertices[4] = new float3(1, 0, 0); + convex.vertices[5] = new float3(1, 0, 1); + convex.vertices[6] = new float3(1, 1, 0); + convex.vertices[7] = new float3(1, 1, 1); + + convex.facets[0] = new Plane(new float3(-1, 0, 0), 0); + convex.facets[1] = new Plane(new float3(1, 0, 0), -1); + convex.facets[2] = new Plane(new float3(0, -1, 0), 0); + convex.facets[3] = new Plane(new float3(0, 1, 0), -1); + convex.facets[4] = new Plane(new float3(0, 0, -1), 0); + convex.facets[5] = new Plane(new float3(0, 0, 1), -1); + + convex.edges[0] = new ConvexH.HalfEdge(11, 0, 0); + convex.edges[1] = new ConvexH.HalfEdge(23, 1, 0); + convex.edges[2] = new ConvexH.HalfEdge(15, 3, 0); + convex.edges[3] = new ConvexH.HalfEdge(16, 2, 0); + + convex.edges[4] = new ConvexH.HalfEdge(13, 6, 1); + convex.edges[5] = new ConvexH.HalfEdge(21, 7, 1); + convex.edges[6] = new ConvexH.HalfEdge(9, 5, 1); + convex.edges[7] = new ConvexH.HalfEdge(18, 4, 1); + + convex.edges[8] = new ConvexH.HalfEdge(19, 0, 2); + convex.edges[9] = new ConvexH.HalfEdge(6, 4, 2); + convex.edges[10] = new ConvexH.HalfEdge(20, 5, 2); + convex.edges[11] = new ConvexH.HalfEdge(0, 1, 2); + + convex.edges[12] = new ConvexH.HalfEdge(22, 3, 3); + convex.edges[13] = new ConvexH.HalfEdge(4, 7, 3); + convex.edges[14] = new ConvexH.HalfEdge(17, 6, 3); + convex.edges[15] = new ConvexH.HalfEdge(2, 2, 3); + + convex.edges[16] = new ConvexH.HalfEdge(3, 0, 4); + convex.edges[17] = new ConvexH.HalfEdge(14, 2, 4); + convex.edges[18] = new ConvexH.HalfEdge(7, 6, 4); + convex.edges[19] = new ConvexH.HalfEdge(8, 4, 4); + + convex.edges[20] = new ConvexH.HalfEdge(10, 1, 5); + convex.edges[21] = new ConvexH.HalfEdge(5, 5, 5); + convex.edges[22] = new ConvexH.HalfEdge(12, 7, 5); + convex.edges[23] = new ConvexH.HalfEdge(1, 3, 5); + + return convex; + } + + public static ConvexH ConvexHMakeCube(float3 bmin, float3 bmax) + { + ConvexH convex = test_cube(); + convex.vertices[0] = new float3(bmin.x, bmin.y, bmin.z); + convex.vertices[1] = new float3(bmin.x, bmin.y, bmax.z); + convex.vertices[2] = new float3(bmin.x, bmax.y, bmin.z); + convex.vertices[3] = new float3(bmin.x, bmax.y, bmax.z); + convex.vertices[4] = new float3(bmax.x, bmin.y, bmin.z); + convex.vertices[5] = new float3(bmax.x, bmin.y, bmax.z); + convex.vertices[6] = new float3(bmax.x, bmax.y, bmin.z); + convex.vertices[7] = new float3(bmax.x, bmax.y, bmax.z); + + convex.facets[0] = new Plane(new float3(-1, 0, 0), bmin.x); + convex.facets[1] = new Plane(new float3(1, 0, 0), -bmax.x); + convex.facets[2] = new Plane(new float3(0, -1, 0), bmin.y); + convex.facets[3] = new Plane(new float3(0, 1, 0), -bmax.y); + convex.facets[4] = new Plane(new float3(0, 0, -1), bmin.z); + convex.facets[5] = new Plane(new float3(0, 0, 1), -bmax.z); + return convex; + } + + public static ConvexH ConvexHCrop(ref ConvexH convex, Plane slice, float planetestepsilon) + { + int i; + int vertcountunder = 0; + int vertcountover = 0; + List vertscoplanar = new List(); // existing vertex members of convex that are coplanar + List edgesplit = new List(); // existing edges that members of convex that cross the splitplane + + Debug.Assert(convex.edges.Count < 480); + + EdgeFlag[] edgeflag = new EdgeFlag[512]; + VertFlag[] vertflag = new VertFlag[256]; + PlaneFlag[] planeflag = new PlaneFlag[128]; + ConvexH.HalfEdge[] tmpunderedges = new ConvexH.HalfEdge[512]; + Plane[] tmpunderplanes = new Plane[128]; + Coplanar[] coplanaredges = new Coplanar[512]; + int coplanaredges_num = 0; + + List createdverts = new List(); + + // do the side-of-plane tests + for (i = 0; i < convex.vertices.Count; i++) + { + vertflag[i].planetest = (byte)PlaneTest(slice, convex.vertices[i], planetestepsilon); + if (vertflag[i].planetest == (0)) + { + // ? vertscoplanar.Add(i); + vertflag[i].undermap = (byte)vertcountunder++; + vertflag[i].overmap = (byte)vertcountover++; + } + else if (vertflag[i].planetest == (1)) + { + vertflag[i].undermap = (byte)vertcountunder++; + } + else + { + Debug.Assert(vertflag[i].planetest == (2)); + vertflag[i].overmap = (byte)vertcountover++; + vertflag[i].undermap = 255; // for debugging purposes + } + } + int vertcountunderold = vertcountunder; // for debugging only + + int under_edge_count = 0; + int underplanescount = 0; + int e0 = 0; + + for (int currentplane = 0; currentplane < convex.facets.Count; currentplane++) + { + int estart = e0; + int enextface = 0; + int planeside = 0; + int e1 = e0 + 1; + int vout = -1; + int vin = -1; + int coplanaredge = -1; + do + { + + if (e1 >= convex.edges.Count || convex.edges[e1].p != currentplane) + { + enextface = e1; + e1 = estart; + } + ConvexH.HalfEdge edge0 = convex.edges[e0]; + ConvexH.HalfEdge edge1 = convex.edges[e1]; + ConvexH.HalfEdge edgea = convex.edges[edge0.ea]; + + planeside |= vertflag[edge0.v].planetest; + //if((vertflag[edge0.v].planetest & vertflag[edge1.v].planetest) == COPLANAR) { + // assert(ecop==-1); + // ecop=e; + //} + + if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (2)) + { + // both endpoints over plane + edgeflag[e0].undermap = -1; + } + else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (1)) + { + // at least one endpoint under, the other coplanar or under + + edgeflag[e0].undermap = (short)under_edge_count; + tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap; + tmpunderedges[under_edge_count].p = (byte)underplanescount; + if (edge0.ea < e0) + { + // connect the neighbors + Debug.Assert(edgeflag[edge0.ea].undermap != -1); + tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; + tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; + } + under_edge_count++; + } + else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (0)) + { + // both endpoints coplanar + // must check a 3rd point to see if UNDER + int e2 = e1 + 1; + if (e2 >= convex.edges.Count || convex.edges[e2].p != currentplane) + { + e2 = estart; + } + Debug.Assert(convex.edges[e2].p == currentplane); + ConvexH.HalfEdge edge2 = convex.edges[e2]; + if (vertflag[edge2.v].planetest == (1)) + { + + edgeflag[e0].undermap = (short)under_edge_count; + tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap; + tmpunderedges[under_edge_count].p = (byte)underplanescount; + tmpunderedges[under_edge_count].ea = -1; + // make sure this edge is added to the "coplanar" list + coplanaredge = under_edge_count; + vout = vertflag[edge0.v].undermap; + vin = vertflag[edge1.v].undermap; + under_edge_count++; + } + else + { + edgeflag[e0].undermap = -1; + } + } + else if (vertflag[edge0.v].planetest == (1) && vertflag[edge1.v].planetest == (2)) + { + // first is under 2nd is over + + edgeflag[e0].undermap = (short)under_edge_count; + tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap; + tmpunderedges[under_edge_count].p = (byte)underplanescount; + if (edge0.ea < e0) + { + Debug.Assert(edgeflag[edge0.ea].undermap != -1); + // connect the neighbors + tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; + tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; + vout = tmpunderedges[edgeflag[edge0.ea].undermap].v; + } + else + { + Plane p0 = convex.facets[edge0.p]; + Plane pa = convex.facets[edgea.p]; + createdverts.Add(ThreePlaneIntersection(p0, pa, slice)); + //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]))); + //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])); + vout = vertcountunder++; + } + under_edge_count++; + /// hmmm something to think about: i might be able to output this edge regarless of + // wheter or not we know v-in yet. ok i;ll try this now: + tmpunderedges[under_edge_count].v = (byte)vout; + tmpunderedges[under_edge_count].p = (byte)underplanescount; + tmpunderedges[under_edge_count].ea = -1; + coplanaredge = under_edge_count; + under_edge_count++; + + if (vin != -1) + { + // we previously processed an edge where we came under + // now we know about vout as well + + // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! + } + + } + else if (vertflag[edge0.v].planetest == (0) && vertflag[edge1.v].planetest == (2)) + { + // first is coplanar 2nd is over + + edgeflag[e0].undermap = -1; + vout = vertflag[edge0.v].undermap; + // I hate this but i have to make sure part of this face is UNDER before ouputting this vert + int k = estart; + Debug.Assert(edge0.p == currentplane); + while (!((planeside & 1) != 0) && k < convex.edges.Count && convex.edges[k].p == edge0.p) + { + planeside |= vertflag[convex.edges[k].v].planetest; + k++; + } + if ((planeside & 1) != 0) + { + tmpunderedges[under_edge_count].v = (byte)vout; + tmpunderedges[under_edge_count].p = (byte)underplanescount; + tmpunderedges[under_edge_count].ea = -1; + coplanaredge = under_edge_count; // hmmm should make a note of the edge # for later on + under_edge_count++; + + } + } + else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (1)) + { + // first is over next is under + // new vertex!!! + Debug.Assert(vin == -1); + if (e0 < edge0.ea) + { + Plane p0 = convex.facets[edge0.p]; + Plane pa = convex.facets[edgea.p]; + createdverts.Add(ThreePlaneIntersection(p0, pa, slice)); + //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])); + //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]))); + vin = vertcountunder++; + } + else + { + // find the new vertex that was created by edge[edge0.ea] + int nea = edgeflag[edge0.ea].undermap; + Debug.Assert(tmpunderedges[nea].p == tmpunderedges[nea + 1].p); + vin = tmpunderedges[nea + 1].v; + Debug.Assert(vin < vertcountunder); + Debug.Assert(vin >= vertcountunderold); // for debugging only + } + if (vout != -1) + { + // we previously processed an edge where we went over + // now we know vin too + // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! + } + // output edge + tmpunderedges[under_edge_count].v = (byte)vin; + tmpunderedges[under_edge_count].p = (byte)underplanescount; + edgeflag[e0].undermap = (short)under_edge_count; + if (e0 > edge0.ea) + { + Debug.Assert(edgeflag[edge0.ea].undermap != -1); + // connect the neighbors + tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; + tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; + } + Debug.Assert(edgeflag[e0].undermap == under_edge_count); + under_edge_count++; + } + else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (0)) + { + // first is over next is coplanar + + edgeflag[e0].undermap = -1; + vin = vertflag[edge1.v].undermap; + Debug.Assert(vin != -1); + if (vout != -1) + { + // we previously processed an edge where we came under + // now we know both endpoints + // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! + } + + } + else + { + Debug.Assert(false); + } + + + e0 = e1; + e1++; // do the modulo at the beginning of the loop + + } while (e0 != estart); + e0 = enextface; + if ((planeside & 1) != 0) + { + planeflag[currentplane].undermap = (byte)underplanescount; + tmpunderplanes[underplanescount] = convex.facets[currentplane]; + underplanescount++; + } + else + { + planeflag[currentplane].undermap = 0; + } + if (vout >= 0 && (planeside & 1) != 0) + { + Debug.Assert(vin >= 0); + Debug.Assert(coplanaredge >= 0); + Debug.Assert(coplanaredge != 511); + coplanaredges[coplanaredges_num].ea = (ushort)coplanaredge; + coplanaredges[coplanaredges_num].v0 = (byte)vin; + coplanaredges[coplanaredges_num].v1 = (byte)vout; + coplanaredges_num++; + } + } + + // add the new plane to the mix: + if (coplanaredges_num > 0) + { + tmpunderplanes[underplanescount++] = slice; + } + for (i = 0; i < coplanaredges_num - 1; i++) + { + if (coplanaredges[i].v1 != coplanaredges[i + 1].v0) + { + int j = 0; + for (j = i + 2; j < coplanaredges_num; j++) + { + if (coplanaredges[i].v1 == coplanaredges[j].v0) + { + Coplanar tmp = coplanaredges[i + 1]; + coplanaredges[i + 1] = coplanaredges[j]; + coplanaredges[j] = tmp; + break; + } + } + if (j >= coplanaredges_num) + { + Debug.Assert(j < coplanaredges_num); + return null; + } + } + } + + ConvexH punder = new ConvexH(vertcountunder, under_edge_count + coplanaredges_num, underplanescount); + ConvexH under = punder; + + { + int k = 0; + for (i = 0; i < convex.vertices.Count; i++) + { + if (vertflag[i].planetest != (2)) + { + under.vertices[k++] = convex.vertices[i]; + } + } + i = 0; + while (k < vertcountunder) + { + under.vertices[k++] = createdverts[i++]; + } + Debug.Assert(i == createdverts.Count); + } + + for (i = 0; i < coplanaredges_num; i++) + { + ConvexH.HalfEdge edge = under.edges[under_edge_count + i]; + edge.p = (byte)(underplanescount - 1); + edge.ea = (short)coplanaredges[i].ea; + edge.v = (byte)coplanaredges[i].v0; + under.edges[under_edge_count + i] = edge; + + tmpunderedges[coplanaredges[i].ea].ea = (short)(under_edge_count + i); + } + + under.edges = new List(tmpunderedges); + under.facets = new List(tmpunderplanes); + return punder; + } + + public static ConvexH ConvexHDup(ConvexH src) + { + ConvexH dst = new ConvexH(src.vertices.Count, src.edges.Count, src.facets.Count); + dst.vertices = new List(src.vertices.Count); + foreach (float3 f in src.vertices) + dst.vertices.Add(new float3(f)); + dst.edges = new List(src.edges.Count); + foreach (ConvexH.HalfEdge e in src.edges) + dst.edges.Add(new ConvexH.HalfEdge(e)); + dst.facets = new List(src.facets.Count); + foreach (Plane p in src.facets) + dst.facets.Add(new Plane(p)); + return dst; + } + + public static int candidateplane(List planes, int planes_count, ConvexH convex, float epsilon) + { + int p = 0; + float md = 0; + int i; + for (i = 0; i < planes_count; i++) + { + float d = 0; + for (int j = 0; j < convex.vertices.Count; j++) + { + d = Math.Max(d, float3.dot(convex.vertices[j], planes[i].normal) + planes[i].dist); + } + if (i == 0 || d > md) + { + p = i; + md = d; + } + } + return (md > epsilon) ? p : -1; + } + + public static float3 orth(float3 v) + { + float3 a = float3.cross(v, new float3(0f, 0f, 1f)); + float3 b = float3.cross(v, new float3(0f, 1f, 0f)); + return float3.normalize((float3.magnitude(a) > float3.magnitude(b)) ? a : b); + } + + public static int maxdir(List p, int count, float3 dir) + { + Debug.Assert(count != 0); + int m = 0; + float currDotm = float3.dot(p[0], dir); + for (int i = 1; i < count; i++) + { + float currDoti = float3.dot(p[i], dir); + if (currDoti > currDotm) + { + currDotm = currDoti; + m = i; + } + } + return m; + } + + public static int maxdirfiltered(List p, int count, float3 dir, byte[] allow) + { + //Debug.Assert(count != 0); + int m = 0; + float currDotm = float3.dot(p[0], dir); + float currDoti; + + while (allow[m] == 0) + m++; + + for (int i = 1; i < count; i++) + { + if (allow[i] != 0) + { + currDoti = float3.dot(p[i], dir); + if (currDoti > currDotm) + { + currDotm = currDoti; + m = i; + } + } + } + //Debug.Assert(m != -1); + return m; + } + + public static int maxdirsterid(List p, int count, float3 dir, byte[] allow) + { + int m = -1; + while (m == -1) + { + m = maxdirfiltered(p, count, dir, allow); + if (allow[m] == 3) + return m; + float3 u = orth(dir); + float3 v = float3.cross(u, dir); + int ma = -1; + for (float x = 0.0f; x <= 360.0f; x += 45.0f) + { + int mb; + { + float s = (float)Math.Sin((3.14159264f / 180.0f) * (x)); + float c = (float)Math.Cos((3.14159264f / 180.0f) * (x)); + mb = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow); + } + if (ma == m && mb == m) + { + allow[m] = 3; + return m; + } + if (ma != -1 && ma != mb) // Yuck - this is really ugly + { + int mc = ma; + for (float xx = x - 40.0f; xx <= x; xx += 5.0f) + { + float s = (float)Math.Sin((3.14159264f / 180.0f) * (xx)); + float c = (float)Math.Cos((3.14159264f / 180.0f) * (xx)); + int md = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow); + if (mc == m && md == m) + { + allow[m] = 3; + return m; + } + mc = md; + } + } + ma = mb; + } + allow[m] = 0; + m = -1; + } + + Debug.Assert(false); + return m; + } + + public static int4 FindSimplex(List verts, byte[] allow) + { + float3[] basis = new float3[3]; + basis[0] = new float3(0.01f, 0.02f, 1.0f); + int p0 = maxdirsterid(verts, verts.Count, basis[0], allow); + int p1 = maxdirsterid(verts, verts.Count, -basis[0], allow); + basis[0] = verts[p0] - verts[p1]; + if (p0 == p1 || basis[0] == new float3(0, 0, 0)) + return new int4(-1, -1, -1, -1); + basis[1] = float3.cross(new float3(1, 0.02f, 0), basis[0]); + basis[2] = float3.cross(new float3(-0.02f, 1, 0), basis[0]); + basis[1] = float3.normalize((float3.magnitude(basis[1]) > float3.magnitude(basis[2])) ? basis[1] : basis[2]); + int p2 = maxdirsterid(verts, verts.Count, basis[1], allow); + if (p2 == p0 || p2 == p1) + { + p2 = maxdirsterid(verts, verts.Count, -basis[1], allow); + } + if (p2 == p0 || p2 == p1) + return new int4(-1, -1, -1, -1); + basis[1] = verts[p2] - verts[p0]; + basis[2] = float3.normalize(float3.cross(basis[1], basis[0])); + int p3 = maxdirsterid(verts, verts.Count, basis[2], allow); + if (p3 == p0 || p3 == p1 || p3 == p2) + p3 = maxdirsterid(verts, verts.Count, -basis[2], allow); + if (p3 == p0 || p3 == p1 || p3 == p2) + return new int4(-1, -1, -1, -1); + Debug.Assert(!(p0 == p1 || p0 == p2 || p0 == p3 || p1 == p2 || p1 == p3 || p2 == p3)); + if (float3.dot(verts[p3] - verts[p0], float3.cross(verts[p1] - verts[p0], verts[p2] - verts[p0])) < 0) + { + Swap(ref p2, ref p3); + } + return new int4(p0, p1, p2, p3); + } + + public static float GetDist(float px, float py, float pz, float3 p2) + { + float dx = px - p2.x; + float dy = py - p2.y; + float dz = pz - p2.z; + + return dx * dx + dy * dy + dz * dz; + } + + public static void ReleaseHull(PHullResult result) + { + if (result.Indices != null) + result.Indices = null; + if (result.Vertices != null) + result.Vertices = null; + } + + public static int calchullgen(List verts, int vlimit, List tris) + { + if (verts.Count < 4) + return 0; + if (vlimit == 0) + vlimit = 1000000000; + int j; + float3 bmin = new float3(verts[0]); + float3 bmax = new float3(verts[0]); + List isextreme = new List(verts.Count); + byte[] allow = new byte[verts.Count]; + for (j = 0; j < verts.Count; j++) + { + allow[j] = 1; + isextreme.Add(0); + bmin = float3.VectorMin(bmin, verts[j]); + bmax = float3.VectorMax(bmax, verts[j]); + } + float epsilon = float3.magnitude(bmax - bmin) * 0.001f; + + int4 p = FindSimplex(verts, allow); + if (p.x == -1) // simplex failed + return 0; + + float3 center = (verts[p[0]] + verts[p[1]] + verts[p[2]] + verts[p[3]]) / 4.0f; // a valid interior point + HullTriangle t0 = new HullTriangle(p[2], p[3], p[1], tris); + t0.n = new int3(2, 3, 1); + HullTriangle t1 = new HullTriangle(p[3], p[2], p[0], tris); + t1.n = new int3(3, 2, 0); + HullTriangle t2 = new HullTriangle(p[0], p[1], p[3], tris); + t2.n = new int3(0, 1, 3); + HullTriangle t3 = new HullTriangle(p[1], p[0], p[2], tris); + t3.n = new int3(1, 0, 2); + isextreme[p[0]] = isextreme[p[1]] = isextreme[p[2]] = isextreme[p[3]] = 1; + checkit(t0, tris); + checkit(t1, tris); + checkit(t2, tris); + checkit(t3, tris); + + for (j = 0; j < tris.Count; j++) + { + HullTriangle t = tris[j]; + Debug.Assert((object)t != null); + Debug.Assert(t.vmax < 0); + float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]); + t.vmax = maxdirsterid(verts, verts.Count, n, allow); + t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]); + } + HullTriangle te; + vlimit -= 4; + while (vlimit > 0 && (te = extrudable(epsilon, tris)) != null) + { + int3 ti = te; + int v = te.vmax; + Debug.Assert(isextreme[v] == 0); // wtf we've already done this vertex + isextreme[v] = 1; + //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already + j = tris.Count; + while (j-- != 0) + { + if (tris.Count <= j || (object)tris[j] == null) + continue; + int3 t = tris[j]; + if (above(verts, t, verts[v], 0.01f * epsilon)) + { + extrude(tris[j], v, tris); + } + } + // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle + j = tris.Count; + while (j-- != 0) + { + if (tris.Count <= j || (object)tris[j] == null) + continue; + if (!hasvert(tris[j], v)) + break; + int3 nt = tris[j]; + if (above(verts, nt, center, 0.01f * epsilon) || float3.magnitude(float3.cross(verts[nt[1]] - verts[nt[0]], verts[nt[2]] - verts[nt[1]])) < epsilon * epsilon * 0.1f) + { + HullTriangle nb = tris[tris[j].n[0]]; + Debug.Assert(nb != null); + Debug.Assert(!hasvert(nb, v)); + Debug.Assert(nb.id < j); + extrude(nb, v, tris); + j = tris.Count; + } + } + j = tris.Count; + while (j-- != 0) + { + HullTriangle t = tris[j]; + if (t == null) + continue; + if (t.vmax >= 0) + break; + float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]); + t.vmax = maxdirsterid(verts, verts.Count, n, allow); + if (isextreme[t.vmax] != 0) + { + t.vmax = -1; // already done that vertex - algorithm needs to be able to terminate. + } + else + { + t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]); + } + } + vlimit--; + } + return 1; + } + + public static bool calchull(List verts, out List tris_out, int vlimit, List tris) + { + tris_out = null; + + int rc = calchullgen(verts, vlimit, tris); + if (rc == 0) + return false; + List ts = new List(); + for (int i = 0; i < tris.Count; i++) + { + if ((object)tris[i] != null) + { + for (int j = 0; j < 3; j++) + ts.Add((tris[i])[j]); + tris[i] = null; + } + } + + tris_out = ts; + tris.Clear(); + return true; + } + + public static int calchullpbev(List verts, int vlimit, out List planes, float bevangle, List tris) + { + int i; + int j; + planes = new List(); + int rc = calchullgen(verts, vlimit, tris); + if (rc == 0) + return 0; + for (i = 0; i < tris.Count; i++) + { + if (tris[i] != null) + { + Plane p = new Plane(); + HullTriangle t = tris[i]; + p.normal = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]); + p.dist = -float3.dot(p.normal, verts[(t)[0]]); + planes.Add(p); + for (j = 0; j < 3; j++) + { + if (t.n[j] < t.id) + continue; + HullTriangle s = tris[t.n[j]]; + float3 snormal = TriNormal(verts[(s)[0]], verts[(s)[1]], verts[(s)[2]]); + if (float3.dot(snormal, p.normal) >= Math.Cos(bevangle * (3.14159264f / 180.0f))) + continue; + float3 n = float3.normalize(snormal + p.normal); + planes.Add(new Plane(n, -float3.dot(n, verts[maxdir(verts, verts.Count, n)]))); + } + } + } + + tris.Clear(); + return 1; + } + + public static int overhull(List planes, List verts, int maxplanes, out List verts_out, out List faces_out, float inflate) + { + verts_out = null; + faces_out = null; + + int i; + int j; + if (verts.Count < 4) + return 0; + maxplanes = Math.Min(maxplanes, planes.Count); + float3 bmin = new float3(verts[0]); + float3 bmax = new float3(verts[0]); + for (i = 0; i < verts.Count; i++) + { + bmin = float3.VectorMin(bmin, verts[i]); + bmax = float3.VectorMax(bmax, verts[i]); + } + // float diameter = magnitude(bmax-bmin); + // inflate *=diameter; // RELATIVE INFLATION + bmin -= new float3(inflate, inflate, inflate); + bmax += new float3(inflate, inflate, inflate); + for (i = 0; i < planes.Count; i++) + { + planes[i].dist -= inflate; + } + float3 emin = new float3(bmin); + float3 emax = new float3(bmax); + float epsilon = float3.magnitude(emax - emin) * 0.025f; + float planetestepsilon = float3.magnitude(emax - emin) * (0.001f); + // todo: add bounding cube planes to force bevel. or try instead not adding the diameter expansion ??? must think. + // ConvexH *convex = ConvexHMakeCube(bmin - float3(diameter,diameter,diameter),bmax+float3(diameter,diameter,diameter)); + ConvexH c = ConvexHMakeCube(new float3(bmin), new float3(bmax)); + int k; + while (maxplanes-- != 0 && (k = candidateplane(planes, planes.Count, c, epsilon)) >= 0) + { + ConvexH tmp = c; + c = ConvexHCrop(ref tmp, planes[k], planetestepsilon); + if (c == null) // might want to debug this case better!!! + { + c = tmp; + break; + } + if (AssertIntact(c, planetestepsilon) == false) // might want to debug this case better too!!! + { + c = tmp; + break; + } + tmp.edges = null; + tmp.facets = null; + tmp.vertices = null; + } + + Debug.Assert(AssertIntact(c, planetestepsilon)); + //return c; + //C++ TO C# CONVERTER TODO TASK: The memory management function 'malloc' has no equivalent in C#: + faces_out = new List(); //(int)malloc(sizeof(int) * (1 + c.facets.Count + c.edges.Count)); // new int[1+c->facets.count+c->edges.count]; + int faces_count_out = 0; + i = 0; + faces_out[faces_count_out++] = -1; + k = 0; + while (i < c.edges.Count) + { + j = 1; + while (j + i < c.edges.Count && c.edges[i].p == c.edges[i + j].p) + { + j++; + } + faces_out[faces_count_out++] = j; + while (j-- != 0) + { + faces_out[faces_count_out++] = c.edges[i].v; + i++; + } + k++; + } + faces_out[0] = k; // number of faces. + Debug.Assert(k == c.facets.Count); + Debug.Assert(faces_count_out == 1 + c.facets.Count + c.edges.Count); + verts_out = c.vertices; // new float3[c->vertices.count]; + int verts_count_out = c.vertices.Count; + for (i = 0; i < c.vertices.Count; i++) + { + verts_out[i] = new float3(c.vertices[i]); + } + + c.edges = null; + c.facets = null; + c.vertices = null; + return 1; + } + + public static int overhullv(List verts, int maxplanes, out List verts_out, out List faces_out, float inflate, float bevangle, int vlimit, List tris) + { + verts_out = null; + faces_out = null; + + if (verts.Count == 0) + return 0; + List planes = new List(); + int rc = calchullpbev(verts, vlimit, out planes, bevangle, tris); + if (rc == 0) + return 0; + return overhull(planes, verts, maxplanes, out verts_out, out faces_out, inflate); + } + + public static void addPoint(ref uint vcount, List p, float x, float y, float z) + { + p.Add(new float3(x, y, z)); + vcount++; + } + + public static bool ComputeHull(List vertices, ref PHullResult result, int vlimit, float inflate) + { + List tris = new List(); + List faces; + List verts_out; + + if (inflate == 0.0f) + { + List tris_out; + bool ret = calchull(vertices, out tris_out, vlimit, tris); + if (ret == false) + return false; + + result.Indices = tris_out; + result.Vertices = vertices; + return true; + } + else + { + int ret = overhullv(vertices, 35, out verts_out, out faces, inflate, 120.0f, vlimit, tris); + if (ret == 0) + return false; + + List tris2 = new List(); + int n = faces[0]; + int k = 1; + for (int i = 0; i < n; i++) + { + int pn = faces[k++]; + for (int j = 2; j < pn; j++) + tris2.Add(new int3(faces[k], faces[k + j - 1], faces[k + j])); + k += pn; + } + Debug.Assert(tris2.Count == faces.Count - 1 - (n * 3)); + + result.Indices = new List(tris2.Count * 3); + for (int i = 0; i < tris2.Count; i++) + { + result.Indices.Add(tris2[i].x); + result.Indices.Add(tris2[i].y); + result.Indices.Add(tris2[i].z); + } + result.Vertices = verts_out; + + return true; + } + } + + private static bool CleanupVertices(List svertices, out List vertices, float normalepsilon, out float3 scale) + { + const float EPSILON = 0.000001f; + + vertices = new List(); + scale = new float3(1f, 1f, 1f); + + if (svertices.Count == 0) + return false; + + uint vcount = 0; + + float[] recip = new float[3]; + + float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue }; + float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue }; + + for (int i = 0; i < svertices.Count; i++) + { + float3 p = svertices[i]; + + for (int j = 0; j < 3; j++) + { + if (p[j] < bmin[j]) + bmin[j] = p[j]; + if (p[j] > bmax[j]) + bmax[j] = p[j]; + } + } + + float dx = bmax[0] - bmin[0]; + float dy = bmax[1] - bmin[1]; + float dz = bmax[2] - bmin[2]; + + float3 center = new float3(); + + center.x = dx * 0.5f + bmin[0]; + center.y = dy * 0.5f + bmin[1]; + center.z = dz * 0.5f + bmin[2]; + + if (dx < EPSILON || dy < EPSILON || dz < EPSILON || svertices.Count < 3) + { + float len = Single.MaxValue; + + if (dx > EPSILON && dx < len) + len = dx; + if (dy > EPSILON && dy < len) + len = dy; + if (dz > EPSILON && dz < len) + len = dz; + + if (len == Single.MaxValue) + { + dx = dy = dz = 0.01f; // one centimeter + } + else + { + if (dx < EPSILON) // 1/5th the shortest non-zero edge. + dx = len * 0.05f; + if (dy < EPSILON) + dy = len * 0.05f; + if (dz < EPSILON) + dz = len * 0.05f; + } + + float x1 = center[0] - dx; + float x2 = center[0] + dx; + + float y1 = center[1] - dy; + float y2 = center[1] + dy; + + float z1 = center[2] - dz; + float z2 = center[2] + dz; + + addPoint(ref vcount, vertices, x1, y1, z1); + addPoint(ref vcount, vertices, x2, y1, z1); + addPoint(ref vcount, vertices, x2, y2, z1); + addPoint(ref vcount, vertices, x1, y2, z1); + addPoint(ref vcount, vertices, x1, y1, z2); + addPoint(ref vcount, vertices, x2, y1, z2); + addPoint(ref vcount, vertices, x2, y2, z2); + addPoint(ref vcount, vertices, x1, y2, z2); + + return true; // return cube + } + else + { + scale.x = dx; + scale.y = dy; + scale.z = dz; + + recip[0] = 1f / dx; + recip[1] = 1f / dy; + recip[2] = 1f / dz; + + center.x *= recip[0]; + center.y *= recip[1]; + center.z *= recip[2]; + } + + for (int i = 0; i < svertices.Count; i++) + { + float3 p = svertices[i]; + + float px = p[0]; + float py = p[1]; + float pz = p[2]; + + px = px * recip[0]; // normalize + py = py * recip[1]; // normalize + pz = pz * recip[2]; // normalize + + if (true) + { + int j; + + for (j = 0; j < vcount; j++) + { + float3 v = vertices[j]; + + float x = v[0]; + float y = v[1]; + float z = v[2]; + + float dx1 = Math.Abs(x - px); + float dy1 = Math.Abs(y - py); + float dz1 = Math.Abs(z - pz); + + if (dx1 < normalepsilon && dy1 < normalepsilon && dz1 < normalepsilon) + { + // ok, it is close enough to the old one + // now let us see if it is further from the center of the point cloud than the one we already recorded. + // in which case we keep this one instead. + float dist1 = GetDist(px, py, pz, center); + float dist2 = GetDist(v[0], v[1], v[2], center); + + if (dist1 > dist2) + { + v.x = px; + v.y = py; + v.z = pz; + } + + break; + } + } + + if (j == vcount) + { + float3 dest = new float3(px, py, pz); + vertices.Add(dest); + vcount++; + } + } + } + + // ok..now make sure we didn't prune so many vertices it is now invalid. + if (true) + { + float[] bmin2 = { Single.MaxValue, Single.MaxValue, Single.MaxValue }; + float[] bmax2 = { Single.MinValue, Single.MinValue, Single.MinValue }; + + for (int i = 0; i < vcount; i++) + { + float3 p = vertices[i]; + for (int j = 0; j < 3; j++) + { + if (p[j] < bmin2[j]) + bmin2[j] = p[j]; + if (p[j] > bmax2[j]) + bmax2[j] = p[j]; + } + } + + float dx2 = bmax2[0] - bmin2[0]; + float dy2 = bmax2[1] - bmin2[1]; + float dz2 = bmax2[2] - bmin2[2]; + + if (dx2 < EPSILON || dy2 < EPSILON || dz2 < EPSILON || vcount < 3) + { + float cx = dx2 * 0.5f + bmin2[0]; + float cy = dy2 * 0.5f + bmin2[1]; + float cz = dz2 * 0.5f + bmin2[2]; + + float len = Single.MaxValue; + + if (dx2 >= EPSILON && dx2 < len) + len = dx2; + if (dy2 >= EPSILON && dy2 < len) + len = dy2; + if (dz2 >= EPSILON && dz2 < len) + len = dz2; + + if (len == Single.MaxValue) + { + dx2 = dy2 = dz2 = 0.01f; // one centimeter + } + else + { + if (dx2 < EPSILON) // 1/5th the shortest non-zero edge. + dx2 = len * 0.05f; + if (dy2 < EPSILON) + dy2 = len * 0.05f; + if (dz2 < EPSILON) + dz2 = len * 0.05f; + } + + float x1 = cx - dx2; + float x2 = cx + dx2; + + float y1 = cy - dy2; + float y2 = cy + dy2; + + float z1 = cz - dz2; + float z2 = cz + dz2; + + vcount = 0; // add box + + addPoint(ref vcount, vertices, x1, y1, z1); + addPoint(ref vcount, vertices, x2, y1, z1); + addPoint(ref vcount, vertices, x2, y2, z1); + addPoint(ref vcount, vertices, x1, y2, z1); + addPoint(ref vcount, vertices, x1, y1, z2); + addPoint(ref vcount, vertices, x2, y1, z2); + addPoint(ref vcount, vertices, x2, y2, z2); + addPoint(ref vcount, vertices, x1, y2, z2); + + return true; + } + } + + return true; + } + + private static void BringOutYourDead(List verts, out List overts, List indices) + { + int[] used = new int[verts.Count]; + int ocount = 0; + + overts = new List(); + + for (int i = 0; i < indices.Count; i++) + { + int v = indices[i]; // original array index + + Debug.Assert(v >= 0 && v < verts.Count); + + if (used[v] != 0) // if already remapped + { + indices[i] = used[v] - 1; // index to new array + } + else + { + indices[i] = ocount; // new index mapping + + overts.Add(verts[v]); // copy old vert to new vert array + + ocount++; // increment output vert count + + Debug.Assert(ocount >= 0 && ocount <= verts.Count); + + used[v] = ocount; // assign new index remapping + } + } + } + + public static HullError CreateConvexHull(HullDesc desc, ref HullResult result) + { + HullError ret = HullError.QE_FAIL; + + PHullResult hr = new PHullResult(); + + uint vcount = (uint)desc.Vertices.Count; + if (vcount < 8) + vcount = 8; + + List vsource; + float3 scale = new float3(); + + bool ok = CleanupVertices(desc.Vertices, out vsource, desc.NormalEpsilon, out scale); // normalize point cloud, remove duplicates! + + if (ok) + { + if (true) // scale vertices back to their original size. + { + for (int i = 0; i < vsource.Count; i++) + { + float3 v = vsource[i]; + v.x *= scale[0]; + v.y *= scale[1]; + v.z *= scale[2]; + } + } + + float skinwidth = 0; + if (desc.HasHullFlag(HullFlag.QF_SKIN_WIDTH)) + skinwidth = desc.SkinWidth; + + ok = ComputeHull(vsource, ref hr, (int)desc.MaxVertices, skinwidth); + + if (ok) + { + List vscratch; + BringOutYourDead(hr.Vertices, out vscratch, hr.Indices); + + ret = HullError.QE_OK; + + if (desc.HasHullFlag(HullFlag.QF_TRIANGLES)) // if he wants the results as triangle! + { + result.Polygons = false; + result.Indices = hr.Indices; + result.OutputVertices = vscratch; + } + else + { + result.Polygons = true; + result.OutputVertices = vscratch; + + if (true) + { + List source = hr.Indices; + List dest = new List(); + for (int i = 0; i < hr.Indices.Count / 3; i++) + { + dest.Add(3); + dest.Add(source[i * 3 + 0]); + dest.Add(source[i * 3 + 1]); + dest.Add(source[i * 3 + 2]); + } + + result.Indices = dest; + } + } + } + } + + return ret; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/LICENSE.txt b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/LICENSE.txt new file mode 100644 index 0000000..714ae89 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/LICENSE.txt @@ -0,0 +1,28 @@ +ConvexDecompositionDotNet +------------------------- + +The MIT License + +Copyright (c) 2010 Intel Corporation. +All rights reserved. + +Based on the convexdecomposition library from + by John W. Ratcliff and Stan Melax. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Plane.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Plane.cs new file mode 100644 index 0000000..da9ae0c --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Plane.cs @@ -0,0 +1,99 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class Plane + { + public float3 normal = new float3(); + public float dist; // distance below origin - the D from plane equasion Ax+By+Cz+D=0 + + public Plane(float3 n, float d) + { + normal = new float3(n); + dist = d; + } + + public Plane(Plane p) + { + normal = new float3(p.normal); + dist = p.dist; + } + + public Plane() + { + dist = 0; + } + + public void Transform(float3 position, Quaternion orientation) + { + // Transforms the plane to the space defined by the + // given position/orientation + float3 newNormal = Quaternion.Inverse(orientation) * normal; + float3 origin = Quaternion.Inverse(orientation) * (-normal * dist - position); + + normal = newNormal; + dist = -float3.dot(newNormal, origin); + } + + public override int GetHashCode() + { + return normal.GetHashCode() ^ dist.GetHashCode(); + } + + public override bool Equals(object obj) + { + Plane p = obj as Plane; + if (p == null) + return false; + + return this == p; + } + + public static bool operator ==(Plane a, Plane b) + { + return (a.normal == b.normal && a.dist == b.dist); + } + + public static bool operator !=(Plane a, Plane b) + { + return !(a == b); + } + + public static Plane PlaneFlip(Plane plane) + { + return new Plane(-plane.normal, -plane.dist); + } + + public static bool coplanar(Plane a, Plane b) + { + return (a == b || a == PlaneFlip(b)); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/PlaneTri.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/PlaneTri.cs new file mode 100644 index 0000000..42f7a22 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/PlaneTri.cs @@ -0,0 +1,211 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public enum PlaneTriResult : int + { + PTR_FRONT, + PTR_BACK, + PTR_SPLIT + } + + public static class PlaneTri + { + private static float DistToPt(float3 p, float4 plane) + { + return p.x * plane.x + p.y * plane.y + p.z * plane.z + plane.w; + } + + private static PlaneTriResult getSidePlane(float3 p, float4 plane, float epsilon) + { + float d = DistToPt(p, plane); + + if ((d + epsilon) > 0f) + return PlaneTriResult.PTR_FRONT; // it is 'in front' within the provided epsilon value. + + return PlaneTriResult.PTR_BACK; + } + + private static void add(float3 p, float3[] dest, ref int pcount) + { + dest[pcount++] = new float3(p); + Debug.Assert(pcount <= 4); + } + + // assumes that the points are on opposite sides of the plane! + private static void intersect(float3 p1, float3 p2, float3 split, float4 plane) + { + float dp1 = DistToPt(p1, plane); + float[] dir = new float[3]; + + dir[0] = p2[0] - p1[0]; + dir[1] = p2[1] - p1[1]; + dir[2] = p2[2] - p1[2]; + + float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2]; + float dot2 = dp1 - plane[3]; + + float t = -(plane[3] + dot2) / dot1; + + split.x = (dir[0] * t) + p1[0]; + split.y = (dir[1] * t) + p1[1]; + split.z = (dir[2] * t) + p1[2]; + } + + public static PlaneTriResult planeTriIntersection(float4 plane, FaceTri triangle, float epsilon, ref float3[] front, out int fcount, ref float3[] back, out int bcount) + { + fcount = 0; + bcount = 0; + + // get the three vertices of the triangle. + float3 p1 = triangle.P1; + float3 p2 = triangle.P2; + float3 p3 = triangle.P3; + + PlaneTriResult r1 = getSidePlane(p1, plane, epsilon); // compute the side of the plane each vertex is on + PlaneTriResult r2 = getSidePlane(p2, plane, epsilon); + PlaneTriResult r3 = getSidePlane(p3, plane, epsilon); + + if (r1 == r2 && r1 == r3) // if all three vertices are on the same side of the plane. + { + if (r1 == PlaneTriResult.PTR_FRONT) // if all three are in front of the plane, then copy to the 'front' output triangle. + { + add(p1, front, ref fcount); + add(p2, front, ref fcount); + add(p3, front, ref fcount); + } + else + { + add(p1, back, ref bcount); // if all three are in 'back' then copy to the 'back' output triangle. + add(p2, back, ref bcount); + add(p3, back, ref bcount); + } + return r1; // if all three points are on the same side of the plane return result + } + + // ok.. we need to split the triangle at the plane. + + // First test ray segment P1 to P2 + if (r1 == r2) // if these are both on the same side... + { + if (r1 == PlaneTriResult.PTR_FRONT) + { + add(p1, front, ref fcount); + add(p2, front, ref fcount); + } + else + { + add(p1, back, ref bcount); + add(p2, back, ref bcount); + } + } + else + { + float3 split = new float3(); + intersect(p1, p2, split, plane); + + if (r1 == PlaneTriResult.PTR_FRONT) + { + + add(p1, front, ref fcount); + add(split, front, ref fcount); + + add(split, back, ref bcount); + add(p2, back, ref bcount); + + } + else + { + add(p1, back, ref bcount); + add(split, back, ref bcount); + + add(split, front, ref fcount); + add(p2, front, ref fcount); + } + + } + + // Next test ray segment P2 to P3 + if (r2 == r3) // if these are both on the same side... + { + if (r3 == PlaneTriResult.PTR_FRONT) + { + add(p3, front, ref fcount); + } + else + { + add(p3, back, ref bcount); + } + } + else + { + float3 split = new float3(); // split the point + intersect(p2, p3, split, plane); + + if (r3 == PlaneTriResult.PTR_FRONT) + { + add(split, front, ref fcount); + add(split, back, ref bcount); + + add(p3, front, ref fcount); + } + else + { + add(split, front, ref fcount); + add(split, back, ref bcount); + + add(p3, back, ref bcount); + } + } + + // Next test ray segment P3 to P1 + if (r3 != r1) // if these are both on the same side... + { + float3 split = new float3(); // split the point + intersect(p3, p1, split, plane); + + if (r1 == PlaneTriResult.PTR_FRONT) + { + add(split, front, ref fcount); + add(split, back, ref bcount); + } + else + { + add(split, front, ref fcount); + add(split, back, ref bcount); + } + } + + return PlaneTriResult.PTR_SPLIT; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b9cd6f5 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ConvexDecompositionDotNet")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Intel Corporation")] +[assembly: AssemblyProduct("ConvexDecompositionDotNet")] +[assembly: AssemblyCopyright("Copyright © Intel Corporation 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2a1c9467-1a17-4c8d-bf9f-4b4d86dd0cbb")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Quaternion.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Quaternion.cs new file mode 100644 index 0000000..045f620 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Quaternion.cs @@ -0,0 +1,209 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class Quaternion : float4 + { + public Quaternion() + { + x = y = z = 0.0f; + w = 1.0f; + } + + public Quaternion(float3 v, float t) + { + v = float3.normalize(v); + w = (float)Math.Cos(t / 2.0f); + v = v * (float)Math.Sin(t / 2.0f); + x = v.x; + y = v.y; + z = v.z; + } + + public Quaternion(float _x, float _y, float _z, float _w) + { + x = _x; + y = _y; + z = _z; + w = _w; + } + + public float angle() + { + return (float)Math.Acos(w) * 2.0f; + } + + public float3 axis() + { + float3 a = new float3(x, y, z); + if (Math.Abs(angle()) < 0.0000001f) + return new float3(1f, 0f, 0f); + return a * (1 / (float)Math.Sin(angle() / 2.0f)); + } + + public float3 xdir() + { + return new float3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y)); + } + + public float3 ydir() + { + return new float3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x)); + } + + public float3 zdir() + { + return new float3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y)); + } + + public float3x3 getmatrix() + { + return new float3x3(xdir(), ydir(), zdir()); + } + + public static implicit operator float3x3(Quaternion q) + { + return q.getmatrix(); + } + + public static Quaternion operator *(Quaternion a, Quaternion b) + { + Quaternion c = new Quaternion(); + c.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z; + c.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y; + c.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x; + c.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w; + return c; + } + + public static float3 operator *(Quaternion q, float3 v) + { + // The following is equivalent to: + //return (q.getmatrix() * v); + float qx2 = q.x * q.x; + float qy2 = q.y * q.y; + float qz2 = q.z * q.z; + + float qxqy = q.x * q.y; + float qxqz = q.x * q.z; + float qxqw = q.x * q.w; + float qyqz = q.y * q.z; + float qyqw = q.y * q.w; + float qzqw = q.z * q.w; + return new float3((1 - 2 * (qy2 + qz2)) * v.x + (2 * (qxqy - qzqw)) * v.y + (2 * (qxqz + qyqw)) * v.z, (2 * (qxqy + qzqw)) * v.x + (1 - 2 * (qx2 + qz2)) * v.y + (2 * (qyqz - qxqw)) * v.z, (2 * (qxqz - qyqw)) * v.x + (2 * (qyqz + qxqw)) * v.y + (1 - 2 * (qx2 + qy2)) * v.z); + } + + public static Quaternion operator +(Quaternion a, Quaternion b) + { + return new Quaternion(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); + } + + public static Quaternion operator *(Quaternion a, float b) + { + return new Quaternion(a.x *b, a.y *b, a.z *b, a.w *b); + } + + public static Quaternion normalize(Quaternion a) + { + float m = (float)Math.Sqrt(a.w * a.w + a.x * a.x + a.y * a.y + a.z * a.z); + if (m < 0.000000001f) + { + a.w = 1; + a.x = a.y = a.z = 0; + return a; + } + return a * (1f / m); + } + + public static float dot(Quaternion a, Quaternion b) + { + return (a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z); + } + + public static Quaternion slerp(Quaternion a, Quaternion b, float interp) + { + if (dot(a, b) < 0.0) + { + a.w = -a.w; + a.x = -a.x; + a.y = -a.y; + a.z = -a.z; + } + float d = dot(a, b); + if (d >= 1.0) + { + return a; + } + float theta = (float)Math.Acos(d); + if (theta == 0.0f) + { + return (a); + } + return a * ((float)Math.Sin(theta - interp * theta) / (float)Math.Sin(theta)) + b * ((float)Math.Sin(interp * theta) / (float)Math.Sin(theta)); + } + + public static Quaternion Interpolate(Quaternion q0, Quaternion q1, float alpha) + { + return slerp(q0, q1, alpha); + } + + public static Quaternion Inverse(Quaternion q) + { + return new Quaternion(-q.x, -q.y, -q.z, q.w); + } + + public static Quaternion YawPitchRoll(float yaw, float pitch, float roll) + { + roll *= (3.14159264f / 180.0f); + yaw *= (3.14159264f / 180.0f); + pitch *= (3.14159264f / 180.0f); + return new Quaternion(new float3(0.0f, 0.0f, 1.0f), yaw) * new Quaternion(new float3(1.0f, 0.0f, 0.0f), pitch) * new Quaternion(new float3(0.0f, 1.0f, 0.0f), roll); + } + + public static float Yaw(Quaternion q) + { + float3 v = q.ydir(); + return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f); + } + + public static float Pitch(Quaternion q) + { + float3 v = q.ydir(); + return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f); + } + + public static float Roll(Quaternion q) + { + q = new Quaternion(new float3(0.0f, 0.0f, 1.0f), -Yaw(q) * (3.14159264f / 180.0f)) * q; + q = new Quaternion(new float3(1.0f, 0.0f, 0.0f), -Pitch(q) * (3.14159264f / 180.0f)) * q; + return (float)Math.Atan2(-q.xdir().z, q.xdir().x) * (180.0f / 3.14159264f); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/README.txt b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/README.txt new file mode 100644 index 0000000..fc53ae7 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/README.txt @@ -0,0 +1,7 @@ +ConvexDecompositionDotNet +========================= + +A C# port of the ConvexDecomposition library by John W. Ratcliff and Stan Melax. +The original C++ version is available at . +See the blog post at +for a thorough explanation of generating convex hulls from concave meshes. diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/SplitPlane.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/SplitPlane.cs new file mode 100644 index 0000000..9f56bc5 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/SplitPlane.cs @@ -0,0 +1,265 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class Rect3d + { + public float[] mMin = new float[3]; + public float[] mMax = new float[3]; + + public Rect3d() + { + } + + public Rect3d(float[] bmin, float[] bmax) + { + mMin[0] = bmin[0]; + mMin[1] = bmin[1]; + mMin[2] = bmin[2]; + + mMax[0] = bmax[0]; + mMax[1] = bmax[1]; + mMax[2] = bmax[2]; + } + + public void SetMin(float[] bmin) + { + mMin[0] = bmin[0]; + mMin[1] = bmin[1]; + mMin[2] = bmin[2]; + } + + public void SetMax(float[] bmax) + { + mMax[0] = bmax[0]; + mMax[1] = bmax[1]; + mMax[2] = bmax[2]; + } + + public void SetMin(float x, float y, float z) + { + mMin[0] = x; + mMin[1] = y; + mMin[2] = z; + } + + public void SetMax(float x, float y, float z) + { + mMax[0] = x; + mMax[1] = y; + mMax[2] = z; + } + } + + public static class SplitPlane + { + public static bool computeSplitPlane(List vertices, List indices, ref float4 plane) + { + float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue }; + float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue }; + + for (int i = 0; i < vertices.Count; i++) + { + float3 p = vertices[i]; + + if (p[0] < bmin[0]) + bmin[0] = p[0]; + if (p[1] < bmin[1]) + bmin[1] = p[1]; + if (p[2] < bmin[2]) + bmin[2] = p[2]; + + if (p[0] > bmax[0]) + bmax[0] = p[0]; + if (p[1] > bmax[1]) + bmax[1] = p[1]; + if (p[2] > bmax[2]) + bmax[2] = p[2]; + } + + float dx = bmax[0] - bmin[0]; + float dy = bmax[1] - bmin[1]; + float dz = bmax[2] - bmin[2]; + + float laxis = dx; + + int axis = 0; + + if (dy > dx) + { + axis = 1; + laxis = dy; + } + + if (dz > dx && dz > dy) + { + axis = 2; + laxis = dz; + } + + float[] p1 = new float[3]; + float[] p2 = new float[3]; + float[] p3 = new float[3]; + + p3[0] = p2[0] = p1[0] = bmin[0] + dx * 0.5f; + p3[1] = p2[1] = p1[1] = bmin[1] + dy * 0.5f; + p3[2] = p2[2] = p1[2] = bmin[2] + dz * 0.5f; + + Rect3d b = new Rect3d(bmin, bmax); + + Rect3d b1 = new Rect3d(); + Rect3d b2 = new Rect3d(); + + splitRect(axis, b, b1, b2, p1); + + switch (axis) + { + case 0: + p2[1] = bmin[1]; + p2[2] = bmin[2]; + + if (dz > dy) + { + p3[1] = bmax[1]; + p3[2] = bmin[2]; + } + else + { + p3[1] = bmin[1]; + p3[2] = bmax[2]; + } + + break; + case 1: + p2[0] = bmin[0]; + p2[2] = bmin[2]; + + if (dx > dz) + { + p3[0] = bmax[0]; + p3[2] = bmin[2]; + } + else + { + p3[0] = bmin[0]; + p3[2] = bmax[2]; + } + + break; + case 2: + p2[0] = bmin[0]; + p2[1] = bmin[1]; + + if (dx > dy) + { + p3[0] = bmax[0]; + p3[1] = bmin[1]; + } + else + { + p3[0] = bmin[0]; + p3[1] = bmax[1]; + } + + break; + } + + computePlane(p1, p2, p3, plane); + + return true; + } + + internal static void computePlane(float[] A, float[] B, float[] C, float4 plane) + { + float vx = (B[0] - C[0]); + float vy = (B[1] - C[1]); + float vz = (B[2] - C[2]); + + float wx = (A[0] - B[0]); + float wy = (A[1] - B[1]); + float wz = (A[2] - B[2]); + + float vw_x = vy * wz - vz * wy; + float vw_y = vz * wx - vx * wz; + float vw_z = vx * wy - vy * wx; + + float mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z)); + + if (mag < 0.000001f) + { + mag = 0; + } + else + { + mag = 1.0f / mag; + } + + float x = vw_x * mag; + float y = vw_y * mag; + float z = vw_z * mag; + + float D = 0.0f - ((x * A[0]) + (y * A[1]) + (z * A[2])); + + plane.x = x; + plane.y = y; + plane.z = z; + plane.w = D; + } + + public static void splitRect(int axis, Rect3d source, Rect3d b1, Rect3d b2, float[] midpoint) + { + switch (axis) + { + case 0: + b1.SetMin(source.mMin); + b1.SetMax(midpoint[0], source.mMax[1], source.mMax[2]); + + b2.SetMin(midpoint[0], source.mMin[1], source.mMin[2]); + b2.SetMax(source.mMax); + break; + case 1: + b1.SetMin(source.mMin); + b1.SetMax(source.mMax[0], midpoint[1], source.mMax[2]); + + b2.SetMin(source.mMin[0], midpoint[1], source.mMin[2]); + b2.SetMax(source.mMax); + break; + case 2: + b1.SetMin(source.mMin); + b1.SetMax(source.mMax[0], source.mMax[1], midpoint[2]); + + b2.SetMin(source.mMin[0], source.mMin[1], midpoint[2]); + b2.SetMax(source.mMax); + break; + } + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/VertexLookup.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/VertexLookup.cs new file mode 100644 index 0000000..bfe11e5 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/VertexLookup.cs @@ -0,0 +1,70 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class VertexPool + { + private List mVertices = new List(); + private Dictionary mIndices = new Dictionary(); + + public int getIndex(float3 vtx) + { + int idx; + if (mIndices.TryGetValue(vtx, out idx)) + return idx; + + idx = mVertices.Count; + mVertices.Add(vtx); + mIndices.Add(vtx, idx); + return idx; + } + + public float3 Get(int idx) + { + return mVertices[idx]; + } + + public int GetSize() + { + return mVertices.Count; + } + + public List GetVertices() + { + return mVertices; + } + + public void Clear() + { + mVertices.Clear(); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float2.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float2.cs new file mode 100644 index 0000000..e7358c1 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float2.cs @@ -0,0 +1,70 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class float2 + { + public float x; + public float y; + + public float2() + { + } + + public float2(float _x, float _y) + { + x = _x; + y = _y; + } + + public float this[int i] + { + get + { + switch (i) + { + case 0: return x; + case 1: return y; + } + throw new ArgumentOutOfRangeException(); + } + } + + public static float2 operator -(float2 a, float2 b) + { + return new float2(a.x - b.x, a.y - b.y); + } + + public static float2 operator +(float2 a, float2 b) + { + return new float2(a.x + b.x, a.y + b.y); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3.cs new file mode 100644 index 0000000..fde9b32 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3.cs @@ -0,0 +1,444 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class float3 : IEquatable + { + public float x; + public float y; + public float z; + + public float3() + { + x = 0; + y = 0; + z = 0; + } + + public float3(float _x, float _y, float _z) + { + x = _x; + y = _y; + z = _z; + } + + public float3(float3 f) + { + x = f.x; + y = f.y; + z = f.z; + } + + public float this[int i] + { + get + { + switch (i) + { + case 0: return x; + case 1: return y; + case 2: return z; + } + throw new ArgumentOutOfRangeException(); + } + } + + public float Distance(float3 a) + { + float3 d = new float3(a.x - x, a.y - y, a.z - z); + return d.Length(); + } + + public float Distance2(float3 a) + { + float dx = a.x - x; + float dy = a.y - y; + float dz = a.z - z; + return dx * dx + dy * dy + dz * dz; + } + + public float Length() + { + return (float)Math.Sqrt(x * x + y * y + z * z); + } + + public float Area(float3 p1, float3 p2) + { + float A = Partial(p1); + A += p1.Partial(p2); + A += p2.Partial(this); + return A * 0.5f; + } + + public float Partial(float3 p) + { + return (x * p.y) - (p.x * y); + } + + // Given a point and a line (defined by two points), compute the closest point + // in the line. (The line is treated as infinitely long.) + public void NearestPointInLine(float3 point, float3 line0, float3 line1) + { + float3 nearestPoint = new float3(); + float3 lineDelta = line1 - line0; + + // Handle degenerate lines + if (lineDelta == float3.Zero) + { + nearestPoint = line0; + } + else + { + float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta); + nearestPoint = line0 + lineDelta * delta; + } + + this.x = nearestPoint.x; + this.y = nearestPoint.y; + this.z = nearestPoint.z; + } + + // Given a point and a line segment (defined by two points), compute the closest point + // in the line. Cap the point at the endpoints of the line segment. + public void NearestPointInLineSegment(float3 point, float3 line0, float3 line1) + { + float3 nearestPoint = new float3(); + float3 lineDelta = line1 - line0; + + // Handle degenerate lines + if (lineDelta == Zero) + { + nearestPoint = line0; + } + else + { + float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta); + + // Clamp the point to conform to the segment's endpoints + if (delta < 0) + delta = 0; + else if (delta > 1) + delta = 1; + + nearestPoint = line0 + lineDelta * delta; + } + + this.x = nearestPoint.x; + this.y = nearestPoint.y; + this.z = nearestPoint.z; + } + + // Given a point and a triangle (defined by three points), compute the closest point + // in the triangle. Clamp the point so it's confined to the area of the triangle. + public void NearestPointInTriangle(float3 point, float3 triangle0, float3 triangle1, float3 triangle2) + { + float3 nearestPoint = new float3(); + + float3 lineDelta0 = triangle1 - triangle0; + float3 lineDelta1 = triangle2 - triangle0; + + // Handle degenerate triangles + if ((lineDelta0 == Zero) || (lineDelta1 == Zero)) + { + nearestPoint.NearestPointInLineSegment(point, triangle1, triangle2); + } + else if (lineDelta0 == lineDelta1) + { + nearestPoint.NearestPointInLineSegment(point, triangle0, triangle1); + } + else + { + float3[] axis = new float3[3] { new float3(), new float3(), new float3() }; + axis[0].NearestPointInLine(triangle0, triangle1, triangle2); + axis[1].NearestPointInLine(triangle1, triangle0, triangle2); + axis[2].NearestPointInLine(triangle2, triangle0, triangle1); + + float3 axisDot = new float3(); + axisDot.x = dot(triangle0 - axis[0], point - axis[0]); + axisDot.y = dot(triangle1 - axis[1], point - axis[1]); + axisDot.z = dot(triangle2 - axis[2], point - axis[2]); + + bool bForce = true; + float bestMagnitude2 = 0; + float closeMagnitude2; + float3 closePoint = new float3(); + + if (axisDot.x < 0f) + { + closePoint.NearestPointInLineSegment(point, triangle1, triangle2); + closeMagnitude2 = point.Distance2(closePoint); + if (bForce || (bestMagnitude2 > closeMagnitude2)) + { + bForce = false; + bestMagnitude2 = closeMagnitude2; + nearestPoint = closePoint; + } + } + if (axisDot.y < 0f) + { + closePoint.NearestPointInLineSegment(point, triangle0, triangle2); + closeMagnitude2 = point.Distance2(closePoint); + if (bForce || (bestMagnitude2 > closeMagnitude2)) + { + bForce = false; + bestMagnitude2 = closeMagnitude2; + nearestPoint = closePoint; + } + } + if (axisDot.z < 0f) + { + closePoint.NearestPointInLineSegment(point, triangle0, triangle1); + closeMagnitude2 = point.Distance2(closePoint); + if (bForce || (bestMagnitude2 > closeMagnitude2)) + { + bForce = false; + bestMagnitude2 = closeMagnitude2; + nearestPoint = closePoint; + } + } + + // If bForce is true at this point, it means the nearest point lies + // inside the triangle; use the nearest-point-on-a-plane equation + if (bForce) + { + float3 normal; + + // Get the normal of the polygon (doesn't have to be a unit vector) + normal = float3.cross(lineDelta0, lineDelta1); + + float3 pointDelta = point - triangle0; + float delta = float3.dot(normal, pointDelta) / float3.dot(normal, normal); + + nearestPoint = point - normal * delta; + } + } + + this.x = nearestPoint.x; + this.y = nearestPoint.y; + this.z = nearestPoint.z; + } + + public static float3 operator +(float3 a, float3 b) + { + return new float3(a.x + b.x, a.y + b.y, a.z + b.z); + } + + public static float3 operator -(float3 a, float3 b) + { + return new float3(a.x - b.x, a.y - b.y, a.z - b.z); + } + + public static float3 operator -(float3 a, float s) + { + return new float3(a.x - s, a.y - s, a.z - s); + } + + public static float3 operator -(float3 v) + { + return new float3(-v.x, -v.y, -v.z); + } + + public static float3 operator *(float3 v, float s) + { + return new float3(v.x * s, v.y * s, v.z * s); + } + + public static float3 operator *(float s, float3 v) + { + return new float3(v.x * s, v.y * s, v.z * s); + } + + public static float3 operator *(float3 v, float3x3 m) + { + return new float3((m.x.x * v.x + m.y.x * v.y + m.z.x * v.z), (m.x.y * v.x + m.y.y * v.y + m.z.y * v.z), (m.x.z * v.x + m.y.z * v.y + m.z.z * v.z)); + } + + public static float3 operator *(float3x3 m, float3 v) + { + return new float3(dot(m.x, v), dot(m.y, v), dot(m.z, v)); + } + + public static float3 operator /(float3 v, float s) + { + float sinv = 1.0f / s; + return new float3(v.x * sinv, v.y * sinv, v.z * sinv); + } + + public bool Equals(float3 other) + { + return this == other; + } + + public override bool Equals(object obj) + { + float3 f = obj as float3; + if (f == null) + return false; + + return this == f; + } + + public override int GetHashCode() + { + return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); + } + + public static bool operator ==(float3 a, float3 b) + { + // If both are null, or both are same instance, return true. + if (System.Object.ReferenceEquals(a, b)) + return true; + // If one is null, but not both, return false. + if (((object)a == null) || ((object)b == null)) + return false; + + return (a.x == b.x && a.y == b.y && a.z == b.z); + } + + public static bool operator !=(float3 a, float3 b) + { + return (a.x != b.x || a.y != b.y || a.z != b.z); + } + + public static float dot(float3 a, float3 b) + { + return a.x * b.x + a.y * b.y + a.z * b.z; + } + + public static float3 cmul(float3 v1, float3 v2) + { + return new float3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z); + } + + public static float3 cross(float3 a, float3 b) + { + return new float3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); + } + + public static float3 Interpolate(float3 v0, float3 v1, float alpha) + { + return v0 * (1 - alpha) + v1 * alpha; + } + + public static float3 Round(float3 a, int digits) + { + return new float3((float)Math.Round(a.x, digits), (float)Math.Round(a.y, digits), (float)Math.Round(a.z, digits)); + } + + public static float3 VectorMax(float3 a, float3 b) + { + return new float3(Math.Max(a.x, b.x), Math.Max(a.y, b.y), Math.Max(a.z, b.z)); + } + + public static float3 VectorMin(float3 a, float3 b) + { + return new float3(Math.Min(a.x, b.x), Math.Min(a.y, b.y), Math.Min(a.z, b.z)); + } + + public static float3 vabs(float3 v) + { + return new float3(Math.Abs(v.x), Math.Abs(v.y), Math.Abs(v.z)); + } + + public static float magnitude(float3 v) + { + return (float)Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z); + } + + public static float3 normalize(float3 v) + { + float d = magnitude(v); + if (d == 0) + d = 0.1f; + d = 1 / d; + return new float3(v.x * d, v.y * d, v.z * d); + } + + public static float3 safenormalize(float3 v) + { + if (magnitude(v) <= 0.0f) + return new float3(1, 0, 0); + else + return normalize(v); + } + + public static float Yaw(float3 v) + { + return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f); + } + + public static float Pitch(float3 v) + { + return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f); + } + + public float ComputePlane(float3 A, float3 B, float3 C) + { + float vx, vy, vz, wx, wy, wz, vw_x, vw_y, vw_z, mag; + + vx = (B.x - C.x); + vy = (B.y - C.y); + vz = (B.z - C.z); + + wx = (A.x - B.x); + wy = (A.y - B.y); + wz = (A.z - B.z); + + vw_x = vy * wz - vz * wy; + vw_y = vz * wx - vx * wz; + vw_z = vx * wy - vy * wx; + + mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z)); + + if (mag < 0.000001f) + { + mag = 0; + } + else + { + mag = 1.0f / mag; + } + + x = vw_x * mag; + y = vw_y * mag; + z = vw_z * mag; + + float D = 0.0f - ((x * A.x) + (y * A.y) + (z * A.z)); + return D; + } + + public override string ToString() + { + return String.Format("<{0}, {1}, {2}>", x, y, z); + } + + public static readonly float3 Zero = new float3(); + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3x3.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3x3.cs new file mode 100644 index 0000000..c420fde --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3x3.cs @@ -0,0 +1,195 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class float3x3 + { + public float3 x = new float3(); + public float3 y = new float3(); + public float3 z = new float3(); + + public float3x3() + { + } + + public float3x3(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz) + { + x = new float3(xx, xy, xz); + y = new float3(yx, yy, yz); + z = new float3(zx, zy, zz); + } + + public float3x3(float3 _x, float3 _y, float3 _z) + { + x = new float3(_x); + y = new float3(_y); + z = new float3(_z); + } + + public float3 this[int i] + { + get + { + switch (i) + { + case 0: return x; + case 1: return y; + case 2: return z; + } + throw new ArgumentOutOfRangeException(); + } + } + + public float this[int i, int j] + { + get + { + switch (i) + { + case 0: + switch (j) + { + case 0: return x.x; + case 1: return x.y; + case 2: return x.z; + } + break; + case 1: + switch (j) + { + case 0: return y.x; + case 1: return y.y; + case 2: return y.z; + } + break; + case 2: + switch (j) + { + case 0: return z.x; + case 1: return z.y; + case 2: return z.z; + } + break; + } + throw new ArgumentOutOfRangeException(); + } + set + { + switch (i) + { + case 0: + switch (j) + { + case 0: x.x = value; return; + case 1: x.y = value; return; + case 2: x.z = value; return; + } + break; + case 1: + switch (j) + { + case 0: y.x = value; return; + case 1: y.y = value; return; + case 2: y.z = value; return; + } + break; + case 2: + switch (j) + { + case 0: z.x = value; return; + case 1: z.y = value; return; + case 2: z.z = value; return; + } + break; + } + throw new ArgumentOutOfRangeException(); + } + } + + public static float3x3 Transpose(float3x3 m) + { + return new float3x3(new float3(m.x.x, m.y.x, m.z.x), new float3(m.x.y, m.y.y, m.z.y), new float3(m.x.z, m.y.z, m.z.z)); + } + + public static float3x3 operator *(float3x3 a, float3x3 b) + { + return new float3x3(a.x * b, a.y * b, a.z * b); + } + + public static float3x3 operator *(float3x3 a, float s) + { + return new float3x3(a.x * s, a.y * s, a.z * s); + } + + public static float3x3 operator /(float3x3 a, float s) + { + float t = 1f / s; + return new float3x3(a.x * t, a.y * t, a.z * t); + } + + public static float3x3 operator +(float3x3 a, float3x3 b) + { + return new float3x3(a.x + b.x, a.y + b.y, a.z + b.z); + } + + public static float3x3 operator -(float3x3 a, float3x3 b) + { + return new float3x3(a.x - b.x, a.y - b.y, a.z - b.z); + } + + public static float Determinant(float3x3 m) + { + return m.x.x * m.y.y * m.z.z + m.y.x * m.z.y * m.x.z + m.z.x * m.x.y * m.y.z - m.x.x * m.z.y * m.y.z - m.y.x * m.x.y * m.z.z - m.z.x * m.y.y * m.x.z; + } + + public static float3x3 Inverse(float3x3 a) + { + float3x3 b = new float3x3(); + float d = Determinant(a); + Debug.Assert(d != 0); + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + int i1 = (i + 1) % 3; + int i2 = (i + 2) % 3; + int j1 = (j + 1) % 3; + int j2 = (j + 2) % 3; + + // reverse indexs i&j to take transpose + b[i, j] = (a[i1][j1] * a[i2][j2] - a[i1][j2] * a[i2][j1]) / d; + } + } + return b; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4.cs new file mode 100644 index 0000000..b2b6fd3 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4.cs @@ -0,0 +1,170 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class float4 + { + public float x; + public float y; + public float z; + public float w; + + public float4() + { + x = 0; + y = 0; + z = 0; + w = 0; + } + + public float4(float _x, float _y, float _z, float _w) + { + x = _x; + y = _y; + z = _z; + w = _w; + } + + public float4(float3 v, float _w) + { + x = v.x; + y = v.y; + z = v.z; + w = _w; + } + + public float4(float4 f) + { + x = f.x; + y = f.y; + z = f.z; + w = f.w; + } + + public float this[int i] + { + get + { + switch (i) + { + case 0: return x; + case 1: return y; + case 2: return z; + case 3: return w; + } + throw new ArgumentOutOfRangeException(); + } + } + + public float3 xyz() + { + return new float3(x, y, z); + } + + public void setxyz(float3 xyz) + { + x = xyz.x; + y = xyz.y; + z = xyz.z; + } + + public override int GetHashCode() + { + return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); + } + + public override bool Equals(object obj) + { + float4 f = obj as float4; + if (f == null) + return false; + + return this == f; + } + + public static float4 Homogenize(float3 v3) + { + return Homogenize(v3, 1.0f); + } + + //C++ TO C# CONVERTER NOTE: C# does not allow default values for parameters. Overloaded methods are inserted above. + //ORIGINAL LINE: float4 Homogenize(const float3 &v3, const float &w =1.0f) + public static float4 Homogenize(float3 v3, float w) + { + return new float4(v3.x, v3.y, v3.z, w); + } + + public static float4 cmul(float4 a, float4 b) + { + return new float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); + } + + public static float4 operator +(float4 a, float4 b) + { + return new float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); + } + public static float4 operator -(float4 a, float4 b) + { + return new float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); + } + + public static float4 operator *(float4 v, float4x4 m) + { + return v.x * m.x + v.y * m.y + v.z * m.z + v.w * m.w; // yes this actually works + } + + public static bool operator ==(float4 a, float4 b) + { + // If both are null, or both are same instance, return true. + if (System.Object.ReferenceEquals(a, b)) + return true; + // If one is null, but not both, return false. + if (((object)a == null) || ((object)b == null)) + return false; + + return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w); + } + + public static bool operator !=(float4 a, float4 b) + { + return !(a == b); + } + + public static float4 operator *(float4 v, float s) + { + return new float4(v.x * s, v.y * s, v.z * s, v.w * s); + } + + public static float4 operator *(float s, float4 v) + { + return new float4(v.x * s, v.y * s, v.z * s, v.w * s); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4x4.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4x4.cs new file mode 100644 index 0000000..087eba7 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4x4.cs @@ -0,0 +1,284 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class float4x4 + { + public float4 x = new float4(); + public float4 y = new float4(); + public float4 z = new float4(); + public float4 w = new float4(); + + public float4x4() + { + } + + public float4x4(float4 _x, float4 _y, float4 _z, float4 _w) + { + x = new float4(_x); + y = new float4(_y); + z = new float4(_z); + w = new float4(_w); + } + + public float4x4( + float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33) + { + x = new float4(m00, m01, m02, m03); + y = new float4(m10, m11, m12, m13); + z = new float4(m20, m21, m22, m23); + w = new float4(m30, m31, m32, m33); + } + + public float4x4(float4x4 m) + { + x = new float4(m.x); + y = new float4(m.y); + z = new float4(m.z); + w = new float4(m.w); + } + + public float4 this[int i] + { + get + { + switch (i) + { + case 0: return x; + case 1: return y; + case 2: return z; + case 3: return w; + } + throw new ArgumentOutOfRangeException(); + } + set + { + switch (i) + { + case 0: x = value; return; + case 1: y = value; return; + case 2: z = value; return; + case 3: w = value; return; + } + throw new ArgumentOutOfRangeException(); + } + } + + public override int GetHashCode() + { + return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); + } + + public override bool Equals(object obj) + { + float4x4 m = obj as float4x4; + if (m == null) + return false; + + return this == m; + } + + public static float4x4 operator *(float4x4 a, float4x4 b) + { + return new float4x4(a.x * b, a.y * b, a.z * b, a.w * b); + } + + public static bool operator ==(float4x4 a, float4x4 b) + { + return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w); + } + + public static bool operator !=(float4x4 a, float4x4 b) + { + return !(a == b); + } + + public static float4x4 Inverse(float4x4 m) + { + float4x4 d = new float4x4(); + //float dst = d.x.x; + float[] tmp = new float[12]; // temp array for pairs + float[] src = new float[16]; // array of transpose source matrix + float det; // determinant + // transpose matrix + for (int i = 0; i < 4; i++) + { + src[i] = m[i].x; + src[i + 4] = m[i].y; + src[i + 8] = m[i].z; + src[i + 12] = m[i].w; + } + // calculate pairs for first 8 elements (cofactors) + tmp[0] = src[10] * src[15]; + tmp[1] = src[11] * src[14]; + tmp[2] = src[9] * src[15]; + tmp[3] = src[11] * src[13]; + tmp[4] = src[9] * src[14]; + tmp[5] = src[10] * src[13]; + tmp[6] = src[8] * src[15]; + tmp[7] = src[11] * src[12]; + tmp[8] = src[8] * src[14]; + tmp[9] = src[10] * src[12]; + tmp[10] = src[8] * src[13]; + tmp[11] = src[9] * src[12]; + // calculate first 8 elements (cofactors) + d.x.x = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7]; + d.x.x -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7]; + d.x.y = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7]; + d.x.y -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7]; + d.x.z = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7]; + d.x.z -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7]; + d.x.w = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6]; + d.x.w -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6]; + d.y.x = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3]; + d.y.x -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3]; + d.y.y = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3]; + d.y.y -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3]; + d.y.z = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3]; + d.y.z -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3]; + d.y.w = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2]; + d.y.w -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2]; + // calculate pairs for second 8 elements (cofactors) + tmp[0] = src[2]*src[7]; + tmp[1] = src[3]*src[6]; + tmp[2] = src[1]*src[7]; + tmp[3] = src[3]*src[5]; + tmp[4] = src[1]*src[6]; + tmp[5] = src[2]*src[5]; + tmp[6] = src[0]*src[7]; + tmp[7] = src[3]*src[4]; + tmp[8] = src[0]*src[6]; + tmp[9] = src[2]*src[4]; + tmp[10] = src[0]*src[5]; + tmp[11] = src[1]*src[4]; + // calculate second 8 elements (cofactors) + d.z.x = tmp[0]*src[13] + tmp[3]*src[14] + tmp[4]*src[15]; + d.z.x -= tmp[1]*src[13] + tmp[2]*src[14] + tmp[5]*src[15]; + d.z.y = tmp[1]*src[12] + tmp[6]*src[14] + tmp[9]*src[15]; + d.z.y -= tmp[0]*src[12] + tmp[7]*src[14] + tmp[8]*src[15]; + d.z.z = tmp[2]*src[12] + tmp[7]*src[13] + tmp[10]*src[15]; + d.z.z -= tmp[3]*src[12] + tmp[6]*src[13] + tmp[11]*src[15]; + d.z.w = tmp[5]*src[12] + tmp[8]*src[13] + tmp[11]*src[14]; + d.z.w-= tmp[4]*src[12] + tmp[9]*src[13] + tmp[10]*src[14]; + d.w.x = tmp[2]*src[10] + tmp[5]*src[11] + tmp[1]*src[9]; + d.w.x-= tmp[4]*src[11] + tmp[0]*src[9] + tmp[3]*src[10]; + d.w.y = tmp[8]*src[11] + tmp[0]*src[8] + tmp[7]*src[10]; + d.w.y-= tmp[6]*src[10] + tmp[9]*src[11] + tmp[1]*src[8]; + d.w.z = tmp[6]*src[9] + tmp[11]*src[11] + tmp[3]*src[8]; + d.w.z-= tmp[10]*src[11] + tmp[2]*src[8] + tmp[7]*src[9]; + d.w.w = tmp[10]*src[10] + tmp[4]*src[8] + tmp[9]*src[9]; + d.w.w-= tmp[8]*src[9] + tmp[11]*src[10] + tmp[5]*src[8]; + // calculate determinant + det = src[0] * d.x.x + src[1] * d.x.y + src[2] * d.x.z + src[3] * d.x.w; + // calculate matrix inverse + det = 1/det; + for (int j = 0; j < 4; j++) + d[j] *= det; + return d; + } + + public static float4x4 MatrixRigidInverse(float4x4 m) + { + float4x4 trans_inverse = MatrixTranslation(-m.w.xyz()); + float4x4 rot = new float4x4(m); + rot.w = new float4(0f, 0f, 0f, 1f); + return trans_inverse * MatrixTranspose(rot); + } + public static float4x4 MatrixTranspose(float4x4 m) + { + return new float4x4(m.x.x, m.y.x, m.z.x, m.w.x, m.x.y, m.y.y, m.z.y, m.w.y, m.x.z, m.y.z, m.z.z, m.w.z, m.x.w, m.y.w, m.z.w, m.w.w); + } + public static float4x4 MatrixPerspectiveFov(float fovy, float aspect, float zn, float zf) + { + float h = 1.0f / (float)Math.Tan(fovy / 2.0f); // view space height + float w = h / aspect; // view space width + return new float4x4(w, 0, 0, 0, 0, h, 0, 0, 0, 0, zf / (zn - zf), -1, 0, 0, zn * zf / (zn - zf), 0); + } + public static float4x4 MatrixTranslation(float3 t) + { + return new float4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, t.x, t.y, t.z, 1); + } + public static float4x4 MatrixRotationZ(float angle_radians) + { + float s = (float)Math.Sin(angle_radians); + float c = (float)Math.Cos(angle_radians); + return new float4x4(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + } + public static float4x4 MatrixLookAt(float3 eye, float3 at, float3 up) + { + float4x4 m = new float4x4(); + m.w.w = 1.0f; + m.w.setxyz(eye); + m.z.setxyz(float3.normalize(eye - at)); + m.x.setxyz(float3.normalize(float3.cross(up, m.z.xyz()))); + m.y.setxyz(float3.cross(m.z.xyz(), m.x.xyz())); + return MatrixRigidInverse(m); + } + + public static float4x4 MatrixFromQuatVec(Quaternion q, float3 v) + { + // builds a 4x4 transformation matrix based on orientation q and translation v + float qx2 = q.x * q.x; + float qy2 = q.y * q.y; + float qz2 = q.z * q.z; + + float qxqy = q.x * q.y; + float qxqz = q.x * q.z; + float qxqw = q.x * q.w; + float qyqz = q.y * q.z; + float qyqw = q.y * q.w; + float qzqw = q.z * q.w; + + return new float4x4( + 1 - 2 * (qy2 + qz2), + 2 * (qxqy + qzqw), + 2 * (qxqz - qyqw), + 0, + 2 * (qxqy - qzqw), + 1 - 2 * (qx2 + qz2), + 2 * (qyqz + qxqw), + 0, + 2 * (qxqz + qyqw), + 2 * (qyqz - qxqw), + 1 - 2 * (qx2 + qy2), + 0, + v.x, + v.y, + v.z, + 1.0f); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int3.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int3.cs new file mode 100644 index 0000000..90624eb --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int3.cs @@ -0,0 +1,128 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class int3 + { + public int x; + public int y; + public int z; + + public int3() + { + } + + public int3(int _x, int _y, int _z) + { + x = _x; + y = _y; + z = _z; + } + + public int this[int i] + { + get + { + switch (i) + { + case 0: return x; + case 1: return y; + case 2: return z; + } + throw new ArgumentOutOfRangeException(); + } + set + { + switch (i) + { + case 0: x = value; return; + case 1: y = value; return; + case 2: z = value; return; + } + throw new ArgumentOutOfRangeException(); + } + } + + public override int GetHashCode() + { + return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); + } + + public override bool Equals(object obj) + { + int3 i = obj as int3; + if (i == null) + return false; + + return this == i; + } + + public static bool operator ==(int3 a, int3 b) + { + // If both are null, or both are same instance, return true. + if (System.Object.ReferenceEquals(a, b)) + return true; + // If one is null, but not both, return false. + if (((object)a == null) || ((object)b == null)) + return false; + + for (int i = 0; i < 3; i++) + { + if (a[i] != b[i]) + return false; + } + return true; + } + + public static bool operator !=(int3 a, int3 b) + { + return !(a == b); + } + + public static int3 roll3(int3 a) + { + int tmp = a[0]; + a[0] = a[1]; + a[1] = a[2]; + a[2] = tmp; + return a; + } + + public static bool isa(int3 a, int3 b) + { + return (a == b || roll3(a) == b || a == roll3(b)); + } + + public static bool b2b(int3 a, int3 b) + { + return isa(a, new int3(b[2], b[1], b[0])); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int4.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int4.cs new file mode 100644 index 0000000..e9320c0 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int4.cs @@ -0,0 +1,66 @@ +/* The MIT License + * + * Copyright (c) 2010 Intel Corporation. + * All rights reserved. + * + * Based on the convexdecomposition library from + * by John W. Ratcliff and Stan Melax. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +using System; + +namespace OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet +{ + public class int4 + { + public int x; + public int y; + public int z; + public int w; + + public int4() + { + } + + public int4(int _x, int _y, int _z, int _w) + { + x = _x; + y = _y; + z = _z; + w = _w; + } + + public int this[int i] + { + get + { + switch (i) + { + case 0: return x; + case 1: return y; + case 2: return z; + case 3: return w; + } + throw new ArgumentOutOfRangeException(); + } + } + } +} diff --git a/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/HelperTypes.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/HelperTypes.cs new file mode 100644 index 0000000..34a925d --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/HelperTypes.cs @@ -0,0 +1,436 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using OpenMetaverse; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Region.PhysicsModules.Meshing; + +public class Vertex : IComparable +{ + Vector3 vector; + + public float X + { + get { return vector.X; } + set { vector.X = value; } + } + + public float Y + { + get { return vector.Y; } + set { vector.Y = value; } + } + + public float Z + { + get { return vector.Z; } + set { vector.Z = value; } + } + + public Vertex(float x, float y, float z) + { + vector.X = x; + vector.Y = y; + vector.Z = z; + } + + public Vertex normalize() + { + float tlength = vector.Length(); + if (tlength != 0f) + { + float mul = 1.0f / tlength; + return new Vertex(vector.X * mul, vector.Y * mul, vector.Z * mul); + } + else + { + return new Vertex(0f, 0f, 0f); + } + } + + public Vertex cross(Vertex v) + { + return new Vertex(vector.Y * v.Z - vector.Z * v.Y, vector.Z * v.X - vector.X * v.Z, vector.X * v.Y - vector.Y * v.X); + } + + // disable warning: mono compiler moans about overloading + // operators hiding base operator but should not according to C# + // language spec +#pragma warning disable 0108 + public static Vertex operator *(Vertex v, Quaternion q) + { + // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/ + + Vertex v2 = new Vertex(0f, 0f, 0f); + + v2.X = q.W * q.W * v.X + + 2f * q.Y * q.W * v.Z - + 2f * q.Z * q.W * v.Y + + q.X * q.X * v.X + + 2f * q.Y * q.X * v.Y + + 2f * q.Z * q.X * v.Z - + q.Z * q.Z * v.X - + q.Y * q.Y * v.X; + + v2.Y = + 2f * q.X * q.Y * v.X + + q.Y * q.Y * v.Y + + 2f * q.Z * q.Y * v.Z + + 2f * q.W * q.Z * v.X - + q.Z * q.Z * v.Y + + q.W * q.W * v.Y - + 2f * q.X * q.W * v.Z - + q.X * q.X * v.Y; + + v2.Z = + 2f * q.X * q.Z * v.X + + 2f * q.Y * q.Z * v.Y + + q.Z * q.Z * v.Z - + 2f * q.W * q.Y * v.X - + q.Y * q.Y * v.Z + + 2f * q.W * q.X * v.Y - + q.X * q.X * v.Z + + q.W * q.W * v.Z; + + return v2; + } + + public static Vertex operator +(Vertex v1, Vertex v2) + { + return new Vertex(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z); + } + + public static Vertex operator -(Vertex v1, Vertex v2) + { + return new Vertex(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z); + } + + public static Vertex operator *(Vertex v1, Vertex v2) + { + return new Vertex(v1.X * v2.X, v1.Y * v2.Y, v1.Z * v2.Z); + } + + public static Vertex operator +(Vertex v1, float am) + { + v1.X += am; + v1.Y += am; + v1.Z += am; + return v1; + } + + public static Vertex operator -(Vertex v1, float am) + { + v1.X -= am; + v1.Y -= am; + v1.Z -= am; + return v1; + } + + public static Vertex operator *(Vertex v1, float am) + { + v1.X *= am; + v1.Y *= am; + v1.Z *= am; + return v1; + } + + public static Vertex operator /(Vertex v1, float am) + { + if (am == 0f) + { + return new Vertex(0f,0f,0f); + } + float mul = 1.0f / am; + v1.X *= mul; + v1.Y *= mul; + v1.Z *= mul; + return v1; + } +#pragma warning restore 0108 + + + public float dot(Vertex v) + { + return X * v.X + Y * v.Y + Z * v.Z; + } + + public Vertex(Vector3 v) + { + vector = v; + } + + public Vertex Clone() + { + return new Vertex(X, Y, Z); + } + + public static Vertex FromAngle(double angle) + { + return new Vertex((float) Math.Cos(angle), (float) Math.Sin(angle), 0.0f); + } + + public float Length() + { + return vector.Length(); + } + + public virtual bool Equals(Vertex v, float tolerance) + { + Vertex diff = this - v; + float d = diff.Length(); + if (d < tolerance) + return true; + + return false; + } + + + public int CompareTo(Vertex other) + { + if (X < other.X) + return -1; + + if (X > other.X) + return 1; + + if (Y < other.Y) + return -1; + + if (Y > other.Y) + return 1; + + if (Z < other.Z) + return -1; + + if (Z > other.Z) + return 1; + + return 0; + } + + public static bool operator >(Vertex me, Vertex other) + { + return me.CompareTo(other) > 0; + } + + public static bool operator <(Vertex me, Vertex other) + { + return me.CompareTo(other) < 0; + } + + public String ToRaw() + { + // Why this stuff with the number formatter? + // Well, the raw format uses the english/US notation of numbers + // where the "," separates groups of 1000 while the "." marks the border between 1 and 10E-1. + // The german notation uses these characters exactly vice versa! + // The Float.ToString() routine is a localized one, giving different results depending on the country + // settings your machine works with. Unusable for a machine readable file format :-( + NumberFormatInfo nfi = new NumberFormatInfo(); + nfi.NumberDecimalSeparator = "."; + nfi.NumberDecimalDigits = 3; + + String s1 = X.ToString("N2", nfi) + " " + Y.ToString("N2", nfi) + " " + Z.ToString("N2", nfi); + + return s1; + } +} + +public class Triangle +{ + public Vertex v1; + public Vertex v2; + public Vertex v3; + + private float radius_square; + private float cx; + private float cy; + + public Triangle(Vertex _v1, Vertex _v2, Vertex _v3) + { + v1 = _v1; + v2 = _v2; + v3 = _v3; + + CalcCircle(); + } + + public bool isInCircle(float x, float y) + { + float dx, dy; + float dd; + + dx = x - cx; + dy = y - cy; + + dd = dx*dx + dy*dy; + if (dd < radius_square) + return true; + else + return false; + } + + public bool isDegraded() + { + // This means, the vertices of this triangle are somewhat strange. + // They either line up or at least two of them are identical + return (radius_square == 0.0); + } + + private void CalcCircle() + { + // Calculate the center and the radius of a circle given by three points p1, p2, p3 + // It is assumed, that the triangles vertices are already set correctly + double p1x, p2x, p1y, p2y, p3x, p3y; + + // Deviation of this routine: + // A circle has the general equation (M-p)^2=r^2, where M and p are vectors + // this gives us three equations f(p)=r^2, each for one point p1, p2, p3 + // putting respectively two equations together gives two equations + // f(p1)=f(p2) and f(p1)=f(p3) + // bringing all constant terms to one side brings them to the form + // M*v1=c1 resp.M*v2=c2 where v1=(p1-p2) and v2=(p1-p3) (still vectors) + // and c1, c2 are scalars (Naming conventions like the variables below) + // Now using the equations that are formed by the components of the vectors + // and isolate Mx lets you make one equation that only holds My + // The rest is straight forward and eaasy :-) + // + + /* helping variables for temporary results */ + double c1, c2; + double v1x, v1y, v2x, v2y; + + double z, n; + + double rx, ry; + + // Readout the three points, the triangle consists of + p1x = v1.X; + p1y = v1.Y; + + p2x = v2.X; + p2y = v2.Y; + + p3x = v3.X; + p3y = v3.Y; + + /* calc helping values first */ + c1 = (p1x*p1x + p1y*p1y - p2x*p2x - p2y*p2y)/2; + c2 = (p1x*p1x + p1y*p1y - p3x*p3x - p3y*p3y)/2; + + v1x = p1x - p2x; + v1y = p1y - p2y; + + v2x = p1x - p3x; + v2y = p1y - p3y; + + z = (c1*v2x - c2*v1x); + n = (v1y*v2x - v2y*v1x); + + if (n == 0.0) // This is no triangle, i.e there are (at least) two points at the same location + { + radius_square = 0.0f; + return; + } + + cy = (float) (z/n); + + if (v2x != 0.0) + { + cx = (float) ((c2 - v2y*cy)/v2x); + } + else if (v1x != 0.0) + { + cx = (float) ((c1 - v1y*cy)/v1x); + } + else + { + Debug.Assert(false, "Malformed triangle"); /* Both terms zero means nothing good */ + } + + rx = (p1x - cx); + ry = (p1y - cy); + + radius_square = (float) (rx*rx + ry*ry); + } + + public override String ToString() + { + NumberFormatInfo nfi = new NumberFormatInfo(); + nfi.CurrencyDecimalDigits = 2; + nfi.CurrencyDecimalSeparator = "."; + + String s1 = "<" + v1.X.ToString(nfi) + "," + v1.Y.ToString(nfi) + "," + v1.Z.ToString(nfi) + ">"; + String s2 = "<" + v2.X.ToString(nfi) + "," + v2.Y.ToString(nfi) + "," + v2.Z.ToString(nfi) + ">"; + String s3 = "<" + v3.X.ToString(nfi) + "," + v3.Y.ToString(nfi) + "," + v3.Z.ToString(nfi) + ">"; + + return s1 + ";" + s2 + ";" + s3; + } + + public Vector3 getNormal() + { + // Vertices + + // Vectors for edges + Vector3 e1; + Vector3 e2; + + e1 = new Vector3(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z); + e2 = new Vector3(v1.X - v3.X, v1.Y - v3.Y, v1.Z - v3.Z); + + // Cross product for normal + Vector3 n = Vector3.Cross(e1, e2); + + // Length + float l = n.Length(); + + // Normalized "normal" + n = n/l; + + return n; + } + + public void invertNormal() + { + Vertex vt; + vt = v1; + v1 = v2; + v2 = vt; + } + + // Dumps a triangle in the "raw faces" format, blender can import. This is for visualisation and + // debugging purposes + public String ToStringRaw() + { + String output = v1.ToRaw() + " " + v2.ToRaw() + " " + v3.ToRaw(); + return output; + } +} diff --git a/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Mesh.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Mesh.cs new file mode 100644 index 0000000..bf397ee --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Mesh.cs @@ -0,0 +1,333 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using OpenSim.Region.PhysicsModules.SharedBase; +using PrimMesher; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModules.Meshing +{ + public class Mesh : IMesh + { + private Dictionary m_vertices; + private List m_triangles; + GCHandle m_pinnedVertexes; + GCHandle m_pinnedIndex; + IntPtr m_verticesPtr = IntPtr.Zero; + int m_vertexCount = 0; + IntPtr m_indicesPtr = IntPtr.Zero; + int m_indexCount = 0; + public float[] m_normals; + + public Mesh() + { + m_vertices = new Dictionary(); + m_triangles = new List(); + } + + public Mesh Clone() + { + Mesh result = new Mesh(); + + foreach (Triangle t in m_triangles) + { + result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone())); + } + + return result; + } + + public void Add(Triangle triangle) + { + if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) + throw new NotSupportedException("Attempt to Add to a pinned Mesh"); + // If a vertex of the triangle is not yet in the vertices list, + // add it and set its index to the current index count + if (!m_vertices.ContainsKey(triangle.v1)) + m_vertices[triangle.v1] = m_vertices.Count; + if (!m_vertices.ContainsKey(triangle.v2)) + m_vertices[triangle.v2] = m_vertices.Count; + if (!m_vertices.ContainsKey(triangle.v3)) + m_vertices[triangle.v3] = m_vertices.Count; + m_triangles.Add(triangle); + } + + public void CalcNormals() + { + int iTriangles = m_triangles.Count; + + this.m_normals = new float[iTriangles * 3]; + + int i = 0; + foreach (Triangle t in m_triangles) + { + float ux, uy, uz; + float vx, vy, vz; + float wx, wy, wz; + + ux = t.v1.X; + uy = t.v1.Y; + uz = t.v1.Z; + + vx = t.v2.X; + vy = t.v2.Y; + vz = t.v2.Z; + + wx = t.v3.X; + wy = t.v3.Y; + wz = t.v3.Z; + + + // Vectors for edges + float e1x, e1y, e1z; + float e2x, e2y, e2z; + + e1x = ux - vx; + e1y = uy - vy; + e1z = uz - vz; + + e2x = ux - wx; + e2y = uy - wy; + e2z = uz - wz; + + + // Cross product for normal + float nx, ny, nz; + nx = e1y * e2z - e1z * e2y; + ny = e1z * e2x - e1x * e2z; + nz = e1x * e2y - e1y * e2x; + + // Length + float l = (float)Math.Sqrt(nx * nx + ny * ny + nz * nz); + float lReciprocal = 1.0f / l; + + // Normalized "normal" + //nx /= l; + //ny /= l; + //nz /= l; + + m_normals[i] = nx * lReciprocal; + m_normals[i + 1] = ny * lReciprocal; + m_normals[i + 2] = nz * lReciprocal; + + i += 3; + } + } + + public List getVertexList() + { + List result = new List(); + foreach (Vertex v in m_vertices.Keys) + { + result.Add(new Vector3(v.X, v.Y, v.Z)); + } + return result; + } + + public float[] getVertexListAsFloat() + { + if (m_vertices == null) + throw new NotSupportedException(); + float[] result = new float[m_vertices.Count * 3]; + foreach (KeyValuePair kvp in m_vertices) + { + Vertex v = kvp.Key; + int i = kvp.Value; + result[3 * i + 0] = v.X; + result[3 * i + 1] = v.Y; + result[3 * i + 2] = v.Z; + } + return result; + } + + public float[] getVertexListAsFloatLocked() + { + if (m_pinnedVertexes.IsAllocated) + return (float[])(m_pinnedVertexes.Target); + + float[] result = getVertexListAsFloat(); + m_pinnedVertexes = GCHandle.Alloc(result, GCHandleType.Pinned); + // Inform the garbage collector of this unmanaged allocation so it can schedule + // the next GC round more intelligently + GC.AddMemoryPressure(Buffer.ByteLength(result)); + + return result; + } + + public void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount) + { + // A vertex is 3 floats + vertexStride = 3 * sizeof(float); + + // If there isn't an unmanaged array allocated yet, do it now + if (m_verticesPtr == IntPtr.Zero) + { + float[] vertexList = getVertexListAsFloat(); + // Each vertex is 3 elements (floats) + m_vertexCount = vertexList.Length / 3; + int byteCount = m_vertexCount * vertexStride; + m_verticesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); + System.Runtime.InteropServices.Marshal.Copy(vertexList, 0, m_verticesPtr, m_vertexCount * 3); + } + vertices = m_verticesPtr; + vertexCount = m_vertexCount; + } + + public int[] getIndexListAsInt() + { + if (m_triangles == null) + throw new NotSupportedException(); + int[] result = new int[m_triangles.Count * 3]; + for (int i = 0; i < m_triangles.Count; i++) + { + Triangle t = m_triangles[i]; + result[3 * i + 0] = m_vertices[t.v1]; + result[3 * i + 1] = m_vertices[t.v2]; + result[3 * i + 2] = m_vertices[t.v3]; + } + return result; + } + + /// + /// creates a list of index values that defines triangle faces. THIS METHOD FREES ALL NON-PINNED MESH DATA + /// + /// + public int[] getIndexListAsIntLocked() + { + if (m_pinnedIndex.IsAllocated) + return (int[])(m_pinnedIndex.Target); + + int[] result = getIndexListAsInt(); + m_pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned); + // Inform the garbage collector of this unmanaged allocation so it can schedule + // the next GC round more intelligently + GC.AddMemoryPressure(Buffer.ByteLength(result)); + + return result; + } + + public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount) + { + // If there isn't an unmanaged array allocated yet, do it now + if (m_indicesPtr == IntPtr.Zero) + { + int[] indexList = getIndexListAsInt(); + m_indexCount = indexList.Length; + int byteCount = m_indexCount * sizeof(int); + m_indicesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount); + System.Runtime.InteropServices.Marshal.Copy(indexList, 0, m_indicesPtr, m_indexCount); + } + // A triangle is 3 ints (indices) + triStride = 3 * sizeof(int); + indices = m_indicesPtr; + indexCount = m_indexCount; + } + + public void releasePinned() + { + if (m_pinnedVertexes.IsAllocated) + m_pinnedVertexes.Free(); + if (m_pinnedIndex.IsAllocated) + m_pinnedIndex.Free(); + if (m_verticesPtr != IntPtr.Zero) + { + System.Runtime.InteropServices.Marshal.FreeHGlobal(m_verticesPtr); + m_verticesPtr = IntPtr.Zero; + } + if (m_indicesPtr != IntPtr.Zero) + { + System.Runtime.InteropServices.Marshal.FreeHGlobal(m_indicesPtr); + m_indicesPtr = IntPtr.Zero; + } + } + + /// + /// frees up the source mesh data to minimize memory - call this method after calling get*Locked() functions + /// + public void releaseSourceMeshData() + { + m_triangles = null; + m_vertices = null; + } + + public void Append(IMesh newMesh) + { + if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) + throw new NotSupportedException("Attempt to Append to a pinned Mesh"); + + if (!(newMesh is Mesh)) + return; + + foreach (Triangle t in ((Mesh)newMesh).m_triangles) + Add(t); + } + + // Do a linear transformation of mesh. + public void TransformLinear(float[,] matrix, float[] offset) + { + if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero) + throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh"); + + foreach (Vertex v in m_vertices.Keys) + { + if (v == null) + continue; + float x, y, z; + x = v.X*matrix[0, 0] + v.Y*matrix[1, 0] + v.Z*matrix[2, 0]; + y = v.X*matrix[0, 1] + v.Y*matrix[1, 1] + v.Z*matrix[2, 1]; + z = v.X*matrix[0, 2] + v.Y*matrix[1, 2] + v.Z*matrix[2, 2]; + v.X = x + offset[0]; + v.Y = y + offset[1]; + v.Z = z + offset[2]; + } + } + + public void DumpRaw(String path, String name, String title) + { + if (path == null) + return; + String fileName = name + "_" + title + ".raw"; + String completePath = System.IO.Path.Combine(path, fileName); + StreamWriter sw = new StreamWriter(completePath); + foreach (Triangle t in m_triangles) + { + String s = t.ToStringRaw(); + sw.WriteLine(s); + } + sw.Close(); + } + + public void TrimExcess() + { + m_triangles.TrimExcess(); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs new file mode 100644 index 0000000..4d25bf3 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs @@ -0,0 +1,1010 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +//#define SPAM + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.IO; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO.Compression; +using PrimMesher; +using log4net; +using Nini.Config; +using Mono.Addins; + +namespace OpenSim.Region.PhysicsModules.Meshing +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "Meshmerizer")] + public class Meshmerizer : IMesher, INonSharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static string LogHeader = "[MESH]"; + + // Setting baseDir to a path will enable the dumping of raw files + // raw files can be imported by blender so a visual inspection of the results can be done +#if SPAM + const string baseDir = "rawFiles"; +#else + private const string baseDir = null; //"rawFiles"; +#endif + private bool m_Enabled = false; + + // If 'true', lots of DEBUG logging of asset parsing details + private bool debugDetail = false; + + private bool cacheSculptMaps = true; + private string decodedSculptMapPath = null; + private bool useMeshiesPhysicsMesh = false; + + private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh + + private List> mConvexHulls = null; + private List mBoundingHull = null; + + // Mesh cache. Static so it can be shared across instances of this class + private static Dictionary m_uniqueMeshes = new Dictionary(); + + #region INonSharedRegionModule + public string Name + { + get { return "Meshmerizer"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Initialise(IConfigSource source) + { + IConfig config = source.Configs["Startup"]; + if (config != null) + { + string mesher = config.GetString("meshing", string.Empty); + if (mesher == Name) + { + m_Enabled = true; + + IConfig mesh_config = source.Configs["Mesh"]; + + decodedSculptMapPath = config.GetString("DecodedSculptMapPath", "j2kDecodeCache"); + cacheSculptMaps = config.GetBoolean("CacheSculptMaps", cacheSculptMaps); + if (mesh_config != null) + { + useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); + debugDetail = mesh_config.GetBoolean("LogMeshDetails", debugDetail); + } + + try + { + if (!Directory.Exists(decodedSculptMapPath)) + Directory.CreateDirectory(decodedSculptMapPath); + } + catch (Exception e) + { + m_log.WarnFormat("[SCULPT]: Unable to create {0} directory: ", decodedSculptMapPath, e.Message); + } + + } + } + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + scene.RegisterModuleInterface(this); + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + + scene.UnregisterModuleInterface(this); + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + } + #endregion + + + /// + /// creates a simple box mesh of the specified size. This mesh is of very low vertex count and may + /// be useful as a backup proxy when level of detail is not needed or when more complex meshes fail + /// for some reason + /// + /// + /// + /// + /// + /// + /// + /// + private static Mesh CreateSimpleBoxMesh(float minX, float maxX, float minY, float maxY, float minZ, float maxZ) + { + Mesh box = new Mesh(); + List vertices = new List(); + // bottom + + vertices.Add(new Vertex(minX, maxY, minZ)); + vertices.Add(new Vertex(maxX, maxY, minZ)); + vertices.Add(new Vertex(maxX, minY, minZ)); + vertices.Add(new Vertex(minX, minY, minZ)); + + box.Add(new Triangle(vertices[0], vertices[1], vertices[2])); + box.Add(new Triangle(vertices[0], vertices[2], vertices[3])); + + // top + + vertices.Add(new Vertex(maxX, maxY, maxZ)); + vertices.Add(new Vertex(minX, maxY, maxZ)); + vertices.Add(new Vertex(minX, minY, maxZ)); + vertices.Add(new Vertex(maxX, minY, maxZ)); + + box.Add(new Triangle(vertices[4], vertices[5], vertices[6])); + box.Add(new Triangle(vertices[4], vertices[6], vertices[7])); + + // sides + + box.Add(new Triangle(vertices[5], vertices[0], vertices[3])); + box.Add(new Triangle(vertices[5], vertices[3], vertices[6])); + + box.Add(new Triangle(vertices[1], vertices[0], vertices[5])); + box.Add(new Triangle(vertices[1], vertices[5], vertices[4])); + + box.Add(new Triangle(vertices[7], vertices[1], vertices[4])); + box.Add(new Triangle(vertices[7], vertices[2], vertices[1])); + + box.Add(new Triangle(vertices[3], vertices[2], vertices[7])); + box.Add(new Triangle(vertices[3], vertices[7], vertices[6])); + + return box; + } + + /// + /// Creates a simple bounding box mesh for a complex input mesh + /// + /// + /// + private static Mesh CreateBoundingBoxMesh(Mesh meshIn) + { + float minX = float.MaxValue; + float maxX = float.MinValue; + float minY = float.MaxValue; + float maxY = float.MinValue; + float minZ = float.MaxValue; + float maxZ = float.MinValue; + + foreach (Vector3 v in meshIn.getVertexList()) + { + if (v.X < minX) minX = v.X; + if (v.Y < minY) minY = v.Y; + if (v.Z < minZ) minZ = v.Z; + + if (v.X > maxX) maxX = v.X; + if (v.Y > maxY) maxY = v.Y; + if (v.Z > maxZ) maxZ = v.Z; + } + + return CreateSimpleBoxMesh(minX, maxX, minY, maxY, minZ, maxZ); + } + + private void ReportPrimError(string message, string primName, PrimMesh primMesh) + { + m_log.Error(message); + m_log.Error("\nPrim Name: " + primName); + m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString()); + } + + /// + /// Add a submesh to an existing list of coords and faces. + /// + /// + /// Size of entire object + /// + /// + private void AddSubMesh(OSDMap subMeshData, Vector3 size, List coords, List faces) + { + // Console.WriteLine("subMeshMap for {0} - {1}", primName, Util.GetFormattedXml((OSD)subMeshMap)); + + // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level + // of Detail Blocks (maps) contain just a NoGeometry key to signal there is no + // geometry for this submesh. + if (subMeshData.ContainsKey("NoGeometry") && ((OSDBoolean)subMeshData["NoGeometry"])) + return; + + OpenMetaverse.Vector3 posMax = ((OSDMap)subMeshData["PositionDomain"])["Max"].AsVector3(); + OpenMetaverse.Vector3 posMin = ((OSDMap)subMeshData["PositionDomain"])["Min"].AsVector3(); + ushort faceIndexOffset = (ushort)coords.Count; + + byte[] posBytes = subMeshData["Position"].AsBinary(); + for (int i = 0; i < posBytes.Length; i += 6) + { + ushort uX = Utils.BytesToUInt16(posBytes, i); + ushort uY = Utils.BytesToUInt16(posBytes, i + 2); + ushort uZ = Utils.BytesToUInt16(posBytes, i + 4); + + Coord c = new Coord( + Utils.UInt16ToFloat(uX, posMin.X, posMax.X) * size.X, + Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y) * size.Y, + Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z) * size.Z); + + coords.Add(c); + } + + byte[] triangleBytes = subMeshData["TriangleList"].AsBinary(); + for (int i = 0; i < triangleBytes.Length; i += 6) + { + ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i) + faceIndexOffset); + ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2) + faceIndexOffset); + ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4) + faceIndexOffset); + Face f = new Face(v1, v2, v3); + faces.Add(f); + } + } + + /// + /// Create a physics mesh from data that comes with the prim. The actual data used depends on the prim type. + /// + /// + /// + /// + /// + /// + private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod) + { +// m_log.DebugFormat( +// "[MESH]: Creating physics proxy for {0}, shape {1}", +// primName, (OpenMetaverse.SculptType)primShape.SculptType); + + List coords; + List faces; + + if (primShape.SculptEntry) + { + if (((OpenMetaverse.SculptType)primShape.SculptType) == SculptType.Mesh) + { + if (!useMeshiesPhysicsMesh) + return null; + + if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, size, out coords, out faces)) + return null; + } + else + { + if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces)) + return null; + } + } + else + { + if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces)) + return null; + } + + // Remove the reference to any JPEG2000 sculpt data so it can be GCed + primShape.SculptData = Utils.EmptyBytes; + + int numCoords = coords.Count; + int numFaces = faces.Count; + + // Create the list of vertices + List vertices = new List(); + for (int i = 0; i < numCoords; i++) + { + Coord c = coords[i]; + vertices.Add(new Vertex(c.X, c.Y, c.Z)); + } + + Mesh mesh = new Mesh(); + // Add the corresponding triangles to the mesh + for (int i = 0; i < numFaces; i++) + { + Face f = faces[i]; + mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); + } + + return mesh; + } + + /// + /// Generate the co-ords and faces necessary to construct a mesh from the mesh data the accompanies a prim. + /// + /// + /// + /// + /// Coords are added to this list by the method. + /// Faces are added to this list by the method. + /// true if coords and faces were successfully generated, false if not + private bool GenerateCoordsAndFacesFromPrimMeshData( + string primName, PrimitiveBaseShape primShape, Vector3 size, out List coords, out List faces) + { +// m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName); + + coords = new List(); + faces = new List(); + OSD meshOsd = null; + + mConvexHulls = null; + mBoundingHull = null; + + if (primShape.SculptData.Length <= 0) + { + // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this + // method twice - once before it has loaded sculpt data from the asset service and once afterwards. + // The first time will always call with unloaded SculptData if this needs to be uploaded. +// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); + return false; + } + + long start = 0; + using (MemoryStream data = new MemoryStream(primShape.SculptData)) + { + try + { + OSD osd = OSDParser.DeserializeLLSDBinary(data); + if (osd is OSDMap) + meshOsd = (OSDMap)osd; + else + { + m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap"); + return false; + } + } + catch (Exception e) + { + m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString()); + } + + start = data.Position; + } + + if (meshOsd is OSDMap) + { + OSDMap physicsParms = null; + OSDMap map = (OSDMap)meshOsd; + if (map.ContainsKey("physics_shape")) + { + physicsParms = (OSDMap)map["physics_shape"]; // old asset format + if (debugDetail) m_log.DebugFormat("{0} prim='{1}': using 'physics_shape' mesh data", LogHeader, primName); + } + else if (map.ContainsKey("physics_mesh")) + { + physicsParms = (OSDMap)map["physics_mesh"]; // new asset format + if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'physics_mesh' mesh data", LogHeader, primName); + } + else if (map.ContainsKey("medium_lod")) + { + physicsParms = (OSDMap)map["medium_lod"]; // if no physics mesh, try to fall back to medium LOD display mesh + if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'medium_lod' mesh data", LogHeader, primName); + } + else if (map.ContainsKey("high_lod")) + { + physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :) + if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'high_lod' mesh data", LogHeader, primName); + } + + if (map.ContainsKey("physics_convex")) + { // pull this out also in case physics engine can use it + OSD convexBlockOsd = null; + try + { + OSDMap convexBlock = (OSDMap)map["physics_convex"]; + { + int convexOffset = convexBlock["offset"].AsInteger() + (int)start; + int convexSize = convexBlock["size"].AsInteger(); + + byte[] convexBytes = new byte[convexSize]; + + System.Buffer.BlockCopy(primShape.SculptData, convexOffset, convexBytes, 0, convexSize); + + try + { + convexBlockOsd = DecompressOsd(convexBytes); + } + catch (Exception e) + { + m_log.ErrorFormat("{0} prim='{1}': exception decoding convex block: {2}", LogHeader, primName, e); + //return false; + } + } + + if (convexBlockOsd != null && convexBlockOsd is OSDMap) + { + convexBlock = convexBlockOsd as OSDMap; + + if (debugDetail) + { + string keys = LogHeader + " keys found in convexBlock: "; + foreach (KeyValuePair kvp in convexBlock) + keys += "'" + kvp.Key + "' "; + m_log.Debug(keys); + } + + Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f); + if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3(); + Vector3 max = new Vector3(0.5f, 0.5f, 0.5f); + if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3(); + + List boundingHull = null; + + if (convexBlock.ContainsKey("BoundingVerts")) + { + byte[] boundingVertsBytes = convexBlock["BoundingVerts"].AsBinary(); + boundingHull = new List(); + for (int i = 0; i < boundingVertsBytes.Length; ) + { + ushort uX = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; + ushort uY = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; + ushort uZ = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; + + Vector3 pos = new Vector3( + Utils.UInt16ToFloat(uX, min.X, max.X), + Utils.UInt16ToFloat(uY, min.Y, max.Y), + Utils.UInt16ToFloat(uZ, min.Z, max.Z) + ); + + boundingHull.Add(pos); + } + + mBoundingHull = boundingHull; + if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed bounding hull. nVerts={2}", LogHeader, primName, mBoundingHull.Count); + } + + if (convexBlock.ContainsKey("HullList")) + { + byte[] hullList = convexBlock["HullList"].AsBinary(); + + byte[] posBytes = convexBlock["Positions"].AsBinary(); + + List> hulls = new List>(); + int posNdx = 0; + + foreach (byte cnt in hullList) + { + int count = cnt == 0 ? 256 : cnt; + List hull = new List(); + + for (int i = 0; i < count; i++) + { + ushort uX = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; + ushort uY = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; + ushort uZ = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; + + Vector3 pos = new Vector3( + Utils.UInt16ToFloat(uX, min.X, max.X), + Utils.UInt16ToFloat(uY, min.Y, max.Y), + Utils.UInt16ToFloat(uZ, min.Z, max.Z) + ); + + hull.Add(pos); + } + + hulls.Add(hull); + } + + mConvexHulls = hulls; + if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed hulls. nHulls={2}", LogHeader, primName, mConvexHulls.Count); + } + else + { + if (debugDetail) m_log.DebugFormat("{0} prim='{1}' has physics_convex but no HullList", LogHeader, primName); + } + } + } + catch (Exception e) + { + m_log.WarnFormat("{0} exception decoding convex block: {1}", LogHeader, e); + } + } + + if (physicsParms == null) + { + m_log.WarnFormat("[MESH]: No recognized physics mesh found in mesh asset for {0}", primName); + return false; + } + + int physOffset = physicsParms["offset"].AsInteger() + (int)start; + int physSize = physicsParms["size"].AsInteger(); + + if (physOffset < 0 || physSize == 0) + return false; // no mesh data in asset + + OSD decodedMeshOsd = new OSD(); + byte[] meshBytes = new byte[physSize]; + System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); + // byte[] decompressed = new byte[physSize * 5]; + try + { + decodedMeshOsd = DecompressOsd(meshBytes); + } + catch (Exception e) + { + m_log.ErrorFormat("{0} prim='{1}': exception decoding physical mesh: {2}", LogHeader, primName, e); + return false; + } + + OSDArray decodedMeshOsdArray = null; + + // physics_shape is an array of OSDMaps, one for each submesh + if (decodedMeshOsd is OSDArray) + { + // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); + + decodedMeshOsdArray = (OSDArray)decodedMeshOsd; + foreach (OSD subMeshOsd in decodedMeshOsdArray) + { + if (subMeshOsd is OSDMap) + AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); + } + if (debugDetail) + m_log.DebugFormat("{0} {1}: mesh decoded. offset={2}, size={3}, nCoords={4}, nFaces={5}", + LogHeader, primName, physOffset, physSize, coords.Count, faces.Count); + } + } + + return true; + } + + /// + /// decompresses a gzipped OSD object + /// + /// the OSD object + /// + /// + private static OSD DecompressOsd(byte[] meshBytes) + { + OSD decodedOsd = null; + + using (MemoryStream inMs = new MemoryStream(meshBytes)) + { + using (MemoryStream outMs = new MemoryStream()) + { + using (DeflateStream decompressionStream = new DeflateStream(inMs, CompressionMode.Decompress)) + { + byte[] readBuffer = new byte[2048]; + inMs.Read(readBuffer, 0, 2); // skip first 2 bytes in header + int readLen = 0; + + while ((readLen = decompressionStream.Read(readBuffer, 0, readBuffer.Length)) > 0) + outMs.Write(readBuffer, 0, readLen); + + outMs.Flush(); + + outMs.Seek(0, SeekOrigin.Begin); + + byte[] decompressedBuf = outMs.GetBuffer(); + + decodedOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); + } + } + } + return decodedOsd; + } + + /// + /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim. + /// + /// + /// + /// + /// + /// Coords are added to this list by the method. + /// Faces are added to this list by the method. + /// true if coords and faces were successfully generated, false if not + private bool GenerateCoordsAndFacesFromPrimSculptData( + string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List coords, out List faces) + { + coords = new List(); + faces = new List(); + PrimMesher.SculptMesh sculptMesh; + Image idata = null; + string decodedSculptFileName = ""; + + if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero) + { + decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString()); + try + { + if (File.Exists(decodedSculptFileName)) + { + idata = Image.FromFile(decodedSculptFileName); + } + } + catch (Exception e) + { + m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message); + + } + //if (idata != null) + // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString()); + } + + if (idata == null) + { + if (primShape.SculptData == null || primShape.SculptData.Length == 0) + return false; + + try + { + OpenMetaverse.Imaging.ManagedImage managedImage; + + OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out managedImage); + + if (managedImage == null) + { + // In some cases it seems that the decode can return a null bitmap without throwing + // an exception + m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName); + + return false; + } + + if ((managedImage.Channels & OpenMetaverse.Imaging.ManagedImage.ImageChannels.Alpha) != 0) + managedImage.ConvertChannels(managedImage.Channels & ~OpenMetaverse.Imaging.ManagedImage.ImageChannels.Alpha); + + Bitmap imgData = OpenMetaverse.Imaging.LoadTGAClass.LoadTGA(new MemoryStream(managedImage.ExportTGA())); + idata = (Image)imgData; + managedImage = null; + + if (cacheSculptMaps) + { + try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); } + catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); } + } + } + catch (DllNotFoundException) + { + m_log.Error("[PHYSICS]: OpenJpeg is not installed correctly on this system. Physics Proxy generation failed. Often times this is because of an old version of GLIBC. You must have version 2.4 or above!"); + return false; + } + catch (IndexOutOfRangeException) + { + m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed"); + return false; + } + catch (Exception ex) + { + m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message); + return false; + } + } + + PrimMesher.SculptMesh.SculptType sculptType; + switch ((OpenMetaverse.SculptType)primShape.SculptType) + { + case OpenMetaverse.SculptType.Cylinder: + sculptType = PrimMesher.SculptMesh.SculptType.cylinder; + break; + case OpenMetaverse.SculptType.Plane: + sculptType = PrimMesher.SculptMesh.SculptType.plane; + break; + case OpenMetaverse.SculptType.Torus: + sculptType = PrimMesher.SculptMesh.SculptType.torus; + break; + case OpenMetaverse.SculptType.Sphere: + sculptType = PrimMesher.SculptMesh.SculptType.sphere; + break; + default: + sculptType = PrimMesher.SculptMesh.SculptType.plane; + break; + } + + bool mirror = ((primShape.SculptType & 128) != 0); + bool invert = ((primShape.SculptType & 64) != 0); + + sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert); + + idata.Dispose(); + + sculptMesh.DumpRaw(baseDir, primName, "primMesh"); + + sculptMesh.Scale(size.X, size.Y, size.Z); + + coords = sculptMesh.coords; + faces = sculptMesh.faces; + + return true; + } + + /// + /// Generate the co-ords and faces necessary to construct a mesh from the shape data the accompanies a prim. + /// + /// + /// + /// + /// Coords are added to this list by the method. + /// Faces are added to this list by the method. + /// true if coords and faces were successfully generated, false if not + private bool GenerateCoordsAndFacesFromPrimShapeData( + string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List coords, out List faces) + { + PrimMesh primMesh; + coords = new List(); + faces = new List(); + + float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f; + float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f; + float pathBegin = (float)primShape.PathBegin * 2.0e-5f; + float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f; + float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f; + float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f; + + float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f; + float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f; + float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f; + if (profileHollow > 0.95f) + profileHollow = 0.95f; + + int sides = 4; + LevelOfDetail iLOD = (LevelOfDetail)lod; + if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) + sides = 3; + else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) + { + switch (iLOD) + { + case LevelOfDetail.High: sides = 24; break; + case LevelOfDetail.Medium: sides = 12; break; + case LevelOfDetail.Low: sides = 6; break; + case LevelOfDetail.VeryLow: sides = 3; break; + default: sides = 24; break; + } + } + else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) + { // half circle, prim is a sphere + switch (iLOD) + { + case LevelOfDetail.High: sides = 24; break; + case LevelOfDetail.Medium: sides = 12; break; + case LevelOfDetail.Low: sides = 6; break; + case LevelOfDetail.VeryLow: sides = 3; break; + default: sides = 24; break; + } + + profileBegin = 0.5f * profileBegin + 0.5f; + profileEnd = 0.5f * profileEnd + 0.5f; + } + + int hollowSides = sides; + if (primShape.HollowShape == HollowShape.Circle) + { + switch (iLOD) + { + case LevelOfDetail.High: hollowSides = 24; break; + case LevelOfDetail.Medium: hollowSides = 12; break; + case LevelOfDetail.Low: hollowSides = 6; break; + case LevelOfDetail.VeryLow: hollowSides = 3; break; + default: hollowSides = 24; break; + } + } + else if (primShape.HollowShape == HollowShape.Square) + hollowSides = 4; + else if (primShape.HollowShape == HollowShape.Triangle) + hollowSides = 3; + + primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides); + + if (primMesh.errorMessage != null) + if (primMesh.errorMessage.Length > 0) + m_log.Error("[ERROR] " + primMesh.errorMessage); + + primMesh.topShearX = pathShearX; + primMesh.topShearY = pathShearY; + primMesh.pathCutBegin = pathBegin; + primMesh.pathCutEnd = pathEnd; + + if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible) + { + primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10; + primMesh.twistEnd = primShape.PathTwist * 18 / 10; + primMesh.taperX = pathScaleX; + primMesh.taperY = pathScaleY; + + if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) + { + ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); + if (profileBegin < 0.0f) profileBegin = 0.0f; + if (profileEnd > 1.0f) profileEnd = 1.0f; + } +#if SPAM + m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString()); +#endif + try + { + primMesh.ExtrudeLinear(); + } + catch (Exception ex) + { + ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); + return false; + } + } + else + { + primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f; + primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f; + primMesh.radius = 0.01f * primShape.PathRadiusOffset; + primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions; + primMesh.skew = 0.01f * primShape.PathSkew; + primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10; + primMesh.twistEnd = primShape.PathTwist * 36 / 10; + primMesh.taperX = primShape.PathTaperX * 0.01f; + primMesh.taperY = primShape.PathTaperY * 0.01f; + + if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) + { + ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); + if (profileBegin < 0.0f) profileBegin = 0.0f; + if (profileEnd > 1.0f) profileEnd = 1.0f; + } +#if SPAM + m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString()); +#endif + try + { + primMesh.ExtrudeCircular(); + } + catch (Exception ex) + { + ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); + return false; + } + } + + primMesh.DumpRaw(baseDir, primName, "primMesh"); + + primMesh.Scale(size.X, size.Y, size.Z); + + coords = primMesh.coords; + faces = primMesh.faces; + + return true; + } + + /// + /// temporary prototype code - please do not use until the interface has been finalized! + /// + /// value to scale the hull points by + /// a list of vertices in the bounding hull if it exists and has been successfully decoded, otherwise null + public List GetBoundingHull(Vector3 size) + { + if (mBoundingHull == null) + return null; + + List verts = new List(); + foreach (var vert in mBoundingHull) + verts.Add(vert * size); + + return verts; + } + + /// + /// temporary prototype code - please do not use until the interface has been finalized! + /// + /// value to scale the hull points by + /// a list of hulls if they exist and have been successfully decoded, otherwise null + public List> GetConvexHulls(Vector3 size) + { + if (mConvexHulls == null) + return null; + + List> hulls = new List>(); + foreach (var hull in mConvexHulls) + { + List verts = new List(); + foreach (var vert in hull) + verts.Add(vert * size); + hulls.Add(verts); + } + + return hulls; + } + + public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) + { + return CreateMesh(primName, primShape, size, lod, false, true); + } + + public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) + { + return CreateMesh(primName, primShape, size, lod, isPhysical, true); + } + + public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) + { +#if SPAM + m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); +#endif + + Mesh mesh = null; + ulong key = 0; + + // If this mesh has been created already, return it instead of creating another copy + // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory + if (shouldCache) + { + key = primShape.GetMeshKey(size, lod); + lock (m_uniqueMeshes) + { + if (m_uniqueMeshes.TryGetValue(key, out mesh)) + return mesh; + } + } + + if (size.X < 0.01f) size.X = 0.01f; + if (size.Y < 0.01f) size.Y = 0.01f; + if (size.Z < 0.01f) size.Z = 0.01f; + + mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod); + + if (mesh != null) + { + if ((!isPhysical) && size.X < minSizeForComplexMesh && size.Y < minSizeForComplexMesh && size.Z < minSizeForComplexMesh) + { +#if SPAM + m_log.Debug("Meshmerizer: prim " + primName + " has a size of " + size.ToString() + " which is below threshold of " + + minSizeForComplexMesh.ToString() + " - creating simple bounding box"); +#endif + mesh = CreateBoundingBoxMesh(mesh); + mesh.DumpRaw(baseDir, primName, "Z extruded"); + } + + // trim the vertex and triangle lists to free up memory + mesh.TrimExcess(); + + if (shouldCache) + { + lock (m_uniqueMeshes) + { + m_uniqueMeshes.Add(key, mesh); + } + } + } + + return mesh; + } + + } +} diff --git a/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/PrimMesher.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/PrimMesher.cs new file mode 100644 index 0000000..4049ee1 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/PrimMesher.cs @@ -0,0 +1,2324 @@ +/* + * Copyright (c) Contributors + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace PrimMesher +{ + public struct Quat + { + /// X value + public float X; + /// Y value + public float Y; + /// Z value + public float Z; + /// W value + public float W; + + public Quat(float x, float y, float z, float w) + { + X = x; + Y = y; + Z = z; + W = w; + } + + public Quat(Coord axis, float angle) + { + axis = axis.Normalize(); + + angle *= 0.5f; + float c = (float)Math.Cos(angle); + float s = (float)Math.Sin(angle); + + X = axis.X * s; + Y = axis.Y * s; + Z = axis.Z * s; + W = c; + + Normalize(); + } + + public float Length() + { + return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); + } + + public Quat Normalize() + { + const float MAG_THRESHOLD = 0.0000001f; + float mag = Length(); + + // Catch very small rounding errors when normalizing + if (mag > MAG_THRESHOLD) + { + float oomag = 1f / mag; + X *= oomag; + Y *= oomag; + Z *= oomag; + W *= oomag; + } + else + { + X = 0f; + Y = 0f; + Z = 0f; + W = 1f; + } + + return this; + } + + public static Quat operator *(Quat q1, Quat q2) + { + float x = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y; + float y = q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X; + float z = q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W; + float w = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z; + return new Quat(x, y, z, w); + } + + public override string ToString() + { + return "< X: " + this.X.ToString() + ", Y: " + this.Y.ToString() + ", Z: " + this.Z.ToString() + ", W: " + this.W.ToString() + ">"; + } + } + + public struct Coord + { + public float X; + public float Y; + public float Z; + + public Coord(float x, float y, float z) + { + this.X = x; + this.Y = y; + this.Z = z; + } + + public float Length() + { + return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z); + } + + public Coord Invert() + { + this.X = -this.X; + this.Y = -this.Y; + this.Z = -this.Z; + + return this; + } + + public Coord Normalize() + { + const float MAG_THRESHOLD = 0.0000001f; + float mag = Length(); + + // Catch very small rounding errors when normalizing + if (mag > MAG_THRESHOLD) + { + float oomag = 1.0f / mag; + this.X *= oomag; + this.Y *= oomag; + this.Z *= oomag; + } + else + { + this.X = 0.0f; + this.Y = 0.0f; + this.Z = 0.0f; + } + + return this; + } + + public override string ToString() + { + return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString(); + } + + public static Coord Cross(Coord c1, Coord c2) + { + return new Coord( + c1.Y * c2.Z - c2.Y * c1.Z, + c1.Z * c2.X - c2.Z * c1.X, + c1.X * c2.Y - c2.X * c1.Y + ); + } + + public static Coord operator +(Coord v, Coord a) + { + return new Coord(v.X + a.X, v.Y + a.Y, v.Z + a.Z); + } + + public static Coord operator *(Coord v, Coord m) + { + return new Coord(v.X * m.X, v.Y * m.Y, v.Z * m.Z); + } + + public static Coord operator *(Coord v, Quat q) + { + // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/ + + Coord c2 = new Coord(0.0f, 0.0f, 0.0f); + + c2.X = q.W * q.W * v.X + + 2f * q.Y * q.W * v.Z - + 2f * q.Z * q.W * v.Y + + q.X * q.X * v.X + + 2f * q.Y * q.X * v.Y + + 2f * q.Z * q.X * v.Z - + q.Z * q.Z * v.X - + q.Y * q.Y * v.X; + + c2.Y = + 2f * q.X * q.Y * v.X + + q.Y * q.Y * v.Y + + 2f * q.Z * q.Y * v.Z + + 2f * q.W * q.Z * v.X - + q.Z * q.Z * v.Y + + q.W * q.W * v.Y - + 2f * q.X * q.W * v.Z - + q.X * q.X * v.Y; + + c2.Z = + 2f * q.X * q.Z * v.X + + 2f * q.Y * q.Z * v.Y + + q.Z * q.Z * v.Z - + 2f * q.W * q.Y * v.X - + q.Y * q.Y * v.Z + + 2f * q.W * q.X * v.Y - + q.X * q.X * v.Z + + q.W * q.W * v.Z; + + return c2; + } + } + + public struct UVCoord + { + public float U; + public float V; + + + public UVCoord(float u, float v) + { + this.U = u; + this.V = v; + } + + public UVCoord Flip() + { + this.U = 1.0f - this.U; + this.V = 1.0f - this.V; + return this; + } + } + + public struct Face + { + public int primFace; + + // vertices + public int v1; + public int v2; + public int v3; + + //normals + public int n1; + public int n2; + public int n3; + + // uvs + public int uv1; + public int uv2; + public int uv3; + + public Face(int v1, int v2, int v3) + { + primFace = 0; + + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + + this.n1 = 0; + this.n2 = 0; + this.n3 = 0; + + this.uv1 = 0; + this.uv2 = 0; + this.uv3 = 0; + + } + + public Face(int v1, int v2, int v3, int n1, int n2, int n3) + { + primFace = 0; + + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + + this.n1 = n1; + this.n2 = n2; + this.n3 = n3; + + this.uv1 = 0; + this.uv2 = 0; + this.uv3 = 0; + } + + public Coord SurfaceNormal(List coordList) + { + Coord c1 = coordList[this.v1]; + Coord c2 = coordList[this.v2]; + Coord c3 = coordList[this.v3]; + + Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); + Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); + + return Coord.Cross(edge1, edge2).Normalize(); + } + } + + public struct ViewerFace + { + public int primFaceNumber; + + public Coord v1; + public Coord v2; + public Coord v3; + + public int coordIndex1; + public int coordIndex2; + public int coordIndex3; + + public Coord n1; + public Coord n2; + public Coord n3; + + public UVCoord uv1; + public UVCoord uv2; + public UVCoord uv3; + + public ViewerFace(int primFaceNumber) + { + this.primFaceNumber = primFaceNumber; + + this.v1 = new Coord(); + this.v2 = new Coord(); + this.v3 = new Coord(); + + this.coordIndex1 = this.coordIndex2 = this.coordIndex3 = -1; // -1 means not assigned yet + + this.n1 = new Coord(); + this.n2 = new Coord(); + this.n3 = new Coord(); + + this.uv1 = new UVCoord(); + this.uv2 = new UVCoord(); + this.uv3 = new UVCoord(); + } + + public void Scale(float x, float y, float z) + { + this.v1.X *= x; + this.v1.Y *= y; + this.v1.Z *= z; + + this.v2.X *= x; + this.v2.Y *= y; + this.v2.Z *= z; + + this.v3.X *= x; + this.v3.Y *= y; + this.v3.Z *= z; + } + + public void AddPos(float x, float y, float z) + { + this.v1.X += x; + this.v2.X += x; + this.v3.X += x; + + this.v1.Y += y; + this.v2.Y += y; + this.v3.Y += y; + + this.v1.Z += z; + this.v2.Z += z; + this.v3.Z += z; + } + + public void AddRot(Quat q) + { + this.v1 *= q; + this.v2 *= q; + this.v3 *= q; + + this.n1 *= q; + this.n2 *= q; + this.n3 *= q; + } + + public void CalcSurfaceNormal() + { + + Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z); + Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z); + + this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize(); + } + } + + internal struct Angle + { + internal float angle; + internal float X; + internal float Y; + + internal Angle(float angle, float x, float y) + { + this.angle = angle; + this.X = x; + this.Y = y; + } + } + + internal class AngleList + { + private float iX, iY; // intersection point + + private static Angle[] angles3 = + { + new Angle(0.0f, 1.0f, 0.0f), + new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), + new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), + new Angle(1.0f, 1.0f, 0.0f) + }; + + private static Coord[] normals3 = + { + new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(), + new Coord(-0.5f, 0.0f, 0.0f).Normalize(), + new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(), + new Coord(0.25f, 0.4330127019f, 0.0f).Normalize() + }; + + private static Angle[] angles4 = + { + new Angle(0.0f, 1.0f, 0.0f), + new Angle(0.25f, 0.0f, 1.0f), + new Angle(0.5f, -1.0f, 0.0f), + new Angle(0.75f, 0.0f, -1.0f), + new Angle(1.0f, 1.0f, 0.0f) + }; + + private static Coord[] normals4 = + { + new Coord(0.5f, 0.5f, 0.0f).Normalize(), + new Coord(-0.5f, 0.5f, 0.0f).Normalize(), + new Coord(-0.5f, -0.5f, 0.0f).Normalize(), + new Coord(0.5f, -0.5f, 0.0f).Normalize(), + new Coord(0.5f, 0.5f, 0.0f).Normalize() + }; + + private static Angle[] angles24 = + { + new Angle(0.0f, 1.0f, 0.0f), + new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f), + new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f), + new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f), + new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f), + new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f), + new Angle(0.25f, 0.0f, 1.0f), + new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f), + new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), + new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f), + new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f), + new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f), + new Angle(0.5f, -1.0f, 0.0f), + new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f), + new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f), + new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f), + new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), + new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f), + new Angle(0.75f, 0.0f, -1.0f), + new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f), + new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f), + new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f), + new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f), + new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f), + new Angle(1.0f, 1.0f, 0.0f) + }; + + private Angle interpolatePoints(float newPoint, Angle p1, Angle p2) + { + float m = (newPoint - p1.angle) / (p2.angle - p1.angle); + return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y)); + } + + private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) + { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ + double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); + double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); + + if (denom != 0.0) + { + double ua = uaNumerator / denom; + iX = (float)(x1 + ua * (x2 - x1)); + iY = (float)(y1 + ua * (y2 - y1)); + } + } + + internal List angles; + internal List normals; + + internal void makeAngles(int sides, float startAngle, float stopAngle) + { + angles = new List(); + normals = new List(); + + double twoPi = System.Math.PI * 2.0; + float twoPiInv = 1.0f / (float)twoPi; + + if (sides < 1) + throw new Exception("number of sides not greater than zero"); + if (stopAngle <= startAngle) + throw new Exception("stopAngle not greater than startAngle"); + + if ((sides == 3 || sides == 4 || sides == 24)) + { + startAngle *= twoPiInv; + stopAngle *= twoPiInv; + + Angle[] sourceAngles; + if (sides == 3) + sourceAngles = angles3; + else if (sides == 4) + sourceAngles = angles4; + else sourceAngles = angles24; + + int startAngleIndex = (int)(startAngle * sides); + int endAngleIndex = sourceAngles.Length - 1; + if (stopAngle < 1.0f) + endAngleIndex = (int)(stopAngle * sides) + 1; + if (endAngleIndex == startAngleIndex) + endAngleIndex++; + + for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++) + { + angles.Add(sourceAngles[angleIndex]); + if (sides == 3) + normals.Add(normals3[angleIndex]); + else if (sides == 4) + normals.Add(normals4[angleIndex]); + } + + if (startAngle > 0.0f) + angles[0] = interpolatePoints(startAngle, angles[0], angles[1]); + + if (stopAngle < 1.0f) + { + int lastAngleIndex = angles.Count - 1; + angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]); + } + } + else + { + double stepSize = twoPi / sides; + + int startStep = (int)(startAngle / stepSize); + double angle = stepSize * startStep; + int step = startStep; + double stopAngleTest = stopAngle; + if (stopAngle < twoPi) + { + stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1); + if (stopAngleTest < stopAngle) + stopAngleTest += stepSize; + if (stopAngleTest > twoPi) + stopAngleTest = twoPi; + } + + while (angle <= stopAngleTest) + { + Angle newAngle; + newAngle.angle = (float)angle; + newAngle.X = (float)System.Math.Cos(angle); + newAngle.Y = (float)System.Math.Sin(angle); + angles.Add(newAngle); + step += 1; + angle = stepSize * step; + } + + if (startAngle > angles[0].angle) + { + Angle newAngle; + intersection(angles[0].X, angles[0].Y, angles[1].X, angles[1].Y, 0.0f, 0.0f, (float)Math.Cos(startAngle), (float)Math.Sin(startAngle)); + newAngle.angle = startAngle; + newAngle.X = iX; + newAngle.Y = iY; + angles[0] = newAngle; + } + + int index = angles.Count - 1; + if (stopAngle < angles[index].angle) + { + Angle newAngle; + intersection(angles[index - 1].X, angles[index - 1].Y, angles[index].X, angles[index].Y, 0.0f, 0.0f, (float)Math.Cos(stopAngle), (float)Math.Sin(stopAngle)); + newAngle.angle = stopAngle; + newAngle.X = iX; + newAngle.Y = iY; + angles[index] = newAngle; + } + } + } + } + + /// + /// generates a profile for extrusion + /// + public class Profile + { + private const float twoPi = 2.0f * (float)Math.PI; + + public string errorMessage = null; + + public List coords; + public List faces; + public List vertexNormals; + public List us; + public List faceUVs; + public List faceNumbers; + + // use these for making individual meshes for each prim face + public List outerCoordIndices = null; + public List hollowCoordIndices = null; + public List cut1CoordIndices = null; + public List cut2CoordIndices = null; + + public Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); + public Coord cutNormal1 = new Coord(); + public Coord cutNormal2 = new Coord(); + + public int numOuterVerts = 0; + public int numHollowVerts = 0; + + public int outerFaceNumber = -1; + public int hollowFaceNumber = -1; + + public bool calcVertexNormals = false; + public int bottomFaceNumber = 0; + public int numPrimFaces = 0; + + public Profile() + { + this.coords = new List(); + this.faces = new List(); + this.vertexNormals = new List(); + this.us = new List(); + this.faceUVs = new List(); + this.faceNumbers = new List(); + } + + public Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) + { + this.calcVertexNormals = calcVertexNormals; + this.coords = new List(); + this.faces = new List(); + this.vertexNormals = new List(); + this.us = new List(); + this.faceUVs = new List(); + this.faceNumbers = new List(); + + Coord center = new Coord(0.0f, 0.0f, 0.0f); + + List hollowCoords = new List(); + List hollowNormals = new List(); + List hollowUs = new List(); + + if (calcVertexNormals) + { + this.outerCoordIndices = new List(); + this.hollowCoordIndices = new List(); + this.cut1CoordIndices = new List(); + this.cut2CoordIndices = new List(); + } + + bool hasHollow = (hollow > 0.0f); + + bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f); + + AngleList angles = new AngleList(); + AngleList hollowAngles = new AngleList(); + + float xScale = 0.5f; + float yScale = 0.5f; + if (sides == 4) // corners of a square are sqrt(2) from center + { + xScale = 0.707107f; + yScale = 0.707107f; + } + + float startAngle = profileStart * twoPi; + float stopAngle = profileEnd * twoPi; + + try { angles.makeAngles(sides, startAngle, stopAngle); } + catch (Exception ex) + { + + errorMessage = "makeAngles failed: Exception: " + ex.ToString() + + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); + + return; + } + + this.numOuterVerts = angles.angles.Count; + + // flag to create as few triangles as possible for 3 or 4 side profile + bool simpleFace = (sides < 5 && !hasHollow && !hasProfileCut); + + if (hasHollow) + { + if (sides == hollowSides) + hollowAngles = angles; + else + { + try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); } + catch (Exception ex) + { + errorMessage = "makeAngles failed: Exception: " + ex.ToString() + + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); + + return; + } + } + this.numHollowVerts = hollowAngles.angles.Count; + } + else if (!simpleFace) + { + this.coords.Add(center); + if (this.calcVertexNormals) + this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); + this.us.Add(0.0f); + } + + float z = 0.0f; + + Angle angle; + Coord newVert = new Coord(); + if (hasHollow && hollowSides != sides) + { + int numHollowAngles = hollowAngles.angles.Count; + for (int i = 0; i < numHollowAngles; i++) + { + angle = hollowAngles.angles[i]; + newVert.X = hollow * xScale * angle.X; + newVert.Y = hollow * yScale * angle.Y; + newVert.Z = z; + + hollowCoords.Add(newVert); + if (this.calcVertexNormals) + { + if (hollowSides < 5) + hollowNormals.Add(hollowAngles.normals[i].Invert()); + else + hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); + + if (hollowSides == 4) + hollowUs.Add(angle.angle * hollow * 0.707107f); + else + hollowUs.Add(angle.angle * hollow); + } + } + } + + int index = 0; + int numAngles = angles.angles.Count; + + for (int i = 0; i < numAngles; i++) + { + angle = angles.angles[i]; + newVert.X = angle.X * xScale; + newVert.Y = angle.Y * yScale; + newVert.Z = z; + this.coords.Add(newVert); + if (this.calcVertexNormals) + { + this.outerCoordIndices.Add(this.coords.Count - 1); + + if (sides < 5) + { + this.vertexNormals.Add(angles.normals[i]); + float u = angle.angle; + this.us.Add(u); + } + else + { + this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f)); + this.us.Add(angle.angle); + } + } + + if (hasHollow) + { + if (hollowSides == sides) + { + newVert.X *= hollow; + newVert.Y *= hollow; + newVert.Z = z; + hollowCoords.Add(newVert); + if (this.calcVertexNormals) + { + if (sides < 5) + { + hollowNormals.Add(angles.normals[i].Invert()); + } + + else + hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); + + hollowUs.Add(angle.angle * hollow); + } + } + } + else if (!simpleFace && createFaces && angle.angle > 0.0001f) + { + Face newFace = new Face(); + newFace.v1 = 0; + newFace.v2 = index; + newFace.v3 = index + 1; + + this.faces.Add(newFace); + } + index += 1; + } + + if (hasHollow) + { + hollowCoords.Reverse(); + if (this.calcVertexNormals) + { + hollowNormals.Reverse(); + hollowUs.Reverse(); + } + + if (createFaces) + { + int numTotalVerts = this.numOuterVerts + this.numHollowVerts; + + if (this.numOuterVerts == this.numHollowVerts) + { + Face newFace = new Face(); + + for (int coordIndex = 0; coordIndex < this.numOuterVerts - 1; coordIndex++) + { + newFace.v1 = coordIndex; + newFace.v2 = coordIndex + 1; + newFace.v3 = numTotalVerts - coordIndex - 1; + this.faces.Add(newFace); + + newFace.v1 = coordIndex + 1; + newFace.v2 = numTotalVerts - coordIndex - 2; + newFace.v3 = numTotalVerts - coordIndex - 1; + this.faces.Add(newFace); + } + } + else + { + if (this.numOuterVerts < this.numHollowVerts) + { + Face newFace = new Face(); + int j = 0; // j is the index for outer vertices + int maxJ = this.numOuterVerts - 1; + for (int i = 0; i < this.numHollowVerts; i++) // i is the index for inner vertices + { + if (j < maxJ) + if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle < hollowAngles.angles[i].angle - angles.angles[j].angle + 0.000001f) + { + newFace.v1 = numTotalVerts - i - 1; + newFace.v2 = j; + newFace.v3 = j + 1; + + this.faces.Add(newFace); + j += 1; + } + + newFace.v1 = j; + newFace.v2 = numTotalVerts - i - 2; + newFace.v3 = numTotalVerts - i - 1; + + this.faces.Add(newFace); + } + } + else // numHollowVerts < numOuterVerts + { + Face newFace = new Face(); + int j = 0; // j is the index for inner vertices + int maxJ = this.numHollowVerts - 1; + for (int i = 0; i < this.numOuterVerts; i++) + { + if (j < maxJ) + if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle < angles.angles[i].angle - hollowAngles.angles[j].angle + 0.000001f) + { + newFace.v1 = i; + newFace.v2 = numTotalVerts - j - 2; + newFace.v3 = numTotalVerts - j - 1; + + this.faces.Add(newFace); + j += 1; + } + + newFace.v1 = numTotalVerts - j - 1; + newFace.v2 = i; + newFace.v3 = i + 1; + + this.faces.Add(newFace); + } + } + } + } + + if (calcVertexNormals) + { + foreach (Coord hc in hollowCoords) + { + this.coords.Add(hc); + hollowCoordIndices.Add(this.coords.Count - 1); + } + } + else + this.coords.AddRange(hollowCoords); + + if (this.calcVertexNormals) + { + this.vertexNormals.AddRange(hollowNormals); + this.us.AddRange(hollowUs); + + } + } + + if (simpleFace && createFaces) + { + if (sides == 3) + this.faces.Add(new Face(0, 1, 2)); + else if (sides == 4) + { + this.faces.Add(new Face(0, 1, 2)); + this.faces.Add(new Face(0, 2, 3)); + } + } + + if (calcVertexNormals && hasProfileCut) + { + int lastOuterVertIndex = this.numOuterVerts - 1; + + if (hasHollow) + { + this.cut1CoordIndices.Add(0); + this.cut1CoordIndices.Add(this.coords.Count - 1); + + this.cut2CoordIndices.Add(lastOuterVertIndex + 1); + this.cut2CoordIndices.Add(lastOuterVertIndex); + + this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y; + this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X); + + this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y; + this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X); + } + + else + { + this.cut1CoordIndices.Add(0); + this.cut1CoordIndices.Add(1); + + this.cut2CoordIndices.Add(lastOuterVertIndex); + this.cut2CoordIndices.Add(0); + + this.cutNormal1.X = this.vertexNormals[1].Y; + this.cutNormal1.Y = -this.vertexNormals[1].X; + + this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y; + this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X; + + } + this.cutNormal1.Normalize(); + this.cutNormal2.Normalize(); + } + + this.MakeFaceUVs(); + + hollowCoords = null; + hollowNormals = null; + hollowUs = null; + + if (calcVertexNormals) + { // calculate prim face numbers + + // face number order is top, outer, hollow, bottom, start cut, end cut + // I know it's ugly but so is the whole concept of prim face numbers + + int faceNum = 1; // start with outer faces + this.outerFaceNumber = faceNum; + + int startVert = hasProfileCut && !hasHollow ? 1 : 0; + if (startVert > 0) + this.faceNumbers.Add(-1); + for (int i = 0; i < this.numOuterVerts - 1; i++) + this.faceNumbers.Add(sides < 5 && i <= sides ? faceNum++ : faceNum); + + this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++); + + if (sides > 4 && (hasHollow || hasProfileCut)) + faceNum++; + + if (sides < 5 && (hasHollow || hasProfileCut) && this.numOuterVerts < sides) + faceNum++; + + if (hasHollow) + { + for (int i = 0; i < this.numHollowVerts; i++) + this.faceNumbers.Add(faceNum); + + this.hollowFaceNumber = faceNum++; + } + + this.bottomFaceNumber = faceNum++; + + if (hasHollow && hasProfileCut) + this.faceNumbers.Add(faceNum++); + + for (int i = 0; i < this.faceNumbers.Count; i++) + if (this.faceNumbers[i] == -1) + this.faceNumbers[i] = faceNum++; + + this.numPrimFaces = faceNum; + } + + } + + public void MakeFaceUVs() + { + this.faceUVs = new List(); + foreach (Coord c in this.coords) + this.faceUVs.Add(new UVCoord(1.0f - (0.5f + c.X), 1.0f - (0.5f - c.Y))); + } + + public Profile Copy() + { + return this.Copy(true); + } + + public Profile Copy(bool needFaces) + { + Profile copy = new Profile(); + + copy.coords.AddRange(this.coords); + copy.faceUVs.AddRange(this.faceUVs); + + if (needFaces) + copy.faces.AddRange(this.faces); + if ((copy.calcVertexNormals = this.calcVertexNormals) == true) + { + copy.vertexNormals.AddRange(this.vertexNormals); + copy.faceNormal = this.faceNormal; + copy.cutNormal1 = this.cutNormal1; + copy.cutNormal2 = this.cutNormal2; + copy.us.AddRange(this.us); + copy.faceNumbers.AddRange(this.faceNumbers); + + copy.cut1CoordIndices = new List(this.cut1CoordIndices); + copy.cut2CoordIndices = new List(this.cut2CoordIndices); + copy.hollowCoordIndices = new List(this.hollowCoordIndices); + copy.outerCoordIndices = new List(this.outerCoordIndices); + } + copy.numOuterVerts = this.numOuterVerts; + copy.numHollowVerts = this.numHollowVerts; + + return copy; + } + + public void AddPos(Coord v) + { + this.AddPos(v.X, v.Y, v.Z); + } + + public void AddPos(float x, float y, float z) + { + int i; + int numVerts = this.coords.Count; + Coord vert; + + for (i = 0; i < numVerts; i++) + { + vert = this.coords[i]; + vert.X += x; + vert.Y += y; + vert.Z += z; + this.coords[i] = vert; + } + } + + public void AddRot(Quat q) + { + int i; + int numVerts = this.coords.Count; + + for (i = 0; i < numVerts; i++) + this.coords[i] *= q; + + if (this.calcVertexNormals) + { + int numNormals = this.vertexNormals.Count; + for (i = 0; i < numNormals; i++) + this.vertexNormals[i] *= q; + + this.faceNormal *= q; + this.cutNormal1 *= q; + this.cutNormal2 *= q; + + } + } + + public void Scale(float x, float y) + { + int i; + int numVerts = this.coords.Count; + Coord vert; + + for (i = 0; i < numVerts; i++) + { + vert = this.coords[i]; + vert.X *= x; + vert.Y *= y; + this.coords[i] = vert; + } + } + + /// + /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices + /// + public void FlipNormals() + { + int i; + int numFaces = this.faces.Count; + Face tmpFace; + int tmp; + + for (i = 0; i < numFaces; i++) + { + tmpFace = this.faces[i]; + tmp = tmpFace.v3; + tmpFace.v3 = tmpFace.v1; + tmpFace.v1 = tmp; + this.faces[i] = tmpFace; + } + + if (this.calcVertexNormals) + { + int normalCount = this.vertexNormals.Count; + if (normalCount > 0) + { + Coord n = this.vertexNormals[normalCount - 1]; + n.Z = -n.Z; + this.vertexNormals[normalCount - 1] = n; + } + } + + this.faceNormal.X = -this.faceNormal.X; + this.faceNormal.Y = -this.faceNormal.Y; + this.faceNormal.Z = -this.faceNormal.Z; + + int numfaceUVs = this.faceUVs.Count; + for (i = 0; i < numfaceUVs; i++) + { + UVCoord uv = this.faceUVs[i]; + uv.V = 1.0f - uv.V; + this.faceUVs[i] = uv; + } + } + + public void AddValue2FaceVertexIndices(int num) + { + int numFaces = this.faces.Count; + Face tmpFace; + for (int i = 0; i < numFaces; i++) + { + tmpFace = this.faces[i]; + tmpFace.v1 += num; + tmpFace.v2 += num; + tmpFace.v3 += num; + + this.faces[i] = tmpFace; + } + } + + public void AddValue2FaceNormalIndices(int num) + { + if (this.calcVertexNormals) + { + int numFaces = this.faces.Count; + Face tmpFace; + for (int i = 0; i < numFaces; i++) + { + tmpFace = this.faces[i]; + tmpFace.n1 += num; + tmpFace.n2 += num; + tmpFace.n3 += num; + + this.faces[i] = tmpFace; + } + } + } + + public void DumpRaw(String path, String name, String title) + { + if (path == null) + return; + String fileName = name + "_" + title + ".raw"; + String completePath = System.IO.Path.Combine(path, fileName); + StreamWriter sw = new StreamWriter(completePath); + + for (int i = 0; i < this.faces.Count; i++) + { + string s = this.coords[this.faces[i].v1].ToString(); + s += " " + this.coords[this.faces[i].v2].ToString(); + s += " " + this.coords[this.faces[i].v3].ToString(); + + sw.WriteLine(s); + } + + sw.Close(); + } + } + + public struct PathNode + { + public Coord position; + public Quat rotation; + public float xScale; + public float yScale; + public float percentOfPath; + } + + public enum PathType { Linear = 0, Circular = 1, Flexible = 2 } + + public class Path + { + public List pathNodes = new List(); + + public float twistBegin = 0.0f; + public float twistEnd = 0.0f; + public float topShearX = 0.0f; + public float topShearY = 0.0f; + public float pathCutBegin = 0.0f; + public float pathCutEnd = 1.0f; + public float dimpleBegin = 0.0f; + public float dimpleEnd = 1.0f; + public float skew = 0.0f; + public float holeSizeX = 1.0f; // called pathScaleX in pbs + public float holeSizeY = 0.25f; + public float taperX = 0.0f; + public float taperY = 0.0f; + public float radius = 0.0f; + public float revolutions = 1.0f; + public int stepsPerRevolution = 24; + + private const float twoPi = 2.0f * (float)Math.PI; + + public void Create(PathType pathType, int steps) + { + if (this.taperX > 0.999f) + this.taperX = 0.999f; + if (this.taperX < -0.999f) + this.taperX = -0.999f; + if (this.taperY > 0.999f) + this.taperY = 0.999f; + if (this.taperY < -0.999f) + this.taperY = -0.999f; + + if (pathType == PathType.Linear || pathType == PathType.Flexible) + { + int step = 0; + + float length = this.pathCutEnd - this.pathCutBegin; + float twistTotal = twistEnd - twistBegin; + float twistTotalAbs = Math.Abs(twistTotal); + if (twistTotalAbs > 0.01f) + steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number + + float start = -0.5f; + float stepSize = length / (float)steps; + float percentOfPathMultiplier = stepSize * 0.999999f; + float xOffset = this.topShearX * this.pathCutBegin; + float yOffset = this.topShearY * this.pathCutBegin; + float zOffset = start; + float xOffsetStepIncrement = this.topShearX * length / steps; + float yOffsetStepIncrement = this.topShearY * length / steps; + + float percentOfPath = this.pathCutBegin; + zOffset += percentOfPath; + + // sanity checks + + bool done = false; + + while (!done) + { + PathNode newNode = new PathNode(); + + newNode.xScale = 1.0f; + if (this.taperX == 0.0f) + newNode.xScale = 1.0f; + else if (this.taperX > 0.0f) + newNode.xScale = 1.0f - percentOfPath * this.taperX; + else newNode.xScale = 1.0f + (1.0f - percentOfPath) * this.taperX; + + newNode.yScale = 1.0f; + if (this.taperY == 0.0f) + newNode.yScale = 1.0f; + else if (this.taperY > 0.0f) + newNode.yScale = 1.0f - percentOfPath * this.taperY; + else newNode.yScale = 1.0f + (1.0f - percentOfPath) * this.taperY; + + float twist = twistBegin + twistTotal * percentOfPath; + + newNode.rotation = new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); + newNode.position = new Coord(xOffset, yOffset, zOffset); + newNode.percentOfPath = percentOfPath; + + pathNodes.Add(newNode); + + if (step < steps) + { + step += 1; + percentOfPath += percentOfPathMultiplier; + xOffset += xOffsetStepIncrement; + yOffset += yOffsetStepIncrement; + zOffset += stepSize; + if (percentOfPath > this.pathCutEnd) + done = true; + } + else done = true; + } + } // end of linear path code + + else // pathType == Circular + { + float twistTotal = twistEnd - twistBegin; + + // if the profile has a lot of twist, add more layers otherwise the layers may overlap + // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't + // accurately match the viewer + float twistTotalAbs = Math.Abs(twistTotal); + if (twistTotalAbs > 0.01f) + { + if (twistTotalAbs > Math.PI * 1.5f) + steps *= 2; + if (twistTotalAbs > Math.PI * 3.0f) + steps *= 2; + } + + float yPathScale = this.holeSizeY * 0.5f; + float pathLength = this.pathCutEnd - this.pathCutBegin; + float totalSkew = this.skew * 2.0f * pathLength; + float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew; + float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY)); + float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f; + + // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end + // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used + // to calculate the sine for generating the path radius appears to approximate it's effects there + // too, but there are some subtle differences in the radius which are noticeable as the prim size + // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on + // the meshes generated with this technique appear nearly identical in shape to the same prims when + // displayed by the viewer. + + float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f; + float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f; + float stepSize = twoPi / this.stepsPerRevolution; + + int step = (int)(startAngle / stepSize); + float angle = startAngle; + + bool done = false; + while (!done) // loop through the length of the path and add the layers + { + PathNode newNode = new PathNode(); + + float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX; + float yProfileScale = this.holeSizeY; + + float percentOfPath = angle / (twoPi * this.revolutions); + float percentOfAngles = (angle - startAngle) / (endAngle - startAngle); + + if (this.taperX > 0.01f) + xProfileScale *= 1.0f - percentOfPath * this.taperX; + else if (this.taperX < -0.01f) + xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX; + + if (this.taperY > 0.01f) + yProfileScale *= 1.0f - percentOfPath * this.taperY; + else if (this.taperY < -0.01f) + yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY; + + newNode.xScale = xProfileScale; + newNode.yScale = yProfileScale; + + float radiusScale = 1.0f; + if (this.radius > 0.001f) + radiusScale = 1.0f - this.radius * percentOfPath; + else if (this.radius < 0.001f) + radiusScale = 1.0f + this.radius * (1.0f - percentOfPath); + + float twist = twistBegin + twistTotal * percentOfPath; + + float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles); + xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor; + + float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale; + + float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale; + + newNode.position = new Coord(xOffset, yOffset, zOffset); + + // now orient the rotation of the profile layer relative to it's position on the path + // adding taperY to the angle used to generate the quat appears to approximate the viewer + + newNode.rotation = new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY); + + // next apply twist rotation to the profile layer + if (twistTotal != 0.0f || twistBegin != 0.0f) + newNode.rotation *= new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); + + newNode.percentOfPath = percentOfPath; + + pathNodes.Add(newNode); + + // calculate terms for next iteration + // calculate the angle for the next iteration of the loop + + if (angle >= endAngle - 0.01) + done = true; + else + { + step += 1; + angle = stepSize * step; + if (angle > endAngle) + angle = endAngle; + } + } + } + } + } + + public class PrimMesh + { + public string errorMessage = ""; + private const float twoPi = 2.0f * (float)Math.PI; + + public List coords; + public List normals; + public List faces; + + public List viewerFaces; + + private int sides = 4; + private int hollowSides = 4; + private float profileStart = 0.0f; + private float profileEnd = 1.0f; + private float hollow = 0.0f; + public int twistBegin = 0; + public int twistEnd = 0; + public float topShearX = 0.0f; + public float topShearY = 0.0f; + public float pathCutBegin = 0.0f; + public float pathCutEnd = 1.0f; + public float dimpleBegin = 0.0f; + public float dimpleEnd = 1.0f; + public float skew = 0.0f; + public float holeSizeX = 1.0f; // called pathScaleX in pbs + public float holeSizeY = 0.25f; + public float taperX = 0.0f; + public float taperY = 0.0f; + public float radius = 0.0f; + public float revolutions = 1.0f; + public int stepsPerRevolution = 24; + + private int profileOuterFaceNumber = -1; + private int profileHollowFaceNumber = -1; + + private bool hasProfileCut = false; + private bool hasHollow = false; + public bool calcVertexNormals = false; + private bool normalsProcessed = false; + public bool viewerMode = false; + public bool sphereMode = false; + + public int numPrimFaces = 0; + + /// + /// Human readable string representation of the parameters used to create a mesh. + /// + /// + public string ParamsToDisplayString() + { + string s = ""; + s += "sides..................: " + this.sides.ToString(); + s += "\nhollowSides..........: " + this.hollowSides.ToString(); + s += "\nprofileStart.........: " + this.profileStart.ToString(); + s += "\nprofileEnd...........: " + this.profileEnd.ToString(); + s += "\nhollow...............: " + this.hollow.ToString(); + s += "\ntwistBegin...........: " + this.twistBegin.ToString(); + s += "\ntwistEnd.............: " + this.twistEnd.ToString(); + s += "\ntopShearX............: " + this.topShearX.ToString(); + s += "\ntopShearY............: " + this.topShearY.ToString(); + s += "\npathCutBegin.........: " + this.pathCutBegin.ToString(); + s += "\npathCutEnd...........: " + this.pathCutEnd.ToString(); + s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString(); + s += "\ndimpleEnd............: " + this.dimpleEnd.ToString(); + s += "\nskew.................: " + this.skew.ToString(); + s += "\nholeSizeX............: " + this.holeSizeX.ToString(); + s += "\nholeSizeY............: " + this.holeSizeY.ToString(); + s += "\ntaperX...............: " + this.taperX.ToString(); + s += "\ntaperY...............: " + this.taperY.ToString(); + s += "\nradius...............: " + this.radius.ToString(); + s += "\nrevolutions..........: " + this.revolutions.ToString(); + s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString(); + s += "\nsphereMode...........: " + this.sphereMode.ToString(); + s += "\nhasProfileCut........: " + this.hasProfileCut.ToString(); + s += "\nhasHollow............: " + this.hasHollow.ToString(); + s += "\nviewerMode...........: " + this.viewerMode.ToString(); + + return s; + } + + public int ProfileOuterFaceNumber + { + get { return profileOuterFaceNumber; } + } + + public int ProfileHollowFaceNumber + { + get { return profileHollowFaceNumber; } + } + + public bool HasProfileCut + { + get { return hasProfileCut; } + } + + public bool HasHollow + { + get { return hasHollow; } + } + + + /// + /// Constructs a PrimMesh object and creates the profile for extrusion. + /// + /// + /// + /// + /// + /// + public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) + { + this.coords = new List(); + this.faces = new List(); + + this.sides = sides; + this.profileStart = profileStart; + this.profileEnd = profileEnd; + this.hollow = hollow; + this.hollowSides = hollowSides; + + if (sides < 3) + this.sides = 3; + if (hollowSides < 3) + this.hollowSides = 3; + if (profileStart < 0.0f) + this.profileStart = 0.0f; + if (profileEnd > 1.0f) + this.profileEnd = 1.0f; + if (profileEnd < 0.02f) + this.profileEnd = 0.02f; + if (profileStart >= profileEnd) + this.profileStart = profileEnd - 0.02f; + if (hollow > 0.99f) + this.hollow = 0.99f; + if (hollow < 0.0f) + this.hollow = 0.0f; + } + + /// + /// Extrudes a profile along a path. + /// + public void Extrude(PathType pathType) + { + bool needEndFaces = false; + + this.coords = new List(); + this.faces = new List(); + + if (this.viewerMode) + { + this.viewerFaces = new List(); + this.calcVertexNormals = true; + } + + if (this.calcVertexNormals) + this.normals = new List(); + + int steps = 1; + + float length = this.pathCutEnd - this.pathCutBegin; + normalsProcessed = false; + + if (this.viewerMode && this.sides == 3) + { + // prisms don't taper well so add some vertical resolution + // other prims may benefit from this but just do prisms for now + if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01) + steps = (int)(steps * 4.5 * length); + } + + if (this.sphereMode) + this.hasProfileCut = this.profileEnd - this.profileStart < 0.4999f; + else + this.hasProfileCut = this.profileEnd - this.profileStart < 0.9999f; + this.hasHollow = (this.hollow > 0.001f); + + float twistBegin = this.twistBegin / 360.0f * twoPi; + float twistEnd = this.twistEnd / 360.0f * twoPi; + float twistTotal = twistEnd - twistBegin; + float twistTotalAbs = Math.Abs(twistTotal); + if (twistTotalAbs > 0.01f) + steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number + + float hollow = this.hollow; + + if (pathType == PathType.Circular) + { + needEndFaces = false; + if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) + needEndFaces = true; + else if (this.taperX != 0.0f || this.taperY != 0.0f) + needEndFaces = true; + else if (this.skew != 0.0f) + needEndFaces = true; + else if (twistTotal != 0.0f) + needEndFaces = true; + else if (this.radius != 0.0f) + needEndFaces = true; + } + else needEndFaces = true; + + // sanity checks + float initialProfileRot = 0.0f; + if (pathType == PathType.Circular) + { + if (this.sides == 3) + { + initialProfileRot = (float)Math.PI; + if (this.hollowSides == 4) + { + if (hollow > 0.7f) + hollow = 0.7f; + hollow *= 0.707f; + } + else hollow *= 0.5f; + } + else if (this.sides == 4) + { + initialProfileRot = 0.25f * (float)Math.PI; + if (this.hollowSides != 4) + hollow *= 0.707f; + } + else if (this.sides > 4) + { + initialProfileRot = (float)Math.PI; + if (this.hollowSides == 4) + { + if (hollow > 0.7f) + hollow = 0.7f; + hollow /= 0.7f; + } + } + } + else + { + if (this.sides == 3) + { + if (this.hollowSides == 4) + { + if (hollow > 0.7f) + hollow = 0.7f; + hollow *= 0.707f; + } + else hollow *= 0.5f; + } + else if (this.sides == 4) + { + initialProfileRot = 1.25f * (float)Math.PI; + if (this.hollowSides != 4) + hollow *= 0.707f; + } + else if (this.sides == 24 && this.hollowSides == 4) + hollow *= 1.414f; + } + + Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals); + this.errorMessage = profile.errorMessage; + + this.numPrimFaces = profile.numPrimFaces; + + int cut1FaceNumber = profile.bottomFaceNumber + 1; + int cut2FaceNumber = cut1FaceNumber + 1; + if (!needEndFaces) + { + cut1FaceNumber -= 2; + cut2FaceNumber -= 2; + } + + profileOuterFaceNumber = profile.outerFaceNumber; + if (!needEndFaces) + profileOuterFaceNumber--; + + if (hasHollow) + { + profileHollowFaceNumber = profile.hollowFaceNumber; + if (!needEndFaces) + profileHollowFaceNumber--; + } + + int cut1Vert = -1; + int cut2Vert = -1; + if (hasProfileCut) + { + cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; + cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; + } + + if (initialProfileRot != 0.0f) + { + profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); + if (viewerMode) + profile.MakeFaceUVs(); + } + + Coord lastCutNormal1 = new Coord(); + Coord lastCutNormal2 = new Coord(); + float thisV = 0.0f; + float lastV = 0.0f; + + Path path = new Path(); + path.twistBegin = twistBegin; + path.twistEnd = twistEnd; + path.topShearX = topShearX; + path.topShearY = topShearY; + path.pathCutBegin = pathCutBegin; + path.pathCutEnd = pathCutEnd; + path.dimpleBegin = dimpleBegin; + path.dimpleEnd = dimpleEnd; + path.skew = skew; + path.holeSizeX = holeSizeX; + path.holeSizeY = holeSizeY; + path.taperX = taperX; + path.taperY = taperY; + path.radius = radius; + path.revolutions = revolutions; + path.stepsPerRevolution = stepsPerRevolution; + + path.Create(pathType, steps); + + for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) + { + PathNode node = path.pathNodes[nodeIndex]; + Profile newLayer = profile.Copy(); + newLayer.Scale(node.xScale, node.yScale); + + newLayer.AddRot(node.rotation); + newLayer.AddPos(node.position); + + if (needEndFaces && nodeIndex == 0) + { + newLayer.FlipNormals(); + + // add the bottom faces to the viewerFaces list + if (this.viewerMode) + { + Coord faceNormal = newLayer.faceNormal; + ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber); + int numFaces = newLayer.faces.Count; + List faces = newLayer.faces; + + for (int i = 0; i < numFaces; i++) + { + Face face = faces[i]; + newViewerFace.v1 = newLayer.coords[face.v1]; + newViewerFace.v2 = newLayer.coords[face.v2]; + newViewerFace.v3 = newLayer.coords[face.v3]; + + newViewerFace.coordIndex1 = face.v1; + newViewerFace.coordIndex2 = face.v2; + newViewerFace.coordIndex3 = face.v3; + + newViewerFace.n1 = faceNormal; + newViewerFace.n2 = faceNormal; + newViewerFace.n3 = faceNormal; + + newViewerFace.uv1 = newLayer.faceUVs[face.v1]; + newViewerFace.uv2 = newLayer.faceUVs[face.v2]; + newViewerFace.uv3 = newLayer.faceUVs[face.v3]; + + if (pathType == PathType.Linear) + { + newViewerFace.uv1.Flip(); + newViewerFace.uv2.Flip(); + newViewerFace.uv3.Flip(); + } + + this.viewerFaces.Add(newViewerFace); + } + } + } // if (nodeIndex == 0) + + // append this layer + + int coordsLen = this.coords.Count; + newLayer.AddValue2FaceVertexIndices(coordsLen); + + this.coords.AddRange(newLayer.coords); + + if (this.calcVertexNormals) + { + newLayer.AddValue2FaceNormalIndices(this.normals.Count); + this.normals.AddRange(newLayer.vertexNormals); + } + + if (node.percentOfPath < this.pathCutBegin + 0.01f || node.percentOfPath > this.pathCutEnd - 0.01f) + this.faces.AddRange(newLayer.faces); + + // fill faces between layers + + int numVerts = newLayer.coords.Count; + Face newFace1 = new Face(); + Face newFace2 = new Face(); + + thisV = 1.0f - node.percentOfPath; + + if (nodeIndex > 0) + { + int startVert = coordsLen + 1; + int endVert = this.coords.Count; + + if (sides < 5 || this.hasProfileCut || this.hasHollow) + startVert--; + + for (int i = startVert; i < endVert; i++) + { + int iNext = i + 1; + if (i == endVert - 1) + iNext = startVert; + + int whichVert = i - startVert; + + newFace1.v1 = i; + newFace1.v2 = i - numVerts; + newFace1.v3 = iNext; + + newFace1.n1 = newFace1.v1; + newFace1.n2 = newFace1.v2; + newFace1.n3 = newFace1.v3; + this.faces.Add(newFace1); + + newFace2.v1 = iNext; + newFace2.v2 = i - numVerts; + newFace2.v3 = iNext - numVerts; + + newFace2.n1 = newFace2.v1; + newFace2.n2 = newFace2.v2; + newFace2.n3 = newFace2.v3; + this.faces.Add(newFace2); + + if (this.viewerMode) + { + // add the side faces to the list of viewerFaces here + + int primFaceNum = profile.faceNumbers[whichVert]; + if (!needEndFaces) + primFaceNum -= 1; + + ViewerFace newViewerFace1 = new ViewerFace(primFaceNum); + ViewerFace newViewerFace2 = new ViewerFace(primFaceNum); + + int uIndex = whichVert; + if (!hasHollow && sides > 4 && uIndex < newLayer.us.Count - 1) + { + uIndex++; + } + + float u1 = newLayer.us[uIndex]; + float u2 = 1.0f; + if (uIndex < (int)newLayer.us.Count - 1) + u2 = newLayer.us[uIndex + 1]; + + if (whichVert == cut1Vert || whichVert == cut2Vert) + { + u1 = 0.0f; + u2 = 1.0f; + } + else if (sides < 5) + { + if (whichVert < profile.numOuterVerts) + { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled + // to reflect the entire texture width + u1 *= sides; + u2 *= sides; + u2 -= (int)u1; + u1 -= (int)u1; + if (u2 < 0.1f) + u2 = 1.0f; + } + } + + if (this.sphereMode) + { + if (whichVert != cut1Vert && whichVert != cut2Vert) + { + u1 = u1 * 2.0f - 1.0f; + u2 = u2 * 2.0f - 1.0f; + + if (whichVert >= newLayer.numOuterVerts) + { + u1 -= hollow; + u2 -= hollow; + } + + } + } + + newViewerFace1.uv1.U = u1; + newViewerFace1.uv2.U = u1; + newViewerFace1.uv3.U = u2; + + newViewerFace1.uv1.V = thisV; + newViewerFace1.uv2.V = lastV; + newViewerFace1.uv3.V = thisV; + + newViewerFace2.uv1.U = u2; + newViewerFace2.uv2.U = u1; + newViewerFace2.uv3.U = u2; + + newViewerFace2.uv1.V = thisV; + newViewerFace2.uv2.V = lastV; + newViewerFace2.uv3.V = lastV; + + newViewerFace1.v1 = this.coords[newFace1.v1]; + newViewerFace1.v2 = this.coords[newFace1.v2]; + newViewerFace1.v3 = this.coords[newFace1.v3]; + + newViewerFace2.v1 = this.coords[newFace2.v1]; + newViewerFace2.v2 = this.coords[newFace2.v2]; + newViewerFace2.v3 = this.coords[newFace2.v3]; + + newViewerFace1.coordIndex1 = newFace1.v1; + newViewerFace1.coordIndex2 = newFace1.v2; + newViewerFace1.coordIndex3 = newFace1.v3; + + newViewerFace2.coordIndex1 = newFace2.v1; + newViewerFace2.coordIndex2 = newFace2.v2; + newViewerFace2.coordIndex3 = newFace2.v3; + + // profile cut faces + if (whichVert == cut1Vert) + { + newViewerFace1.primFaceNumber = cut1FaceNumber; + newViewerFace2.primFaceNumber = cut1FaceNumber; + newViewerFace1.n1 = newLayer.cutNormal1; + newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; + + newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; + newViewerFace2.n2 = lastCutNormal1; + } + else if (whichVert == cut2Vert) + { + newViewerFace1.primFaceNumber = cut2FaceNumber; + newViewerFace2.primFaceNumber = cut2FaceNumber; + newViewerFace1.n1 = newLayer.cutNormal2; + newViewerFace1.n2 = lastCutNormal2; + newViewerFace1.n3 = lastCutNormal2; + + newViewerFace2.n1 = newLayer.cutNormal2; + newViewerFace2.n3 = newLayer.cutNormal2; + newViewerFace2.n2 = lastCutNormal2; + } + + else // outer and hollow faces + { + if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts)) + { // looks terrible when path is twisted... need vertex normals here + newViewerFace1.CalcSurfaceNormal(); + newViewerFace2.CalcSurfaceNormal(); + } + else + { + newViewerFace1.n1 = this.normals[newFace1.n1]; + newViewerFace1.n2 = this.normals[newFace1.n2]; + newViewerFace1.n3 = this.normals[newFace1.n3]; + + newViewerFace2.n1 = this.normals[newFace2.n1]; + newViewerFace2.n2 = this.normals[newFace2.n2]; + newViewerFace2.n3 = this.normals[newFace2.n3]; + } + } + + this.viewerFaces.Add(newViewerFace1); + this.viewerFaces.Add(newViewerFace2); + + } + } + } + + lastCutNormal1 = newLayer.cutNormal1; + lastCutNormal2 = newLayer.cutNormal2; + lastV = thisV; + + if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode) + { + // add the top faces to the viewerFaces list here + Coord faceNormal = newLayer.faceNormal; + ViewerFace newViewerFace = new ViewerFace(0); + int numFaces = newLayer.faces.Count; + List faces = newLayer.faces; + + for (int i = 0; i < numFaces; i++) + { + Face face = faces[i]; + newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; + newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; + newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; + + newViewerFace.coordIndex1 = face.v1 - coordsLen; + newViewerFace.coordIndex2 = face.v2 - coordsLen; + newViewerFace.coordIndex3 = face.v3 - coordsLen; + + newViewerFace.n1 = faceNormal; + newViewerFace.n2 = faceNormal; + newViewerFace.n3 = faceNormal; + + newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; + newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; + newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; + + if (pathType == PathType.Linear) + { + newViewerFace.uv1.Flip(); + newViewerFace.uv2.Flip(); + newViewerFace.uv3.Flip(); + } + + this.viewerFaces.Add(newViewerFace); + } + } + + + } // for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) + + } + + + /// + /// DEPRICATED - use Extrude(PathType.Linear) instead + /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. + /// + /// + public void ExtrudeLinear() + { + this.Extrude(PathType.Linear); + } + + + /// + /// DEPRICATED - use Extrude(PathType.Circular) instead + /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. + /// + /// + public void ExtrudeCircular() + { + this.Extrude(PathType.Circular); + } + + + private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) + { + Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); + Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); + + Coord normal = Coord.Cross(edge1, edge2); + + normal.Normalize(); + + return normal; + } + + private Coord SurfaceNormal(Face face) + { + return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]); + } + + /// + /// Calculate the surface normal for a face in the list of faces + /// + /// + /// + public Coord SurfaceNormal(int faceIndex) + { + int numFaces = this.faces.Count; + if (faceIndex < 0 || faceIndex >= numFaces) + throw new Exception("faceIndex out of range"); + + return SurfaceNormal(this.faces[faceIndex]); + } + + /// + /// Duplicates a PrimMesh object. All object properties are copied by value, including lists. + /// + /// + public PrimMesh Copy() + { + PrimMesh copy = new PrimMesh(this.sides, this.profileStart, this.profileEnd, this.hollow, this.hollowSides); + copy.twistBegin = this.twistBegin; + copy.twistEnd = this.twistEnd; + copy.topShearX = this.topShearX; + copy.topShearY = this.topShearY; + copy.pathCutBegin = this.pathCutBegin; + copy.pathCutEnd = this.pathCutEnd; + copy.dimpleBegin = this.dimpleBegin; + copy.dimpleEnd = this.dimpleEnd; + copy.skew = this.skew; + copy.holeSizeX = this.holeSizeX; + copy.holeSizeY = this.holeSizeY; + copy.taperX = this.taperX; + copy.taperY = this.taperY; + copy.radius = this.radius; + copy.revolutions = this.revolutions; + copy.stepsPerRevolution = this.stepsPerRevolution; + copy.calcVertexNormals = this.calcVertexNormals; + copy.normalsProcessed = this.normalsProcessed; + copy.viewerMode = this.viewerMode; + copy.numPrimFaces = this.numPrimFaces; + copy.errorMessage = this.errorMessage; + + copy.coords = new List(this.coords); + copy.faces = new List(this.faces); + copy.viewerFaces = new List(this.viewerFaces); + copy.normals = new List(this.normals); + + return copy; + } + + /// + /// Calculate surface normals for all of the faces in the list of faces in this mesh + /// + public void CalcNormals() + { + if (normalsProcessed) + return; + + normalsProcessed = true; + + int numFaces = faces.Count; + + if (!this.calcVertexNormals) + this.normals = new List(); + + for (int i = 0; i < numFaces; i++) + { + Face face = faces[i]; + + this.normals.Add(SurfaceNormal(i).Normalize()); + + int normIndex = normals.Count - 1; + face.n1 = normIndex; + face.n2 = normIndex; + face.n3 = normIndex; + + this.faces[i] = face; + } + } + + /// + /// Adds a value to each XYZ vertex coordinate in the mesh + /// + /// + /// + /// + public void AddPos(float x, float y, float z) + { + int i; + int numVerts = this.coords.Count; + Coord vert; + + for (i = 0; i < numVerts; i++) + { + vert = this.coords[i]; + vert.X += x; + vert.Y += y; + vert.Z += z; + this.coords[i] = vert; + } + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.AddPos(x, y, z); + this.viewerFaces[i] = v; + } + } + } + + /// + /// Rotates the mesh + /// + /// + public void AddRot(Quat q) + { + int i; + int numVerts = this.coords.Count; + + for (i = 0; i < numVerts; i++) + this.coords[i] *= q; + + if (this.normals != null) + { + int numNormals = this.normals.Count; + for (i = 0; i < numNormals; i++) + this.normals[i] *= q; + } + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.v1 *= q; + v.v2 *= q; + v.v3 *= q; + + v.n1 *= q; + v.n2 *= q; + v.n3 *= q; + this.viewerFaces[i] = v; + } + } + } + +#if VERTEX_INDEXER + public VertexIndexer GetVertexIndexer() + { + if (this.viewerMode && this.viewerFaces.Count > 0) + return new VertexIndexer(this); + return null; + } +#endif + + /// + /// Scales the mesh + /// + /// + /// + /// + public void Scale(float x, float y, float z) + { + int i; + int numVerts = this.coords.Count; + //Coord vert; + + Coord m = new Coord(x, y, z); + for (i = 0; i < numVerts; i++) + this.coords[i] *= m; + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.v1 *= m; + v.v2 *= m; + v.v3 *= m; + this.viewerFaces[i] = v; + } + + } + + } + + /// + /// Dumps the mesh to a Blender compatible "Raw" format file + /// + /// + /// + /// + public void DumpRaw(String path, String name, String title) + { + if (path == null) + return; + String fileName = name + "_" + title + ".raw"; + String completePath = System.IO.Path.Combine(path, fileName); + StreamWriter sw = new StreamWriter(completePath); + + for (int i = 0; i < this.faces.Count; i++) + { + string s = this.coords[this.faces[i].v1].ToString(); + s += " " + this.coords[this.faces[i].v2].ToString(); + s += " " + this.coords[this.faces[i].v3].ToString(); + + sw.WriteLine(s); + } + + sw.Close(); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMap.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMap.cs new file mode 100644 index 0000000..740424e --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMap.cs @@ -0,0 +1,183 @@ +/* + * Copyright (c) Contributors + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// to build without references to System.Drawing, comment this out +#define SYSTEM_DRAWING + +using System; +using System.Collections.Generic; +using System.Text; + +#if SYSTEM_DRAWING +using System.Drawing; +using System.Drawing.Imaging; + +namespace PrimMesher +{ + public class SculptMap + { + public int width; + public int height; + public byte[] redBytes; + public byte[] greenBytes; + public byte[] blueBytes; + + public SculptMap() + { + } + + public SculptMap(Bitmap bm, int lod) + { + int bmW = bm.Width; + int bmH = bm.Height; + + if (bmW == 0 || bmH == 0) + throw new Exception("SculptMap: bitmap has no data"); + + int numLodPixels = lod * 2 * lod * 2; // (32 * 2)^2 = 64^2 pixels for default sculpt map image + + bool needsScaling = false; + + bool smallMap = bmW * bmH <= lod * lod; + + width = bmW; + height = bmH; + while (width * height > numLodPixels) + { + width >>= 1; + height >>= 1; + needsScaling = true; + } + + + + try + { + if (needsScaling) + bm = ScaleImage(bm, width, height, + System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor); + } + + catch (Exception e) + { + throw new Exception("Exception in ScaleImage(): e: " + e.ToString()); + } + + if (width * height > lod * lod) + { + width >>= 1; + height >>= 1; + } + + int numBytes = (width + 1) * (height + 1); + redBytes = new byte[numBytes]; + greenBytes = new byte[numBytes]; + blueBytes = new byte[numBytes]; + + int byteNdx = 0; + + try + { + for (int y = 0; y <= height; y++) + { + for (int x = 0; x <= width; x++) + { + Color c; + + if (smallMap) + c = bm.GetPixel(x < width ? x : x - 1, + y < height ? y : y - 1); + else + c = bm.GetPixel(x < width ? x * 2 : x * 2 - 1, + y < height ? y * 2 : y * 2 - 1); + + redBytes[byteNdx] = c.R; + greenBytes[byteNdx] = c.G; + blueBytes[byteNdx] = c.B; + + ++byteNdx; + } + } + } + catch (Exception e) + { + throw new Exception("Caught exception processing byte arrays in SculptMap(): e: " + e.ToString()); + } + + width++; + height++; + } + + public List> ToRows(bool mirror) + { + int numRows = height; + int numCols = width; + + List> rows = new List>(numRows); + + float pixScale = 1.0f / 255; + + int rowNdx, colNdx; + int smNdx = 0; + + for (rowNdx = 0; rowNdx < numRows; rowNdx++) + { + List row = new List(numCols); + for (colNdx = 0; colNdx < numCols; colNdx++) + { + if (mirror) + row.Add(new Coord(-(redBytes[smNdx] * pixScale - 0.5f), (greenBytes[smNdx] * pixScale - 0.5f), blueBytes[smNdx] * pixScale - 0.5f)); + else + row.Add(new Coord(redBytes[smNdx] * pixScale - 0.5f, greenBytes[smNdx] * pixScale - 0.5f, blueBytes[smNdx] * pixScale - 0.5f)); + + ++smNdx; + } + rows.Add(row); + } + return rows; + } + + private Bitmap ScaleImage(Bitmap srcImage, int destWidth, int destHeight, + System.Drawing.Drawing2D.InterpolationMode interpMode) + { + Bitmap scaledImage = new Bitmap(srcImage, destWidth, destHeight); + scaledImage.SetResolution(96.0f, 96.0f); + + Graphics grPhoto = Graphics.FromImage(scaledImage); + grPhoto.InterpolationMode = interpMode; + + grPhoto.DrawImage(srcImage, + new Rectangle(0, 0, destWidth, destHeight), + new Rectangle(0, 0, srcImage.Width, srcImage.Height), + GraphicsUnit.Pixel); + + grPhoto.Dispose(); + return scaledImage; + } + } +} +#endif diff --git a/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMesh.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMesh.cs new file mode 100644 index 0000000..4a7f3ad --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMesh.cs @@ -0,0 +1,646 @@ +/* + * Copyright (c) Contributors + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// to build without references to System.Drawing, comment this out +#define SYSTEM_DRAWING + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +#if SYSTEM_DRAWING +using System.Drawing; +using System.Drawing.Imaging; +#endif + +namespace PrimMesher +{ + + public class SculptMesh + { + public List coords; + public List faces; + + public List viewerFaces; + public List normals; + public List uvs; + + public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 }; + +#if SYSTEM_DRAWING + + public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) + { + Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); + SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); + bitmap.Dispose(); + return sculptMesh; + } + + + public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert) + { + Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); + _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0); + bitmap.Dispose(); + } +#endif + + /// + /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications + /// Construct a sculpt mesh from a 2D array of floats + /// + /// + /// + /// + /// + /// + /// + public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode) + { + float xStep, yStep; + float uStep, vStep; + + int numYElements = zMap.GetLength(0); + int numXElements = zMap.GetLength(1); + + try + { + xStep = (xEnd - xBegin) / (float)(numXElements - 1); + yStep = (yEnd - yBegin) / (float)(numYElements - 1); + + uStep = 1.0f / (numXElements - 1); + vStep = 1.0f / (numYElements - 1); + } + catch (DivideByZeroException) + { + return; + } + + coords = new List(); + faces = new List(); + normals = new List(); + uvs = new List(); + + viewerFaces = new List(); + + int p1, p2, p3, p4; + + int x, y; + int xStart = 0, yStart = 0; + + for (y = yStart; y < numYElements; y++) + { + int rowOffset = y * numXElements; + + for (x = xStart; x < numXElements; x++) + { + /* + * p1-----p2 + * | \ f2 | + * | \ | + * | f1 \| + * p3-----p4 + */ + + p4 = rowOffset + x; + p3 = p4 - 1; + + p2 = p4 - numXElements; + p1 = p3 - numXElements; + + Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]); + this.coords.Add(c); + if (viewerMode) + { + this.normals.Add(new Coord()); + this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y)); + } + + if (y > 0 && x > 0) + { + Face f1, f2; + + if (viewerMode) + { + f1 = new Face(p1, p4, p3, p1, p4, p3); + f1.uv1 = p1; + f1.uv2 = p4; + f1.uv3 = p3; + + f2 = new Face(p1, p2, p4, p1, p2, p4); + f2.uv1 = p1; + f2.uv2 = p2; + f2.uv3 = p4; + } + else + { + f1 = new Face(p1, p4, p3); + f2 = new Face(p1, p2, p4); + } + + this.faces.Add(f1); + this.faces.Add(f2); + } + } + } + + if (viewerMode) + calcVertexNormals(SculptType.plane, numXElements, numYElements); + } + +#if SYSTEM_DRAWING + public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) + { + _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false); + } + + public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) + { + _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert); + } +#endif + + public SculptMesh(List> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) + { + _SculptMesh(rows, sculptType, viewerMode, mirror, invert); + } + +#if SYSTEM_DRAWING + /// + /// converts a bitmap to a list of lists of coords, while scaling the image. + /// the scaling is done in floating point so as to allow for reduced vertex position + /// quantization as the position will be averaged between pixel values. this routine will + /// likely fail if the bitmap width and height are not powers of 2. + /// + /// + /// + /// + /// + private List> bitmap2Coords(Bitmap bitmap, int scale, bool mirror) + { + int numRows = bitmap.Height / scale; + int numCols = bitmap.Width / scale; + List> rows = new List>(numRows); + + float pixScale = 1.0f / (scale * scale); + pixScale /= 255; + + int imageX, imageY = 0; + + int rowNdx, colNdx; + + for (rowNdx = 0; rowNdx < numRows; rowNdx++) + { + List row = new List(numCols); + for (colNdx = 0; colNdx < numCols; colNdx++) + { + imageX = colNdx * scale; + int imageYStart = rowNdx * scale; + int imageYEnd = imageYStart + scale; + int imageXEnd = imageX + scale; + float rSum = 0.0f; + float gSum = 0.0f; + float bSum = 0.0f; + for (; imageX < imageXEnd; imageX++) + { + for (imageY = imageYStart; imageY < imageYEnd; imageY++) + { + Color c = bitmap.GetPixel(imageX, imageY); + if (c.A != 255) + { + bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B)); + c = bitmap.GetPixel(imageX, imageY); + } + rSum += c.R; + gSum += c.G; + bSum += c.B; + } + } + if (mirror) + row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); + else + row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); + + } + rows.Add(row); + } + return rows; + } + + private List> bitmap2CoordsSampled(Bitmap bitmap, int scale, bool mirror) + { + int numRows = bitmap.Height / scale; + int numCols = bitmap.Width / scale; + List> rows = new List>(numRows); + + float pixScale = 1.0f / 256.0f; + + int imageX, imageY = 0; + + int rowNdx, colNdx; + + for (rowNdx = 0; rowNdx <= numRows; rowNdx++) + { + List row = new List(numCols); + imageY = rowNdx * scale; + if (rowNdx == numRows) imageY--; + for (colNdx = 0; colNdx <= numCols; colNdx++) + { + imageX = colNdx * scale; + if (colNdx == numCols) imageX--; + + Color c = bitmap.GetPixel(imageX, imageY); + if (c.A != 255) + { + bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B)); + c = bitmap.GetPixel(imageX, imageY); + } + + if (mirror) + row.Add(new Coord(-(c.R * pixScale - 0.5f), c.G * pixScale - 0.5f, c.B * pixScale - 0.5f)); + else + row.Add(new Coord(c.R * pixScale - 0.5f, c.G * pixScale - 0.5f, c.B * pixScale - 0.5f)); + + } + rows.Add(row); + } + return rows; + } + + + void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) + { + _SculptMesh(new SculptMap(sculptBitmap, lod).ToRows(mirror), sculptType, viewerMode, mirror, invert); + } +#endif + + void _SculptMesh(List> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) + { + coords = new List(); + faces = new List(); + normals = new List(); + uvs = new List(); + + sculptType = (SculptType)(((int)sculptType) & 0x07); + + if (mirror) + invert = !invert; + + viewerFaces = new List(); + + int width = rows[0].Count; + + int p1, p2, p3, p4; + + int imageX, imageY; + + if (sculptType != SculptType.plane) + { + if (rows.Count % 2 == 0) + { + for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++) + rows[rowNdx].Add(rows[rowNdx][0]); + } + else + { + int lastIndex = rows[0].Count - 1; + + for (int i = 0; i < rows.Count; i++) + rows[i][0] = rows[i][lastIndex]; + } + } + + Coord topPole = rows[0][width / 2]; + Coord bottomPole = rows[rows.Count - 1][width / 2]; + + if (sculptType == SculptType.sphere) + { + if (rows.Count % 2 == 0) + { + int count = rows[0].Count; + List topPoleRow = new List(count); + List bottomPoleRow = new List(count); + + for (int i = 0; i < count; i++) + { + topPoleRow.Add(topPole); + bottomPoleRow.Add(bottomPole); + } + rows.Insert(0, topPoleRow); + rows.Add(bottomPoleRow); + } + else + { + int count = rows[0].Count; + + List topPoleRow = rows[0]; + List bottomPoleRow = rows[rows.Count - 1]; + + for (int i = 0; i < count; i++) + { + topPoleRow[i] = topPole; + bottomPoleRow[i] = bottomPole; + } + } + } + + if (sculptType == SculptType.torus) + rows.Add(rows[0]); + + int coordsDown = rows.Count; + int coordsAcross = rows[0].Count; +// int lastColumn = coordsAcross - 1; + + float widthUnit = 1.0f / (coordsAcross - 1); + float heightUnit = 1.0f / (coordsDown - 1); + + for (imageY = 0; imageY < coordsDown; imageY++) + { + int rowOffset = imageY * coordsAcross; + + for (imageX = 0; imageX < coordsAcross; imageX++) + { + /* + * p1-----p2 + * | \ f2 | + * | \ | + * | f1 \| + * p3-----p4 + */ + + p4 = rowOffset + imageX; + p3 = p4 - 1; + + p2 = p4 - coordsAcross; + p1 = p3 - coordsAcross; + + this.coords.Add(rows[imageY][imageX]); + if (viewerMode) + { + this.normals.Add(new Coord()); + this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); + } + + if (imageY > 0 && imageX > 0) + { + Face f1, f2; + + if (viewerMode) + { + if (invert) + { + f1 = new Face(p1, p4, p3, p1, p4, p3); + f1.uv1 = p1; + f1.uv2 = p4; + f1.uv3 = p3; + + f2 = new Face(p1, p2, p4, p1, p2, p4); + f2.uv1 = p1; + f2.uv2 = p2; + f2.uv3 = p4; + } + else + { + f1 = new Face(p1, p3, p4, p1, p3, p4); + f1.uv1 = p1; + f1.uv2 = p3; + f1.uv3 = p4; + + f2 = new Face(p1, p4, p2, p1, p4, p2); + f2.uv1 = p1; + f2.uv2 = p4; + f2.uv3 = p2; + } + } + else + { + if (invert) + { + f1 = new Face(p1, p4, p3); + f2 = new Face(p1, p2, p4); + } + else + { + f1 = new Face(p1, p3, p4); + f2 = new Face(p1, p4, p2); + } + } + + this.faces.Add(f1); + this.faces.Add(f2); + } + } + } + + if (viewerMode) + calcVertexNormals(sculptType, coordsAcross, coordsDown); + } + + /// + /// Duplicates a SculptMesh object. All object properties are copied by value, including lists. + /// + /// + public SculptMesh Copy() + { + return new SculptMesh(this); + } + + public SculptMesh(SculptMesh sm) + { + coords = new List(sm.coords); + faces = new List(sm.faces); + viewerFaces = new List(sm.viewerFaces); + normals = new List(sm.normals); + uvs = new List(sm.uvs); + } + + private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) + { // compute vertex normals by summing all the surface normals of all the triangles sharing + // each vertex and then normalizing + int numFaces = this.faces.Count; + for (int i = 0; i < numFaces; i++) + { + Face face = this.faces[i]; + Coord surfaceNormal = face.SurfaceNormal(this.coords); + this.normals[face.n1] += surfaceNormal; + this.normals[face.n2] += surfaceNormal; + this.normals[face.n3] += surfaceNormal; + } + + int numNormals = this.normals.Count; + for (int i = 0; i < numNormals; i++) + this.normals[i] = this.normals[i].Normalize(); + + if (sculptType != SculptType.plane) + { // blend the vertex normals at the cylinder seam + for (int y = 0; y < ySize; y++) + { + int rowOffset = y * xSize; + + this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize(); + } + } + + foreach (Face face in this.faces) + { + ViewerFace vf = new ViewerFace(0); + vf.v1 = this.coords[face.v1]; + vf.v2 = this.coords[face.v2]; + vf.v3 = this.coords[face.v3]; + + vf.coordIndex1 = face.v1; + vf.coordIndex2 = face.v2; + vf.coordIndex3 = face.v3; + + vf.n1 = this.normals[face.n1]; + vf.n2 = this.normals[face.n2]; + vf.n3 = this.normals[face.n3]; + + vf.uv1 = this.uvs[face.uv1]; + vf.uv2 = this.uvs[face.uv2]; + vf.uv3 = this.uvs[face.uv3]; + + this.viewerFaces.Add(vf); + } + } + + /// + /// Adds a value to each XYZ vertex coordinate in the mesh + /// + /// + /// + /// + public void AddPos(float x, float y, float z) + { + int i; + int numVerts = this.coords.Count; + Coord vert; + + for (i = 0; i < numVerts; i++) + { + vert = this.coords[i]; + vert.X += x; + vert.Y += y; + vert.Z += z; + this.coords[i] = vert; + } + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.AddPos(x, y, z); + this.viewerFaces[i] = v; + } + } + } + + /// + /// Rotates the mesh + /// + /// + public void AddRot(Quat q) + { + int i; + int numVerts = this.coords.Count; + + for (i = 0; i < numVerts; i++) + this.coords[i] *= q; + + int numNormals = this.normals.Count; + for (i = 0; i < numNormals; i++) + this.normals[i] *= q; + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.v1 *= q; + v.v2 *= q; + v.v3 *= q; + + v.n1 *= q; + v.n2 *= q; + v.n3 *= q; + + this.viewerFaces[i] = v; + } + } + } + + public void Scale(float x, float y, float z) + { + int i; + int numVerts = this.coords.Count; + + Coord m = new Coord(x, y, z); + for (i = 0; i < numVerts; i++) + this.coords[i] *= m; + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.v1 *= m; + v.v2 *= m; + v.v3 *= m; + this.viewerFaces[i] = v; + } + } + } + + public void DumpRaw(String path, String name, String title) + { + if (path == null) + return; + String fileName = name + "_" + title + ".raw"; + String completePath = System.IO.Path.Combine(path, fileName); + StreamWriter sw = new StreamWriter(completePath); + + for (int i = 0; i < this.faces.Count; i++) + { + string s = this.coords[this.faces[i].v1].ToString(); + s += " " + this.coords[this.faces[i].v2].ToString(); + s += " " + this.coords[this.faces[i].v3].ToString(); + + sw.WriteLine(s); + } + + sw.Close(); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/Meshing/Properties/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/Meshing/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b4bdb5a --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Meshing/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Mono.Addins; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenSim.Region.PhysicsModules.Meshing")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("http://opensimulator.org")] +[assembly: AssemblyProduct("OpenSim")] +[assembly: AssemblyCopyright("OpenSimulator developers")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4b7e35c2-a9dd-4b10-b778-eb417f4f6884")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("0.8.3.*")] + +[assembly: Addin("OpenSim.Region.PhysicsModules.Meshing", OpenSim.VersionInfo.VersionNumber)] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Region/PhysicsModules/Meshing/ZeroMesher.cs b/OpenSim/Region/PhysicsModules/Meshing/ZeroMesher.cs new file mode 100644 index 0000000..0a3b3a4 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Meshing/ZeroMesher.cs @@ -0,0 +1,132 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenMetaverse; +using Nini.Config; +using Mono.Addins; +using log4net; + +/* + * This is the zero mesher. + * Whatever you want him to mesh, he can't, telling you that by responding with a null pointer. + * Effectivly this is for switching off meshing and for testing as each physics machine should deal + * with the null pointer situation. + * But it's also a convenience thing, as physics machines can rely on having a mesher in any situation, even + * if it's a dump one like this. + * Note, that this mesher is *not* living in a module but in the manager itself, so + * it's always availabe and thus the default in case of configuration errors +*/ + +namespace OpenSim.Region.PhysicsModules.Meshing +{ + + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ZeroMesher")] + public class ZeroMesher : IMesher, INonSharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private bool m_Enabled = false; + + #region INonSharedRegionModule + public string Name + { + get { return "ZeroMesher"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Initialise(IConfigSource source) + { + // TODO: Move this out of Startup + IConfig config = source.Configs["Startup"]; + if (config != null) + { + // This is the default Mesher + string mesher = config.GetString("meshing", Name); + if (mesher == Name) + m_Enabled = true; + } + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + scene.RegisterModuleInterface(this); + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + + scene.UnregisterModuleInterface(this); + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + } + #endregion + + #region IMesher + public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) + { + return CreateMesh(primName, primShape, size, lod, false, false); + } + + public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) + { + return CreateMesh(primName, primShape, size, lod, false, false); + } + + public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) + { + // Remove the reference to the encoded JPEG2000 data so it can be GCed + primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; + + return null; + } + #endregion + + + } +} diff --git a/OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs new file mode 100644 index 0000000..7869739 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs @@ -0,0 +1,62 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Reflection; +using System.Runtime.InteropServices; +using Mono.Addins; + +// Information about this assembly is defined by the following +// attributes. +// +// change them to the information which is associated with the assembly +// you compile. + +[assembly : AssemblyTitle("OdePlugin")] +[assembly : AssemblyDescription("")] +[assembly : AssemblyConfiguration("")] +[assembly : AssemblyCompany("http://opensimulator.org")] +[assembly : AssemblyProduct("OdePlugin")] +[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] +[assembly : AssemblyTrademark("")] +[assembly : AssemblyCulture("")] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. + +[assembly : ComVisible(false)] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all values by your own or you can build default build and revision +// numbers with the '*' character (the default): + +[assembly : AssemblyVersion("0.8.2.*")] + +[assembly: Addin("OpenSim.Region.PhysicsModule.ODE", OpenSim.VersionInfo.VersionNumber)] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs b/OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs new file mode 100644 index 0000000..b35c299 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs @@ -0,0 +1,1409 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using OpenMetaverse; +using Ode.NET; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; +using log4net; + +namespace OpenSim.Region.PhysicsModule.ODE +{ + /// + /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves. + /// + public enum dParam : int + { + LowStop = 0, + HiStop = 1, + Vel = 2, + FMax = 3, + FudgeFactor = 4, + Bounce = 5, + CFM = 6, + StopERP = 7, + StopCFM = 8, + LoStop2 = 256, + HiStop2 = 257, + Vel2 = 258, + FMax2 = 259, + StopERP2 = 7 + 256, + StopCFM2 = 8 + 256, + LoStop3 = 512, + HiStop3 = 513, + Vel3 = 514, + FMax3 = 515, + StopERP3 = 7 + 512, + StopCFM3 = 8 + 512 + } + + public class OdeCharacter : PhysicsActor + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Vector3 _position; + private d.Vector3 _zeroPosition; + private bool _zeroFlag = false; + private bool m_lastUpdateSent = false; + private Vector3 _velocity; + private Vector3 m_taintTargetVelocity; + private Vector3 _target_velocity; + private Vector3 _acceleration; + private Vector3 m_rotationalVelocity; + private float m_mass = 80f; + private float m_density = 60f; + private bool m_pidControllerActive = true; + private float PID_D = 800.0f; + private float PID_P = 900.0f; + //private static float POSTURE_SERVO = 10000.0f; + private float CAPSULE_RADIUS = 0.37f; + private float CAPSULE_LENGTH = 2.140599f; + private float m_tensor = 3800000f; +// private float heightFudgeFactor = 0.52f; + private float walkDivisor = 1.3f; + private float runDivisor = 0.8f; + private bool flying = false; + private bool m_iscolliding = false; + private bool m_iscollidingGround = false; + private bool m_wascolliding = false; + private bool m_wascollidingGround = false; + private bool m_iscollidingObj = false; + private bool m_alwaysRun = false; + private bool m_hackSentFall = false; + private bool m_hackSentFly = false; + private int m_requestedUpdateFrequency = 0; + private Vector3 m_taintPosition; + internal bool m_avatarplanted = false; + /// + /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force + /// while calculatios are going on + /// + private Vector3 m_taintForce; + + // taints and their non-tainted counterparts + private bool m_isPhysical = false; // the current physical status + private bool m_tainted_isPhysical = false; // set when the physical status is tainted (false=not existing in physics engine, true=existing) + internal float MinimumGroundFlightOffset = 3f; + + private float m_tainted_CAPSULE_LENGTH; // set when the capsule length changes. + + /// + /// Base movement for calculating tilt. + /// + private float m_tiltBaseMovement = (float)Math.Sqrt(2); + + /// + /// Used to introduce a fixed tilt because a straight-up capsule falls through terrain, probably a bug in terrain collider + /// + private float m_tiltMagnitudeWhenProjectedOnXYPlane = 0.1131371f; + + private float m_buoyancy = 0f; + + // private CollisionLocker ode; + private bool[] m_colliderarr = new bool[11]; + private bool[] m_colliderGroundarr = new bool[11]; + + // Default we're a Character + private CollisionCategories m_collisionCategories = (CollisionCategories.Character); + + // Default, Collide with Other Geometries, spaces, bodies and characters. + private CollisionCategories m_collisionFlags = (CollisionCategories.Geom + | CollisionCategories.Space + | CollisionCategories.Body + | CollisionCategories.Character + | CollisionCategories.Land); + /// + /// Body for dynamics simulation + /// + internal IntPtr Body { get; private set; } + + private OdeScene _parent_scene; + + /// + /// Collision geometry + /// + internal IntPtr Shell { get; private set; } + + private IntPtr Amotor = IntPtr.Zero; + private d.Mass ShellMass; + + private int m_eventsubscription = 0; + private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate(); + + // unique UUID of this character object + internal UUID m_uuid { get; private set; } + internal bool bad = false; + + /// + /// ODE Avatar. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Only used right now to return information to LSL. Not actually used to set mass in ODE! + /// + /// + /// + public OdeCharacter( + String avName, OdeScene parent_scene, Vector3 pos, Vector3 vel, Vector3 size, float pid_d, float pid_p, + float capsule_radius, float tensor, float density, + float walk_divisor, float rundivisor) + { + m_uuid = UUID.Random(); + + if (pos.IsFinite()) + { + if (pos.Z > 9999999f) + { + pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5; + } + if (pos.Z < -90000f) + { + pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5; + } + + _position = pos; + m_taintPosition = pos; + } + else + { + _position + = new Vector3( + (float)_parent_scene.WorldExtents.X * 0.5f, + (float)_parent_scene.WorldExtents.Y * 0.5f, + parent_scene.GetTerrainHeightAtXY(128f, 128f) + 10f); + m_taintPosition = _position; + + m_log.WarnFormat("[ODE CHARACTER]: Got NaN Position on Character Create for {0}", avName); + } + + _velocity = vel; + m_taintTargetVelocity = vel; + + _parent_scene = parent_scene; + + PID_D = pid_d; + PID_P = pid_p; + CAPSULE_RADIUS = capsule_radius; + m_tensor = tensor; + m_density = density; +// heightFudgeFactor = height_fudge_factor; + walkDivisor = walk_divisor; + runDivisor = rundivisor; + + // m_StandUpRotation = + // new d.Matrix3(0.5f, 0.7071068f, 0.5f, -0.7071068f, 0f, 0.7071068f, 0.5f, -0.7071068f, + // 0.5f); + + // We can set taint and actual to be the same here, since the entire character will be set up when the + // m_tainted_isPhysical is processed. + SetTaintedCapsuleLength(size); + CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH; + + m_isPhysical = false; // current status: no ODE information exists + m_tainted_isPhysical = true; // new tainted status: need to create ODE information + + _parent_scene.AddPhysicsActorTaint(this); + + Name = avName; + } + + public override int PhysicsActorType + { + get { return (int) ActorTypes.Agent; } + set { return; } + } + + /// + /// If this is set, the avatar will move faster + /// + public override bool SetAlwaysRun + { + get { return m_alwaysRun; } + set { m_alwaysRun = value; } + } + + public override bool Grabbed + { + set { return; } + } + + public override bool Selected + { + set { return; } + } + + public override float Buoyancy + { + get { return m_buoyancy; } + set { m_buoyancy = value; } + } + + public override bool FloatOnWater + { + set { return; } + } + + public override bool IsPhysical + { + get { return false; } + set { return; } + } + + public override bool ThrottleUpdates + { + get { return false; } + set { return; } + } + + public override bool Flying + { + get { return flying; } + set + { + flying = value; +// m_log.DebugFormat("[ODE CHARACTER]: Set OdeCharacter Flying to {0}", flying); + } + } + + /// + /// Returns if the avatar is colliding in general. + /// This includes the ground and objects and avatar. + /// + public override bool IsColliding + { + get { return m_iscolliding; } + set + { + int i; + int truecount = 0; + int falsecount = 0; + + if (m_colliderarr.Length >= 10) + { + for (i = 0; i < 10; i++) + { + m_colliderarr[i] = m_colliderarr[i + 1]; + } + } + m_colliderarr[10] = value; + + for (i = 0; i < 11; i++) + { + if (m_colliderarr[i]) + { + truecount++; + } + else + { + falsecount++; + } + } + + // Equal truecounts and false counts means we're colliding with something. + + if (falsecount > 1.2*truecount) + { + m_iscolliding = false; + } + else + { + m_iscolliding = true; + } + + if (m_wascolliding != m_iscolliding) + { + //base.SendCollisionUpdate(new CollisionEventUpdate()); + } + + m_wascolliding = m_iscolliding; + } + } + + /// + /// Returns if an avatar is colliding with the ground + /// + public override bool CollidingGround + { + get { return m_iscollidingGround; } + set + { + // Collisions against the ground are not really reliable + // So, to get a consistant value we have to average the current result over time + // Currently we use 1 second = 10 calls to this. + int i; + int truecount = 0; + int falsecount = 0; + + if (m_colliderGroundarr.Length >= 10) + { + for (i = 0; i < 10; i++) + { + m_colliderGroundarr[i] = m_colliderGroundarr[i + 1]; + } + } + m_colliderGroundarr[10] = value; + + for (i = 0; i < 11; i++) + { + if (m_colliderGroundarr[i]) + { + truecount++; + } + else + { + falsecount++; + } + } + + // Equal truecounts and false counts means we're colliding with something. + + if (falsecount > 1.2*truecount) + { + m_iscollidingGround = false; + } + else + { + m_iscollidingGround = true; + } + if (m_wascollidingGround != m_iscollidingGround) + { + //base.SendCollisionUpdate(new CollisionEventUpdate()); + } + m_wascollidingGround = m_iscollidingGround; + } + } + + /// + /// Returns if the avatar is colliding with an object + /// + public override bool CollidingObj + { + get { return m_iscollidingObj; } + set + { + m_iscollidingObj = value; + if (value && !m_avatarplanted) + m_pidControllerActive = false; + else + m_pidControllerActive = true; + } + } + + /// + /// turn the PID controller on or off. + /// The PID Controller will turn on all by itself in many situations + /// + /// + public void SetPidStatus(bool status) + { + m_pidControllerActive = status; + } + + public override bool Stopped + { + get { return _zeroFlag; } + } + + /// + /// This 'puts' an avatar somewhere in the physics space. + /// Not really a good choice unless you 'know' it's a good + /// spot otherwise you're likely to orbit the avatar. + /// + public override Vector3 Position + { + get { return _position; } + set + { + if (Body == IntPtr.Zero || Shell == IntPtr.Zero) + { + if (value.IsFinite()) + { + if (value.Z > 9999999f) + { + value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5; + } + if (value.Z < -90000f) + { + value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5; + } + + m_taintPosition = value; + _parent_scene.AddPhysicsActorTaint(this); + } + else + { + m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Position from Scene on character {0}", Name); + } + } + } + } + + public override Vector3 RotationalVelocity + { + get { return m_rotationalVelocity; } + set { m_rotationalVelocity = value; } + } + + /// + /// This property sets the height of the avatar only. We use the height to make sure the avatar stands up straight + /// and use it to offset landings properly + /// + public override Vector3 Size + { + get { return new Vector3(CAPSULE_RADIUS * 2, CAPSULE_RADIUS * 2, CAPSULE_LENGTH); } + set + { + SetTaintedCapsuleLength(value); + + // If we reset velocity here, then an avatar stalls when it crosses a border for the first time + // (as the height of the new root agent is set). +// Velocity = Vector3.Zero; + + _parent_scene.AddPhysicsActorTaint(this); + } + } + + private void SetTaintedCapsuleLength(Vector3 size) + { + if (size.IsFinite()) + { + m_pidControllerActive = true; + + m_tainted_CAPSULE_LENGTH = size.Z - CAPSULE_RADIUS * 2.0f; + + // m_log.InfoFormat("[ODE CHARACTER]: Size = {0}, Capsule Length = {1} (Capsule Radius = {2})", + // size, m_tainted_CAPSULE_LENGTH, CAPSULE_RADIUS); + } + else + { + m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Size for {0} in {1}", Name, _parent_scene.PhysicsSceneName); + } + } + + private void AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3 movementVector) + { + movementVector.Z = 0f; + float magnitude = (float)Math.Sqrt((double)(movementVector.X * movementVector.X + movementVector.Y * movementVector.Y)); + if (magnitude < 0.1f) return; + + // normalize the velocity vector + float invMagnitude = 1.0f / magnitude; + movementVector.X *= invMagnitude; + movementVector.Y *= invMagnitude; + + // if we change the capsule heading too often, the capsule can fall down + // therefore we snap movement vector to just 1 of 4 predefined directions (ne, nw, se, sw), + // meaning only 4 possible capsule tilt orientations + if (movementVector.X > 0) + { + // east + if (movementVector.Y > 0) + { + // northeast + movementVector.X = m_tiltBaseMovement; + movementVector.Y = m_tiltBaseMovement; + } + else + { + // southeast + movementVector.X = m_tiltBaseMovement; + movementVector.Y = -m_tiltBaseMovement; + } + } + else + { + // west + if (movementVector.Y > 0) + { + // northwest + movementVector.X = -m_tiltBaseMovement; + movementVector.Y = m_tiltBaseMovement; + } + else + { + // southwest + movementVector.X = -m_tiltBaseMovement; + movementVector.Y = -m_tiltBaseMovement; + } + } + + // movementVector.Z is zero + + // calculate tilt components based on desired amount of tilt and current (snapped) heading. + // the "-" sign is to force the tilt to be OPPOSITE the direction of movement. + float xTiltComponent = -movementVector.X * m_tiltMagnitudeWhenProjectedOnXYPlane; + float yTiltComponent = -movementVector.Y * m_tiltMagnitudeWhenProjectedOnXYPlane; + + //m_log.Debug("[ODE CHARACTER]: changing avatar tilt"); + d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, xTiltComponent); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, xTiltComponent); // must be same as lowstop, else a different, spurious tilt is introduced + d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, yTiltComponent); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, yTiltComponent); // same as lowstop + d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop + } + + /// + /// Uses the capped cyllinder volume formula to calculate the avatar's mass. + /// This may be used in calculations in the scene/scenepresence + /// + public override float Mass + { + get + { + float AVvolume = (float)(Math.PI * Math.Pow(CAPSULE_RADIUS, 2) * CAPSULE_LENGTH); + return m_density * AVvolume; + } + } + + public override void link(PhysicsActor obj) {} + + public override void delink() {} + + public override void LockAngularMotion(Vector3 axis) {} + +// This code is very useful. Written by DanX0r. We're just not using it right now. +// Commented out to prevent a warning. +// +// private void standupStraight() +// { +// // The purpose of this routine here is to quickly stabilize the Body while it's popped up in the air. +// // The amotor needs a few seconds to stabilize so without it, the avatar shoots up sky high when you +// // change appearance and when you enter the simulator +// // After this routine is done, the amotor stabilizes much quicker +// d.Vector3 feet; +// d.Vector3 head; +// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet); +// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head); +// float posture = head.Z - feet.Z; + +// // restoring force proportional to lack of posture: +// float servo = (2.5f - posture) * POSTURE_SERVO; +// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f); +// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f); +// //d.Matrix3 bodyrotation = d.BodyGetRotation(Body); +// //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyFArotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22); +// } + + public override Vector3 Force + { + get { return _target_velocity; } + set { return; } + } + + public override int VehicleType + { + get { return 0; } + set { return; } + } + + public override void VehicleFloatParam(int param, float value) + { + } + + public override void VehicleVectorParam(int param, Vector3 value) + { + } + + public override void VehicleRotationParam(int param, Quaternion rotation) + { + } + + public override void VehicleFlags(int param, bool remove) + { + } + + public override void SetVolumeDetect(int param) + { + } + + public override Vector3 CenterOfMass + { + get { return Vector3.Zero; } + } + + public override Vector3 GeometricCenter + { + get { return Vector3.Zero; } + } + + public override PrimitiveBaseShape Shape + { + set { return; } + } + + public override Vector3 TargetVelocity + { + get + { + return m_taintTargetVelocity; + } + + set + { + Velocity = value; + } + } + + + public override Vector3 Velocity + { + get + { + // There's a problem with Vector3.Zero! Don't Use it Here! + if (_zeroFlag) + return Vector3.Zero; + m_lastUpdateSent = false; + return _velocity; + } + + set + { + if (value.IsFinite()) + { + m_pidControllerActive = true; + m_taintTargetVelocity = value; + _parent_scene.AddPhysicsActorTaint(this); + } + else + { + m_log.WarnFormat("[ODE CHARACTER]: Got a NaN velocity from Scene for {0}", Name); + } + +// m_log.DebugFormat("[PHYSICS]: Set target velocity of {0}", m_taintTargetVelocity); + } + } + + public override Vector3 Torque + { + get { return Vector3.Zero; } + set { return; } + } + + public override float CollisionScore + { + get { return 0f; } + set { } + } + + public override bool Kinematic + { + get { return false; } + set { } + } + + public override Quaternion Orientation + { + get { return Quaternion.Identity; } + set { + //Matrix3 or = Orientation.ToRotationMatrix(); + //d.Matrix3 ord = new d.Matrix3(or.m00, or.m10, or.m20, or.m01, or.m11, or.m21, or.m02, or.m12, or.m22); + //d.BodySetRotation(Body, ref ord); + } + } + + public override Vector3 Acceleration + { + get { return _acceleration; } + set { _acceleration = value; } + } + + /// + /// Adds the force supplied to the Target Velocity + /// The PID controller takes this target velocity and tries to make it a reality + /// + /// + public override void AddForce(Vector3 force, bool pushforce) + { + if (force.IsFinite()) + { + if (pushforce) + { + m_pidControllerActive = false; + force *= 100f; + m_taintForce += force; + _parent_scene.AddPhysicsActorTaint(this); + + // If uncommented, things get pushed off world + // + // m_log.Debug("Push!"); + // m_taintTargetVelocity.X += force.X; + // m_taintTargetVelocity.Y += force.Y; + // m_taintTargetVelocity.Z += force.Z; + } + else + { + m_pidControllerActive = true; + m_taintTargetVelocity += force; + } + } + else + { + m_log.WarnFormat("[ODE CHARACTER]: Got a NaN force applied to {0}", Name); + } + //m_lastUpdateSent = false; + } + + public override void AddAngularForce(Vector3 force, bool pushforce) + { + } + + public override void SetMomentum(Vector3 momentum) + { + } + + /// + /// Called from Simulate + /// This is the avatar's movement control + PID Controller + /// + /// The character will be added to this list if there is something wrong (non-finite + /// position or velocity). + /// + internal void Move(List defects) + { + // no lock; for now it's only called from within Simulate() + + // If the PID Controller isn't active then we set our force + // calculating base velocity to the current position + + if (Body == IntPtr.Zero) + return; + + if (m_pidControllerActive == false) + { + _zeroPosition = d.BodyGetPosition(Body); + } + //PidStatus = true; + + d.Vector3 localpos = d.BodyGetPosition(Body); + Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z); + + if (!localPos.IsFinite()) + { + m_log.WarnFormat( + "[ODE CHARACTER]: Avatar position of {0} for {1} is non-finite! Removing from physics scene.", + localPos, Name); + + defects.Add(this); + + return; + } + + Vector3 vec = Vector3.Zero; + d.Vector3 vel = d.BodyGetLinearVel(Body); + +// m_log.DebugFormat( +// "[ODE CHARACTER]: Current velocity in Move() is <{0},{1},{2}>, target {3} for {4}", +// vel.X, vel.Y, vel.Z, _target_velocity, Name); + + float movementdivisor = 1f; + + if (!m_alwaysRun) + { + movementdivisor = walkDivisor; + } + else + { + movementdivisor = runDivisor; + } + + // if velocity is zero, use position control; otherwise, velocity control + if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding) + { + // keep track of where we stopped. No more slippin' & slidin' + if (!_zeroFlag) + { + _zeroFlag = true; + _zeroPosition = d.BodyGetPosition(Body); + } + + if (m_pidControllerActive) + { + // We only want to deactivate the PID Controller if we think we want to have our surrogate + // react to the physics scene by moving it's position. + // Avatar to Avatar collisions + // Prim to avatar collisions + + d.Vector3 pos = d.BodyGetPosition(Body); + vec.X = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2); + vec.Y = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y)* (PID_P * 2); + if (flying) + { + vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P; + } + } + //PidStatus = true; + } + else + { + m_pidControllerActive = true; + _zeroFlag = false; + if (m_iscolliding && !flying) + { + // We're standing on something + vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D); + vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D); + } + else if (m_iscolliding && flying) + { + // We're flying and colliding with something + vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 16); + vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 16); + } + else if (!m_iscolliding && flying) + { + // we're in mid air suspended + vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 6); + vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 6); + +// m_log.DebugFormat( +// "[ODE CHARACTER]: !m_iscolliding && flying, vec {0}, _target_velocity {1}, movementdivisor {2}, vel {3}", +// vec, _target_velocity, movementdivisor, vel); + } + + if (flying) + { + // This also acts as anti-gravity so that we hover when flying rather than fall. + vec.Z = (_target_velocity.Z - vel.Z) * (PID_D); + } + else + { + if (m_iscolliding && _target_velocity.Z > 0.0f) + { + // We're colliding with something and we're not flying but we're moving + // This means we're walking or running. + d.Vector3 pos = d.BodyGetPosition(Body); + vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P; + vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D; + vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; + } + else if (!m_iscolliding) + { + // we're not colliding and we're not flying so that means we're falling! + // m_iscolliding includes collisions with the ground. + vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D; + vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; + } + } + } + + if (flying) + { + // Anti-gravity so that we hover when flying rather than fall. + vec.Z += ((-1 * _parent_scene.gravityz) * m_mass); + + //Added for auto fly height. Kitto Flora + //d.Vector3 pos = d.BodyGetPosition(Body); + float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset; + + if (_position.Z < target_altitude) + { + vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f; + } + // end add Kitto Flora + } + + if (vec.IsFinite()) + { + // Apply the total force acting on this avatar + d.BodyAddForce(Body, vec.X, vec.Y, vec.Z); + + if (!_zeroFlag) + AlignAvatarTiltWithCurrentDirectionOfMovement(vec); + } + else + { + m_log.WarnFormat( + "[ODE CHARACTER]: Got a NaN force vector {0} in Move() for {1}. Removing character from physics scene.", + vec, Name); + + defects.Add(this); + + return; + } + + d.Vector3 newVel = d.BodyGetLinearVel(Body); + if (newVel.X >= 256 || newVel.X <= 256 || newVel.Y >= 256 || newVel.Y <= 256 || newVel.Z >= 256 || newVel.Z <= 256) + { +// m_log.DebugFormat( +// "[ODE CHARACTER]: Limiting falling velocity from {0} to {1} for {2}", newVel.Z, -9.8, Name); + + newVel.X = Util.Clamp(newVel.X, -255f, 255f); + newVel.Y = Util.Clamp(newVel.Y, -255f, 255f); + + if (!flying) + newVel.Z + = Util.Clamp( + newVel.Z, -_parent_scene.AvatarTerminalVelocity, _parent_scene.AvatarTerminalVelocity); + else + newVel.Z = Util.Clamp(newVel.Z, -255f, 255f); + + d.BodySetLinearVel(Body, newVel.X, newVel.Y, newVel.Z); + } + } + + /// + /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. + /// + /// The character will be added to this list if there is something wrong (non-finite + /// position or velocity). + /// + internal void UpdatePositionAndVelocity(List defects) + { + // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! + d.Vector3 newPos; + try + { + newPos = d.BodyGetPosition(Body); + } + catch (NullReferenceException) + { + bad = true; + defects.Add(this); + newPos = new d.Vector3(_position.X, _position.Y, _position.Z); + base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! + m_log.WarnFormat("[ODE CHARACTER]: Avatar Null reference for Avatar {0}, physical actor {1}", Name, m_uuid); + + return; + } + + // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) + if (newPos.X < 0.0f) newPos.X = 0.0f; + if (newPos.Y < 0.0f) newPos.Y = 0.0f; + if (newPos.X > (int)_parent_scene.WorldExtents.X - 0.05f) newPos.X = (int)_parent_scene.WorldExtents.X - 0.05f; + if (newPos.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) newPos.Y = (int)_parent_scene.WorldExtents.Y - 0.05f; + + _position.X = newPos.X; + _position.Y = newPos.Y; + _position.Z = newPos.Z; + + // I think we need to update the taintPosition too -- Diva 12/24/10 + m_taintPosition = _position; + + // Did we move last? = zeroflag + // This helps keep us from sliding all over + + if (_zeroFlag) + { + _velocity = Vector3.Zero; + + // Did we send out the 'stopped' message? + if (!m_lastUpdateSent) + { + m_lastUpdateSent = true; + //base.RequestPhysicsterseUpdate(); + } + } + else + { + m_lastUpdateSent = false; + d.Vector3 newVelocity; + + try + { + newVelocity = d.BodyGetLinearVel(Body); + } + catch (NullReferenceException) + { + newVelocity.X = _velocity.X; + newVelocity.Y = _velocity.Y; + newVelocity.Z = _velocity.Z; + } + + _velocity.X = newVelocity.X; + _velocity.Y = newVelocity.Y; + _velocity.Z = newVelocity.Z; + + if (_velocity.Z < -6 && !m_hackSentFall) + { + m_hackSentFall = true; + m_pidControllerActive = false; + } + else if (flying && !m_hackSentFly) + { + //m_hackSentFly = true; + //base.SendCollisionUpdate(new CollisionEventUpdate()); + } + else + { + m_hackSentFly = false; + m_hackSentFall = false; + } + } + } + + /// + /// This creates the Avatar's physical Surrogate in ODE at the position supplied + /// + /// + /// WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access + /// to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only + /// place that is safe to call this routine AvatarGeomAndBodyCreation. + /// + /// + /// + /// + /// + private void CreateOdeStructures(float npositionX, float npositionY, float npositionZ, float tensor) + { + if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero)) + { + m_log.ErrorFormat( + "[ODE CHARACTER]: Creating ODE structures for {0} even though some already exist. Shell = {1}, Body = {2}, Amotor = {3}", + Name, Shell, Body, Amotor); + } + + int dAMotorEuler = 1; +// _parent_scene.waitForSpaceUnlock(_parent_scene.space); + if (CAPSULE_LENGTH <= 0) + { + m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); + CAPSULE_LENGTH = 0.01f; + } + + if (CAPSULE_RADIUS <= 0) + { + m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); + CAPSULE_RADIUS = 0.01f; + } + +// lock (OdeScene.UniversalColliderSyncObject) + Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH); + + d.GeomSetCategoryBits(Shell, (int)m_collisionCategories); + d.GeomSetCollideBits(Shell, (int)m_collisionFlags); + + d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH); + Body = d.BodyCreate(_parent_scene.world); + d.BodySetPosition(Body, npositionX, npositionY, npositionZ); + + _position.X = npositionX; + _position.Y = npositionY; + _position.Z = npositionZ; + + m_taintPosition = _position; + + d.BodySetMass(Body, ref ShellMass); + d.Matrix3 m_caprot; + // 90 Stand up on the cap of the capped cyllinder + if (_parent_scene.IsAvCapsuleTilted) + { + d.RFromAxisAndAngle(out m_caprot, 1, 0, 1, (float)(Math.PI / 2)); + } + else + { + d.RFromAxisAndAngle(out m_caprot, 0, 0, 1, (float)(Math.PI / 2)); + } + + d.GeomSetRotation(Shell, ref m_caprot); + d.BodySetRotation(Body, ref m_caprot); + + d.GeomSetBody(Shell, Body); + + // The purpose of the AMotor here is to keep the avatar's physical + // surrogate from rotating while moving + Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero); + d.JointAttach(Amotor, Body, IntPtr.Zero); + d.JointSetAMotorMode(Amotor, dAMotorEuler); + d.JointSetAMotorNumAxes(Amotor, 3); + d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0); + d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0); + d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1); + d.JointSetAMotorAngle(Amotor, 0, 0); + d.JointSetAMotorAngle(Amotor, 1, 0); + d.JointSetAMotorAngle(Amotor, 2, 0); + + // These lowstops and high stops are effectively (no wiggle room) + if (_parent_scene.IsAvCapsuleTilted) + { + d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f); + d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f); + d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f); + } + else + { + #region Documentation of capsule motor LowStop and HighStop parameters + // Intentionally introduce some tilt into the capsule by setting + // the motor stops to small epsilon values. This small tilt prevents + // the capsule from falling into the terrain; a straight-up capsule + // (with -0..0 motor stops) falls into the terrain for reasons yet + // to be comprehended in their entirety. + #endregion + AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3.Zero); + d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0.08f); + d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f); + d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0.08f); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.08f); // must be same as lowstop, else a different, spurious tilt is introduced + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.08f); // same as lowstop + } + + // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the + // capped cyllinder will fall over + d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f); + d.JointSetAMotorParam(Amotor, (int)dParam.FMax, tensor); + + //d.Matrix3 bodyrotation = d.BodyGetRotation(Body); + //d.QfromR( + //d.Matrix3 checkrotation = new d.Matrix3(0.7071068,0.5, -0.7071068, + // + //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22); + //standupStraight(); + + _parent_scene.geom_name_map[Shell] = Name; + _parent_scene.actor_name_map[Shell] = this; + } + + /// + /// Cleanup the things we use in the scene. + /// + internal void Destroy() + { + m_tainted_isPhysical = false; + _parent_scene.AddPhysicsActorTaint(this); + } + + /// + /// Used internally to destroy the ODE structures associated with this character. + /// + internal void DestroyOdeStructures() + { + // Create avatar capsule and related ODE data + if (Shell == IntPtr.Zero || Body == IntPtr.Zero || Amotor == IntPtr.Zero) + { + m_log.ErrorFormat( + "[ODE CHARACTER]: Destroying ODE structures for {0} even though some are already null. Shell = {1}, Body = {2}, Amotor = {3}", + Name, Shell, Body, Amotor); + } + + // destroy avatar capsule and related ODE data + if (Amotor != IntPtr.Zero) + { + // Kill the Amotor + d.JointDestroy(Amotor); + Amotor = IntPtr.Zero; + } + + //kill the Geometry +// _parent_scene.waitForSpaceUnlock(_parent_scene.space); + + if (Body != IntPtr.Zero) + { + //kill the body + d.BodyDestroy(Body); + Body = IntPtr.Zero; + } + + if (Shell != IntPtr.Zero) + { +// lock (OdeScene.UniversalColliderSyncObject) + d.GeomDestroy(Shell); + + _parent_scene.geom_name_map.Remove(Shell); + _parent_scene.actor_name_map.Remove(Shell); + + Shell = IntPtr.Zero; + } + } + + public override void CrossingFailure() + { + } + + public override Vector3 PIDTarget { set { return; } } + public override bool PIDActive + { + get { return false; } + set { return; } + } + public override float PIDTau { set { return; } } + + public override float PIDHoverHeight { set { return; } } + public override bool PIDHoverActive { set { return; } } + public override PIDHoverType PIDHoverType { set { return; } } + public override float PIDHoverTau { set { return; } } + + public override Quaternion APIDTarget{ set { return; } } + + public override bool APIDActive{ set { return; } } + + public override float APIDStrength{ set { return; } } + + public override float APIDDamping{ set { return; } } + + public override void SubscribeEvents(int ms) + { + m_requestedUpdateFrequency = ms; + m_eventsubscription = ms; + + // Don't clear collision event reporting here. This is called directly from scene code and so can lead + // to a race condition with the simulate loop + + _parent_scene.AddCollisionEventReporting(this); + } + + public override void UnSubscribeEvents() + { + _parent_scene.RemoveCollisionEventReporting(this); + + // Don't clear collision event reporting here. This is called directly from scene code and so can lead + // to a race condition with the simulate loop + + m_requestedUpdateFrequency = 0; + m_eventsubscription = 0; + } + + internal void AddCollisionEvent(uint CollidedWith, ContactPoint contact) + { + if (m_eventsubscription > 0) + { +// m_log.DebugFormat( +// "[PHYSICS]: Adding collision event for {0}, collidedWith {1}, contact {2}", "", CollidedWith, contact); + + CollisionEventsThisFrame.AddCollider(CollidedWith, contact); + } + } + + internal void SendCollisions() + { + if (m_eventsubscription > m_requestedUpdateFrequency) + { + base.SendCollisionUpdate(CollisionEventsThisFrame); + + CollisionEventsThisFrame.Clear(); + m_eventsubscription = 0; + } + } + + public override bool SubscribedEvents() + { + if (m_eventsubscription > 0) + return true; + return false; + } + + internal void ProcessTaints() + { + if (m_taintPosition != _position) + { + if (Body != IntPtr.Zero) + { + d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z); + _position = m_taintPosition; + } + } + + if (m_taintForce != Vector3.Zero) + { + if (Body != IntPtr.Zero) + { + // FIXME: This is not a good solution since it's subject to a race condition if a force is another + // thread sets a new force while we're in this loop (since it could be obliterated by + // m_taintForce = Vector3.Zero. Need to lock ProcessTaints() when we set a new tainted force. + d.BodyAddForce(Body, m_taintForce.X, m_taintForce.Y, m_taintForce.Z); + } + + m_taintForce = Vector3.Zero; + } + + if (m_taintTargetVelocity != _target_velocity) + _target_velocity = m_taintTargetVelocity; + + if (m_tainted_isPhysical != m_isPhysical) + { + if (m_tainted_isPhysical) + { + CreateOdeStructures(_position.X, _position.Y, _position.Z, m_tensor); + _parent_scene.AddCharacter(this); + } + else + { + _parent_scene.RemoveCharacter(this); + DestroyOdeStructures(); + } + + m_isPhysical = m_tainted_isPhysical; + } + + if (m_tainted_CAPSULE_LENGTH != CAPSULE_LENGTH) + { + if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero) + { +// m_log.DebugFormat( +// "[ODE CHARACTER]: Changing capsule size from {0} to {1} for {2}", +// CAPSULE_LENGTH, m_tainted_CAPSULE_LENGTH, Name); + + m_pidControllerActive = true; + + // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate() + DestroyOdeStructures(); + + float prevCapsule = CAPSULE_LENGTH; + CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH; + + CreateOdeStructures( + _position.X, + _position.Y, + _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor); + + // As with Size, we reset velocity. However, this isn't strictly necessary since it doesn't + // appear to stall initial region crossings when done here. Being done for consistency. +// Velocity = Vector3.Zero; + } + else + { + m_log.Warn("[ODE CHARACTER]: trying to change capsule size for " + Name + ", but the following ODE data is missing - " + + (Shell==IntPtr.Zero ? "Shell ":"") + + (Body==IntPtr.Zero ? "Body ":"") + + (Amotor==IntPtr.Zero ? "Amotor ":"")); + } + } + } + + internal void AddCollisionFrameTime(int p) + { + // protect it from overflow crashing + if (m_eventsubscription + p >= int.MaxValue) + m_eventsubscription = 0; + m_eventsubscription += p; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.c_comments b/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.c_comments new file mode 100644 index 0000000..1060aa6 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.c_comments @@ -0,0 +1,630 @@ +/* + * Revised August 26 2009 by Kitto Flora. ODEDynamics.cs replaces + * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: + * ODEPrim.cs contains methods dealing with Prim editing, Prim + * characteristics and Kinetic motion. + * ODEDynamics.cs contains methods dealing with Prim Physical motion + * (dynamics) and the associated settings. Old Linear and angular + * motors for dynamic motion have been replace with MoveLinear() + * and MoveAngular(); 'Physical' is used only to switch ODE dynamic + * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_ is to + * switch between 'VEHICLE' parameter use and general dynamics + * settings use. + * + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using log4net; +using OpenMetaverse; +using Ode.NET; +using OpenSim.Framework; +using OpenSim.Region.Physics.Manager; + +namespace OpenSim.Region.Physics.OdePlugin +{ + public class ODEDynamics + { + public Vehicle Type + { + get { return m_type; } + } + + public IntPtr Body + { + get { return m_body; } + } + + private int frcount = 0; // Used to limit dynamics debug output to + // every 100th frame + + // private OdeScene m_parentScene = null; + private IntPtr m_body = IntPtr.Zero; + private IntPtr m_jointGroup = IntPtr.Zero; + private IntPtr m_aMotor = IntPtr.Zero; + + + // Vehicle properties + private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind + // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier + private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: + // HOVER_TERRAIN_ONLY + // HOVER_GLOBAL_HEIGHT + // NO_DEFLECTION_UP + // HOVER_WATER_ONLY + // HOVER_UP_ONLY + // LIMIT_MOTOR_UP + // LIMIT_ROLL_ONLY + + // Linear properties + private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time + private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL + private Vector3 m_dir = Vector3.Zero; // velocity applied to body + private Vector3 m_linearFrictionTimescale = Vector3.Zero; + private float m_linearMotorDecayTimescale = 0; + private float m_linearMotorTimescale = 0; + private Vector3 m_lastLinearVelocityVector = Vector3.Zero; + // private bool m_LinearMotorSetLastFrame = false; + // private Vector3 m_linearMotorOffset = Vector3.Zero; + + //Angular properties + private Vector3 m_angularMotorDirection = Vector3.Zero; + private Vector3 m_angularMotorDirectionLASTSET = Vector3.Zero; + private Vector3 m_angularFrictionTimescale = Vector3.Zero; + private float m_angularMotorDecayTimescale = 0; + private float m_angularMotorTimescale = 0; + private Vector3 m_lastAngularVelocityVector = Vector3.Zero; + + //Deflection properties + // private float m_angularDeflectionEfficiency = 0; + // private float m_angularDeflectionTimescale = 0; + // private float m_linearDeflectionEfficiency = 0; + // private float m_linearDeflectionTimescale = 0; + + //Banking properties + // private float m_bankingEfficiency = 0; + // private float m_bankingMix = 0; + // private float m_bankingTimescale = 0; + + //Hover and Buoyancy properties + private float m_VhoverHeight = 0f; + private float m_VhoverEfficiency = 0f; + private float m_VhoverTimescale = 0f; + private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height + private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. + // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) + // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. + // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. + + //Attractor properties + private float m_verticalAttractionEfficiency = 0; + private float m_verticalAttractionTimescale = 0; + + + + + + internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) + { + switch (pParam) + { + case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: + if (pValue < 0.01f) pValue = 0.01f; + // m_angularDeflectionEfficiency = pValue; + break; + case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + // m_angularDeflectionTimescale = pValue; + break; + case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + m_angularMotorDecayTimescale = pValue; + break; + case Vehicle.ANGULAR_MOTOR_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + m_angularMotorTimescale = pValue; + break; + case Vehicle.BANKING_EFFICIENCY: + if (pValue < 0.01f) pValue = 0.01f; + // m_bankingEfficiency = pValue; + break; + case Vehicle.BANKING_MIX: + if (pValue < 0.01f) pValue = 0.01f; + // m_bankingMix = pValue; + break; + case Vehicle.BANKING_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + // m_bankingTimescale = pValue; + break; + case Vehicle.BUOYANCY: + if (pValue < -1f) pValue = -1f; + if (pValue > 1f) pValue = 1f; + m_VehicleBuoyancy = pValue; + break; + case Vehicle.HOVER_EFFICIENCY: + if (pValue < 0f) pValue = 0f; + if (pValue > 1f) pValue = 1f; + m_VhoverEfficiency = pValue; + break; + case Vehicle.HOVER_HEIGHT: + m_VhoverHeight = pValue; + break; + case Vehicle.HOVER_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + m_VhoverTimescale = pValue; + break; + case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: + if (pValue < 0.01f) pValue = 0.01f; + // m_linearDeflectionEfficiency = pValue; + break; + case Vehicle.LINEAR_DEFLECTION_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + // m_linearDeflectionTimescale = pValue; + break; + case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + m_linearMotorDecayTimescale = pValue; + break; + case Vehicle.LINEAR_MOTOR_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + m_linearMotorTimescale = pValue; + break; + case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: + if (pValue < 0.0f) pValue = 0.0f; + if (pValue > 1.0f) pValue = 1.0f; + m_verticalAttractionEfficiency = pValue; + break; + case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + m_verticalAttractionTimescale = pValue; + break; + + // These are vector properties but the engine lets you use a single float value to + // set all of the components to the same value + case Vehicle.ANGULAR_FRICTION_TIMESCALE: + m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); + break; + case Vehicle.ANGULAR_MOTOR_DIRECTION: + m_angularMotorDirection = new Vector3(pValue, pValue, pValue); + m_angularMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); + break; + case Vehicle.LINEAR_FRICTION_TIMESCALE: + m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); + break; + case Vehicle.LINEAR_MOTOR_DIRECTION: + m_linearMotorDirection = new Vector3(pValue, pValue, pValue); + m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); + break; + case Vehicle.LINEAR_MOTOR_OFFSET: + // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); + break; + + } + + }//end ProcessFloatVehicleParam + + internal void ProcessVectorVehicleParam(Vehicle pParam, PhysicsVector pValue) + { + switch (pParam) + { + case Vehicle.ANGULAR_FRICTION_TIMESCALE: + m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + case Vehicle.ANGULAR_MOTOR_DIRECTION: + m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); + m_angularMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + case Vehicle.LINEAR_FRICTION_TIMESCALE: + m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + case Vehicle.LINEAR_MOTOR_DIRECTION: + m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); + m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + case Vehicle.LINEAR_MOTOR_OFFSET: + // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + } + + }//end ProcessVectorVehicleParam + + internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) + { + switch (pParam) + { + case Vehicle.REFERENCE_FRAME: + // m_referenceFrame = pValue; + break; + } + + }//end ProcessRotationVehicleParam + + internal void ProcessTypeChange(Vehicle pType) + { +Console.WriteLine("ProcessTypeChange to " + pType); + + // Set Defaults For Type + m_type = pType; + switch (pType) + { + case Vehicle.TYPE_SLED: + m_linearFrictionTimescale = new Vector3(30, 1, 1000); + m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 1000; + m_linearMotorDecayTimescale = 120; + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 1000; + m_angularMotorDecayTimescale = 120; + m_VhoverHeight = 0; + m_VhoverEfficiency = 1; + m_VhoverTimescale = 10; + m_VehicleBuoyancy = 0; + // m_linearDeflectionEfficiency = 1; + // m_linearDeflectionTimescale = 1; + // m_angularDeflectionEfficiency = 1; + // m_angularDeflectionTimescale = 1000; + // m_bankingEfficiency = 0; + // m_bankingMix = 1; + // m_bankingTimescale = 10; + // m_referenceFrame = Quaternion.Identity; + m_flags &= + ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | + VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); + m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); + break; + case Vehicle.TYPE_CAR: + m_linearFrictionTimescale = new Vector3(100, 2, 1000); + m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 1; + m_linearMotorDecayTimescale = 60; + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 1; + m_angularMotorDecayTimescale = 0.8f; + m_VhoverHeight = 0; + m_VhoverEfficiency = 0; + m_VhoverTimescale = 1000; + m_VehicleBuoyancy = 0; + // // m_linearDeflectionEfficiency = 1; + // // m_linearDeflectionTimescale = 2; + // // m_angularDeflectionEfficiency = 0; + // m_angularDeflectionTimescale = 10; + m_verticalAttractionEfficiency = 1; + m_verticalAttractionTimescale = 10; + // m_bankingEfficiency = -0.2f; + // m_bankingMix = 1; + // m_bankingTimescale = 1; + // m_referenceFrame = Quaternion.Identity; + m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); + m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_UP_ONLY | + VehicleFlag.LIMIT_MOTOR_UP); + break; + case Vehicle.TYPE_BOAT: + m_linearFrictionTimescale = new Vector3(10, 3, 2); + m_angularFrictionTimescale = new Vector3(10,10,10); + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 5; + m_linearMotorDecayTimescale = 60; + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 4; + m_angularMotorDecayTimescale = 4; + m_VhoverHeight = 0; + m_VhoverEfficiency = 0.5f; + m_VhoverTimescale = 2; + m_VehicleBuoyancy = 1; + // m_linearDeflectionEfficiency = 0.5f; + // m_linearDeflectionTimescale = 3; + // m_angularDeflectionEfficiency = 0.5f; + // m_angularDeflectionTimescale = 5; + m_verticalAttractionEfficiency = 0.5f; + m_verticalAttractionTimescale = 5; + // m_bankingEfficiency = -0.3f; + // m_bankingMix = 0.8f; + // m_bankingTimescale = 1; + // m_referenceFrame = Quaternion.Identity; + m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.LIMIT_ROLL_ONLY | + VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); + m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | + VehicleFlag.LIMIT_MOTOR_UP); + break; + case Vehicle.TYPE_AIRPLANE: + m_linearFrictionTimescale = new Vector3(200, 10, 5); + m_angularFrictionTimescale = new Vector3(20, 20, 20); + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 2; + m_linearMotorDecayTimescale = 60; + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 4; + m_angularMotorDecayTimescale = 4; + m_VhoverHeight = 0; + m_VhoverEfficiency = 0.5f; + m_VhoverTimescale = 1000; + m_VehicleBuoyancy = 0; + // m_linearDeflectionEfficiency = 0.5f; + // m_linearDeflectionTimescale = 3; + // m_angularDeflectionEfficiency = 1; + // m_angularDeflectionTimescale = 2; + m_verticalAttractionEfficiency = 0.9f; + m_verticalAttractionTimescale = 2; + // m_bankingEfficiency = 1; + // m_bankingMix = 0.7f; + // m_bankingTimescale = 2; + // m_referenceFrame = Quaternion.Identity; + m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | + VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP); + m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); + break; + case Vehicle.TYPE_BALLOON: + m_linearFrictionTimescale = new Vector3(5, 5, 5); + m_angularFrictionTimescale = new Vector3(10, 10, 10); + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 5; + m_linearMotorDecayTimescale = 60; + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 6; + m_angularMotorDecayTimescale = 10; + m_VhoverHeight = 5; + m_VhoverEfficiency = 0.8f; + m_VhoverTimescale = 10; + m_VehicleBuoyancy = 1; + // m_linearDeflectionEfficiency = 0; + // m_linearDeflectionTimescale = 5; + // m_angularDeflectionEfficiency = 0; + // m_angularDeflectionTimescale = 5; + m_verticalAttractionEfficiency = 1; + m_verticalAttractionTimescale = 1000; + // m_bankingEfficiency = 0; + // m_bankingMix = 0.7f; + // m_bankingTimescale = 5; + // m_referenceFrame = Quaternion.Identity; + m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | + VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP); + m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); + break; + + } + }//end SetDefaultsForType + + internal void Enable(IntPtr pBody, OdeScene pParentScene) + { +//Console.WriteLine("Enable m_type=" + m_type + " m_VehicleBuoyancy=" + m_VehicleBuoyancy); + if (m_type == Vehicle.TYPE_NONE) + return; + + m_body = pBody; + //KF: This used to set up the linear and angular joints + } + + internal void Step(float pTimestep, OdeScene pParentScene) + { + if (m_body == IntPtr.Zero || m_type == Vehicle.TYPE_NONE) + return; + frcount++; // used to limit debug comment output + if (frcount > 100) + frcount = 0; + + MoveLinear(pTimestep, pParentScene); + MoveAngular(pTimestep); + }// end Step + + private void MoveLinear(float pTimestep, OdeScene _pParentScene) + { + if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant + { + if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); + + // add drive to body + Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); + m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector? + + // This will work temporarily, but we really need to compare speed on an axis + // KF: Limit body velocity to applied velocity? + if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) + m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; + if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) + m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; + if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) + m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; + + // decay applied velocity + Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); + //Console.WriteLine("decay: " + decayfraction); + m_linearMotorDirection -= m_linearMotorDirection * decayfraction; + //Console.WriteLine("actual: " + m_linearMotorDirection); + } + else + { // requested is not significant + // if what remains of applied is small, zero it. + if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) + m_lastLinearVelocityVector = Vector3.Zero; + } + + + // convert requested object velocity to world-referenced vector + m_dir = m_lastLinearVelocityVector; + d.Quaternion rot = d.BodyGetQuaternion(Body); + Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object + m_dir *= rotq; // apply obj rotation to velocity vector + + // add Gravity andBuoyancy + // KF: So far I have found no good method to combine a script-requested + // .Z velocity and gravity. Therefore only 0g will used script-requested + // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. + Vector3 grav = Vector3.Zero; + if(m_VehicleBuoyancy < 1.0f) + { + // There is some gravity, make a gravity force vector + // that is applied after object velocity. + d.Mass objMass; + d.BodyGetMass(Body, out objMass); + // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; + grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); + // Preserve the current Z velocity + d.Vector3 vel_now = d.BodyGetLinearVel(Body); + m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity + } // else its 1.0, no gravity. + + // Check if hovering + if( (m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) + { + // We should hover, get the target height + d.Vector3 pos = d.BodyGetPosition(Body); + if((m_flags & VehicleFlag.HOVER_WATER_ONLY) == VehicleFlag.HOVER_WATER_ONLY) + { + m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; + } + else if((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) == VehicleFlag.HOVER_TERRAIN_ONLY) + { + m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; + } + else if((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) == VehicleFlag.HOVER_GLOBAL_HEIGHT) + { + m_VhoverTargetHeight = m_VhoverHeight; + } + + if((m_flags & VehicleFlag.HOVER_UP_ONLY) == VehicleFlag.HOVER_UP_ONLY) + { + // If body is aready heigher, use its height as target height + if(pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; + } + +// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped +// m_VhoverTimescale = 0f; // time to acheive height +// pTimestep is time since last frame,in secs + float herr0 = pos.Z - m_VhoverTargetHeight; +//if(frcount == 0) Console.WriteLine("herr0=" + herr0); + // Replace Vertical speed with correction figure if significant + if(Math.Abs(herr0) > 0.01f ) + { + d.Mass objMass; + d.BodyGetMass(Body, out objMass); + m_dir.Z = - ( (herr0 * pTimestep * 50.0f) / m_VhoverTimescale); + // m_VhoverEfficiency is not yet implemented + } + else + { + m_dir.Z = 0f; + } + } + + // Apply velocity + d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z); +//if(frcount == 0) Console.WriteLine("Move " + Body + ":"+ m_dir.X + " " + m_dir.Y + " " + m_dir.Z); + // apply gravity force + d.BodyAddForce(Body, grav.X, grav.Y, grav.Z); +//if(frcount == 0) Console.WriteLine("Force " + Body + ":" + grav.X + " " + grav.Y + " " + grav.Z); + + + // apply friction + Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); + m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; + } // end MoveLinear() + + private void MoveAngular(float pTimestep) + { + + // m_angularMotorDirection is the latest value from the script, and is decayed here + // m_angularMotorDirectionLASTSET is the latest value from the script + // m_lastAngularVelocityVector is what is being applied to the Body, varied up and down here + + if (!m_angularMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) + { + if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); + // ramp up to new value + Vector3 addAmount = m_angularMotorDirection / (m_angularMotorTimescale / pTimestep); + m_lastAngularVelocityVector += (addAmount * 10f); +//if(frcount == 0) Console.WriteLine("add: " + addAmount); + + // limit applied value to what was set by script + // This will work temporarily, but we really need to compare speed on an axis + if (Math.Abs(m_lastAngularVelocityVector.X) > Math.Abs(m_angularMotorDirectionLASTSET.X)) + m_lastAngularVelocityVector.X = m_angularMotorDirectionLASTSET.X; + if (Math.Abs(m_lastAngularVelocityVector.Y) > Math.Abs(m_angularMotorDirectionLASTSET.Y)) + m_lastAngularVelocityVector.Y = m_angularMotorDirectionLASTSET.Y; + if (Math.Abs(m_lastAngularVelocityVector.Z) > Math.Abs(m_angularMotorDirectionLASTSET.Z)) + m_lastAngularVelocityVector.Z = m_angularMotorDirectionLASTSET.Z; + + // decay the requested value + Vector3 decayfraction = ((Vector3.One / (m_angularMotorDecayTimescale / pTimestep))); + //Console.WriteLine("decay: " + decayfraction); + m_angularMotorDirection -= m_angularMotorDirection * decayfraction; + //Console.WriteLine("actual: " + m_linearMotorDirection); + } + // KF: m_lastAngularVelocityVector is rotational speed in rad/sec ? + + // Vertical attractor section + +// d.Mass objMass; +// d.BodyGetMass(Body, out objMass); +// float servo = 100f * objMass.mass * m_verticalAttractionEfficiency / (m_verticalAttractionTimescale * pTimestep); + float servo = 0.1f * m_verticalAttractionEfficiency / (m_verticalAttractionTimescale * pTimestep); + // get present body rotation + d.Quaternion rot = d.BodyGetQuaternion(Body); + Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); + // make a vector pointing up + Vector3 verterr = Vector3.Zero; + verterr.Z = 1.0f; + // rotate it to Body Angle + verterr = verterr * rotq; + // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. + // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go + // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. + if (verterr.Z < 0.0f) + { + verterr.X = 2.0f - verterr.X; + verterr.Y = 2.0f - verterr.Y; + } + // Error is 0 (no error) to +/- 2 (max error) + // scale it by servo + verterr = verterr * servo; + + // rotate to object frame + // verterr = verterr * rotq; + + // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so + // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. + m_lastAngularVelocityVector.X += verterr.Y; + m_lastAngularVelocityVector.Y -= verterr.X; +/* +if(frcount == 0) + { +// Console.WriteLine("AngleMotor " + m_lastAngularVelocityVector); + Console.WriteLine(String.Format("VA Body:{0} servo:{1} err:<{2},{3},{4}> VAE:{5}", + Body, servo, verterr.X, verterr.Y, verterr.Z, m_verticalAttractionEfficiency)); + } + */ + d.BodySetAngularVel (Body, m_lastAngularVelocityVector.X, m_lastAngularVelocityVector.Y, m_lastAngularVelocityVector.Z); + // apply friction + Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep); + m_lastAngularVelocityVector -= m_lastAngularVelocityVector * decayamount; + + } //end MoveAngular + } +} diff --git a/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs b/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs new file mode 100644 index 0000000..8f8e2bd --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs @@ -0,0 +1,974 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces + * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: + * ODEPrim.cs contains methods dealing with Prim editing, Prim + * characteristics and Kinetic motion. + * ODEDynamics.cs contains methods dealing with Prim Physical motion + * (dynamics) and the associated settings. Old Linear and angular + * motors for dynamic motion have been replace with MoveLinear() + * and MoveAngular(); 'Physical' is used only to switch ODE dynamic + * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_ is to + * switch between 'VEHICLE' parameter use and general dynamics + * settings use. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using log4net; +using OpenMetaverse; +using Ode.NET; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +namespace OpenSim.Region.PhysicsModule.ODE +{ + public class ODEDynamics + { + public Vehicle Type + { + get { return m_type; } + } + + public IntPtr Body + { + get { return m_body; } + } + + private int frcount = 0; // Used to limit dynamics debug output to + // every 100th frame + + // private OdeScene m_parentScene = null; + private IntPtr m_body = IntPtr.Zero; +// private IntPtr m_jointGroup = IntPtr.Zero; +// private IntPtr m_aMotor = IntPtr.Zero; + + + // Vehicle properties + private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind + // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier + private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: + // HOVER_TERRAIN_ONLY + // HOVER_GLOBAL_HEIGHT + // NO_DEFLECTION_UP + // HOVER_WATER_ONLY + // HOVER_UP_ONLY + // LIMIT_MOTOR_UP + // LIMIT_ROLL_ONLY + private VehicleFlag m_Hoverflags = (VehicleFlag)0; + private Vector3 m_BlockingEndPoint = Vector3.Zero; + private Quaternion m_RollreferenceFrame = Quaternion.Identity; + // Linear properties + private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time + private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL + private Vector3 m_dir = Vector3.Zero; // velocity applied to body + private Vector3 m_linearFrictionTimescale = Vector3.Zero; + private float m_linearMotorDecayTimescale = 0; + private float m_linearMotorTimescale = 0; + private Vector3 m_lastLinearVelocityVector = Vector3.Zero; + private d.Vector3 m_lastPositionVector = new d.Vector3(); + // private bool m_LinearMotorSetLastFrame = false; + // private Vector3 m_linearMotorOffset = Vector3.Zero; + + //Angular properties + private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor + private int m_angularMotorApply = 0; // application frame counter + private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity + private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate + private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate + private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate + private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body + // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body + + //Deflection properties + // private float m_angularDeflectionEfficiency = 0; + // private float m_angularDeflectionTimescale = 0; + // private float m_linearDeflectionEfficiency = 0; + // private float m_linearDeflectionTimescale = 0; + + //Banking properties + // private float m_bankingEfficiency = 0; + // private float m_bankingMix = 0; + // private float m_bankingTimescale = 0; + + //Hover and Buoyancy properties + private float m_VhoverHeight = 0f; +// private float m_VhoverEfficiency = 0f; + private float m_VhoverTimescale = 0f; + private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height + private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. + // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) + // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. + // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. + + //Attractor properties + private float m_verticalAttractionEfficiency = 1.0f; // damped + private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. + + internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) + { + switch (pParam) + { + case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: + if (pValue < 0.01f) pValue = 0.01f; + // m_angularDeflectionEfficiency = pValue; + break; + case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + // m_angularDeflectionTimescale = pValue; + break; + case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + m_angularMotorDecayTimescale = pValue; + break; + case Vehicle.ANGULAR_MOTOR_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + m_angularMotorTimescale = pValue; + break; + case Vehicle.BANKING_EFFICIENCY: + if (pValue < 0.01f) pValue = 0.01f; + // m_bankingEfficiency = pValue; + break; + case Vehicle.BANKING_MIX: + if (pValue < 0.01f) pValue = 0.01f; + // m_bankingMix = pValue; + break; + case Vehicle.BANKING_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + // m_bankingTimescale = pValue; + break; + case Vehicle.BUOYANCY: + if (pValue < -1f) pValue = -1f; + if (pValue > 1f) pValue = 1f; + m_VehicleBuoyancy = pValue; + break; +// case Vehicle.HOVER_EFFICIENCY: +// if (pValue < 0f) pValue = 0f; +// if (pValue > 1f) pValue = 1f; +// m_VhoverEfficiency = pValue; +// break; + case Vehicle.HOVER_HEIGHT: + m_VhoverHeight = pValue; + break; + case Vehicle.HOVER_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + m_VhoverTimescale = pValue; + break; + case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: + if (pValue < 0.01f) pValue = 0.01f; + // m_linearDeflectionEfficiency = pValue; + break; + case Vehicle.LINEAR_DEFLECTION_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + // m_linearDeflectionTimescale = pValue; + break; + case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + m_linearMotorDecayTimescale = pValue; + break; + case Vehicle.LINEAR_MOTOR_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + m_linearMotorTimescale = pValue; + break; + case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: + if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable + if (pValue > 1.0f) pValue = 1.0f; + m_verticalAttractionEfficiency = pValue; + break; + case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: + if (pValue < 0.01f) pValue = 0.01f; + m_verticalAttractionTimescale = pValue; + break; + + // These are vector properties but the engine lets you use a single float value to + // set all of the components to the same value + case Vehicle.ANGULAR_FRICTION_TIMESCALE: + m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); + break; + case Vehicle.ANGULAR_MOTOR_DIRECTION: + m_angularMotorDirection = new Vector3(pValue, pValue, pValue); + m_angularMotorApply = 10; + break; + case Vehicle.LINEAR_FRICTION_TIMESCALE: + m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); + break; + case Vehicle.LINEAR_MOTOR_DIRECTION: + m_linearMotorDirection = new Vector3(pValue, pValue, pValue); + m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); + break; + case Vehicle.LINEAR_MOTOR_OFFSET: + // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); + break; + + } + }//end ProcessFloatVehicleParam + + internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) + { + switch (pParam) + { + case Vehicle.ANGULAR_FRICTION_TIMESCALE: + m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + case Vehicle.ANGULAR_MOTOR_DIRECTION: + m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); + // Limit requested angular speed to 2 rps= 4 pi rads/sec + if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f; + if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f; + if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f; + if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f; + if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f; + if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f; + m_angularMotorApply = 10; + break; + case Vehicle.LINEAR_FRICTION_TIMESCALE: + m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + case Vehicle.LINEAR_MOTOR_DIRECTION: + m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); + m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + case Vehicle.LINEAR_MOTOR_OFFSET: + // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + case Vehicle.BLOCK_EXIT: + m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + } + }//end ProcessVectorVehicleParam + + internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) + { + switch (pParam) + { + case Vehicle.REFERENCE_FRAME: + // m_referenceFrame = pValue; + break; + case Vehicle.ROLL_FRAME: + m_RollreferenceFrame = pValue; + break; + } + }//end ProcessRotationVehicleParam + + internal void ProcessVehicleFlags(int pParam, bool remove) + { + if (remove) + { + if (pParam == -1) + { + m_flags = (VehicleFlag)0; + m_Hoverflags = (VehicleFlag)0; + return; + } + if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) + { + if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != (VehicleFlag)0) + m_Hoverflags &= ~(VehicleFlag.HOVER_GLOBAL_HEIGHT); + } + if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY) + { + if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != (VehicleFlag)0) + m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY); + } + if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY) + { + if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != (VehicleFlag)0) + m_Hoverflags &= ~(VehicleFlag.HOVER_UP_ONLY); + } + if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY) + { + if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != (VehicleFlag)0) + m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY); + } + if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP) + { + if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != (VehicleFlag)0) + m_flags &= ~(VehicleFlag.LIMIT_MOTOR_UP); + } + if ((pParam & (int)VehicleFlag.LIMIT_ROLL_ONLY) == (int)VehicleFlag.LIMIT_ROLL_ONLY) + { + if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != (VehicleFlag)0) + m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); + } + if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK) + { + if ((m_flags & VehicleFlag.MOUSELOOK_BANK) != (VehicleFlag)0) + m_flags &= ~(VehicleFlag.MOUSELOOK_BANK); + } + if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER) + { + if ((m_flags & VehicleFlag.MOUSELOOK_STEER) != (VehicleFlag)0) + m_flags &= ~(VehicleFlag.MOUSELOOK_STEER); + } + if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP) + { + if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) != (VehicleFlag)0) + m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP); + } + if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED) + { + if ((m_flags & VehicleFlag.CAMERA_DECOUPLED) != (VehicleFlag)0) + m_flags &= ~(VehicleFlag.CAMERA_DECOUPLED); + } + if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X) + { + if ((m_flags & VehicleFlag.NO_X) != (VehicleFlag)0) + m_flags &= ~(VehicleFlag.NO_X); + } + if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y) + { + if ((m_flags & VehicleFlag.NO_Y) != (VehicleFlag)0) + m_flags &= ~(VehicleFlag.NO_Y); + } + if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z) + { + if ((m_flags & VehicleFlag.NO_Z) != (VehicleFlag)0) + m_flags &= ~(VehicleFlag.NO_Z); + } + if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT) + { + if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != (VehicleFlag)0) + m_Hoverflags &= ~(VehicleFlag.LOCK_HOVER_HEIGHT); + } + if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION) + { + if ((m_flags & VehicleFlag.NO_DEFLECTION) != (VehicleFlag)0) + m_flags &= ~(VehicleFlag.NO_DEFLECTION); + } + if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION) + { + if ((m_flags & VehicleFlag.LOCK_ROTATION) != (VehicleFlag)0) + m_flags &= ~(VehicleFlag.LOCK_ROTATION); + } + } + else + { + if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) + { + m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT | m_flags); + } + if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY) + { + m_Hoverflags |= (VehicleFlag.HOVER_TERRAIN_ONLY | m_flags); + } + if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY) + { + m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY | m_flags); + } + if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY) + { + m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY | m_flags); + } + if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP) + { + m_flags |= (VehicleFlag.LIMIT_MOTOR_UP | m_flags); + } + if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK) + { + m_flags |= (VehicleFlag.MOUSELOOK_BANK | m_flags); + } + if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER) + { + m_flags |= (VehicleFlag.MOUSELOOK_STEER | m_flags); + } + if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP) + { + m_flags |= (VehicleFlag.NO_DEFLECTION_UP | m_flags); + } + if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED) + { + m_flags |= (VehicleFlag.CAMERA_DECOUPLED | m_flags); + } + if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X) + { + m_flags |= (VehicleFlag.NO_X); + } + if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y) + { + m_flags |= (VehicleFlag.NO_Y); + } + if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z) + { + m_flags |= (VehicleFlag.NO_Z); + } + if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT) + { + m_Hoverflags |= (VehicleFlag.LOCK_HOVER_HEIGHT); + } + if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION) + { + m_flags |= (VehicleFlag.NO_DEFLECTION); + } + if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION) + { + m_flags |= (VehicleFlag.LOCK_ROTATION); + } + } + }//end ProcessVehicleFlags + + internal void ProcessTypeChange(Vehicle pType) + { + // Set Defaults For Type + m_type = pType; + switch (pType) + { + case Vehicle.TYPE_NONE: + m_linearFrictionTimescale = new Vector3(0, 0, 0); + m_angularFrictionTimescale = new Vector3(0, 0, 0); + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 0; + m_linearMotorDecayTimescale = 0; + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 0; + m_angularMotorDecayTimescale = 0; + m_VhoverHeight = 0; + m_VhoverTimescale = 0; + m_VehicleBuoyancy = 0; + m_flags = (VehicleFlag)0; + break; + + case Vehicle.TYPE_SLED: + m_linearFrictionTimescale = new Vector3(30, 1, 1000); + m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 1000; + m_linearMotorDecayTimescale = 120; + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 1000; + m_angularMotorDecayTimescale = 120; + m_VhoverHeight = 0; +// m_VhoverEfficiency = 1; + m_VhoverTimescale = 10; + m_VehicleBuoyancy = 0; + // m_linearDeflectionEfficiency = 1; + // m_linearDeflectionTimescale = 1; + // m_angularDeflectionEfficiency = 1; + // m_angularDeflectionTimescale = 1000; + // m_bankingEfficiency = 0; + // m_bankingMix = 1; + // m_bankingTimescale = 10; + // m_referenceFrame = Quaternion.Identity; + m_Hoverflags &= + ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | + VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); + m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); + break; + case Vehicle.TYPE_CAR: + m_linearFrictionTimescale = new Vector3(100, 2, 1000); + m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 1; + m_linearMotorDecayTimescale = 60; + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 1; + m_angularMotorDecayTimescale = 0.8f; + m_VhoverHeight = 0; +// m_VhoverEfficiency = 0; + m_VhoverTimescale = 1000; + m_VehicleBuoyancy = 0; + // // m_linearDeflectionEfficiency = 1; + // // m_linearDeflectionTimescale = 2; + // // m_angularDeflectionEfficiency = 0; + // m_angularDeflectionTimescale = 10; + m_verticalAttractionEfficiency = 1f; + m_verticalAttractionTimescale = 10f; + // m_bankingEfficiency = -0.2f; + // m_bankingMix = 1; + // m_bankingTimescale = 1; + // m_referenceFrame = Quaternion.Identity; + m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); + m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | + VehicleFlag.LIMIT_MOTOR_UP); + m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY); + break; + case Vehicle.TYPE_BOAT: + m_linearFrictionTimescale = new Vector3(10, 3, 2); + m_angularFrictionTimescale = new Vector3(10,10,10); + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 5; + m_linearMotorDecayTimescale = 60; + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 4; + m_angularMotorDecayTimescale = 4; + m_VhoverHeight = 0; +// m_VhoverEfficiency = 0.5f; + m_VhoverTimescale = 2; + m_VehicleBuoyancy = 1; + // m_linearDeflectionEfficiency = 0.5f; + // m_linearDeflectionTimescale = 3; + // m_angularDeflectionEfficiency = 0.5f; + // m_angularDeflectionTimescale = 5; + m_verticalAttractionEfficiency = 0.5f; + m_verticalAttractionTimescale = 5f; + // m_bankingEfficiency = -0.3f; + // m_bankingMix = 0.8f; + // m_bankingTimescale = 1; + // m_referenceFrame = Quaternion.Identity; + m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | + VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); + m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); + m_flags |= (VehicleFlag.NO_DEFLECTION_UP | + VehicleFlag.LIMIT_MOTOR_UP); + m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY); + break; + case Vehicle.TYPE_AIRPLANE: + m_linearFrictionTimescale = new Vector3(200, 10, 5); + m_angularFrictionTimescale = new Vector3(20, 20, 20); + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 2; + m_linearMotorDecayTimescale = 60; + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 4; + m_angularMotorDecayTimescale = 4; + m_VhoverHeight = 0; +// m_VhoverEfficiency = 0.5f; + m_VhoverTimescale = 1000; + m_VehicleBuoyancy = 0; + // m_linearDeflectionEfficiency = 0.5f; + // m_linearDeflectionTimescale = 3; + // m_angularDeflectionEfficiency = 1; + // m_angularDeflectionTimescale = 2; + m_verticalAttractionEfficiency = 0.9f; + m_verticalAttractionTimescale = 2f; + // m_bankingEfficiency = 1; + // m_bankingMix = 0.7f; + // m_bankingTimescale = 2; + // m_referenceFrame = Quaternion.Identity; + m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | + VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); + m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); + m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); + break; + case Vehicle.TYPE_BALLOON: + m_linearFrictionTimescale = new Vector3(5, 5, 5); + m_angularFrictionTimescale = new Vector3(10, 10, 10); + m_linearMotorDirection = Vector3.Zero; + m_linearMotorTimescale = 5; + m_linearMotorDecayTimescale = 60; + m_angularMotorDirection = Vector3.Zero; + m_angularMotorTimescale = 6; + m_angularMotorDecayTimescale = 10; + m_VhoverHeight = 5; +// m_VhoverEfficiency = 0.8f; + m_VhoverTimescale = 10; + m_VehicleBuoyancy = 1; + // m_linearDeflectionEfficiency = 0; + // m_linearDeflectionTimescale = 5; + // m_angularDeflectionEfficiency = 0; + // m_angularDeflectionTimescale = 5; + m_verticalAttractionEfficiency = 1f; + m_verticalAttractionTimescale = 100f; + // m_bankingEfficiency = 0; + // m_bankingMix = 0.7f; + // m_bankingTimescale = 5; + // m_referenceFrame = Quaternion.Identity; + m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | + VehicleFlag.HOVER_UP_ONLY); + m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); + m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); + m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT); + break; + + } + }//end SetDefaultsForType + + internal void Enable(IntPtr pBody, OdeScene pParentScene) + { + if (m_type == Vehicle.TYPE_NONE) + return; + + m_body = pBody; + } + + internal void Step(float pTimestep, OdeScene pParentScene) + { + if (m_body == IntPtr.Zero || m_type == Vehicle.TYPE_NONE) + return; + frcount++; // used to limit debug comment output + if (frcount > 100) + frcount = 0; + + MoveLinear(pTimestep, pParentScene); + MoveAngular(pTimestep); + LimitRotation(pTimestep); + }// end Step + + private void MoveLinear(float pTimestep, OdeScene _pParentScene) + { + if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant + { + if (!d.BodyIsEnabled(Body)) + d.BodyEnable(Body); + + // add drive to body + Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); + m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector? + + // This will work temporarily, but we really need to compare speed on an axis + // KF: Limit body velocity to applied velocity? + if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) + m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; + if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) + m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; + if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) + m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; + + // decay applied velocity + Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); + //Console.WriteLine("decay: " + decayfraction); + m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; + //Console.WriteLine("actual: " + m_linearMotorDirection); + } + else + { // requested is not significant + // if what remains of applied is small, zero it. + if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) + m_lastLinearVelocityVector = Vector3.Zero; + } + + // convert requested object velocity to world-referenced vector + m_dir = m_lastLinearVelocityVector; + d.Quaternion rot = d.BodyGetQuaternion(Body); + Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object + m_dir *= rotq; // apply obj rotation to velocity vector + + // add Gravity andBuoyancy + // KF: So far I have found no good method to combine a script-requested + // .Z velocity and gravity. Therefore only 0g will used script-requested + // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. + Vector3 grav = Vector3.Zero; + // There is some gravity, make a gravity force vector + // that is applied after object velocity. + d.Mass objMass; + d.BodyGetMass(Body, out objMass); + // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; + grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); + // Preserve the current Z velocity + d.Vector3 vel_now = d.BodyGetLinearVel(Body); + m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity + + d.Vector3 pos = d.BodyGetPosition(Body); +// 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); + Vector3 posChange = new Vector3(); + posChange.X = pos.X - m_lastPositionVector.X; + posChange.Y = pos.Y - m_lastPositionVector.Y; + posChange.Z = pos.Z - m_lastPositionVector.Z; + double Zchange = Math.Abs(posChange.Z); + if (m_BlockingEndPoint != Vector3.Zero) + { + if (pos.X >= (m_BlockingEndPoint.X - (float)1)) + { + pos.X -= posChange.X + 1; + d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); + } + if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) + { + pos.Y -= posChange.Y + 1; + d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); + } + if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) + { + pos.Z -= posChange.Z + 1; + d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); + } + if (pos.X <= 0) + { + pos.X += posChange.X + 1; + d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); + } + if (pos.Y <= 0) + { + pos.Y += posChange.Y + 1; + d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); + } + } + if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y)) + { + pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2; + d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); + } + + // Check if hovering + if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) + { + // We should hover, get the target height + if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) + { + m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; + } + if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) + { + m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; + } + if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) + { + m_VhoverTargetHeight = m_VhoverHeight; + } + + if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0) + { + // If body is aready heigher, use its height as target height + if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; + } + if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) + { + if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) + { + d.BodySetPosition(Body, pos.X, pos.Y, m_VhoverTargetHeight); + } + } + else + { + float herr0 = pos.Z - m_VhoverTargetHeight; + // Replace Vertical speed with correction figure if significant + if (Math.Abs(herr0) > 0.01f) + { + m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); + //KF: m_VhoverEfficiency is not yet implemented + } + else + { + m_dir.Z = 0f; + } + } + +// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped +// m_VhoverTimescale = 0f; // time to acheive height +// pTimestep is time since last frame,in secs + } + + if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) + { + //Start Experimental Values + if (Zchange > .3) + { + grav.Z = (float)(grav.Z * 3); + } + if (Zchange > .15) + { + grav.Z = (float)(grav.Z * 2); + } + if (Zchange > .75) + { + grav.Z = (float)(grav.Z * 1.5); + } + if (Zchange > .05) + { + grav.Z = (float)(grav.Z * 1.25); + } + if (Zchange > .025) + { + grav.Z = (float)(grav.Z * 1.125); + } + float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y); + float postemp = (pos.Z - terraintemp); + if (postemp > 2.5f) + { + grav.Z = (float)(grav.Z * 1.037125); + } + //End Experimental Values + } + if ((m_flags & (VehicleFlag.NO_X)) != 0) + { + m_dir.X = 0; + } + if ((m_flags & (VehicleFlag.NO_Y)) != 0) + { + m_dir.Y = 0; + } + if ((m_flags & (VehicleFlag.NO_Z)) != 0) + { + m_dir.Z = 0; + } + + m_lastPositionVector = d.BodyGetPosition(Body); + + // Apply velocity + d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z); + // apply gravity force + d.BodyAddForce(Body, grav.X, grav.Y, grav.Z); + + + // apply friction + Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); + m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; + } // end MoveLinear() + + private void MoveAngular(float pTimestep) + { + /* + private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor + private int m_angularMotorApply = 0; // application frame counter + private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down) + private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate + private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate + private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate + private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body + */ + + // Get what the body is doing, this includes 'external' influences + d.Vector3 angularVelocity = d.BodyGetAngularVel(Body); + // Vector3 angularVelocity = Vector3.Zero; + + if (m_angularMotorApply > 0) + { + // ramp up to new value + // current velocity += error / (time to get there / step interval) + // requested speed - last motor speed + m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); + m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); + m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); + + m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected + // velocity may still be acheived. + } + else + { + // no motor recently applied, keep the body velocity + /* m_angularMotorVelocity.X = angularVelocity.X; + m_angularMotorVelocity.Y = angularVelocity.Y; + m_angularMotorVelocity.Z = angularVelocity.Z; */ + + // and decay the velocity + m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); + } // end motor section + + // Vertical attractor section + Vector3 vertattr = Vector3.Zero; + + if (m_verticalAttractionTimescale < 300) + { + float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); + // get present body rotation + d.Quaternion rot = d.BodyGetQuaternion(Body); + Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); + // make a vector pointing up + Vector3 verterr = Vector3.Zero; + verterr.Z = 1.0f; + // rotate it to Body Angle + verterr = verterr * rotq; + // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. + // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go + // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. + if (verterr.Z < 0.0f) + { + verterr.X = 2.0f - verterr.X; + verterr.Y = 2.0f - verterr.Y; + } + // Error is 0 (no error) to +/- 2 (max error) + // scale it by VAservo + verterr = verterr * VAservo; +//if (frcount == 0) Console.WriteLine("VAerr=" + verterr); + + // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so + // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. + vertattr.X = verterr.Y; + vertattr.Y = - verterr.X; + vertattr.Z = 0f; + + // scaling appears better usingsquare-law + float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); + vertattr.X += bounce * angularVelocity.X; + vertattr.Y += bounce * angularVelocity.Y; + + } // else vertical attractor is off + + // m_lastVertAttractor = vertattr; + + // Bank section tba + // Deflection section tba + + // Sum velocities + m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection + + if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) + { + m_lastAngularVelocity.X = 0; + m_lastAngularVelocity.Y = 0; + } + + if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) + { + if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); + } + else + { + m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. + } + + // apply friction + Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep); + m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; + + // Apply to the body + d.BodySetAngularVel (Body, m_lastAngularVelocity.X, m_lastAngularVelocity.Y, m_lastAngularVelocity.Z); + + } //end MoveAngular + internal void LimitRotation(float timestep) + { + d.Quaternion rot = d.BodyGetQuaternion(Body); + Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object + d.Quaternion m_rot = new d.Quaternion(); + bool changed = false; + m_rot.X = rotq.X; + m_rot.Y = rotq.Y; + m_rot.Z = rotq.Z; + m_rot.W = rotq.W; + if (m_RollreferenceFrame != Quaternion.Identity) + { + if (rotq.X >= m_RollreferenceFrame.X) + { + m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); + } + if (rotq.Y >= m_RollreferenceFrame.Y) + { + m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); + } + if (rotq.X <= -m_RollreferenceFrame.X) + { + m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); + } + if (rotq.Y <= -m_RollreferenceFrame.Y) + { + m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); + } + changed = true; + } + if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) + { + m_rot.X = 0; + m_rot.Y = 0; + changed = true; + } + if (changed) + d.BodySetQuaternion(Body, ref m_rot); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs b/OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs new file mode 100644 index 0000000..0b9c45f --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs @@ -0,0 +1,3382 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Revised August 26 2009 by Kitto Flora. ODEDynamics.cs replaces + * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: + * ODEPrim.cs contains methods dealing with Prim editing, Prim + * characteristics and Kinetic motion. + * ODEDynamics.cs contains methods dealing with Prim Physical motion + * (dynamics) and the associated settings. Old Linear and angular + * motors for dynamic motion have been replace with MoveLinear() + * and MoveAngular(); 'Physical' is used only to switch ODE dynamic + * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_ is to + * switch between 'VEHICLE' parameter use and general dynamics + * settings use. + */ + +//#define SPAM + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; +using log4net; +using OpenMetaverse; +using Ode.NET; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +namespace OpenSim.Region.PhysicsModule.ODE +{ + /// + /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves. + /// + public class OdePrim : PhysicsActor + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private bool m_isphysical; + + public int ExpectedCollisionContacts { get { return m_expectedCollisionContacts; } } + private int m_expectedCollisionContacts = 0; + + /// + /// Gets collide bits so that we can still perform land collisions if a mesh fails to load. + /// + private int BadMeshAssetCollideBits + { + get { return m_isphysical ? (int)CollisionCategories.Land : 0; } + } + + /// + /// Is this prim subject to physics? Even if not, it's still solid for collision purposes. + /// + public override bool IsPhysical + { + get { return m_isphysical; } + set + { + m_isphysical = value; + if (!m_isphysical) // Zero the remembered last velocity + m_lastVelocity = Vector3.Zero; + } + } + + private Vector3 _position; + private Vector3 _velocity; + private Vector3 _torque; + private Vector3 m_lastVelocity; + private Vector3 m_lastposition; + private Quaternion m_lastorientation = new Quaternion(); + private Vector3 m_rotationalVelocity; + private Vector3 _size; + private Vector3 _acceleration; + // private d.Vector3 _zeroPosition = new d.Vector3(0.0f, 0.0f, 0.0f); + private Quaternion _orientation; + private Vector3 m_taintposition; + private Vector3 m_taintsize; + private Vector3 m_taintVelocity; + private Vector3 m_taintTorque; + private Quaternion m_taintrot; + private Vector3 m_angularlock = Vector3.One; + private Vector3 m_taintAngularLock = Vector3.One; + private IntPtr Amotor = IntPtr.Zero; + + private bool m_assetFailed = false; + + private Vector3 m_PIDTarget; + private float m_PIDTau; + private float PID_D = 35f; + private float PID_G = 25f; + + // KF: These next 7 params apply to llSetHoverHeight(float height, integer water, float tau), + // and are for non-VEHICLES only. + + private float m_PIDHoverHeight; + private float m_PIDHoverTau; + private bool m_useHoverPID; + private PIDHoverType m_PIDHoverType = PIDHoverType.Ground; + private float m_targetHoverHeight; + private float m_groundHeight; + private float m_waterHeight; + private float m_buoyancy; //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle. + + // private float m_tensor = 5f; + private int body_autodisable_frames = 20; + + + private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom + | CollisionCategories.Space + | CollisionCategories.Body + | CollisionCategories.Character + ); + private bool m_taintshape; + private bool m_taintPhysics; + private bool m_collidesLand = true; + private bool m_collidesWater; + + // Default we're a Geometry + private CollisionCategories m_collisionCategories = (CollisionCategories.Geom); + + // Default, Collide with Other Geometries, spaces and Bodies + private CollisionCategories m_collisionFlags = m_default_collisionFlags; + + public bool m_taintremove { get; private set; } + public bool m_taintdisable { get; private set; } + internal bool m_disabled; + public bool m_taintadd { get; private set; } + public bool m_taintselected { get; private set; } + public bool m_taintCollidesWater { get; private set; } + + private bool m_taintforce = false; + private bool m_taintaddangularforce = false; + private Vector3 m_force; + private List m_forcelist = new List(); + private List m_angularforcelist = new List(); + + private PrimitiveBaseShape _pbs; + private OdeScene _parent_scene; + + /// + /// The physics space which contains prim geometries + /// + public IntPtr m_targetSpace = IntPtr.Zero; + + /// + /// The prim geometry, used for collision detection. + /// + /// + /// This is never null except for a brief period when the geometry needs to be replaced (due to resizing or + /// mesh change) or when the physical prim is being removed from the scene. + /// + public IntPtr prim_geom { get; private set; } + + public IntPtr _triMeshData { get; private set; } + + private IntPtr _linkJointGroup = IntPtr.Zero; + private PhysicsActor _parent; + private PhysicsActor m_taintparent; + + private List childrenPrim = new List(); + + private bool iscolliding; + private bool m_isSelected; + + internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively + + private bool m_throttleUpdates; + private int throttleCounter; + public int m_interpenetrationcount { get; private set; } + internal float m_collisionscore; + public int m_roundsUnderMotionThreshold { get; private set; } + private int m_crossingfailures; + + public bool outofBounds { get; private set; } + private float m_density = 10.000006836f; // Aluminum g/cm3; + + public bool _zeroFlag { get; private set; } + private bool m_lastUpdateSent; + + public IntPtr Body = IntPtr.Zero; + private Vector3 _target_velocity; + private d.Mass pMass; + + private int m_eventsubscription; + private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate(); + + /// + /// Signal whether there were collisions on the previous frame, so we know if we need to send the + /// empty CollisionEventsThisFrame to the prim so that it can detect the end of a collision. + /// + /// + /// This is probably a temporary measure, pending storing this information consistently in CollisionEventUpdate itself. + /// + private bool m_collisionsOnPreviousFrame; + + private IntPtr m_linkJoint = IntPtr.Zero; + + internal volatile bool childPrim; + + private ODEDynamics m_vehicle; + + internal int m_material = (int)Material.Wood; + + public OdePrim( + String primName, OdeScene parent_scene, Vector3 pos, Vector3 size, + Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) + { + Name = primName; + m_vehicle = new ODEDynamics(); + //gc = GCHandle.Alloc(prim_geom, GCHandleType.Pinned); + + if (!pos.IsFinite()) + { + pos = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), + parent_scene.GetTerrainHeightAtXY(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f)) + 0.5f); + m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Position for {0}", Name); + } + _position = pos; + m_taintposition = pos; + PID_D = parent_scene.bodyPIDD; + PID_G = parent_scene.bodyPIDG; + m_density = parent_scene.geomDefaultDensity; + // m_tensor = parent_scene.bodyMotorJointMaxforceTensor; + body_autodisable_frames = parent_scene.bodyFramesAutoDisable; + + prim_geom = IntPtr.Zero; + + if (!pos.IsFinite()) + { + size = new Vector3(0.5f, 0.5f, 0.5f); + m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Size for {0}", Name); + } + + if (size.X <= 0) size.X = 0.01f; + if (size.Y <= 0) size.Y = 0.01f; + if (size.Z <= 0) size.Z = 0.01f; + + _size = size; + m_taintsize = _size; + + if (!QuaternionIsFinite(rotation)) + { + rotation = Quaternion.Identity; + m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Rotation for {0}", Name); + } + + _orientation = rotation; + m_taintrot = _orientation; + _pbs = pbs; + + _parent_scene = parent_scene; + m_targetSpace = (IntPtr)0; + + if (pos.Z < 0) + { + IsPhysical = false; + } + else + { + IsPhysical = pisPhysical; + // If we're physical, we need to be in the master space for now. + // linksets *should* be in a space together.. but are not currently + if (IsPhysical) + m_targetSpace = _parent_scene.space; + } + + m_taintadd = true; + m_assetFailed = false; + _parent_scene.AddPhysicsActorTaint(this); + } + + public override int PhysicsActorType + { + get { return (int) ActorTypes.Prim; } + set { return; } + } + + public override bool SetAlwaysRun + { + get { return false; } + set { return; } + } + + public override bool Grabbed + { + set { return; } + } + + public override bool Selected + { + set + { + // This only makes the object not collidable if the object + // is physical or the object is modified somehow *IN THE FUTURE* + // without this, if an avatar selects prim, they can walk right + // through it while it's selected + m_collisionscore = 0; + + if ((IsPhysical && !_zeroFlag) || !value) + { + m_taintselected = value; + _parent_scene.AddPhysicsActorTaint(this); + } + else + { + m_taintselected = value; + m_isSelected = value; + } + + if (m_isSelected) + disableBodySoft(); + } + } + + /// + /// Set a new geometry for this prim. + /// + /// + private void SetGeom(IntPtr geom) + { + prim_geom = geom; +//Console.WriteLine("SetGeom to " + prim_geom + " for " + Name); + + if (m_assetFailed) + { + d.GeomSetCategoryBits(prim_geom, 0); + d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits); + } + else + { + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + } + + _parent_scene.geom_name_map[prim_geom] = Name; + _parent_scene.actor_name_map[prim_geom] = this; + + if (childPrim) + { + if (_parent != null && _parent is OdePrim) + { + OdePrim parent = (OdePrim)_parent; +//Console.WriteLine("SetGeom calls ChildSetGeom"); + parent.ChildSetGeom(this); + } + } + //m_log.Warn("Setting Geom to: " + prim_geom); + } + + private void enableBodySoft() + { + if (!childPrim) + { + if (IsPhysical && Body != IntPtr.Zero) + { + d.BodyEnable(Body); + if (m_vehicle.Type != Vehicle.TYPE_NONE) + m_vehicle.Enable(Body, _parent_scene); + } + + m_disabled = false; + } + } + + private void disableBodySoft() + { + m_disabled = true; + + if (IsPhysical && Body != IntPtr.Zero) + { + d.BodyDisable(Body); + } + } + + /// + /// Make a prim subject to physics. + /// + private void enableBody() + { + // Don't enable this body if we're a child prim + // this should be taken care of in the parent function not here + if (!childPrim) + { + // Sets the geom to a body + Body = d.BodyCreate(_parent_scene.world); + + setMass(); + d.BodySetPosition(Body, _position.X, _position.Y, _position.Z); + d.Quaternion myrot = new d.Quaternion(); + myrot.X = _orientation.X; + myrot.Y = _orientation.Y; + myrot.Z = _orientation.Z; + myrot.W = _orientation.W; + d.BodySetQuaternion(Body, ref myrot); + d.GeomSetBody(prim_geom, Body); + + if (m_assetFailed) + { + d.GeomSetCategoryBits(prim_geom, 0); + d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits); + } + else + { + m_collisionCategories |= CollisionCategories.Body; + m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); + } + + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + + d.BodySetAutoDisableFlag(Body, true); + d.BodySetAutoDisableSteps(Body, body_autodisable_frames); + + // disconnect from world gravity so we can apply buoyancy + d.BodySetGravityMode (Body, false); + + m_interpenetrationcount = 0; + m_collisionscore = 0; + m_disabled = false; + + // The body doesn't already have a finite rotation mode set here + if ((!m_angularlock.ApproxEquals(Vector3.One, 0.0f)) && _parent == null) + { + createAMotor(m_angularlock); + } + if (m_vehicle.Type != Vehicle.TYPE_NONE) + { + m_vehicle.Enable(Body, _parent_scene); + } + + _parent_scene.ActivatePrim(this); + } + } + + #region Mass Calculation + + private float CalculateMass() + { + float volume = _size.X * _size.Y * _size.Z; // default + float tmp; + + float returnMass = 0; + float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; + float hollowVolume = hollowAmount * hollowAmount; + + switch (_pbs.ProfileShape) + { + case ProfileShape.Square: + // default box + + if (_pbs.PathCurve == (byte)Extrusion.Straight) + { + if (hollowAmount > 0.0) + { + switch (_pbs.HollowShape) + { + case HollowShape.Square: + case HollowShape.Same: + break; + + case HollowShape.Circle: + + hollowVolume *= 0.78539816339f; + break; + + case HollowShape.Triangle: + + hollowVolume *= (0.5f * .5f); + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + + else if (_pbs.PathCurve == (byte)Extrusion.Curve1) + { + //a tube + + volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); + tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); + volume -= volume*tmp*tmp; + + if (hollowAmount > 0.0) + { + hollowVolume *= hollowAmount; + + switch (_pbs.HollowShape) + { + case HollowShape.Square: + case HollowShape.Same: + break; + + case HollowShape.Circle: + hollowVolume *= 0.78539816339f;; + break; + + case HollowShape.Triangle: + hollowVolume *= 0.5f * 0.5f; + break; + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + + break; + + case ProfileShape.Circle: + + if (_pbs.PathCurve == (byte)Extrusion.Straight) + { + volume *= 0.78539816339f; // elipse base + + if (hollowAmount > 0.0) + { + switch (_pbs.HollowShape) + { + case HollowShape.Same: + case HollowShape.Circle: + break; + + case HollowShape.Square: + hollowVolume *= 0.5f * 2.5984480504799f; + break; + + case HollowShape.Triangle: + hollowVolume *= .5f * 1.27323954473516f; + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + + else if (_pbs.PathCurve == (byte)Extrusion.Curve1) + { + volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); + tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); + volume *= (1.0f - tmp * tmp); + + if (hollowAmount > 0.0) + { + + // calculate the hollow volume by it's shape compared to the prim shape + hollowVolume *= hollowAmount; + + switch (_pbs.HollowShape) + { + case HollowShape.Same: + case HollowShape.Circle: + break; + + case HollowShape.Square: + hollowVolume *= 0.5f * 2.5984480504799f; + break; + + case HollowShape.Triangle: + hollowVolume *= .5f * 1.27323954473516f; + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + break; + + case ProfileShape.HalfCircle: + if (_pbs.PathCurve == (byte)Extrusion.Curve1) + { + volume *= 0.52359877559829887307710723054658f; + } + break; + + case ProfileShape.EquilateralTriangle: + + if (_pbs.PathCurve == (byte)Extrusion.Straight) + { + volume *= 0.32475953f; + + if (hollowAmount > 0.0) + { + + // calculate the hollow volume by it's shape compared to the prim shape + switch (_pbs.HollowShape) + { + case HollowShape.Same: + case HollowShape.Triangle: + hollowVolume *= .25f; + break; + + case HollowShape.Square: + hollowVolume *= 0.499849f * 3.07920140172638f; + break; + + case HollowShape.Circle: + // Hollow shape is a perfect cyllinder in respect to the cube's scale + // Cyllinder hollow volume calculation + + hollowVolume *= 0.1963495f * 3.07920140172638f; + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + else if (_pbs.PathCurve == (byte)Extrusion.Curve1) + { + volume *= 0.32475953f; + volume *= 0.01f * (float)(200 - _pbs.PathScaleX); + tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); + volume *= (1.0f - tmp * tmp); + + if (hollowAmount > 0.0) + { + + hollowVolume *= hollowAmount; + + switch (_pbs.HollowShape) + { + case HollowShape.Same: + case HollowShape.Triangle: + hollowVolume *= .25f; + break; + + case HollowShape.Square: + hollowVolume *= 0.499849f * 3.07920140172638f; + break; + + case HollowShape.Circle: + + hollowVolume *= 0.1963495f * 3.07920140172638f; + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + break; + + default: + break; + } + + float taperX1; + float taperY1; + float taperX; + float taperY; + float pathBegin; + float pathEnd; + float profileBegin; + float profileEnd; + + if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) + { + taperX1 = _pbs.PathScaleX * 0.01f; + if (taperX1 > 1.0f) + taperX1 = 2.0f - taperX1; + taperX = 1.0f - taperX1; + + taperY1 = _pbs.PathScaleY * 0.01f; + if (taperY1 > 1.0f) + taperY1 = 2.0f - taperY1; + taperY = 1.0f - taperY1; + } + else + { + taperX = _pbs.PathTaperX * 0.01f; + if (taperX < 0.0f) + taperX = -taperX; + taperX1 = 1.0f - taperX; + + taperY = _pbs.PathTaperY * 0.01f; + if (taperY < 0.0f) + taperY = -taperY; + taperY1 = 1.0f - taperY; + } + + volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); + + pathBegin = (float)_pbs.PathBegin * 2.0e-5f; + pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f; + volume *= (pathEnd - pathBegin); + +// this is crude aproximation + profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f; + profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f; + volume *= (profileEnd - profileBegin); + + returnMass = m_density * volume; + + if (returnMass <= 0) + returnMass = 0.0001f;//ckrinke: Mass must be greater then zero. +// else if (returnMass > _parent_scene.maximumMassObject) +// returnMass = _parent_scene.maximumMassObject; + + // Recursively calculate mass + bool HasChildPrim = false; + lock (childrenPrim) + { + if (childrenPrim.Count > 0) + { + HasChildPrim = true; + } + } + + if (HasChildPrim) + { + OdePrim[] childPrimArr = new OdePrim[0]; + + lock (childrenPrim) + childPrimArr = childrenPrim.ToArray(); + + for (int i = 0; i < childPrimArr.Length; i++) + { + if (childPrimArr[i] != null && !childPrimArr[i].m_taintremove) + returnMass += childPrimArr[i].CalculateMass(); + // failsafe, this shouldn't happen but with OpenSim, you never know :) + if (i > 256) + break; + } + } + + if (returnMass > _parent_scene.maximumMassObject) + returnMass = _parent_scene.maximumMassObject; + + return returnMass; + } + + #endregion + + private void setMass() + { + if (Body != (IntPtr) 0) + { + float newmass = CalculateMass(); + + //m_log.Info("[PHYSICS]: New Mass: " + newmass.ToString()); + + d.MassSetBoxTotal(out pMass, newmass, _size.X, _size.Y, _size.Z); + d.BodySetMass(Body, ref pMass); + } + } + + private void setAngularVelocity(float x, float y, float z) + { + if (Body != (IntPtr)0) + { + d.BodySetAngularVel(Body, x, y, z); + } + } + + /// + /// Stop a prim from being subject to physics. + /// + internal void disableBody() + { + //this kills the body so things like 'mesh' can re-create it. + lock (this) + { + if (!childPrim) + { + if (Body != IntPtr.Zero) + { + _parent_scene.DeactivatePrim(this); + m_collisionCategories &= ~CollisionCategories.Body; + m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); + + if (m_assetFailed) + { + d.GeomSetCategoryBits(prim_geom, 0); + d.GeomSetCollideBits(prim_geom, 0); + } + else + { + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + } + + d.BodyDestroy(Body); + lock (childrenPrim) + { + if (childrenPrim.Count > 0) + { + foreach (OdePrim prm in childrenPrim) + { + _parent_scene.DeactivatePrim(prm); + prm.Body = IntPtr.Zero; + } + } + } + Body = IntPtr.Zero; + } + } + else + { + _parent_scene.DeactivatePrim(this); + + m_collisionCategories &= ~CollisionCategories.Body; + m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); + + if (m_assetFailed) + { + d.GeomSetCategoryBits(prim_geom, 0); + d.GeomSetCollideBits(prim_geom, 0); + } + else + { + + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + } + + Body = IntPtr.Zero; + } + } + + m_disabled = true; + m_collisionscore = 0; + } + + private static Dictionary m_MeshToTriMeshMap = new Dictionary(); + + private void setMesh(OdeScene parent_scene, IMesh mesh) + { +// m_log.DebugFormat("[ODE PRIM]: Setting mesh on {0} to {1}", Name, mesh); + + // This sleeper is there to moderate how long it takes between + // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object + + //Thread.Sleep(10); + + //Kill Body so that mesh can re-make the geom + if (IsPhysical && Body != IntPtr.Zero) + { + if (childPrim) + { + if (_parent != null) + { + OdePrim parent = (OdePrim)_parent; + parent.ChildDelink(this); + } + } + else + { + disableBody(); + } + } + + IntPtr vertices, indices; + int vertexCount, indexCount; + int vertexStride, triStride; + mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap + mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage + m_expectedCollisionContacts = indexCount; + mesh.releaseSourceMeshData(); // free up the original mesh data to save memory + + // We must lock here since m_MeshToTriMeshMap is static and multiple scene threads may call this method at + // the same time. + lock (m_MeshToTriMeshMap) + { + if (m_MeshToTriMeshMap.ContainsKey(mesh)) + { + _triMeshData = m_MeshToTriMeshMap[mesh]; + } + else + { + _triMeshData = d.GeomTriMeshDataCreate(); + + d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride); + d.GeomTriMeshDataPreprocess(_triMeshData); + m_MeshToTriMeshMap[mesh] = _triMeshData; + } + } + +// _parent_scene.waitForSpaceUnlock(m_targetSpace); + try + { + SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null)); + } + catch (AccessViolationException) + { + m_log.ErrorFormat("[PHYSICS]: MESH LOCKED FOR {0}", Name); + return; + } + + // if (IsPhysical && Body == (IntPtr) 0) + // { + // Recreate the body + // m_interpenetrationcount = 0; + // m_collisionscore = 0; + + // enableBody(); + // } + } + + internal void ProcessTaints() + { +#if SPAM +Console.WriteLine("ZProcessTaints for " + Name); +#endif + + // This must be processed as the very first taint so that later operations have a prim_geom to work with + // if this is a new prim. + if (m_taintadd) + changeadd(); + + if (!_position.ApproxEquals(m_taintposition, 0f)) + changemove(); + + if (m_taintrot != _orientation) + { + if (childPrim && IsPhysical) // For physical child prim... + { + rotate(); + // KF: ODE will also rotate the parent prim! + // so rotate the root back to where it was + OdePrim parent = (OdePrim)_parent; + parent.rotate(); + } + else + { + //Just rotate the prim + rotate(); + } + } + + if (m_taintPhysics != IsPhysical && !(m_taintparent != _parent)) + changePhysicsStatus(); + + if (!_size.ApproxEquals(m_taintsize, 0f)) + changesize(); + + if (m_taintshape) + changeshape(); + + if (m_taintforce) + changeAddForce(); + + if (m_taintaddangularforce) + changeAddAngularForce(); + + if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f)) + changeSetTorque(); + + if (m_taintdisable) + changedisable(); + + if (m_taintselected != m_isSelected) + changeSelectedStatus(); + + if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f)) + changevelocity(); + + if (m_taintparent != _parent) + changelink(); + + if (m_taintCollidesWater != m_collidesWater) + changefloatonwater(); + + if (!m_angularlock.ApproxEquals(m_taintAngularLock,0f)) + changeAngularLock(); + } + + /// + /// Change prim in response to an angular lock taint. + /// + private void changeAngularLock() + { + // do we have a Physical object? + if (Body != IntPtr.Zero) + { + //Check that we have a Parent + //If we have a parent then we're not authorative here + if (_parent == null) + { + if (!m_taintAngularLock.ApproxEquals(Vector3.One, 0f)) + { + //d.BodySetFiniteRotationMode(Body, 0); + //d.BodySetFiniteRotationAxis(Body,m_taintAngularLock.X,m_taintAngularLock.Y,m_taintAngularLock.Z); + createAMotor(m_taintAngularLock); + } + else + { + if (Amotor != IntPtr.Zero) + { + d.JointDestroy(Amotor); + Amotor = IntPtr.Zero; + } + } + } + } + + // Store this for later in case we get turned into a separate body + m_angularlock = m_taintAngularLock; + } + + /// + /// Change prim in response to a link taint. + /// + private void changelink() + { + // If the newly set parent is not null + // create link + if (_parent == null && m_taintparent != null) + { + if (m_taintparent.PhysicsActorType == (int)ActorTypes.Prim) + { + OdePrim obj = (OdePrim)m_taintparent; + //obj.disableBody(); +//Console.WriteLine("changelink calls ParentPrim"); + obj.AddChildPrim(this); + + /* + if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body) + { + _linkJointGroup = d.JointGroupCreate(0); + m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup); + d.JointAttach(m_linkJoint, obj.Body, Body); + d.JointSetFixed(m_linkJoint); + } + */ + } + } + // If the newly set parent is null + // destroy link + else if (_parent != null && m_taintparent == null) + { +//Console.WriteLine(" changelink B"); + + if (_parent is OdePrim) + { + OdePrim obj = (OdePrim)_parent; + obj.ChildDelink(this); + childPrim = false; + //_parent = null; + } + + /* + if (Body != (IntPtr)0 && _linkJointGroup != (IntPtr)0) + d.JointGroupDestroy(_linkJointGroup); + + _linkJointGroup = (IntPtr)0; + m_linkJoint = (IntPtr)0; + */ + } + + _parent = m_taintparent; + m_taintPhysics = IsPhysical; + } + + /// + /// Add a child prim to this parent prim. + /// + /// Child prim + private void AddChildPrim(OdePrim prim) + { + if (LocalID == prim.LocalID) + return; + + if (Body == IntPtr.Zero) + { + Body = d.BodyCreate(_parent_scene.world); + setMass(); + } + + lock (childrenPrim) + { + if (childrenPrim.Contains(prim)) + return; + +// m_log.DebugFormat( +// "[ODE PRIM]: Linking prim {0} {1} to {2} {3}", prim.Name, prim.LocalID, Name, LocalID); + + childrenPrim.Add(prim); + + foreach (OdePrim prm in childrenPrim) + { + d.Mass m2; + d.MassSetZero(out m2); + d.MassSetBoxTotal(out m2, prm.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z); + + d.Quaternion quat = new d.Quaternion(); + quat.W = prm._orientation.W; + quat.X = prm._orientation.X; + quat.Y = prm._orientation.Y; + quat.Z = prm._orientation.Z; + + d.Matrix3 mat = new d.Matrix3(); + d.RfromQ(out mat, ref quat); + d.MassRotate(ref m2, ref mat); + d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z); + d.MassAdd(ref pMass, ref m2); + } + + foreach (OdePrim prm in childrenPrim) + { + prm.m_collisionCategories |= CollisionCategories.Body; + prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); + +//Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + Name); + if (prm.m_assetFailed) + { + d.GeomSetCategoryBits(prm.prim_geom, 0); + d.GeomSetCollideBits(prm.prim_geom, prm.BadMeshAssetCollideBits); + } + else + { + d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories); + d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags); + } + + d.Quaternion quat = new d.Quaternion(); + quat.W = prm._orientation.W; + quat.X = prm._orientation.X; + quat.Y = prm._orientation.Y; + quat.Z = prm._orientation.Z; + + d.Matrix3 mat = new d.Matrix3(); + d.RfromQ(out mat, ref quat); + if (Body != IntPtr.Zero) + { + d.GeomSetBody(prm.prim_geom, Body); + prm.childPrim = true; + d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z); + //d.GeomSetOffsetPosition(prim.prim_geom, + // (Position.X - prm.Position.X) - pMass.c.X, + // (Position.Y - prm.Position.Y) - pMass.c.Y, + // (Position.Z - prm.Position.Z) - pMass.c.Z); + d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat); + //d.GeomSetOffsetRotation(prm.prim_geom, ref mat); + d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); + d.BodySetMass(Body, ref pMass); + } + else + { + m_log.DebugFormat("[PHYSICS]: {0} ain't got no boooooooooddy, no body", Name); + } + + prm.m_interpenetrationcount = 0; + prm.m_collisionscore = 0; + prm.m_disabled = false; + + prm.Body = Body; + _parent_scene.ActivatePrim(prm); + } + + m_collisionCategories |= CollisionCategories.Body; + m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); + + if (m_assetFailed) + { + d.GeomSetCategoryBits(prim_geom, 0); + d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits); + } + else + { + //Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + Name); + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + //Console.WriteLine(" Post GeomSetCategoryBits 2"); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + } + + d.Quaternion quat2 = new d.Quaternion(); + quat2.W = _orientation.W; + quat2.X = _orientation.X; + quat2.Y = _orientation.Y; + quat2.Z = _orientation.Z; + + d.Matrix3 mat2 = new d.Matrix3(); + d.RfromQ(out mat2, ref quat2); + d.GeomSetBody(prim_geom, Body); + d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z); + //d.GeomSetOffsetPosition(prim.prim_geom, + // (Position.X - prm.Position.X) - pMass.c.X, + // (Position.Y - prm.Position.Y) - pMass.c.Y, + // (Position.Z - prm.Position.Z) - pMass.c.Z); + //d.GeomSetOffsetRotation(prim_geom, ref mat2); + d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); + d.BodySetMass(Body, ref pMass); + + d.BodySetAutoDisableFlag(Body, true); + d.BodySetAutoDisableSteps(Body, body_autodisable_frames); + + m_interpenetrationcount = 0; + m_collisionscore = 0; + m_disabled = false; + + // The body doesn't already have a finite rotation mode set here + if ((!m_angularlock.ApproxEquals(Vector3.One, 0f)) && _parent == null) + { + createAMotor(m_angularlock); + } + + d.BodySetPosition(Body, Position.X, Position.Y, Position.Z); + + if (m_vehicle.Type != Vehicle.TYPE_NONE) + m_vehicle.Enable(Body, _parent_scene); + + _parent_scene.ActivatePrim(this); + } + } + + private void ChildSetGeom(OdePrim odePrim) + { +// m_log.DebugFormat( +// "[ODE PRIM]: ChildSetGeom {0} {1} for {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID); + + //if (IsPhysical && Body != IntPtr.Zero) + lock (childrenPrim) + { + foreach (OdePrim prm in childrenPrim) + { + //prm.childPrim = true; + prm.disableBody(); + //prm.m_taintparent = null; + //prm._parent = null; + //prm.m_taintPhysics = false; + //prm.m_disabled = true; + //prm.childPrim = false; + } + } + + disableBody(); + + // Spurious - Body == IntPtr.Zero after disableBody() +// if (Body != IntPtr.Zero) +// { +// _parent_scene.DeactivatePrim(this); +// } + + lock (childrenPrim) + { + foreach (OdePrim prm in childrenPrim) + { +//Console.WriteLine("ChildSetGeom calls ParentPrim"); + AddChildPrim(prm); + } + } + } + + private void ChildDelink(OdePrim odePrim) + { +// m_log.DebugFormat( +// "[ODE PRIM]: Delinking prim {0} {1} from {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID); + + // Okay, we have a delinked child.. need to rebuild the body. + lock (childrenPrim) + { + foreach (OdePrim prm in childrenPrim) + { + prm.childPrim = true; + prm.disableBody(); + //prm.m_taintparent = null; + //prm._parent = null; + //prm.m_taintPhysics = false; + //prm.m_disabled = true; + //prm.childPrim = false; + } + } + + disableBody(); + + lock (childrenPrim) + { + //Console.WriteLine("childrenPrim.Remove " + odePrim); + childrenPrim.Remove(odePrim); + } + + // Spurious - Body == IntPtr.Zero after disableBody() +// if (Body != IntPtr.Zero) +// { +// _parent_scene.DeactivatePrim(this); +// } + + lock (childrenPrim) + { + foreach (OdePrim prm in childrenPrim) + { +//Console.WriteLine("ChildDelink calls ParentPrim"); + AddChildPrim(prm); + } + } + } + + /// + /// Change prim in response to a selection taint. + /// + private void changeSelectedStatus() + { + if (m_taintselected) + { + m_collisionCategories = CollisionCategories.Selected; + m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space); + + // We do the body disable soft twice because 'in theory' a collision could have happened + // in between the disabling and the collision properties setting + // which would wake the physical body up from a soft disabling and potentially cause it to fall + // through the ground. + + // NOTE FOR JOINTS: this doesn't always work for jointed assemblies because if you select + // just one part of the assembly, the rest of the assembly is non-selected and still simulating, + // so that causes the selected part to wake up and continue moving. + + // even if you select all parts of a jointed assembly, it is not guaranteed that the entire + // assembly will stop simulating during the selection, because of the lack of atomicity + // of select operations (their processing could be interrupted by a thread switch, causing + // simulation to continue before all of the selected object notifications trickle down to + // the physics engine). + + // e.g. we select 100 prims that are connected by joints. non-atomically, the first 50 are + // selected and disabled. then, due to a thread switch, the selection processing is + // interrupted and the physics engine continues to simulate, so the last 50 items, whose + // selection was not yet processed, continues to simulate. this wakes up ALL of the + // first 50 again. then the last 50 are disabled. then the first 50, which were just woken + // up, start simulating again, which in turn wakes up the last 50. + + if (IsPhysical) + { + disableBodySoft(); + } + + if (m_assetFailed) + { + d.GeomSetCategoryBits(prim_geom, 0); + d.GeomSetCollideBits(prim_geom, 0); + } + else + { + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + } + + if (IsPhysical) + { + disableBodySoft(); + } + } + else + { + m_collisionCategories = CollisionCategories.Geom; + + if (IsPhysical) + m_collisionCategories |= CollisionCategories.Body; + + m_collisionFlags = m_default_collisionFlags; + + if (m_collidesLand) + m_collisionFlags |= CollisionCategories.Land; + if (m_collidesWater) + m_collisionFlags |= CollisionCategories.Water; + + if (m_assetFailed) + { + d.GeomSetCategoryBits(prim_geom, 0); + d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits); + } + else + { + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + } + + if (IsPhysical) + { + if (Body != IntPtr.Zero) + { + d.BodySetLinearVel(Body, 0f, 0f, 0f); + d.BodySetForce(Body, 0, 0, 0); + enableBodySoft(); + } + } + } + + resetCollisionAccounting(); + m_isSelected = m_taintselected; + }//end changeSelectedStatus + + internal void ResetTaints() + { + m_taintposition = _position; + m_taintrot = _orientation; + m_taintPhysics = IsPhysical; + m_taintselected = m_isSelected; + m_taintsize = _size; + m_taintshape = false; + m_taintforce = false; + m_taintdisable = false; + m_taintVelocity = Vector3.Zero; + } + + /// + /// Create a geometry for the given mesh in the given target space. + /// + /// + /// If null, then a mesh is used that is based on the profile shape data. + private void CreateGeom(IntPtr m_targetSpace, IMesh mesh) + { +#if SPAM +Console.WriteLine("CreateGeom:"); +#endif + if (mesh != null) + { + setMesh(_parent_scene, mesh); + } + else + { + if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) + { + if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) + { + if (((_size.X / 2f) > 0f)) + { +// _parent_scene.waitForSpaceUnlock(m_targetSpace); + try + { +//Console.WriteLine(" CreateGeom 1"); + SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2)); + m_expectedCollisionContacts = 3; + } + catch (AccessViolationException) + { + m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name); + return; + } + } + else + { +// _parent_scene.waitForSpaceUnlock(m_targetSpace); + try + { +//Console.WriteLine(" CreateGeom 2"); + SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); + m_expectedCollisionContacts = 4; + } + catch (AccessViolationException) + { + m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name); + return; + } + } + } + else + { +// _parent_scene.waitForSpaceUnlock(m_targetSpace); + try + { +//Console.WriteLine(" CreateGeom 3"); + SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); + m_expectedCollisionContacts = 4; + } + catch (AccessViolationException) + { + m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name); + return; + } + } + } + else + { +// _parent_scene.waitForSpaceUnlock(m_targetSpace); + try + { +//Console.WriteLine(" CreateGeom 4"); + SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); + m_expectedCollisionContacts = 4; + } + catch (AccessViolationException) + { + m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name); + return; + } + } + } + } + + /// + /// Remove the existing geom from this prim. + /// + /// + /// If null, then a mesh is used that is based on the profile shape data. + /// true if the geom was successfully removed, false if it was already gone or the remove failed. + internal bool RemoveGeom() + { + if (prim_geom != IntPtr.Zero) + { + try + { + _parent_scene.geom_name_map.Remove(prim_geom); + _parent_scene.actor_name_map.Remove(prim_geom); + d.GeomDestroy(prim_geom); + m_expectedCollisionContacts = 0; + prim_geom = IntPtr.Zero; + } + catch (System.AccessViolationException) + { + prim_geom = IntPtr.Zero; + m_expectedCollisionContacts = 0; + m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name); + + return false; + } + + return true; + } + else + { + m_log.WarnFormat( + "[ODE PRIM]: Called RemoveGeom() on {0} {1} where geometry was already null.", Name, LocalID); + + return false; + } + } + /// + /// Add prim in response to an add taint. + /// + private void changeadd() + { +// m_log.DebugFormat("[ODE PRIM]: Adding prim {0}", Name); + + int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position); + IntPtr targetspace = _parent_scene.calculateSpaceForGeom(_position); + + if (targetspace == IntPtr.Zero) + targetspace = _parent_scene.createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]); + + m_targetSpace = targetspace; + + IMesh mesh = null; + + if (_parent_scene.needsMeshing(_pbs)) + { + // Don't need to re-enable body.. it's done in SetMesh + mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical); + // createmesh returns null when it's a shape that isn't a cube. + // m_log.Debug(m_localID); + if (mesh == null) + CheckMeshAsset(); + else + m_assetFailed = false; + } + +#if SPAM +Console.WriteLine("changeadd 1"); +#endif + CreateGeom(m_targetSpace, mesh); + + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + d.Quaternion myrot = new d.Quaternion(); + myrot.X = _orientation.X; + myrot.Y = _orientation.Y; + myrot.Z = _orientation.Z; + myrot.W = _orientation.W; + d.GeomSetQuaternion(prim_geom, ref myrot); + + if (IsPhysical && Body == IntPtr.Zero) + enableBody(); + + changeSelectedStatus(); + + m_taintadd = false; + } + + /// + /// Move prim in response to a move taint. + /// + private void changemove() + { + if (IsPhysical) + { + if (!m_disabled && !m_taintremove && !childPrim) + { + if (Body == IntPtr.Zero) + enableBody(); + + //Prim auto disable after 20 frames, + //if you move it, re-enable the prim manually. + if (_parent != null) + { + if (m_linkJoint != IntPtr.Zero) + { + d.JointDestroy(m_linkJoint); + m_linkJoint = IntPtr.Zero; + } + } + + if (Body != IntPtr.Zero) + { + d.BodySetPosition(Body, _position.X, _position.Y, _position.Z); + + if (_parent != null) + { + OdePrim odParent = (OdePrim)_parent; + if (Body != (IntPtr)0 && odParent.Body != (IntPtr)0 && Body != odParent.Body) + { +// KF: Fixed Joints were removed? Anyway - this Console.WriteLine does not show up, so routine is not used?? +Console.WriteLine(" JointCreateFixed"); + m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup); + d.JointAttach(m_linkJoint, Body, odParent.Body); + d.JointSetFixed(m_linkJoint); + } + } + d.BodyEnable(Body); + if (m_vehicle.Type != Vehicle.TYPE_NONE) + { + m_vehicle.Enable(Body, _parent_scene); + } + } + else + { + m_log.WarnFormat("[PHYSICS]: Body for {0} still null after enableBody(). This is a crash scenario.", Name); + } + } + //else + // { + //m_log.Debug("[BUG]: race!"); + //} + } + + // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position); + // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position); +// _parent_scene.waitForSpaceUnlock(m_targetSpace); + + IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace); + m_targetSpace = tempspace; + +// _parent_scene.waitForSpaceUnlock(m_targetSpace); + + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + +// _parent_scene.waitForSpaceUnlock(m_targetSpace); + d.SpaceAdd(m_targetSpace, prim_geom); + + changeSelectedStatus(); + + resetCollisionAccounting(); + m_taintposition = _position; + } + + internal void Move(float timestep) + { + float fx = 0; + float fy = 0; + float fz = 0; + + if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // KF: Only move root prims. + { + if (m_vehicle.Type != Vehicle.TYPE_NONE) + { + // 'VEHICLES' are dealt with in ODEDynamics.cs + m_vehicle.Step(timestep, _parent_scene); + } + else + { +//Console.WriteLine("Move " + Name); + if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009 + // NON-'VEHICLES' are dealt with here +// if (d.BodyIsEnabled(Body) && !m_angularlock.ApproxEquals(Vector3.Zero, 0.003f)) +// { +// d.Vector3 avel2 = d.BodyGetAngularVel(Body); +// /* +// if (m_angularlock.X == 1) +// avel2.X = 0; +// if (m_angularlock.Y == 1) +// avel2.Y = 0; +// if (m_angularlock.Z == 1) +// avel2.Z = 0; +// d.BodySetAngularVel(Body, avel2.X, avel2.Y, avel2.Z); +// */ +// } + //float PID_P = 900.0f; + + float m_mass = CalculateMass(); + +// fz = 0f; + //m_log.Info(m_collisionFlags.ToString()); + + + //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle. + // would come from SceneObjectPart.cs, public void SetBuoyancy(float fvalue) , PhysActor.Buoyancy = fvalue; ?? + // m_buoyancy: (unlimited value) <0=Falls fast; 0=1g; 1=0g; >1 = floats up + // gravityz multiplier = 1 - m_buoyancy + fz = _parent_scene.gravityz * (1.0f - m_buoyancy) * m_mass; + + if (PIDActive) + { +//Console.WriteLine("PID " + Name); + // KF - this is for object move? eg. llSetPos() ? + //if (!d.BodyIsEnabled(Body)) + //d.BodySetForce(Body, 0f, 0f, 0f); + // If we're using the PID controller, then we have no gravity + //fz = (-1 * _parent_scene.gravityz) * m_mass; //KF: ?? Prims have no global gravity,so simply... + fz = 0f; + + // no lock; for now it's only called from within Simulate() + + // If the PID Controller isn't active then we set our force + // calculating base velocity to the current position + + if ((m_PIDTau < 1) && (m_PIDTau != 0)) + { + //PID_G = PID_G / m_PIDTau; + m_PIDTau = 1; + } + + if ((PID_G - m_PIDTau) <= 0) + { + PID_G = m_PIDTau + 1; + } + //PidStatus = true; + + // PhysicsVector vec = new PhysicsVector(); + d.Vector3 vel = d.BodyGetLinearVel(Body); + + d.Vector3 pos = d.BodyGetPosition(Body); + _target_velocity = + new Vector3( + (m_PIDTarget.X - pos.X) * ((PID_G - m_PIDTau) * timestep), + (m_PIDTarget.Y - pos.Y) * ((PID_G - m_PIDTau) * timestep), + (m_PIDTarget.Z - pos.Z) * ((PID_G - m_PIDTau) * timestep) + ); + + // if velocity is zero, use position control; otherwise, velocity control + + if (_target_velocity.ApproxEquals(Vector3.Zero,0.1f)) + { + // keep track of where we stopped. No more slippin' & slidin' + + // We only want to deactivate the PID Controller if we think we want to have our surrogate + // react to the physics scene by moving it's position. + // Avatar to Avatar collisions + // Prim to avatar collisions + + //fx = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2); + //fy = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2); + //fz = fz + (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P; + d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z); + d.BodySetLinearVel(Body, 0, 0, 0); + d.BodyAddForce(Body, 0, 0, fz); + return; + } + else + { + _zeroFlag = false; + + // We're flying and colliding with something + fx = ((_target_velocity.X) - vel.X) * (PID_D); + fy = ((_target_velocity.Y) - vel.Y) * (PID_D); + + // vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P; + + fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass); + } + } // end if (PIDActive) + + // Hover PID Controller needs to be mutually exlusive to MoveTo PID controller + if (m_useHoverPID && !PIDActive) + { +//Console.WriteLine("Hover " + Name); + + // If we're using the PID controller, then we have no gravity + fz = (-1 * _parent_scene.gravityz) * m_mass; + + // no lock; for now it's only called from within Simulate() + + // If the PID Controller isn't active then we set our force + // calculating base velocity to the current position + + if ((m_PIDTau < 1)) + { + PID_G = PID_G / m_PIDTau; + } + + if ((PID_G - m_PIDTau) <= 0) + { + PID_G = m_PIDTau + 1; + } + + // Where are we, and where are we headed? + d.Vector3 pos = d.BodyGetPosition(Body); + d.Vector3 vel = d.BodyGetLinearVel(Body); + + // Non-Vehicles have a limited set of Hover options. + // determine what our target height really is based on HoverType + switch (m_PIDHoverType) + { + case PIDHoverType.Ground: + m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y); + m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight; + break; + case PIDHoverType.GroundAndWater: + m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y); + m_waterHeight = _parent_scene.GetWaterLevel(); + if (m_groundHeight > m_waterHeight) + { + m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight; + } + else + { + m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight; + } + break; + + } // end switch (m_PIDHoverType) + + + _target_velocity = + new Vector3(0.0f, 0.0f, + (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep) + ); + + // if velocity is zero, use position control; otherwise, velocity control + + if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f)) + { + // keep track of where we stopped. No more slippin' & slidin' + + // We only want to deactivate the PID Controller if we think we want to have our surrogate + // react to the physics scene by moving it's position. + // Avatar to Avatar collisions + // Prim to avatar collisions + + d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight); + d.BodySetLinearVel(Body, vel.X, vel.Y, 0); + d.BodyAddForce(Body, 0, 0, fz); + return; + } + else + { + _zeroFlag = false; + + // We're flying and colliding with something + fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass); + } + } + + fx *= m_mass; + fy *= m_mass; + //fz *= m_mass; + + fx += m_force.X; + fy += m_force.Y; + fz += m_force.Z; + + //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString()); + if (fx != 0 || fy != 0 || fz != 0) + { + //m_taintdisable = true; + //base.RaiseOutOfBounds(Position); + //d.BodySetLinearVel(Body, fx, fy, 0f); + if (!d.BodyIsEnabled(Body)) + { + // A physical body at rest on a surface will auto-disable after a while, + // this appears to re-enable it incase the surface it is upon vanishes, + // and the body should fall again. + d.BodySetLinearVel(Body, 0f, 0f, 0f); + d.BodySetForce(Body, 0, 0, 0); + enableBodySoft(); + } + + // 35x10 = 350n times the mass per second applied maximum. + float nmax = 35f * m_mass; + float nmin = -35f * m_mass; + + if (fx > nmax) + fx = nmax; + if (fx < nmin) + fx = nmin; + if (fy > nmax) + fy = nmax; + if (fy < nmin) + fy = nmin; + d.BodyAddForce(Body, fx, fy, fz); +//Console.WriteLine("AddForce " + fx + "," + fy + "," + fz); + } + } + } + else + { // is not physical, or is not a body or is selected + // _zeroPosition = d.BodyGetPosition(Body); + return; +//Console.WriteLine("Nothing " + Name); + + } + } + + private void rotate() + { + d.Quaternion myrot = new d.Quaternion(); + myrot.X = _orientation.X; + myrot.Y = _orientation.Y; + myrot.Z = _orientation.Z; + myrot.W = _orientation.W; + if (Body != IntPtr.Zero) + { + // KF: If this is a root prim do BodySet + d.BodySetQuaternion(Body, ref myrot); + if (IsPhysical) + { + if (!m_angularlock.ApproxEquals(Vector3.One, 0f)) + createAMotor(m_angularlock); + } + } + else + { + // daughter prim, do Geom set + d.GeomSetQuaternion(prim_geom, ref myrot); + } + + resetCollisionAccounting(); + m_taintrot = _orientation; + } + + private void resetCollisionAccounting() + { + m_collisionscore = 0; + m_interpenetrationcount = 0; + m_disabled = false; + } + + /// + /// Change prim in response to a disable taint. + /// + private void changedisable() + { + m_disabled = true; + if (Body != IntPtr.Zero) + { + d.BodyDisable(Body); + Body = IntPtr.Zero; + } + + m_taintdisable = false; + } + + /// + /// Change prim in response to a physics status taint + /// + private void changePhysicsStatus() + { + if (IsPhysical) + { + if (Body == IntPtr.Zero) + { + if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim) + { + changeshape(); + } + else + { + enableBody(); + } + } + } + else + { + if (Body != IntPtr.Zero) + { + if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim) + { + RemoveGeom(); + +//Console.WriteLine("changePhysicsStatus for " + Name); + changeadd(); + } + + if (childPrim) + { + if (_parent != null) + { + OdePrim parent = (OdePrim)_parent; + parent.ChildDelink(this); + } + } + else + { + disableBody(); + } + } + } + + changeSelectedStatus(); + + resetCollisionAccounting(); + m_taintPhysics = IsPhysical; + } + + /// + /// Change prim in response to a size taint. + /// + private void changesize() + { +#if SPAM + m_log.DebugFormat("[ODE PRIM]: Called changesize"); +#endif + + if (_size.X <= 0) _size.X = 0.01f; + if (_size.Y <= 0) _size.Y = 0.01f; + if (_size.Z <= 0) _size.Z = 0.01f; + + //kill body to rebuild + if (IsPhysical && Body != IntPtr.Zero) + { + if (childPrim) + { + if (_parent != null) + { + OdePrim parent = (OdePrim)_parent; + parent.ChildDelink(this); + } + } + else + { + disableBody(); + } + } + + if (d.SpaceQuery(m_targetSpace, prim_geom)) + { +// _parent_scene.waitForSpaceUnlock(m_targetSpace); + d.SpaceRemove(m_targetSpace, prim_geom); + } + + RemoveGeom(); + + // we don't need to do space calculation because the client sends a position update also. + + IMesh mesh = null; + + // Construction of new prim + if (_parent_scene.needsMeshing(_pbs)) + { + float meshlod = _parent_scene.meshSculptLOD; + + if (IsPhysical) + meshlod = _parent_scene.MeshSculptphysicalLOD; + // Don't need to re-enable body.. it's done in SetMesh + + if (_parent_scene.needsMeshing(_pbs)) + { + mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical); + if (mesh == null) + CheckMeshAsset(); + else + m_assetFailed = false; + } + + } + + CreateGeom(m_targetSpace, mesh); + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + d.Quaternion myrot = new d.Quaternion(); + myrot.X = _orientation.X; + myrot.Y = _orientation.Y; + myrot.Z = _orientation.Z; + myrot.W = _orientation.W; + d.GeomSetQuaternion(prim_geom, ref myrot); + + //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z); + if (IsPhysical && Body == IntPtr.Zero && !childPrim) + { + // Re creates body on size. + // EnableBody also does setMass() + enableBody(); + d.BodyEnable(Body); + } + + changeSelectedStatus(); + + if (childPrim) + { + if (_parent is OdePrim) + { + OdePrim parent = (OdePrim)_parent; + parent.ChildSetGeom(this); + } + } + resetCollisionAccounting(); + m_taintsize = _size; + } + + /// + /// Change prim in response to a float on water taint. + /// + /// + private void changefloatonwater() + { + m_collidesWater = m_taintCollidesWater; + + if (m_collidesWater) + { + m_collisionFlags |= CollisionCategories.Water; + } + else + { + m_collisionFlags &= ~CollisionCategories.Water; + } + + if (m_assetFailed) + d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits); + else + + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + } + /// + /// Change prim in response to a shape taint. + /// + private void changeshape() + { + m_taintshape = false; + + // Cleanup of old prim geometry and Bodies + if (IsPhysical && Body != IntPtr.Zero) + { + if (childPrim) + { + if (_parent != null) + { + OdePrim parent = (OdePrim)_parent; + parent.ChildDelink(this); + } + } + else + { + disableBody(); + } + } + + RemoveGeom(); + + // we don't need to do space calculation because the client sends a position update also. + if (_size.X <= 0) _size.X = 0.01f; + if (_size.Y <= 0) _size.Y = 0.01f; + if (_size.Z <= 0) _size.Z = 0.01f; + // Construction of new prim + + IMesh mesh = null; + + + if (_parent_scene.needsMeshing(_pbs)) + { + // Don't need to re-enable body.. it's done in CreateMesh + float meshlod = _parent_scene.meshSculptLOD; + + if (IsPhysical) + meshlod = _parent_scene.MeshSculptphysicalLOD; + + // createmesh returns null when it doesn't mesh. + mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical); + if (mesh == null) + CheckMeshAsset(); + else + m_assetFailed = false; + } + + CreateGeom(m_targetSpace, mesh); + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + d.Quaternion myrot = new d.Quaternion(); + //myrot.W = _orientation.w; + myrot.W = _orientation.W; + myrot.X = _orientation.X; + myrot.Y = _orientation.Y; + myrot.Z = _orientation.Z; + d.GeomSetQuaternion(prim_geom, ref myrot); + + //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z); + if (IsPhysical && Body == IntPtr.Zero) + { + // Re creates body on size. + // EnableBody also does setMass() + enableBody(); + if (Body != IntPtr.Zero) + { + d.BodyEnable(Body); + } + } + + changeSelectedStatus(); + + if (childPrim) + { + if (_parent is OdePrim) + { + OdePrim parent = (OdePrim)_parent; + parent.ChildSetGeom(this); + } + } + + resetCollisionAccounting(); +// m_taintshape = false; + } + + /// + /// Change prim in response to an add force taint. + /// + private void changeAddForce() + { + if (!m_isSelected) + { + lock (m_forcelist) + { + //m_log.Info("[PHYSICS]: dequeing forcelist"); + if (IsPhysical) + { + Vector3 iforce = Vector3.Zero; + int i = 0; + try + { + for (i = 0; i < m_forcelist.Count; i++) + { + + iforce = iforce + (m_forcelist[i] * 100); + } + } + catch (IndexOutOfRangeException) + { + m_forcelist = new List(); + m_collisionscore = 0; + m_interpenetrationcount = 0; + m_taintforce = false; + return; + } + catch (ArgumentOutOfRangeException) + { + m_forcelist = new List(); + m_collisionscore = 0; + m_interpenetrationcount = 0; + m_taintforce = false; + return; + } + d.BodyEnable(Body); + d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z); + } + m_forcelist.Clear(); + } + + m_collisionscore = 0; + m_interpenetrationcount = 0; + } + + m_taintforce = false; + } + + /// + /// Change prim in response to a torque taint. + /// + private void changeSetTorque() + { + if (!m_isSelected) + { + if (IsPhysical && Body != IntPtr.Zero) + { + d.BodySetTorque(Body, m_taintTorque.X, m_taintTorque.Y, m_taintTorque.Z); + } + } + + m_taintTorque = Vector3.Zero; + } + + /// + /// Change prim in response to an angular force taint. + /// + private void changeAddAngularForce() + { + if (!m_isSelected) + { + lock (m_angularforcelist) + { + //m_log.Info("[PHYSICS]: dequeing forcelist"); + if (IsPhysical) + { + Vector3 iforce = Vector3.Zero; + for (int i = 0; i < m_angularforcelist.Count; i++) + { + iforce = iforce + (m_angularforcelist[i] * 100); + } + d.BodyEnable(Body); + d.BodyAddTorque(Body, iforce.X, iforce.Y, iforce.Z); + + } + m_angularforcelist.Clear(); + } + + m_collisionscore = 0; + m_interpenetrationcount = 0; + } + + m_taintaddangularforce = false; + } + + /// + /// Change prim in response to a velocity taint. + /// + private void changevelocity() + { + if (!m_isSelected) + { + // Not sure exactly why this sleep is here, but from experimentation it appears to stop an avatar + // walking through a default rez size prim if it keeps kicking it around - justincc. + Thread.Sleep(20); + + if (IsPhysical) + { + if (Body != IntPtr.Zero) + { + d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z); + } + } + + //resetCollisionAccounting(); + } + + m_taintVelocity = Vector3.Zero; + } + + internal void setPrimForRemoval() + { + m_taintremove = true; + } + + public override bool Flying + { + // no flying prims for you + get { return false; } + set { } + } + + public override bool IsColliding + { + get { return iscolliding; } + set { iscolliding = value; } + } + + public override bool CollidingGround + { + get { return false; } + set { return; } + } + + public override bool CollidingObj + { + get { return false; } + set { return; } + } + + public override bool ThrottleUpdates + { + get { return m_throttleUpdates; } + set { m_throttleUpdates = value; } + } + + public override bool Stopped + { + get { return _zeroFlag; } + } + + public override Vector3 Position + { + get { return _position; } + + set { _position = value; + //m_log.Info("[PHYSICS]: " + _position.ToString()); + } + } + + public override Vector3 Size + { + get { return _size; } + set + { + if (value.IsFinite()) + { + _size = value; +// m_log.DebugFormat("[PHYSICS]: Set size on {0} to {1}", Name, value); + } + else + { + m_log.WarnFormat("[PHYSICS]: Got NaN Size on object {0}", Name); + } + } + } + + public override float Mass + { + get { return CalculateMass(); } + } + + public override Vector3 Force + { + //get { return Vector3.Zero; } + get { return m_force; } + set + { + if (value.IsFinite()) + { + m_force = value; + } + else + { + m_log.WarnFormat("[PHYSICS]: NaN in Force Applied to an Object {0}", Name); + } + } + } + + public override int VehicleType + { + get { return (int)m_vehicle.Type; } + set { m_vehicle.ProcessTypeChange((Vehicle)value); } + } + + public override void VehicleFloatParam(int param, float value) + { + m_vehicle.ProcessFloatVehicleParam((Vehicle) param, value); + } + + public override void VehicleVectorParam(int param, Vector3 value) + { + m_vehicle.ProcessVectorVehicleParam((Vehicle) param, value); + } + + public override void VehicleRotationParam(int param, Quaternion rotation) + { + m_vehicle.ProcessRotationVehicleParam((Vehicle) param, rotation); + } + + public override void VehicleFlags(int param, bool remove) + { + m_vehicle.ProcessVehicleFlags(param, remove); + } + + public override void SetVolumeDetect(int param) + { + // We have to lock the scene here so that an entire simulate loop either uses volume detect for all + // possible collisions with this prim or for none of them. + lock (_parent_scene.OdeLock) + { + m_isVolumeDetect = (param != 0); + } + } + + public override Vector3 CenterOfMass + { + get { return Vector3.Zero; } + } + + public override Vector3 GeometricCenter + { + get { return Vector3.Zero; } + } + + public override PrimitiveBaseShape Shape + { + set + { + _pbs = value; + m_assetFailed = false; + m_taintshape = true; + } + } + + public override Vector3 Velocity + { + get + { + // Average previous velocity with the new one so + // client object interpolation works a 'little' better + if (_zeroFlag) + return Vector3.Zero; + + Vector3 returnVelocity = Vector3.Zero; + returnVelocity.X = (m_lastVelocity.X + _velocity.X) * 0.5f; // 0.5f is mathematically equiv to '/ 2' + returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y) * 0.5f; + returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z) * 0.5f; + return returnVelocity; + } + set + { + if (value.IsFinite()) + { + _velocity = value; + + m_taintVelocity = value; + _parent_scene.AddPhysicsActorTaint(this); + } + else + { + m_log.WarnFormat("[PHYSICS]: Got NaN Velocity in Object {0}", Name); + } + + } + } + + public override Vector3 Torque + { + get + { + if (!IsPhysical || Body == IntPtr.Zero) + return Vector3.Zero; + + return _torque; + } + + set + { + if (value.IsFinite()) + { + m_taintTorque = value; + _parent_scene.AddPhysicsActorTaint(this); + } + else + { + m_log.WarnFormat("[PHYSICS]: Got NaN Torque in Object {0}", Name); + } + } + } + + public override float CollisionScore + { + get { return m_collisionscore; } + set { m_collisionscore = value; } + } + + public override bool Kinematic + { + get { return false; } + set { } + } + + public override Quaternion Orientation + { + get { return _orientation; } + set + { + if (QuaternionIsFinite(value)) + _orientation = value; + else + m_log.WarnFormat("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object {0}", Name); + } + } + + private static bool QuaternionIsFinite(Quaternion q) + { + if (Single.IsNaN(q.X) || Single.IsInfinity(q.X)) + return false; + if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y)) + return false; + if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z)) + return false; + if (Single.IsNaN(q.W) || Single.IsInfinity(q.W)) + return false; + return true; + } + + public override Vector3 Acceleration + { + get { return _acceleration; } + set { _acceleration = value; } + } + + public override void AddForce(Vector3 force, bool pushforce) + { + if (force.IsFinite()) + { + lock (m_forcelist) + m_forcelist.Add(force); + + m_taintforce = true; + } + else + { + m_log.WarnFormat("[PHYSICS]: Got Invalid linear force vector from Scene in Object {0}", Name); + } + //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString()); + } + + public override void AddAngularForce(Vector3 force, bool pushforce) + { + if (force.IsFinite()) + { + m_angularforcelist.Add(force); + m_taintaddangularforce = true; + } + else + { + m_log.WarnFormat("[PHYSICS]: Got Invalid Angular force vector from Scene in Object {0}", Name); + } + } + + public override Vector3 RotationalVelocity + { + get + { + Vector3 pv = Vector3.Zero; + if (_zeroFlag) + return pv; + m_lastUpdateSent = false; + + if (m_rotationalVelocity.ApproxEquals(pv, 0.2f)) + return pv; + + return m_rotationalVelocity; + } + set + { + if (value.IsFinite()) + { + m_rotationalVelocity = value; + setAngularVelocity(value.X, value.Y, value.Z); + } + else + { + m_log.WarnFormat("[PHYSICS]: Got NaN RotationalVelocity in Object {0}", Name); + } + } + } + + public override void CrossingFailure() + { + m_crossingfailures++; + if (m_crossingfailures > _parent_scene.geomCrossingFailuresBeforeOutofbounds) + { + base.RaiseOutOfBounds(_position); + return; + } + else if (m_crossingfailures == _parent_scene.geomCrossingFailuresBeforeOutofbounds) + { + m_log.Warn("[PHYSICS]: Too many crossing failures for: " + Name); + } + } + + public override float Buoyancy + { + get { return m_buoyancy; } + set { m_buoyancy = value; } + } + + public override void link(PhysicsActor obj) + { + m_taintparent = obj; + } + + public override void delink() + { + m_taintparent = null; + } + + public override void LockAngularMotion(Vector3 axis) + { + // reverse the zero/non zero values for ODE. + if (axis.IsFinite()) + { + axis.X = (axis.X > 0) ? 1f : 0f; + axis.Y = (axis.Y > 0) ? 1f : 0f; + axis.Z = (axis.Z > 0) ? 1f : 0f; + m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z); + m_taintAngularLock = axis; + } + else + { + m_log.WarnFormat("[PHYSICS]: Got NaN locking axis from Scene on Object {0}", Name); + } + } + + internal void UpdatePositionAndVelocity() + { + // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! + if (_parent == null) + { + Vector3 pv = Vector3.Zero; + bool lastZeroFlag = _zeroFlag; + float m_minvelocity = 0; + if (Body != (IntPtr)0) // FIXME -> or if it is a joint + { + d.Vector3 vec = d.BodyGetPosition(Body); + d.Quaternion ori = d.BodyGetQuaternion(Body); + d.Vector3 vel = d.BodyGetLinearVel(Body); + d.Vector3 rotvel = d.BodyGetAngularVel(Body); + d.Vector3 torque = d.BodyGetTorque(Body); + _torque = new Vector3(torque.X, torque.Y, torque.Z); + Vector3 l_position = Vector3.Zero; + Quaternion l_orientation = Quaternion.Identity; + + // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) + //if (vec.X < 0.0f) { vec.X = 0.0f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); } + //if (vec.Y < 0.0f) { vec.Y = 0.0f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); } + //if (vec.X > 255.95f) { vec.X = 255.95f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); } + //if (vec.Y > 255.95f) { vec.Y = 255.95f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); } + + m_lastposition = _position; + m_lastorientation = _orientation; + + l_position.X = vec.X; + l_position.Y = vec.Y; + l_position.Z = vec.Z; + l_orientation.X = ori.X; + l_orientation.Y = ori.Y; + l_orientation.Z = ori.Z; + l_orientation.W = ori.W; + + if (l_position.X > ((int)_parent_scene.WorldExtents.X - 0.05f) || l_position.X < 0f || l_position.Y > ((int)_parent_scene.WorldExtents.Y - 0.05f) || l_position.Y < 0f) + { + //base.RaiseOutOfBounds(l_position); + + if (m_crossingfailures < _parent_scene.geomCrossingFailuresBeforeOutofbounds) + { + _position = l_position; + //_parent_scene.remActivePrim(this); + if (_parent == null) + base.RequestPhysicsterseUpdate(); + return; + } + else + { + if (_parent == null) + base.RaiseOutOfBounds(l_position); + return; + } + } + + if (l_position.Z < 0) + { + // This is so prim that get lost underground don't fall forever and suck up + // + // Sim resources and memory. + // Disables the prim's movement physics.... + // It's a hack and will generate a console message if it fails. + + //IsPhysical = false; + if (_parent == null) + base.RaiseOutOfBounds(_position); + + _acceleration.X = 0; + _acceleration.Y = 0; + _acceleration.Z = 0; + + _velocity.X = 0; + _velocity.Y = 0; + _velocity.Z = 0; + m_rotationalVelocity.X = 0; + m_rotationalVelocity.Y = 0; + m_rotationalVelocity.Z = 0; + + if (_parent == null) + base.RequestPhysicsterseUpdate(); + + m_throttleUpdates = false; + throttleCounter = 0; + _zeroFlag = true; + //outofBounds = true; + } + + //float Adiff = 1.0f - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)); +//Console.WriteLine("Adiff " + Name + " = " + Adiff); + if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02) + && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02) + && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02) +// && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.01)) + && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.0001)) // KF 0.01 is far to large + { + _zeroFlag = true; +//Console.WriteLine("ZFT 2"); + m_throttleUpdates = false; + } + else + { + //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString()); + _zeroFlag = false; + m_lastUpdateSent = false; + //m_throttleUpdates = false; + } + + if (_zeroFlag) + { + _velocity.X = 0.0f; + _velocity.Y = 0.0f; + _velocity.Z = 0.0f; + + _acceleration.X = 0; + _acceleration.Y = 0; + _acceleration.Z = 0; + + //_orientation.w = 0f; + //_orientation.X = 0f; + //_orientation.Y = 0f; + //_orientation.Z = 0f; + m_rotationalVelocity.X = 0; + m_rotationalVelocity.Y = 0; + m_rotationalVelocity.Z = 0; + if (!m_lastUpdateSent) + { + m_throttleUpdates = false; + throttleCounter = 0; + m_rotationalVelocity = pv; + + if (_parent == null) + { + base.RequestPhysicsterseUpdate(); + } + + m_lastUpdateSent = true; + } + } + else + { + if (lastZeroFlag != _zeroFlag) + { + if (_parent == null) + { + base.RequestPhysicsterseUpdate(); + } + } + + m_lastVelocity = _velocity; + + _position = l_position; + + _velocity.X = vel.X; + _velocity.Y = vel.Y; + _velocity.Z = vel.Z; + + _acceleration = ((_velocity - m_lastVelocity) / 0.1f); + _acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f); + //m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString()); + + // Note here that linearvelocity is affecting angular velocity... so I'm guessing this is a vehicle specific thing... + // it does make sense to do this for tiny little instabilities with physical prim, however 0.5m/frame is fairly large. + // reducing this to 0.02m/frame seems to help the angular rubberbanding quite a bit, however, to make sure it doesn't affect elevators and vehicles + // adding these logical exclusion situations to maintain this where I think it was intended to be. + if (m_throttleUpdates || PIDActive || (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE) || (Amotor != IntPtr.Zero)) + { + m_minvelocity = 0.5f; + } + else + { + m_minvelocity = 0.02f; + } + + if (_velocity.ApproxEquals(pv, m_minvelocity)) + { + m_rotationalVelocity = pv; + } + else + { + m_rotationalVelocity = new Vector3(rotvel.X, rotvel.Y, rotvel.Z); + } + + //m_log.Debug("ODE: " + m_rotationalVelocity.ToString()); + _orientation.X = ori.X; + _orientation.Y = ori.Y; + _orientation.Z = ori.Z; + _orientation.W = ori.W; + m_lastUpdateSent = false; + if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate) + { + if (_parent == null) + { + base.RequestPhysicsterseUpdate(); + } + } + else + { + throttleCounter++; + } + } + m_lastposition = l_position; + } + else + { + // Not a body.. so Make sure the client isn't interpolating + _velocity.X = 0; + _velocity.Y = 0; + _velocity.Z = 0; + + _acceleration.X = 0; + _acceleration.Y = 0; + _acceleration.Z = 0; + + m_rotationalVelocity.X = 0; + m_rotationalVelocity.Y = 0; + m_rotationalVelocity.Z = 0; + _zeroFlag = true; + } + } + } + + public override bool FloatOnWater + { + set { + m_taintCollidesWater = value; + _parent_scene.AddPhysicsActorTaint(this); + } + } + + public override void SetMomentum(Vector3 momentum) + { + } + + public override Vector3 PIDTarget + { + set + { + if (value.IsFinite()) + { + m_PIDTarget = value; + } + else + m_log.WarnFormat("[PHYSICS]: Got NaN PIDTarget from Scene on Object {0}", Name); + } + } + public override bool PIDActive { get; set; } + public override float PIDTau { set { m_PIDTau = value; } } + + public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } } + public override bool PIDHoverActive { set { m_useHoverPID = value; } } + public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } } + public override float PIDHoverTau { set { m_PIDHoverTau = value; } } + + public override Quaternion APIDTarget{ set { return; } } + + public override bool APIDActive{ set { return; } } + + public override float APIDStrength{ set { return; } } + + public override float APIDDamping{ set { return; } } + + private void createAMotor(Vector3 axis) + { + if (Body == IntPtr.Zero) + return; + + if (Amotor != IntPtr.Zero) + { + d.JointDestroy(Amotor); + Amotor = IntPtr.Zero; + } + + float axisnum = 3; + + axisnum = (axisnum - (axis.X + axis.Y + axis.Z)); + + // PhysicsVector totalSize = new PhysicsVector(_size.X, _size.Y, _size.Z); + + + // Inverse Inertia Matrix, set the X, Y, and/r Z inertia to 0 then invert it again. + d.Mass objMass; + d.MassSetZero(out objMass); + DMassCopy(ref pMass, ref objMass); + + //m_log.DebugFormat("1-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", objMass.I.M00, objMass.I.M01, objMass.I.M02, objMass.I.M10, objMass.I.M11, objMass.I.M12, objMass.I.M20, objMass.I.M21, objMass.I.M22); + + Matrix4 dMassMat = FromDMass(objMass); + + Matrix4 mathmat = Inverse(dMassMat); + + /* + //m_log.DebugFormat("2-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", mathmat[0, 0], mathmat[0, 1], mathmat[0, 2], mathmat[1, 0], mathmat[1, 1], mathmat[1, 2], mathmat[2, 0], mathmat[2, 1], mathmat[2, 2]); + + mathmat = Inverse(mathmat); + + + objMass = FromMatrix4(mathmat, ref objMass); + //m_log.DebugFormat("3-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", objMass.I.M00, objMass.I.M01, objMass.I.M02, objMass.I.M10, objMass.I.M11, objMass.I.M12, objMass.I.M20, objMass.I.M21, objMass.I.M22); + + mathmat = Inverse(mathmat); + */ + if (axis.X == 0) + { + mathmat.M33 = 50.0000001f; + //objMass.I.M22 = 0; + } + if (axis.Y == 0) + { + mathmat.M22 = 50.0000001f; + //objMass.I.M11 = 0; + } + if (axis.Z == 0) + { + mathmat.M11 = 50.0000001f; + //objMass.I.M00 = 0; + } + + + + mathmat = Inverse(mathmat); + objMass = FromMatrix4(mathmat, ref objMass); + //m_log.DebugFormat("4-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", objMass.I.M00, objMass.I.M01, objMass.I.M02, objMass.I.M10, objMass.I.M11, objMass.I.M12, objMass.I.M20, objMass.I.M21, objMass.I.M22); + + //return; + if (d.MassCheck(ref objMass)) + { + d.BodySetMass(Body, ref objMass); + } + else + { + //m_log.Debug("[PHYSICS]: Mass invalid, ignoring"); + } + + if (axisnum <= 0) + return; + // int dAMotorEuler = 1; + + Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero); + d.JointAttach(Amotor, Body, IntPtr.Zero); + d.JointSetAMotorMode(Amotor, 0); + + d.JointSetAMotorNumAxes(Amotor,(int)axisnum); + int i = 0; + + if (axis.X == 0) + { + d.JointSetAMotorAxis(Amotor, i, 0, 1, 0, 0); + i++; + } + + if (axis.Y == 0) + { + d.JointSetAMotorAxis(Amotor, i, 0, 0, 1, 0); + i++; + } + + if (axis.Z == 0) + { + d.JointSetAMotorAxis(Amotor, i, 0, 0, 0, 1); + i++; + } + + for (int j = 0; j < (int)axisnum; j++) + { + //d.JointSetAMotorAngle(Amotor, j, 0); + } + + //d.JointSetAMotorAngle(Amotor, 1, 0); + //d.JointSetAMotorAngle(Amotor, 2, 0); + + // These lowstops and high stops are effectively (no wiggle room) + d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0f); + d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f); + d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0f); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0f); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); + d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0f); + //d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 9000f); + d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f); + d.JointSetAMotorParam(Amotor, (int)dParam.FMax, Mass * 50f);// + } + + private Matrix4 FromDMass(d.Mass pMass) + { + Matrix4 obj; + obj.M11 = pMass.I.M00; + obj.M12 = pMass.I.M01; + obj.M13 = pMass.I.M02; + obj.M14 = 0; + obj.M21 = pMass.I.M10; + obj.M22 = pMass.I.M11; + obj.M23 = pMass.I.M12; + obj.M24 = 0; + obj.M31 = pMass.I.M20; + obj.M32 = pMass.I.M21; + obj.M33 = pMass.I.M22; + obj.M34 = 0; + obj.M41 = 0; + obj.M42 = 0; + obj.M43 = 0; + obj.M44 = 1; + return obj; + } + + private d.Mass FromMatrix4(Matrix4 pMat, ref d.Mass obj) + { + obj.I.M00 = pMat[0, 0]; + obj.I.M01 = pMat[0, 1]; + obj.I.M02 = pMat[0, 2]; + obj.I.M10 = pMat[1, 0]; + obj.I.M11 = pMat[1, 1]; + obj.I.M12 = pMat[1, 2]; + obj.I.M20 = pMat[2, 0]; + obj.I.M21 = pMat[2, 1]; + obj.I.M22 = pMat[2, 2]; + return obj; + } + + public override void SubscribeEvents(int ms) + { + m_eventsubscription = ms; + _parent_scene.AddCollisionEventReporting(this); + } + + public override void UnSubscribeEvents() + { + _parent_scene.RemoveCollisionEventReporting(this); + m_eventsubscription = 0; + } + + public void AddCollisionEvent(uint CollidedWith, ContactPoint contact) + { + CollisionEventsThisFrame.AddCollider(CollidedWith, contact); + } + + public void SendCollisions() + { + if (m_collisionsOnPreviousFrame || CollisionEventsThisFrame.Count > 0) + { + base.SendCollisionUpdate(CollisionEventsThisFrame); + + if (CollisionEventsThisFrame.Count > 0) + { + m_collisionsOnPreviousFrame = true; + CollisionEventsThisFrame.Clear(); + } + else + { + m_collisionsOnPreviousFrame = false; + } + } + } + + public override bool SubscribedEvents() + { + if (m_eventsubscription > 0) + return true; + return false; + } + + public static Matrix4 Inverse(Matrix4 pMat) + { + if (determinant3x3(pMat) == 0) + { + return Matrix4.Identity; // should probably throw an error. singluar matrix inverse not possible + } + + return (Adjoint(pMat) / determinant3x3(pMat)); + } + + public static Matrix4 Adjoint(Matrix4 pMat) + { + Matrix4 adjointMatrix = new Matrix4(); + for (int i=0; i<4; i++) + { + for (int j=0; j<4; j++) + { + Matrix4SetValue(ref adjointMatrix, i, j, (float)(Math.Pow(-1, i + j) * (determinant3x3(Minor(pMat, i, j))))); + } + } + + adjointMatrix = Transpose(adjointMatrix); + return adjointMatrix; + } + + public static Matrix4 Minor(Matrix4 matrix, int iRow, int iCol) + { + Matrix4 minor = new Matrix4(); + int m = 0, n = 0; + for (int i = 0; i < 4; i++) + { + if (i == iRow) + continue; + n = 0; + for (int j = 0; j < 4; j++) + { + if (j == iCol) + continue; + Matrix4SetValue(ref minor, m,n, matrix[i, j]); + n++; + } + m++; + } + + return minor; + } + + public static Matrix4 Transpose(Matrix4 pMat) + { + Matrix4 transposeMatrix = new Matrix4(); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + Matrix4SetValue(ref transposeMatrix, i, j, pMat[j, i]); + return transposeMatrix; + } + + public static void Matrix4SetValue(ref Matrix4 pMat, int r, int c, float val) + { + switch (r) + { + case 0: + switch (c) + { + case 0: + pMat.M11 = val; + break; + case 1: + pMat.M12 = val; + break; + case 2: + pMat.M13 = val; + break; + case 3: + pMat.M14 = val; + break; + } + + break; + case 1: + switch (c) + { + case 0: + pMat.M21 = val; + break; + case 1: + pMat.M22 = val; + break; + case 2: + pMat.M23 = val; + break; + case 3: + pMat.M24 = val; + break; + } + + break; + case 2: + switch (c) + { + case 0: + pMat.M31 = val; + break; + case 1: + pMat.M32 = val; + break; + case 2: + pMat.M33 = val; + break; + case 3: + pMat.M34 = val; + break; + } + + break; + case 3: + switch (c) + { + case 0: + pMat.M41 = val; + break; + case 1: + pMat.M42 = val; + break; + case 2: + pMat.M43 = val; + break; + case 3: + pMat.M44 = val; + break; + } + + break; + } + } + + private static float determinant3x3(Matrix4 pMat) + { + float det = 0; + float diag1 = pMat[0, 0]*pMat[1, 1]*pMat[2, 2]; + float diag2 = pMat[0, 1]*pMat[2, 1]*pMat[2, 0]; + float diag3 = pMat[0, 2]*pMat[1, 0]*pMat[2, 1]; + float diag4 = pMat[2, 0]*pMat[1, 1]*pMat[0, 2]; + float diag5 = pMat[2, 1]*pMat[1, 2]*pMat[0, 0]; + float diag6 = pMat[2, 2]*pMat[1, 0]*pMat[0, 1]; + + det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6); + return det; + } + + private static void DMassCopy(ref d.Mass src, ref d.Mass dst) + { + dst.c.W = src.c.W; + dst.c.X = src.c.X; + dst.c.Y = src.c.Y; + dst.c.Z = src.c.Z; + dst.mass = src.mass; + dst.I.M00 = src.I.M00; + dst.I.M01 = src.I.M01; + dst.I.M02 = src.I.M02; + dst.I.M10 = src.I.M10; + dst.I.M11 = src.I.M11; + dst.I.M12 = src.I.M12; + dst.I.M20 = src.I.M20; + dst.I.M21 = src.I.M21; + dst.I.M22 = src.I.M22; + } + + public override void SetMaterial(int pMaterial) + { + m_material = pMaterial; + } + + private void CheckMeshAsset() + { + if (_pbs.SculptEntry && !m_assetFailed && _pbs.SculptTexture != UUID.Zero) + { + m_assetFailed = true; + Util.FireAndForget(delegate + { + RequestAssetDelegate assetProvider = _parent_scene.RequestAssetMethod; + if (assetProvider != null) + assetProvider(_pbs.SculptTexture, MeshAssetReceived); + }, null, "ODEPrim.CheckMeshAsset"); + } + } + + private void MeshAssetReceived(AssetBase asset) + { + if (asset != null && asset.Data != null && asset.Data.Length > 0) + { + if (!_pbs.SculptEntry) + return; + if (_pbs.SculptTexture.ToString() != asset.ID) + return; + + _pbs.SculptData = new byte[asset.Data.Length]; + asset.Data.CopyTo(_pbs.SculptData, 0); +// m_assetFailed = false; + +// m_log.DebugFormat( +// "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}", +// _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name); + + m_taintshape = true; + _parent_scene.AddPhysicsActorTaint(this); + } + else + { + m_log.WarnFormat( + "[ODE PRIM]: Could not get mesh/sculpt asset {0} for {1} at {2} in {3}", + _pbs.SculptTexture, Name, _position, _parent_scene.PhysicsSceneName); + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs b/OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs new file mode 100644 index 0000000..8d610f7 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs @@ -0,0 +1,441 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using OpenMetaverse; +using OpenSim.Region.PhysicsModules.SharedBase; +using Ode.NET; +using log4net; + +namespace OpenSim.Region.PhysicsModule.ODE +{ + /// + /// Processes raycast requests as ODE is in a state to be able to do them. + /// This ensures that it's thread safe and there will be no conflicts. + /// Requests get returned by a different thread then they were requested by. + /// + public class ODERayCastRequestManager + { + /// + /// Pending raycast requests + /// + protected List m_PendingRequests = new List(); + + /// + /// Pending ray requests + /// + protected List m_PendingRayRequests = new List(); + + /// + /// Scene that created this object. + /// + private OdeScene m_scene; + + /// + /// ODE contact array to be filled by the collision testing + /// + d.ContactGeom[] contacts = new d.ContactGeom[5]; + + /// + /// ODE near callback delegate + /// + private d.NearCallback nearCallback; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private List m_contactResults = new List(); + + + public ODERayCastRequestManager(OdeScene pScene) + { + m_scene = pScene; + nearCallback = near; + + } + + /// + /// Queues a raycast + /// + /// Origin of Ray + /// Ray normal + /// Ray length + /// Return method to send the results + public void QueueRequest(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod) + { + lock (m_PendingRequests) + { + ODERayCastRequest req = new ODERayCastRequest(); + req.callbackMethod = retMethod; + req.length = length; + req.Normal = direction; + req.Origin = position; + + m_PendingRequests.Add(req); + } + } + + /// + /// Queues a raycast + /// + /// Origin of Ray + /// Ray normal + /// Ray length + /// + /// Return method to send the results + public void QueueRequest(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod) + { + lock (m_PendingRequests) + { + ODERayRequest req = new ODERayRequest(); + req.callbackMethod = retMethod; + req.length = length; + req.Normal = direction; + req.Origin = position; + req.Count = count; + + m_PendingRayRequests.Add(req); + } + } + + /// + /// Process all queued raycast requests + /// + /// Time in MS the raycasts took to process. + public int ProcessQueuedRequests() + { + int time = System.Environment.TickCount; + lock (m_PendingRequests) + { + if (m_PendingRequests.Count > 0) + { + ODERayCastRequest[] reqs = m_PendingRequests.ToArray(); + for (int i = 0; i < reqs.Length; i++) + { + if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast + RayCast(reqs[i]); // if there isn't anyone to send results + } + + m_PendingRequests.Clear(); + } + } + + lock (m_PendingRayRequests) + { + if (m_PendingRayRequests.Count > 0) + { + ODERayRequest[] reqs = m_PendingRayRequests.ToArray(); + for (int i = 0; i < reqs.Length; i++) + { + if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast + RayCast(reqs[i]); // if there isn't anyone to send results + } + + m_PendingRayRequests.Clear(); + } + } + + lock (m_contactResults) + m_contactResults.Clear(); + + return System.Environment.TickCount - time; + } + + /// + /// Method that actually initiates the raycast + /// + /// + private void RayCast(ODERayCastRequest req) + { + // NOTE: limit ray length or collisions will take all avaiable stack space + // this value may still be too large, depending on machine configuration + // of maximum stack + float len = req.length; + if (len > 250f) + len = 250f; + + // Create the ray + IntPtr ray = d.CreateRay(m_scene.space, req.length); + d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z); + + // Collide test + d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback); + + // Remove Ray + d.GeomDestroy(ray); + + // Define default results + bool hitYN = false; + uint hitConsumerID = 0; + float distance = 999999999999f; + Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f); + Vector3 snormal = Vector3.Zero; + + // Find closest contact and object. + lock (m_contactResults) + { + foreach (ContactResult cResult in m_contactResults) + { + if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact)) + { + closestcontact = cResult.Pos; + hitConsumerID = cResult.ConsumerID; + distance = cResult.Depth; + hitYN = true; + snormal = cResult.Normal; + } + } + + m_contactResults.Clear(); + } + + // Return results + if (req.callbackMethod != null) + req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal); + } + + /// + /// Method that actually initiates the raycast + /// + /// + private void RayCast(ODERayRequest req) + { + // Create the ray + IntPtr ray = d.CreateRay(m_scene.space, req.length); + d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z); + + // Collide test + d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback); + + // Remove Ray + d.GeomDestroy(ray); + + // Find closest contact and object. + lock (m_contactResults) + { + // Return results + if (req.callbackMethod != null) + req.callbackMethod(m_contactResults); + } + } + + // This is the standard Near. Uses space AABBs to speed up detection. + private void near(IntPtr space, IntPtr g1, IntPtr g2) + { + + //Don't test against heightfield Geom, or you'll be sorry! + + /* + terminate called after throwing an instance of 'std::bad_alloc' + what(): std::bad_alloc + Stacktrace: + + at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0x00004> + at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0xffffffff> + at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0x00280> + at (wrapper native-to-managed) OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0xfff + fffff> + at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0x00004> + at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0xffffffff> + at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.RayCast (OpenSim.Region.Physics.OdePlugin.ODERayCastRequest) < + 0x00114> + at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.ProcessQueuedRequests () <0x000eb> + at OpenSim.Region.Physics.OdePlugin.OdeScene.Simulate (single) <0x017e6> + at OpenSim.Region.Framework.Scenes.SceneGraph.UpdatePhysics (double) <0x00042> + at OpenSim.Region.Framework.Scenes.Scene.Update () <0x0039e> + at OpenSim.Region.Framework.Scenes.Scene.Heartbeat (object) <0x00019> + at (wrapper runtime-invoke) object.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <0xffffffff> + + Native stacktrace: + + mono [0x80d2a42] + [0xb7f5840c] + /lib/i686/cmov/libc.so.6(abort+0x188) [0xb7d1a018] + /usr/lib/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x158) [0xb45fc988] + /usr/lib/libstdc++.so.6 [0xb45fa865] + /usr/lib/libstdc++.so.6 [0xb45fa8a2] + /usr/lib/libstdc++.so.6 [0xb45fa9da] + /usr/lib/libstdc++.so.6(_Znwj+0x83) [0xb45fb033] + /usr/lib/libstdc++.so.6(_Znaj+0x1d) [0xb45fb11d] + libode.so(_ZN13dxHeightfield23dCollideHeightfieldZoneEiiiiP6dxGeomiiP12dContactGeomi+0xd04) [0xb46678e4] + libode.so(_Z19dCollideHeightfieldP6dxGeomS0_iP12dContactGeomi+0x54b) [0xb466832b] + libode.so(dCollide+0x102) [0xb46571b2] + [0x95cfdec9] + [0x8ea07fe1] + [0xab260146] + libode.so [0xb465a5c4] + libode.so(_ZN11dxHashSpace8collide2EPvP6dxGeomPFvS0_S2_S2_E+0x75) [0xb465bcf5] + libode.so(dSpaceCollide2+0x177) [0xb465ac67] + [0x95cf978e] + [0x8ea07945] + [0x95cf2bbc] + [0xab2787e7] + [0xab419fb3] + [0xab416657] + [0xab415bda] + [0xb609b08e] + mono(mono_runtime_delegate_invoke+0x34) [0x8192534] + mono [0x81a2f0f] + mono [0x81d28b6] + mono [0x81ea2c6] + /lib/i686/cmov/libpthread.so.0 [0xb7e744c0] + /lib/i686/cmov/libc.so.6(clone+0x5e) [0xb7dcd6de] + */ + + // Exclude heightfield geom + + if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) + return; + if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass || d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass) + return; + + // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms. + if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) + { + if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) + return; + + // Separating static prim geometry spaces. + // We'll be calling near recursivly if one + // of them is a space to find all of the + // contact points in the space + try + { + d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); + } + catch (AccessViolationException) + { + m_log.Warn("[PHYSICS]: Unable to collide test a space"); + return; + } + //Colliding a space or a geom with a space or a geom. so drill down + + //Collide all geoms in each space.. + //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback); + //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback); + return; + } + + if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) + return; + + int count = 0; + try + { + + if (g1 == g2) + return; // Can't collide with yourself + + lock (contacts) + { + count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf); + } + } + catch (SEHException) + { + m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim."); + } + catch (Exception e) + { + m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message); + return; + } + + PhysicsActor p1 = null; + PhysicsActor p2 = null; + + if (g1 != IntPtr.Zero) + m_scene.actor_name_map.TryGetValue(g1, out p1); + + if (g2 != IntPtr.Zero) + m_scene.actor_name_map.TryGetValue(g1, out p2); + + // Loop over contacts, build results. + for (int i = 0; i < count; i++) + { + if (p1 != null) + { + if (p1 is OdePrim) + { + ContactResult collisionresult = new ContactResult(); + + collisionresult.ConsumerID = p1.LocalID; + collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z); + collisionresult.Depth = contacts[i].depth; + collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y, + contacts[i].normal.Z); + lock (m_contactResults) + m_contactResults.Add(collisionresult); + } + } + + if (p2 != null) + { + if (p2 is OdePrim) + { + ContactResult collisionresult = new ContactResult(); + + collisionresult.ConsumerID = p2.LocalID; + collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z); + collisionresult.Depth = contacts[i].depth; + collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y, + contacts[i].normal.Z); + + lock (m_contactResults) + m_contactResults.Add(collisionresult); + } + } + } + } + + /// + /// Dereference the creator scene so that it can be garbage collected if needed. + /// + internal void Dispose() + { + m_scene = null; + } + } + + public struct ODERayCastRequest + { + public Vector3 Origin; + public Vector3 Normal; + public float length; + public RaycastCallback callbackMethod; + } + + public struct ODERayRequest + { + public Vector3 Origin; + public Vector3 Normal; + public int Count; + public float length; + public RayCallback callbackMethod; + } +} \ No newline at end of file diff --git a/OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs b/OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs new file mode 100644 index 0000000..2eb7ba6 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs @@ -0,0 +1,48 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; +using Ode.NET; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Region.PhysicsModule.ODE; + +namespace OpenSim.Region.PhysicsModule.ODE +{ + class OdePhysicsJoint : PhysicsJoint + { + public override bool IsInPhysicsEngine + { + get + { + return (jointID != IntPtr.Zero); + } + } + public IntPtr jointID; + } +} diff --git a/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs new file mode 100644 index 0000000..8cc7f28 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs @@ -0,0 +1,4117 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// changes for varsize regions +// note that raycasts need to have limited range +// (even in normal regions) +// or application thread stack may just blowup +// see RayCast(ODERayCastRequest req) + +//#define USE_DRAWSTUFF +//#define SPAM + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; +using log4net; +using Nini.Config; +using Mono.Addins; +using Ode.NET; +using OpenMetaverse; +#if USE_DRAWSTUFF +using Drawstuff.NET; +#endif +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; + + +namespace OpenSim.Region.PhysicsModule.ODE +{ + public enum StatusIndicators : int + { + Generic = 0, + Start = 1, + End = 2 + } + +// public struct sCollisionData +// { +// public uint ColliderLocalId; +// public uint CollidedWithLocalId; +// public int NumberOfCollisions; +// public int CollisionType; +// public int StatusIndicator; +// public int lastframe; +// } + + [Flags] + public enum CollisionCategories : int + { + Disabled = 0, + Geom = 0x00000001, + Body = 0x00000002, + Space = 0x00000004, + Character = 0x00000008, + Land = 0x00000010, + Water = 0x00000020, + Wind = 0x00000040, + Sensor = 0x00000080, + Selected = 0x00000100 + } + + /// + /// Material type for a primitive + /// + public enum Material : int + { + /// + Stone = 0, + /// + Metal = 1, + /// + Glass = 2, + /// + Wood = 3, + /// + Flesh = 4, + /// + Plastic = 5, + /// + Rubber = 6 + } + + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ODEPhysicsScene")] + public class OdeScene : PhysicsScene, INonSharedRegionModule + { + private readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString()); + private bool m_Enabled = false; + + // private Dictionary m_storedCollisions = new Dictionary(); + + /// + /// Provide a sync object so that only one thread calls d.Collide() at a time across all OdeScene instances. + /// + /// + /// With ODE as of r1755 (though also tested on r1860), only one thread can call d.Collide() at a + /// time, even where physics objects are in entirely different ODE worlds. This is because generating contacts + /// uses a static cache at the ODE level. + /// + /// Without locking, simulators running multiple regions will eventually crash with a native stack trace similar + /// to + /// + /// mono() [0x489171] + /// mono() [0x4d154f] + /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f6ded592c60] + /// .../opensim/bin/libode-x86_64.so(_ZN6Opcode11OBBCollider8_CollideEPKNS_14AABBNoLeafNodeE+0xd7a) [0x7f6dd822628a] + /// + /// ODE provides an experimental option to cache in thread local storage but compiling ODE with this option + /// causes OpenSimulator to immediately crash with a native stack trace similar to + /// + /// mono() [0x489171] + /// mono() [0x4d154f] + /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f03c9849c60] + /// .../opensim/bin/libode-x86_64.so(_Z12dCollideCCTLP6dxGeomS0_iP12dContactGeomi+0x92) [0x7f03b44bcf82] + /// + internal static Object UniversalColliderSyncObject = new Object(); + + /// + /// Is stats collecting enabled for this ODE scene? + /// + public bool CollectStats { get; set; } + + /// + /// Statistics for this scene. + /// + private Dictionary m_stats = new Dictionary(); + + /// + /// Stat name for total number of avatars in this ODE scene. + /// + public const string ODETotalAvatarsStatName = "ODETotalAvatars"; + + /// + /// Stat name for total number of prims in this ODE scene. + /// + public const string ODETotalPrimsStatName = "ODETotalPrims"; + + /// + /// Stat name for total number of prims with active physics in this ODE scene. + /// + public const string ODEActivePrimsStatName = "ODEActivePrims"; + + /// + /// Stat name for the total time spent in ODE frame processing. + /// + /// + /// A sanity check for the main scene loop physics time. + /// + public const string ODETotalFrameMsStatName = "ODETotalFrameMS"; + + /// + /// Stat name for time spent processing avatar taints per frame + /// + public const string ODEAvatarTaintMsStatName = "ODEAvatarTaintFrameMS"; + + /// + /// Stat name for time spent processing prim taints per frame + /// + public const string ODEPrimTaintMsStatName = "ODEPrimTaintFrameMS"; + + /// + /// Stat name for time spent calculating avatar forces per frame. + /// + public const string ODEAvatarForcesFrameMsStatName = "ODEAvatarForcesFrameMS"; + + /// + /// Stat name for time spent calculating prim forces per frame + /// + public const string ODEPrimForcesFrameMsStatName = "ODEPrimForcesFrameMS"; + + /// + /// Stat name for time spent fulfilling raycasting requests per frame + /// + public const string ODERaycastingFrameMsStatName = "ODERaycastingFrameMS"; + + /// + /// Stat name for time spent in native code that actually steps through the simulation. + /// + public const string ODENativeStepFrameMsStatName = "ODENativeStepFrameMS"; + + /// + /// Stat name for the number of milliseconds that ODE spends in native space collision code. + /// + public const string ODENativeSpaceCollisionFrameMsStatName = "ODENativeSpaceCollisionFrameMS"; + + /// + /// Stat name for milliseconds that ODE spends in native geom collision code. + /// + public const string ODENativeGeomCollisionFrameMsStatName = "ODENativeGeomCollisionFrameMS"; + + /// + /// Time spent in collision processing that is not spent in native space or geom collision code. + /// + public const string ODEOtherCollisionFrameMsStatName = "ODEOtherCollisionFrameMS"; + + /// + /// Stat name for time spent notifying listeners of collisions + /// + public const string ODECollisionNotificationFrameMsStatName = "ODECollisionNotificationFrameMS"; + + /// + /// Stat name for milliseconds spent updating avatar position and velocity + /// + public const string ODEAvatarUpdateFrameMsStatName = "ODEAvatarUpdateFrameMS"; + + /// + /// Stat name for the milliseconds spent updating prim position and velocity + /// + public const string ODEPrimUpdateFrameMsStatName = "ODEPrimUpdateFrameMS"; + + /// + /// Stat name for avatar collisions with another entity. + /// + public const string ODEAvatarContactsStatsName = "ODEAvatarContacts"; + + /// + /// Stat name for prim collisions with another entity. + /// + public const string ODEPrimContactsStatName = "ODEPrimContacts"; + + /// + /// Used to hold tick numbers for stat collection purposes. + /// + private int m_nativeCollisionStartTick; + + /// + /// A messy way to tell if we need to avoid adding a collision time because this was already done in the callback. + /// + private bool m_inCollisionTiming; + + /// + /// A temporary holder for the number of avatar collisions in a frame, so we can work out how many object + /// collisions occured using the _perloopcontact if stats collection is enabled. + /// + private int m_tempAvatarCollisionsThisFrame; + + /// + /// Used in calculating physics frame time dilation + /// + private int tickCountFrameRun; + + /// + /// Used in calculating physics frame time dilation + /// + private int latertickcount; + + private Random fluidRandomizer = new Random(Environment.TickCount); + + public bool m_suportCombine = true; + + private uint m_regionWidth = Constants.RegionSize; + private uint m_regionHeight = Constants.RegionSize; + + private float ODE_STEPSIZE = 0.0178f; + private float metersInSpace = 29.9f; + private float m_timeDilation = 1.0f; + + public float gravityx = 0f; + public float gravityy = 0f; + public float gravityz = -9.8f; + + public float AvatarTerminalVelocity { get; set; } + + private float contactsurfacelayer = 0.001f; + + private int worldHashspaceLow = -4; + private int worldHashspaceHigh = 128; + + private int smallHashspaceLow = -4; + private int smallHashspaceHigh = 66; + + private float waterlevel = 0f; + private int framecount = 0; + //private int m_returncollisions = 10; + + private IntPtr contactgroup; + +// internal IntPtr WaterGeom; + + private float nmTerrainContactFriction = 255.0f; + private float nmTerrainContactBounce = 0.1f; + private float nmTerrainContactERP = 0.1025f; + + private float mTerrainContactFriction = 75f; + private float mTerrainContactBounce = 0.1f; + private float mTerrainContactERP = 0.05025f; + + private float nmAvatarObjectContactFriction = 250f; + private float nmAvatarObjectContactBounce = 0.1f; + + private float mAvatarObjectContactFriction = 75f; + private float mAvatarObjectContactBounce = 0.1f; + + private float avPIDD = 3200f; + private float avPIDP = 1400f; + private float avCapRadius = 0.37f; + private float avStandupTensor = 2000000f; + + /// + /// true = old compatibility mode with leaning capsule; false = new corrected mode + /// + /// + /// Even when set to false, the capsule still tilts but this is done in a different way. + /// + public bool IsAvCapsuleTilted { get; private set; } + + private float avDensity = 80f; +// private float avHeightFudgeFactor = 0.52f; + private float avMovementDivisorWalk = 1.3f; + private float avMovementDivisorRun = 0.8f; + private float minimumGroundFlightOffset = 3f; + public float maximumMassObject = 10000.01f; + + public bool meshSculptedPrim = true; + public bool forceSimplePrimMeshing = false; + + public float meshSculptLOD = 32; + public float MeshSculptphysicalLOD = 16; + + public float geomDefaultDensity = 10.000006836f; + + public int geomContactPointsStartthrottle = 3; + public int geomUpdatesPerThrottledUpdate = 15; + private const int avatarExpectedContacts = 3; + + public float bodyPIDD = 35f; + public float bodyPIDG = 25; + + public int geomCrossingFailuresBeforeOutofbounds = 5; + + public float bodyMotorJointMaxforceTensor = 2; + + public int bodyFramesAutoDisable = 20; + + private float[] _watermap; + private bool m_filterCollisions = true; + + private d.NearCallback nearCallback; + public d.TriCallback triCallback; + public d.TriArrayCallback triArrayCallback; + + /// + /// Avatars in the physics scene. + /// + private readonly HashSet _characters = new HashSet(); + + /// + /// Prims in the physics scene. + /// + private readonly HashSet _prims = new HashSet(); + + /// + /// Prims in the physics scene that are subject to physics, not just collisions. + /// + private readonly HashSet _activeprims = new HashSet(); + + /// + /// Prims that the simulator has created/deleted/updated and so need updating in ODE. + /// + private readonly HashSet _taintedPrims = new HashSet(); + + /// + /// Record a character that has taints to be processed. + /// + private readonly HashSet _taintedActors = new HashSet(); + + /// + /// Keep record of contacts in the physics loop so that we can remove duplicates. + /// + private readonly List _perloopContact = new List(); + + /// + /// A dictionary of actors that should receive collision events. + /// + private readonly Dictionary m_collisionEventActors = new Dictionary(); + + /// + /// A dictionary of collision event changes that are waiting to be processed. + /// + private readonly Dictionary m_collisionEventActorsChanges = new Dictionary(); + + /// + /// Maps a unique geometry id (a memory location) to a physics actor name. + /// + /// + /// Only actors participating in collisions have geometries. This has to be maintained separately from + /// actor_name_map because terrain and water currently don't conceptually have a physics actor of their own + /// apart from the singleton PANull + /// + public Dictionary geom_name_map = new Dictionary(); + + /// + /// Maps a unique geometry id (a memory location) to a physics actor. + /// + /// + /// Only actors participating in collisions have geometries. + /// + public Dictionary actor_name_map = new Dictionary(); + + /// + /// Defects list to remove characters that no longer have finite positions due to some other bug. + /// + /// + /// Used repeatedly in Simulate() but initialized once here. + /// + private readonly List defects = new List(); + + private bool m_NINJA_physics_joints_enabled = false; + //private Dictionary jointpart_name_map = new Dictionary(); + private readonly Dictionary> joints_connecting_actor = new Dictionary>(); + private d.ContactGeom[] contacts; + + /// + /// Lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active + /// + private readonly List requestedJointsToBeCreated = new List(); + + /// + /// can lock for longer. accessed only by OdeScene. + /// + private readonly List pendingJoints = new List(); + + /// + /// can lock for longer. accessed only by OdeScene. + /// + private readonly List activeJoints = new List(); + + /// + /// lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active + /// + private readonly List requestedJointsToBeDeleted = new List(); + + private Object externalJointRequestsLock = new Object(); + private readonly Dictionary SOPName_to_activeJoint = new Dictionary(); + private readonly Dictionary SOPName_to_pendingJoint = new Dictionary(); + private readonly DoubleDictionary RegionTerrain = new DoubleDictionary(); + private readonly Dictionary TerrainHeightFieldHeights = new Dictionary(); + + private d.Contact contact; + private d.Contact TerrainContact; + private d.Contact AvatarMovementprimContact; + private d.Contact AvatarMovementTerrainContact; + private d.Contact WaterContact; + private d.Contact[,] m_materialContacts; + +//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it +//Ckrinke private int m_randomizeWater = 200; + private int m_physicsiterations = 10; + private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag + private readonly PhysicsActor PANull = new NullPhysicsActor(); +// private float step_time = 0.0f; +//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it +//Ckrinke private int ms = 0; + public IntPtr world; + //private bool returncollisions = false; + // private uint obj1LocalID = 0; + private uint obj2LocalID = 0; + //private int ctype = 0; + private OdeCharacter cc1; + private OdePrim cp1; + private OdeCharacter cc2; + private OdePrim cp2; + private int p1ExpectedPoints = 0; + private int p2ExpectedPoints = 0; + //private int cStartStop = 0; + //private string cDictKey = ""; + + public IntPtr space; + + //private IntPtr tmpSpace; + // split static geometry collision handling into spaces of 30 meters + public IntPtr[,] staticPrimspace; + + /// + /// Used to lock the entire physics scene. Locked during the main part of Simulate() + /// + internal Object OdeLock = new Object(); + + private bool _worldInitialized = false; + + public IMesher mesher; + + private IConfigSource m_config; + + public bool physics_logging = false; + public int physics_logging_interval = 0; + public bool physics_logging_append_existing_logfile = false; + + private bool avplanted = false; + private bool av_av_collisions_off = false; + + public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); + public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); + + private volatile int m_global_contactcount = 0; + + private Vector3 m_worldOffset = Vector3.Zero; + public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); + private PhysicsScene m_parentScene = null; + + float spacesPerMeterX; + float spacesPerMeterY; + int spaceGridMaxX; + int spaceGridMaxY; + + private ODERayCastRequestManager m_rayCastManager; + + + #region INonSharedRegionModule + public string Name + { + get { return "OpenDynamicsEngine"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Initialise(IConfigSource source) + { + // TODO: Move this out of Startup + IConfig config = source.Configs["Startup"]; + if (config != null) + { + string physics = config.GetString("physics", string.Empty); + if (physics == Name) + { + m_Enabled = true; + m_config = source; + + // We do this so that OpenSimulator on Windows loads the correct native ODE library depending on whether + // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports + // will find it already loaded later on. + // + // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be + // controlled in Ode.NET.dll.config + if (Util.IsWindows()) + Util.LoadArchSpecificWindowsDll("ode.dll"); + + // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to + // http://opensimulator.org/mantis/view.php?id=2750). + d.InitODE(); + + } + } + + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + EngineType = Name; + PhysicsSceneName = EngineType + "/" + scene.RegionInfo.RegionName; + + scene.RegisterModuleInterface(this); + Vector3 extent = new Vector3(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, scene.RegionInfo.RegionSizeZ); + Initialise(extent); + InitialiseFromConfig(m_config); + + // This may not be that good since terrain may not be avaiable at this point + base.Initialise(scene.PhysicsRequestAsset, + (scene.Heightmap != null ? scene.Heightmap.GetFloatsSerialised() : new float[(int)(extent.X * extent.Y)]), + (float)scene.RegionInfo.RegionSettings.WaterHeight); + + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + + mesher = scene.RequestModuleInterface(); + if (mesher == null) + m_log.WarnFormat("[ODE SCENE]: No mesher in {0}. Things will not work well.", PhysicsSceneName); + } + #endregion + + /// + /// Initiailizes the scene + /// Sets many properties that ODE requires to be stable + /// These settings need to be tweaked 'exactly' right or weird stuff happens. + /// + private void Initialise(Vector3 regionExtent) + { + WorldExtents.X = regionExtent.X; + m_regionWidth = (uint)regionExtent.X; + WorldExtents.Y = regionExtent.Y; + m_regionHeight = (uint)regionExtent.Y; + + m_suportCombine = false; + + nearCallback = near; + triCallback = TriCallback; + triArrayCallback = TriArrayCallback; + m_rayCastManager = new ODERayCastRequestManager(this); + + // Create the world and the first space + world = d.WorldCreate(); + space = d.HashSpaceCreate(IntPtr.Zero); + + contactgroup = d.JointGroupCreate(0); + + d.WorldSetAutoDisableFlag(world, false); + + #if USE_DRAWSTUFF + Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization)); + viewthread.Start(); + #endif + + // _watermap = new float[258 * 258]; + + // Zero out the prim spaces array (we split our space into smaller spaces so + // we can hit test less. + } + +#if USE_DRAWSTUFF + public void startvisualization(object o) + { + ds.Functions fn; + fn.version = ds.VERSION; + fn.start = new ds.CallbackFunction(start); + fn.step = new ds.CallbackFunction(step); + fn.command = new ds.CallbackFunction(command); + fn.stop = null; + fn.path_to_textures = "./textures"; + string[] args = new string[0]; + ds.SimulationLoop(args.Length, args, 352, 288, ref fn); + } +#endif + + // Initialize from configs + private void InitialiseFromConfig(IConfigSource config) + { + InitializeExtraStats(); + + m_config = config; + // Defaults + + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + avPIDD = 3200.0f; + avPIDP = 1400.0f; + avStandupTensor = 2000000f; + } + else + { + avPIDD = 2200.0f; + avPIDP = 900.0f; + avStandupTensor = 550000f; + } + + int contactsPerCollision = 80; + + if (m_config != null) + { + IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"]; + if (physicsconfig != null) + { + CollectStats = physicsconfig.GetBoolean("collect_stats", false); + + gravityx = physicsconfig.GetFloat("world_gravityx", 0f); + gravityy = physicsconfig.GetFloat("world_gravityy", 0f); + gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f); + + float avatarTerminalVelocity = physicsconfig.GetFloat("avatar_terminal_velocity", 54f); + AvatarTerminalVelocity = Util.Clamp(avatarTerminalVelocity, 0, 255f); + if (AvatarTerminalVelocity != avatarTerminalVelocity) + { + m_log.WarnFormat( + "[ODE SCENE]: avatar_terminal_velocity of {0} is invalid. Clamping to {1}", + avatarTerminalVelocity, AvatarTerminalVelocity); + } + + worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4); + worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128); + + metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f); + smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4); + smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66); + + contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f); + + nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f); + nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f); + nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f); + + mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f); + mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f); + mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f); + + nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f); + nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f); + + mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f); + mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f); + + ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE); + m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10); + + avDensity = physicsconfig.GetFloat("av_density", 80f); +// avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f); + avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f); + avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f); + avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); + avplanted = physicsconfig.GetBoolean("av_planted", false); + av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false); + + IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false); + + contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); + + geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5); + geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15); + geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5); + + geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f); + bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20); + + bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f); + bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f); + + forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing); + meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true); + meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f); + MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f); + m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false); + + + + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f); + avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f); + avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f); + bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f); + } + else + { + avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f); + avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f); + avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f); + bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f); + } + + physics_logging = physicsconfig.GetBoolean("physics_logging", false); + physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0); + physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false); + + m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false); + minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f); + maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f); + } + } + + contacts = new d.ContactGeom[contactsPerCollision]; + + spacesPerMeterX = 1.0f / metersInSpace; + spacesPerMeterY = 1.0f / metersInSpace; + + spaceGridMaxX = (int)(WorldExtents.X * spacesPerMeterX); + spaceGridMaxY = (int)(WorldExtents.Y * spacesPerMeterY); + + // note: limit number of spaces + if (spaceGridMaxX > 24) + { + spaceGridMaxX = 24; + spacesPerMeterX = spaceGridMaxX / WorldExtents.X; + } + if (spaceGridMaxY > 24) + { + spaceGridMaxY = 24; + spacesPerMeterY = spaceGridMaxY / WorldExtents.Y ; + } + + staticPrimspace = new IntPtr[spaceGridMaxX, spaceGridMaxY]; + + // make this index limits + spaceGridMaxX--; + spaceGridMaxY--; + + + + // Centeral contact friction and bounce + // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why + // an avatar falls through in Z but not in X or Y when walking on a prim. + contact.surface.mode |= d.ContactFlags.SoftERP; + contact.surface.mu = nmAvatarObjectContactFriction; + contact.surface.bounce = nmAvatarObjectContactBounce; + contact.surface.soft_cfm = 0.010f; + contact.surface.soft_erp = 0.010f; + + // Terrain contact friction and Bounce + // This is the *non* moving version. Use this when an avatar + // isn't moving to keep it in place better + TerrainContact.surface.mode |= d.ContactFlags.SoftERP; + TerrainContact.surface.mu = nmTerrainContactFriction; + TerrainContact.surface.bounce = nmTerrainContactBounce; + TerrainContact.surface.soft_erp = nmTerrainContactERP; + + WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM); + WaterContact.surface.mu = 0f; // No friction + WaterContact.surface.bounce = 0.0f; // No bounce + WaterContact.surface.soft_cfm = 0.010f; + WaterContact.surface.soft_erp = 0.010f; + + // Prim contact friction and bounce + // THis is the *non* moving version of friction and bounce + // Use this when an avatar comes in contact with a prim + // and is moving + AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction; + AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce; + + // Terrain contact friction bounce and various error correcting calculations + // Use this when an avatar is in contact with the terrain and moving. + AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP; + AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction; + AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce; + AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP; + + /* + + Stone = 0, + /// + Metal = 1, + /// + Glass = 2, + /// + Wood = 3, + /// + Flesh = 4, + /// + Plastic = 5, + /// + Rubber = 6 + */ + + m_materialContacts = new d.Contact[7,2]; + + m_materialContacts[(int)Material.Stone, 0] = new d.Contact(); + m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction; + m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce; + m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Stone, 1] = new d.Contact(); + m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction; + m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce; + m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Metal, 0] = new d.Contact(); + m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction; + m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce; + m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Metal, 1] = new d.Contact(); + m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction; + m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce; + m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Glass, 0] = new d.Contact(); + m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f; + m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f; + m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f; + + /* + private float nmAvatarObjectContactFriction = 250f; + private float nmAvatarObjectContactBounce = 0.1f; + + private float mAvatarObjectContactFriction = 75f; + private float mAvatarObjectContactBounce = 0.1f; + */ + m_materialContacts[(int)Material.Glass, 1] = new d.Contact(); + m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f; + m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f; + m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Wood, 0] = new d.Contact(); + m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction; + m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce; + m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Wood, 1] = new d.Contact(); + m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction; + m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce; + m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Flesh, 0] = new d.Contact(); + m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction; + m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce; + m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Flesh, 1] = new d.Contact(); + m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction; + m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce; + m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Plastic, 0] = new d.Contact(); + m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction; + m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce; + m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Plastic, 1] = new d.Contact(); + m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction; + m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce; + m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Rubber, 0] = new d.Contact(); + m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction; + m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce; + m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f; + + m_materialContacts[(int)Material.Rubber, 1] = new d.Contact(); + m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP; + m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction; + m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce; + m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f; + m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f; + + d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh); + + // Set the gravity,, don't disable things automatically (we set it explicitly on some things) + + d.WorldSetGravity(world, gravityx, gravityy, gravityz); + d.WorldSetContactSurfaceLayer(world, contactsurfacelayer); + + d.WorldSetLinearDamping(world, 256f); + d.WorldSetAngularDamping(world, 256f); + d.WorldSetAngularDampingThreshold(world, 256f); + d.WorldSetLinearDampingThreshold(world, 256f); + d.WorldSetMaxAngularSpeed(world, 256f); + + // Set how many steps we go without running collision testing + // This is in addition to the step size. + // Essentially Steps * m_physicsiterations + d.WorldSetQuickStepNumIterations(world, m_physicsiterations); + //d.WorldSetContactMaxCorrectingVel(world, 1000.0f); + + for (int i = 0; i < staticPrimspace.GetLength(0); i++) + { + for (int j = 0; j < staticPrimspace.GetLength(1); j++) + { + staticPrimspace[i, j] = IntPtr.Zero; + } + } + + _worldInitialized = true; + } + +// internal void waitForSpaceUnlock(IntPtr space) +// { +// //if (space != IntPtr.Zero) +// //while (d.SpaceLockQuery(space)) { } // Wait and do nothing +// } + +// /// +// /// Debug space message for printing the space that a prim/avatar is in. +// /// +// /// +// /// Returns which split up space the given position is in. +// public string whichspaceamIin(Vector3 pos) +// { +// return calculateSpaceForGeom(pos).ToString(); +// } + + #region Collision Detection + + /// + /// Collides two geometries. + /// + /// + /// + /// /param> + /// + /// + /// + private int CollideGeoms( + IntPtr geom1, IntPtr geom2, int maxContacts, Ode.NET.d.ContactGeom[] contactsArray, int contactGeomSize) + { + int count; + + lock (OdeScene.UniversalColliderSyncObject) + { + // We do this inside the lock so that we don't count any delay in acquiring it + if (CollectStats) + m_nativeCollisionStartTick = Util.EnvironmentTickCount(); + + count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize); + } + + // We do this outside the lock so that any waiting threads aren't held up, though the effect is probably + // negligable + if (CollectStats) + m_stats[ODENativeGeomCollisionFrameMsStatName] + += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); + + return count; + } + + /// + /// Collide two spaces or a space and a geometry. + /// + /// + /// /param> + /// + private void CollideSpaces(IntPtr space1, IntPtr space2, IntPtr data) + { + if (CollectStats) + { + m_inCollisionTiming = true; + m_nativeCollisionStartTick = Util.EnvironmentTickCount(); + } + + d.SpaceCollide2(space1, space2, data, nearCallback); + + if (CollectStats && m_inCollisionTiming) + { + m_stats[ODENativeSpaceCollisionFrameMsStatName] + += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); + m_inCollisionTiming = false; + } + } + + /// + /// This is our near callback. A geometry is near a body + /// + /// The space that contains the geoms. Remember, spaces are also geoms + /// a geometry or space + /// another geometry or space + private void near(IntPtr space, IntPtr g1, IntPtr g2) + { + if (CollectStats && m_inCollisionTiming) + { + m_stats[ODENativeSpaceCollisionFrameMsStatName] + += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); + m_inCollisionTiming = false; + } + +// m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space); + // no lock here! It's invoked from within Simulate(), which is thread-locked + + // Test if we're colliding a geom with a space. + // If so we have to drill down into the space recursively + + if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) + { + if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) + return; + + // Separating static prim geometry spaces. + // We'll be calling near recursivly if one + // of them is a space to find all of the + // contact points in the space + try + { + CollideSpaces(g1, g2, IntPtr.Zero); + } + catch (AccessViolationException) + { + m_log.Error("[ODE SCENE]: Unable to collide test a space"); + return; + } + //Colliding a space or a geom with a space or a geom. so drill down + + //Collide all geoms in each space.. + //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback); + //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback); + return; + } + + if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) + return; + + IntPtr b1 = d.GeomGetBody(g1); + IntPtr b2 = d.GeomGetBody(g2); + + // d.GeomClassID id = d.GeomGetClass(g1); + + String name1 = null; + String name2 = null; + + if (!geom_name_map.TryGetValue(g1, out name1)) + { + name1 = "null"; + } + if (!geom_name_map.TryGetValue(g2, out name2)) + { + name2 = "null"; + } + + //if (id == d.GeomClassId.TriMeshClass) + //{ + // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2); + //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2); + //} + + // Figure out how many contact points we have + int count = 0; + + try + { + // Colliding Geom To Geom + // This portion of the function 'was' blatantly ripped off from BoxStack.cs + + if (g1 == g2) + return; // Can't collide with yourself + + if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) + return; + + count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf); + + // All code after this is only relevant if we have any collisions + if (count <= 0) + return; + + if (count > contacts.Length) + m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); + } + catch (SEHException) + { + m_log.Error( + "[ODE SCENE]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim."); + base.TriggerPhysicsBasedRestart(); + } + catch (Exception e) + { + m_log.ErrorFormat("[ODE SCENE]: Unable to collide test an object: {0}", e.Message); + return; + } + + PhysicsActor p1; + PhysicsActor p2; + + p1ExpectedPoints = 0; + p2ExpectedPoints = 0; + + if (!actor_name_map.TryGetValue(g1, out p1)) + { + p1 = PANull; + } + + if (!actor_name_map.TryGetValue(g2, out p2)) + { + p2 = PANull; + } + + ContactPoint maxDepthContact = new ContactPoint(); + if (p1.CollisionScore + count >= float.MaxValue) + p1.CollisionScore = 0; + p1.CollisionScore += count; + + if (p2.CollisionScore + count >= float.MaxValue) + p2.CollisionScore = 0; + p2.CollisionScore += count; + + for (int i = 0; i < count; i++) + { + d.ContactGeom curContact = contacts[i]; + + if (curContact.depth > maxDepthContact.PenetrationDepth) + { + maxDepthContact = new ContactPoint( + new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z), + new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z), + curContact.depth + ); + } + + //m_log.Warn("[CCOUNT]: " + count); + IntPtr joint; + // If we're colliding with terrain, use 'TerrainContact' instead of contact. + // allows us to have different settings + + // We only need to test p2 for 'jump crouch purposes' + if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim) + { + // Testing if the collision is at the feet of the avatar + + //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f)); + if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f)) + p2.IsColliding = true; + } + else + { + p2.IsColliding = true; + } + + //if ((framecount % m_returncollisions) == 0) + + switch (p1.PhysicsActorType) + { + case (int)ActorTypes.Agent: + p1ExpectedPoints = avatarExpectedContacts; + p2.CollidingObj = true; + break; + case (int)ActorTypes.Prim: + if (p1 != null && p1 is OdePrim) + p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts; + + if (p2.Velocity.LengthSquared() > 0.0f) + p2.CollidingObj = true; + break; + case (int)ActorTypes.Unknown: + p2.CollidingGround = true; + break; + default: + p2.CollidingGround = true; + break; + } + + // we don't want prim or avatar to explode + + #region InterPenetration Handling - Unintended physics explosions +# region disabled code1 + + if (curContact.depth >= 0.08f) + { + //This is disabled at the moment only because it needs more tweaking + //It will eventually be uncommented + /* + if (contact.depth >= 1.00f) + { + //m_log.Debug("[PHYSICS]: " + contact.depth.ToString()); + } + + //If you interpenetrate a prim with an agent + if ((p2.PhysicsActorType == (int) ActorTypes.Agent && + p1.PhysicsActorType == (int) ActorTypes.Prim) || + (p1.PhysicsActorType == (int) ActorTypes.Agent && + p2.PhysicsActorType == (int) ActorTypes.Prim)) + { + + //contact.depth = contact.depth * 4.15f; + /* + if (p2.PhysicsActorType == (int) ActorTypes.Agent) + { + p2.CollidingObj = true; + contact.depth = 0.003f; + p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f); + OdeCharacter character = (OdeCharacter) p2; + character.SetPidStatus(true); + contact.pos = new d.Vector3(contact.pos.X + (p1.Size.X / 2), contact.pos.Y + (p1.Size.Y / 2), contact.pos.Z + (p1.Size.Z / 2)); + + } + else + { + + //contact.depth = 0.0000000f; + } + if (p1.PhysicsActorType == (int) ActorTypes.Agent) + { + + p1.CollidingObj = true; + contact.depth = 0.003f; + p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f); + contact.pos = new d.Vector3(contact.pos.X + (p2.Size.X / 2), contact.pos.Y + (p2.Size.Y / 2), contact.pos.Z + (p2.Size.Z / 2)); + OdeCharacter character = (OdeCharacter)p1; + character.SetPidStatus(true); + } + else + { + + //contact.depth = 0.0000000f; + } + + + + } +*/ + // If you interpenetrate a prim with another prim + /* + if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim) + { + #region disabledcode2 + //OdePrim op1 = (OdePrim)p1; + //OdePrim op2 = (OdePrim)p2; + //op1.m_collisionscore++; + //op2.m_collisionscore++; + + //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000) + //{ + //op1.m_taintdisable = true; + //AddPhysicsActorTaint(p1); + //op2.m_taintdisable = true; + //AddPhysicsActorTaint(p2); + //} + + //if (contact.depth >= 0.25f) + //{ + // Don't collide, one or both prim will expld. + + //op1.m_interpenetrationcount++; + //op2.m_interpenetrationcount++; + //interpenetrations_before_disable = 200; + //if (op1.m_interpenetrationcount >= interpenetrations_before_disable) + //{ + //op1.m_taintdisable = true; + //AddPhysicsActorTaint(p1); + //} + //if (op2.m_interpenetrationcount >= interpenetrations_before_disable) + //{ + // op2.m_taintdisable = true; + //AddPhysicsActorTaint(p2); + //} + + //contact.depth = contact.depth / 8f; + //contact.normal = new d.Vector3(0, 0, 1); + //} + //if (op1.m_disabled || op2.m_disabled) + //{ + //Manually disabled objects stay disabled + //contact.depth = 0f; + //} + #endregion + } + */ +#endregion + if (curContact.depth >= 1.00f) + { + //m_log.Info("[P]: " + contact.depth.ToString()); + if ((p2.PhysicsActorType == (int) ActorTypes.Agent && + p1.PhysicsActorType == (int) ActorTypes.Unknown) || + (p1.PhysicsActorType == (int) ActorTypes.Agent && + p2.PhysicsActorType == (int) ActorTypes.Unknown)) + { + if (p2.PhysicsActorType == (int) ActorTypes.Agent) + { + if (p2 is OdeCharacter) + { + OdeCharacter character = (OdeCharacter) p2; + + //p2.CollidingObj = true; + curContact.depth = 0.00000003f; + p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f); + curContact.pos = + new d.Vector3(curContact.pos.X + (p1.Size.X/2), + curContact.pos.Y + (p1.Size.Y/2), + curContact.pos.Z + (p1.Size.Z/2)); + character.SetPidStatus(true); + } + } + + if (p1.PhysicsActorType == (int) ActorTypes.Agent) + { + if (p1 is OdeCharacter) + { + OdeCharacter character = (OdeCharacter) p1; + + //p2.CollidingObj = true; + curContact.depth = 0.00000003f; + p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f); + curContact.pos = + new d.Vector3(curContact.pos.X + (p1.Size.X/2), + curContact.pos.Y + (p1.Size.Y/2), + curContact.pos.Z + (p1.Size.Z/2)); + character.SetPidStatus(true); + } + } + } + } + } + + #endregion + + // Logic for collision handling + // Note, that if *all* contacts are skipped (VolumeDetect) + // The prim still detects (and forwards) collision events but + // appears to be phantom for the world + Boolean skipThisContact = false; + + if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) + skipThisContact = true; // No collision on volume detect prims + + if (av_av_collisions_off) + if ((p1 is OdeCharacter) && (p2 is OdeCharacter)) + skipThisContact = true; + + if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) + skipThisContact = true; // No collision on volume detect prims + + if (!skipThisContact && curContact.depth < 0f) + skipThisContact = true; + + if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType)) + skipThisContact = true; + + const int maxContactsbeforedeath = 4000; + joint = IntPtr.Zero; + + if (!skipThisContact) + { + _perloopContact.Add(curContact); + + if (name1 == "Terrain" || name2 == "Terrain") + { + if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && + (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) + { + p2ExpectedPoints = avatarExpectedContacts; + // Avatar is moving on terrain, use the movement terrain contact + AvatarMovementTerrainContact.geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact); + m_global_contactcount++; + } + } + else + { + if (p2.PhysicsActorType == (int)ActorTypes.Agent) + { + p2ExpectedPoints = avatarExpectedContacts; + // Avatar is standing on terrain, use the non moving terrain contact + TerrainContact.geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref TerrainContact); + m_global_contactcount++; + } + } + else + { + if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim) + { + // prim prim contact + // int pj294950 = 0; + int movintYN = 0; + int material = (int) Material.Wood; + // prim terrain contact + if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) + { + movintYN = 1; + } + + if (p2 is OdePrim) + { + material = ((OdePrim) p2).m_material; + p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; + } + + // Unnessesary because p1 is defined above + //if (p1 is OdePrim) + // { + // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts; + // } + //m_log.DebugFormat("Material: {0}", material); + + m_materialContacts[material, movintYN].geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); + m_global_contactcount++; + } + } + else + { + int movintYN = 0; + // prim terrain contact + if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) + { + movintYN = 1; + } + + int material = (int)Material.Wood; + + if (p2 is OdePrim) + { + material = ((OdePrim)p2).m_material; + p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; + } + + //m_log.DebugFormat("Material: {0}", material); + m_materialContacts[material, movintYN].geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); + m_global_contactcount++; + } + } + } + } + //if (p2.PhysicsActorType == (int)ActorTypes.Prim) + //{ + //m_log.Debug("[PHYSICS]: prim contacting with ground"); + //} + } + else if (name1 == "Water" || name2 == "Water") + { + /* + if ((p2.PhysicsActorType == (int) ActorTypes.Prim)) + { + } + else + { + } + */ + //WaterContact.surface.soft_cfm = 0.0000f; + //WaterContact.surface.soft_erp = 0.00000f; + if (curContact.depth > 0.1f) + { + curContact.depth *= 52; + //contact.normal = new d.Vector3(0, 0, 1); + //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f); + } + + WaterContact.geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref WaterContact); + m_global_contactcount++; + } + //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth); + } + else + { + if ((p2.PhysicsActorType == (int)ActorTypes.Agent)) + { + p2ExpectedPoints = avatarExpectedContacts; + if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) + { + // Avatar is moving on a prim, use the Movement prim contact + AvatarMovementprimContact.geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact); + m_global_contactcount++; + } + } + else + { + // Avatar is standing still on a prim, use the non movement contact + contact.geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref contact); + m_global_contactcount++; + } + } + } + else if (p2.PhysicsActorType == (int)ActorTypes.Prim) + { + //p1.PhysicsActorType + int material = (int)Material.Wood; + + if (p2 is OdePrim) + { + material = ((OdePrim)p2).m_material; + p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts; + } + + //m_log.DebugFormat("Material: {0}", material); + m_materialContacts[material, 0].geom = curContact; + + if (m_global_contactcount < maxContactsbeforedeath) + { + joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]); + m_global_contactcount++; + } + } + } + + if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide! + { + d.JointAttach(joint, b1, b2); + m_global_contactcount++; + } + } + + collision_accounting_events(p1, p2, maxDepthContact); + + if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle)) + { + // If there are more then 3 contact points, it's likely + // that we've got a pile of objects, so ... + // We don't want to send out hundreds of terse updates over and over again + // so lets throttle them and send them again after it's somewhat sorted out. + p2.ThrottleUpdates = true; + } + //m_log.Debug(count.ToString()); + //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2); + } + } + + private bool checkDupe(d.ContactGeom contactGeom, int atype) + { + if (!m_filterCollisions) + return false; + + bool result = false; + + ActorTypes at = (ActorTypes)atype; + + foreach (d.ContactGeom contact in _perloopContact) + { + //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2)) + //{ + // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2) + if (at == ActorTypes.Agent) + { + if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) + && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) + && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f))) + { + if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f) + { + //contactGeom.depth *= .00005f; + //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); + // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); + result = true; + break; + } +// else +// { +// //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); +// } + } +// else +// { +// //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); +// //int i = 0; +// } + } + else if (at == ActorTypes.Prim) + { + //d.AABB aabb1 = new d.AABB(); + //d.AABB aabb2 = new d.AABB(); + + //d.GeomGetAABB(contactGeom.g2, out aabb2); + //d.GeomGetAABB(contactGeom.g1, out aabb1); + //aabb1. + if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f))) + { + if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z) + { + if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f) + { + result = true; + break; + } + } + //m_log.DebugFormat("[Collision]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); + //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); + } + } + } + + return result; + } + + private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact) + { + // obj1LocalID = 0; + //returncollisions = false; + obj2LocalID = 0; + //ctype = 0; + //cStartStop = 0; + if (!p2.SubscribedEvents() && !p1.SubscribedEvents()) + return; + + switch ((ActorTypes)p2.PhysicsActorType) + { + case ActorTypes.Agent: + cc2 = (OdeCharacter)p2; + + // obj1LocalID = cc2.m_localID; + switch ((ActorTypes)p1.PhysicsActorType) + { + case ActorTypes.Agent: + cc1 = (OdeCharacter)p1; + obj2LocalID = cc1.LocalID; + cc1.AddCollisionEvent(cc2.LocalID, contact); + //ctype = (int)CollisionCategories.Character; + + //if (cc1.CollidingObj) + //cStartStop = (int)StatusIndicators.Generic; + //else + //cStartStop = (int)StatusIndicators.Start; + + //returncollisions = true; + break; + + case ActorTypes.Prim: + if (p1 is OdePrim) + { + cp1 = (OdePrim) p1; + obj2LocalID = cp1.LocalID; + cp1.AddCollisionEvent(cc2.LocalID, contact); + } + //ctype = (int)CollisionCategories.Geom; + + //if (cp1.CollidingObj) + //cStartStop = (int)StatusIndicators.Generic; + //else + //cStartStop = (int)StatusIndicators.Start; + + //returncollisions = true; + break; + + case ActorTypes.Ground: + case ActorTypes.Unknown: + obj2LocalID = 0; + //ctype = (int)CollisionCategories.Land; + //returncollisions = true; + break; + } + + cc2.AddCollisionEvent(obj2LocalID, contact); + break; + + case ActorTypes.Prim: + + if (p2 is OdePrim) + { + cp2 = (OdePrim) p2; + + // obj1LocalID = cp2.m_localID; + switch ((ActorTypes) p1.PhysicsActorType) + { + case ActorTypes.Agent: + if (p1 is OdeCharacter) + { + cc1 = (OdeCharacter) p1; + obj2LocalID = cc1.LocalID; + cc1.AddCollisionEvent(cp2.LocalID, contact); + //ctype = (int)CollisionCategories.Character; + + //if (cc1.CollidingObj) + //cStartStop = (int)StatusIndicators.Generic; + //else + //cStartStop = (int)StatusIndicators.Start; + //returncollisions = true; + } + break; + case ActorTypes.Prim: + + if (p1 is OdePrim) + { + cp1 = (OdePrim) p1; + obj2LocalID = cp1.LocalID; + cp1.AddCollisionEvent(cp2.LocalID, contact); + //ctype = (int)CollisionCategories.Geom; + + //if (cp1.CollidingObj) + //cStartStop = (int)StatusIndicators.Generic; + //else + //cStartStop = (int)StatusIndicators.Start; + + //returncollisions = true; + } + break; + + case ActorTypes.Ground: + case ActorTypes.Unknown: + obj2LocalID = 0; + //ctype = (int)CollisionCategories.Land; + + //returncollisions = true; + break; + } + + cp2.AddCollisionEvent(obj2LocalID, contact); + } + break; + } + //if (returncollisions) + //{ + + //lock (m_storedCollisions) + //{ + //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString(); + //if (m_storedCollisions.ContainsKey(cDictKey)) + //{ + //sCollisionData objd = m_storedCollisions[cDictKey]; + //objd.NumberOfCollisions += 1; + //objd.lastframe = framecount; + //m_storedCollisions[cDictKey] = objd; + //} + //else + //{ + //sCollisionData objd = new sCollisionData(); + //objd.ColliderLocalId = obj1LocalID; + //objd.CollidedWithLocalId = obj2LocalID; + //objd.CollisionType = ctype; + //objd.NumberOfCollisions = 1; + //objd.lastframe = framecount; + //objd.StatusIndicator = cStartStop; + //m_storedCollisions.Add(cDictKey, objd); + //} + //} + // } + } + + private int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount) + { + /* String name1 = null; + String name2 = null; + + if (!geom_name_map.TryGetValue(trimesh, out name1)) + { + name1 = "null"; + } + if (!geom_name_map.TryGetValue(refObject, out name2)) + { + name2 = "null"; + } + + m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2); + */ + return 1; + } + + private int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex) + { +// String name1 = null; +// String name2 = null; +// +// if (!geom_name_map.TryGetValue(trimesh, out name1)) +// { +// name1 = "null"; +// } +// +// if (!geom_name_map.TryGetValue(refObject, out name2)) +// { +// name2 = "null"; +// } + + // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex); + + d.Vector3 v0 = new d.Vector3(); + d.Vector3 v1 = new d.Vector3(); + d.Vector3 v2 = new d.Vector3(); + + d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2); + // m_log.DebugFormat("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z); + + return 1; + } + + /// + /// This is our collision testing routine in ODE + /// + private void collision_optimized() + { + _perloopContact.Clear(); + + foreach (OdeCharacter chr in _characters) + { + // Reset the collision values to false + // since we don't know if we're colliding yet + if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero) + continue; + + chr.IsColliding = false; + chr.CollidingGround = false; + chr.CollidingObj = false; + + // Test the avatar's geometry for collision with the space + // This will return near and the space that they are the closest to + // And we'll run this again against the avatar and the space segment + // This will return with a bunch of possible objects in the space segment + // and we'll run it again on all of them. + try + { + CollideSpaces(space, chr.Shell, IntPtr.Zero); + } + catch (AccessViolationException) + { + m_log.ErrorFormat("[ODE SCENE]: Unable to space collide {0}", PhysicsSceneName); + } + + //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y); + //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10) + //{ + //chr.Position.Z = terrainheight + 10.0f; + //forcedZ = true; + //} + } + + if (CollectStats) + { + m_tempAvatarCollisionsThisFrame = _perloopContact.Count; + m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame; + } + + List removeprims = null; + foreach (OdePrim chr in _activeprims) + { + if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled)) + { + try + { + lock (chr) + { + if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false) + { + CollideSpaces(space, chr.prim_geom, IntPtr.Zero); + } + else + { + if (removeprims == null) + { + removeprims = new List(); + } + removeprims.Add(chr); + m_log.Error( + "[ODE SCENE]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!"); + } + } + } + catch (AccessViolationException) + { + m_log.Error("[ODE SCENE]: Unable to space collide"); + } + } + } + + if (CollectStats) + m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame; + + if (removeprims != null) + { + foreach (OdePrim chr in removeprims) + { + _activeprims.Remove(chr); + } + } + } + + #endregion + + public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) + { + if (!m_suportCombine) + return; + m_worldOffset = offset; + WorldExtents = new Vector2(extents.X, extents.Y); + m_parentScene = pScene; + } + + // Recovered for use by fly height. Kitto Flora + internal float GetTerrainHeightAtXY(float x, float y) + { + IntPtr heightFieldGeom = IntPtr.Zero; + int offsetX = 0; + int offsetY = 0; + + if (m_suportCombine) + { + offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize; + offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize; + } + + if(RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom)) + { + if (heightFieldGeom != IntPtr.Zero) + { + if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom)) + { + + int index; + + + if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y || + (int)x < 0.001f || (int)y < 0.001f) + return 0; + + x = x - offsetX + 1f; + y = y - offsetY + 1f; + + index = (int)((int)x * ((int)m_regionHeight +3) + (int)y); + + if (index < TerrainHeightFieldHeights[heightFieldGeom].Length) + { + //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]); + return (float)TerrainHeightFieldHeights[heightFieldGeom][index]; + } + + else + return 0f; + } + else + { + return 0f; + } + + } + else + { + return 0f; + } + + } + else + { + return 0f; + } + } +// End recovered. Kitto Flora + + /// + /// Add actor to the list that should receive collision events in the simulate loop. + /// + /// + internal void AddCollisionEventReporting(PhysicsActor obj) + { +// m_log.DebugFormat("[PHYSICS]: Adding {0} {1} to collision event reporting", obj.SOPName, obj.LocalID); + + lock (m_collisionEventActorsChanges) + m_collisionEventActorsChanges[obj.LocalID] = obj; + } + + /// + /// Remove actor from the list that should receive collision events in the simulate loop. + /// + /// + internal void RemoveCollisionEventReporting(PhysicsActor obj) + { +// m_log.DebugFormat("[PHYSICS]: Removing {0} {1} from collision event reporting", obj.SOPName, obj.LocalID); + + lock (m_collisionEventActorsChanges) + m_collisionEventActorsChanges[obj.LocalID] = null; + } + + #region Add/Remove Entities + + public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) + { + OdeCharacter newAv + = new OdeCharacter( + avName, this, position, velocity, size, avPIDD, avPIDP, + avCapRadius, avStandupTensor, avDensity, + avMovementDivisorWalk, avMovementDivisorRun); + + newAv.Flying = isFlying; + newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; + newAv.m_avatarplanted = avplanted; + + return newAv; + } + + public override void RemoveAvatar(PhysicsActor actor) + { +// m_log.DebugFormat( +// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}", +// actor.Name, actor.LocalID, Name); + + ((OdeCharacter) actor).Destroy(); + } + + internal void AddCharacter(OdeCharacter chr) + { + chr.m_avatarplanted = avplanted; + if (!_characters.Contains(chr)) + { + _characters.Add(chr); + +// m_log.DebugFormat( +// "[ODE SCENE]: Adding physics character {0} {1} to physics scene {2}. Count now {3}", +// chr.Name, chr.LocalID, Name, _characters.Count); + + if (chr.bad) + m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to characters list", chr.m_uuid); + } + else + { + m_log.ErrorFormat( + "[ODE SCENE]: Tried to add character {0} {1} but they are already in the set!", + chr.Name, chr.LocalID); + } + } + + internal void RemoveCharacter(OdeCharacter chr) + { + if (_characters.Contains(chr)) + { + _characters.Remove(chr); + +// m_log.DebugFormat( +// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}. Count now {3}", +// chr.Name, chr.LocalID, Name, _characters.Count); + } + else + { + m_log.ErrorFormat( + "[ODE SCENE]: Tried to remove character {0} {1} but they are not in the list!", + chr.Name, chr.LocalID); + } + } + + private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, + PrimitiveBaseShape pbs, bool isphysical, uint localID) + { + Vector3 pos = position; + Vector3 siz = size; + Quaternion rot = rotation; + + OdePrim newPrim; + lock (OdeLock) + { + newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical); + + lock (_prims) + _prims.Add(newPrim); + } + newPrim.LocalID = localID; + return newPrim; + } + + /// + /// Make this prim subject to physics. + /// + /// + internal void ActivatePrim(OdePrim prim) + { + // adds active prim.. (ones that should be iterated over in collisions_optimized + if (!_activeprims.Contains(prim)) + _activeprims.Add(prim); + //else + // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent"); + } + + public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, + Vector3 size, Quaternion rotation, bool isPhysical, uint localid) + { +// m_log.DebugFormat("[ODE SCENE]: Adding physics prim {0} {1} to physics scene {2}", primName, localid, Name); + + return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid); + } + + public override float TimeDilation + { + get { return m_timeDilation; } + } + + public override bool SupportsNINJAJoints + { + get { return m_NINJA_physics_joints_enabled; } + } + + // internal utility function: must be called within a lock (OdeLock) + private void InternalAddActiveJoint(PhysicsJoint joint) + { + activeJoints.Add(joint); + SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint); + } + + // internal utility function: must be called within a lock (OdeLock) + private void InternalAddPendingJoint(OdePhysicsJoint joint) + { + pendingJoints.Add(joint); + SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint); + } + + // internal utility function: must be called within a lock (OdeLock) + private void InternalRemovePendingJoint(PhysicsJoint joint) + { + pendingJoints.Remove(joint); + SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene); + } + + // internal utility function: must be called within a lock (OdeLock) + private void InternalRemoveActiveJoint(PhysicsJoint joint) + { + activeJoints.Remove(joint); + SOPName_to_activeJoint.Remove(joint.ObjectNameInScene); + } + + public override void DumpJointInfo() + { + string hdr = "[NINJA] JOINTINFO: "; + foreach (PhysicsJoint j in pendingJoints) + { + m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); + } + m_log.Debug(hdr + pendingJoints.Count + " total pending joints"); + foreach (string jointName in SOPName_to_pendingJoint.Keys) + { + m_log.Debug(hdr + " pending joints dict contains Name: " + jointName); + } + m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries"); + foreach (PhysicsJoint j in activeJoints) + { + m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); + } + m_log.Debug(hdr + activeJoints.Count + " total active joints"); + foreach (string jointName in SOPName_to_activeJoint.Keys) + { + m_log.Debug(hdr + " active joints dict contains Name: " + jointName); + } + m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries"); + + m_log.Debug(hdr + " Per-body joint connectivity information follows."); + m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints."); + foreach (string actorName in joints_connecting_actor.Keys) + { + m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it"); + foreach (PhysicsJoint j in joints_connecting_actor[actorName]) + { + m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); + } + m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor"); + } + } + + public override void RequestJointDeletion(string ObjectNameInScene) + { + lock (externalJointRequestsLock) + { + if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously + { + requestedJointsToBeDeleted.Add(ObjectNameInScene); + } + } + } + + private void DeleteRequestedJoints() + { + List myRequestedJointsToBeDeleted; + lock (externalJointRequestsLock) + { + // make a local copy of the shared list for processing (threading issues) + myRequestedJointsToBeDeleted = new List(requestedJointsToBeDeleted); + } + + foreach (string jointName in myRequestedJointsToBeDeleted) + { + lock (OdeLock) + { + //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName); + if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName)) + { + OdePhysicsJoint joint = null; + if (SOPName_to_activeJoint.ContainsKey(jointName)) + { + joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint; + InternalRemoveActiveJoint(joint); + } + else if (SOPName_to_pendingJoint.ContainsKey(jointName)) + { + joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint; + InternalRemovePendingJoint(joint); + } + + if (joint != null) + { + //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames); + for (int iBodyName = 0; iBodyName < 2; iBodyName++) + { + string bodyName = joint.BodyNames[iBodyName]; + if (bodyName != "NULL") + { + joints_connecting_actor[bodyName].Remove(joint); + if (joints_connecting_actor[bodyName].Count == 0) + { + joints_connecting_actor.Remove(bodyName); + } + } + } + + DoJointDeactivated(joint); + if (joint.jointID != IntPtr.Zero) + { + d.JointDestroy(joint.jointID); + joint.jointID = IntPtr.Zero; + //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName); + } + else + { + //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName); + } + } + else + { + // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName); + } + } + else + { + // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName); + } + } + } + + // remove processed joints from the shared list + lock (externalJointRequestsLock) + { + foreach (string jointName in myRequestedJointsToBeDeleted) + { + requestedJointsToBeDeleted.Remove(jointName); + } + } + } + + // for pending joints we don't know if their associated bodies exist yet or not. + // the joint is actually created during processing of the taints + private void CreateRequestedJoints() + { + List myRequestedJointsToBeCreated; + lock (externalJointRequestsLock) + { + // make a local copy of the shared list for processing (threading issues) + myRequestedJointsToBeCreated = new List(requestedJointsToBeCreated); + } + + foreach (PhysicsJoint joint in myRequestedJointsToBeCreated) + { + lock (OdeLock) + { + if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null) + { + DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation); + continue; + } + if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null) + { + DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation); + continue; + } + + InternalAddPendingJoint(joint as OdePhysicsJoint); + + if (joint.BodyNames.Count >= 2) + { + for (int iBodyName = 0; iBodyName < 2; iBodyName++) + { + string bodyName = joint.BodyNames[iBodyName]; + if (bodyName != "NULL") + { + if (!joints_connecting_actor.ContainsKey(bodyName)) + { + joints_connecting_actor.Add(bodyName, new List()); + } + joints_connecting_actor[bodyName].Add(joint); + } + } + } + } + } + + // remove processed joints from shared list + lock (externalJointRequestsLock) + { + foreach (PhysicsJoint joint in myRequestedJointsToBeCreated) + { + requestedJointsToBeCreated.Remove(joint); + } + } + } + + /// + /// Add a request for joint creation. + /// + /// + /// this joint will just be added to a waiting list that is NOT processed during the main + /// Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public override PhysicsJoint RequestJointCreation( + string objectNameInScene, PhysicsJointType jointType, Vector3 position, + Quaternion rotation, string parms, List bodyNames, string trackedBodyName, Quaternion localRotation) + { + OdePhysicsJoint joint = new OdePhysicsJoint(); + joint.ObjectNameInScene = objectNameInScene; + joint.Type = jointType; + joint.Position = position; + joint.Rotation = rotation; + joint.RawParams = parms; + joint.BodyNames = new List(bodyNames); + joint.TrackedBodyName = trackedBodyName; + joint.LocalRotation = localRotation; + joint.jointID = IntPtr.Zero; + joint.ErrorMessageCount = 0; + + lock (externalJointRequestsLock) + { + if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice + { + requestedJointsToBeCreated.Add(joint); + } + } + + return joint; + } + + private void RemoveAllJointsConnectedToActor(PhysicsActor actor) + { + //m_log.Debug("RemoveAllJointsConnectedToActor: start"); + if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null) + { + List jointsToRemove = new List(); + //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism) + foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName]) + { + jointsToRemove.Add(j); + } + foreach (PhysicsJoint j in jointsToRemove) + { + //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene); + RequestJointDeletion(j.ObjectNameInScene); + //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene); + j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing) + } + } + } + + public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor) + { + //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start"); + lock (OdeLock) + { + //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock"); + RemoveAllJointsConnectedToActor(actor); + } + } + + // normally called from within OnJointMoved, which is called from within a lock (OdeLock) + public override Vector3 GetJointAnchor(PhysicsJoint joint) + { + Debug.Assert(joint.IsInPhysicsEngine); + d.Vector3 pos = new d.Vector3(); + + if (!(joint is OdePhysicsJoint)) + { + DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); + } + else + { + OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; + switch (odeJoint.Type) + { + case PhysicsJointType.Ball: + d.JointGetBallAnchor(odeJoint.jointID, out pos); + break; + case PhysicsJointType.Hinge: + d.JointGetHingeAnchor(odeJoint.jointID, out pos); + break; + } + } + return new Vector3(pos.X, pos.Y, pos.Z); + } + + /// + /// Get joint axis. + /// + /// + /// normally called from within OnJointMoved, which is called from within a lock (OdeLock) + /// WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function + /// appears to be unreliable. Fortunately we can compute the joint axis ourselves by + /// keeping track of the joint's original orientation relative to one of the involved bodies. + /// + /// + /// + public override Vector3 GetJointAxis(PhysicsJoint joint) + { + Debug.Assert(joint.IsInPhysicsEngine); + d.Vector3 axis = new d.Vector3(); + + if (!(joint is OdePhysicsJoint)) + { + DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); + } + else + { + OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; + switch (odeJoint.Type) + { + case PhysicsJointType.Ball: + DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene); + break; + case PhysicsJointType.Hinge: + d.JointGetHingeAxis(odeJoint.jointID, out axis); + break; + } + } + return new Vector3(axis.X, axis.Y, axis.Z); + } + + /// + /// Stop this prim being subject to physics + /// + /// + internal void DeactivatePrim(OdePrim prim) + { + _activeprims.Remove(prim); + } + + public override void RemovePrim(PhysicsActor prim) + { + // As with all ODE physics operations, we don't remove the prim immediately but signal that it should be + // removed in the next physics simulate pass. + if (prim is OdePrim) + { + lock (OdeLock) + { + OdePrim p = (OdePrim) prim; + + p.setPrimForRemoval(); + AddPhysicsActorTaint(prim); + } + } + } + + /// + /// This is called from within simulate but outside the locked portion + /// We need to do our own locking here + /// (Note: As of 20110801 this no longer appears to be true - this is being called within lock (odeLock) in + /// Simulate() -- justincc). + /// + /// Essentially, we need to remove the prim from our space segment, whatever segment it's in. + /// + /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory + /// that the space was using. + /// + /// + internal void RemovePrimThreadLocked(OdePrim prim) + { +// m_log.DebugFormat("[ODE SCENE]: Removing physical prim {0} {1}", prim.Name, prim.LocalID); + + lock (prim) + { + RemoveCollisionEventReporting(prim); + + if (prim.prim_geom != IntPtr.Zero) + { + prim.ResetTaints(); + + if (prim.IsPhysical) + { + prim.disableBody(); + if (prim.childPrim) + { + prim.childPrim = false; + prim.Body = IntPtr.Zero; + prim.m_disabled = true; + prim.IsPhysical = false; + } + + + } + // we don't want to remove the main space + + // If the geometry is in the targetspace, remove it from the target space + //m_log.Warn(prim.m_targetSpace); + + //if (prim.m_targetSpace != IntPtr.Zero) + //{ + //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom)) + //{ + + //if (d.GeomIsSpace(prim.m_targetSpace)) + //{ + //waitForSpaceUnlock(prim.m_targetSpace); + //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom); + prim.m_targetSpace = IntPtr.Zero; + //} + //else + //{ + // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" + + //((OdePrim)prim).m_targetSpace.ToString()); + //} + + //} + //} + //m_log.Warn(prim.prim_geom); + + if (!prim.RemoveGeom()) + m_log.Warn("[ODE SCENE]: Unable to remove prim from physics scene"); + + lock (_prims) + _prims.Remove(prim); + + //If there are no more geometries in the sub-space, we don't need it in the main space anymore + //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0) + //{ + //if (prim.m_targetSpace != null) + //{ + //if (d.GeomIsSpace(prim.m_targetSpace)) + //{ + //waitForSpaceUnlock(prim.m_targetSpace); + //d.SpaceRemove(space, prim.m_targetSpace); + // free up memory used by the space. + //d.SpaceDestroy(prim.m_targetSpace); + //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position); + //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]); + //} + //else + //{ + //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" + + //((OdePrim) prim).m_targetSpace.ToString()); + //} + //} + //} + + if (SupportsNINJAJoints) + RemoveAllJointsConnectedToActorThreadLocked(prim); + } + } + } + + #endregion + + #region Space Separation Calculation + + /// + /// Takes a space pointer and zeros out the array we're using to hold the spaces + /// + /// + private void resetSpaceArrayItemToZero(IntPtr pSpace) + { + for (int x = 0; x < staticPrimspace.GetLength(0); x++) + { + for (int y = 0; y < staticPrimspace.GetLength(1); y++) + { + if (staticPrimspace[x, y] == pSpace) + staticPrimspace[x, y] = IntPtr.Zero; + } + } + } + +// private void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY) +// { +// staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero; +// } + + /// + /// Called when a static prim moves. Allocates a space for the prim based on its position + /// + /// the pointer to the geom that moved + /// the position that the geom moved to + /// a pointer to the space it was in before it was moved. + /// a pointer to the new space it's in + internal IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace) + { + // Called from setting the Position and Size of an ODEPrim so + // it's already in locked space. + + // we don't want to remove the main space + // we don't need to test physical here because this function should + // never be called if the prim is physical(active) + + // All physical prim end up in the root space + //Thread.Sleep(20); + if (currentspace != space) + { + //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString()); + //if (currentspace == IntPtr.Zero) + //{ + //int adfadf = 0; + //} + if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero) + { + if (d.GeomIsSpace(currentspace)) + { +// waitForSpaceUnlock(currentspace); + d.SpaceRemove(currentspace, geom); + } + else + { + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace + + " Geom:" + geom); + } + } + else + { + IntPtr sGeomIsIn = d.GeomGetSpace(geom); + if (sGeomIsIn != IntPtr.Zero) + { + if (d.GeomIsSpace(currentspace)) + { +// waitForSpaceUnlock(sGeomIsIn); + d.SpaceRemove(sGeomIsIn, geom); + } + else + { + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + + sGeomIsIn + " Geom:" + geom); + } + } + } + + //If there are no more geometries in the sub-space, we don't need it in the main space anymore + if (d.SpaceGetNumGeoms(currentspace) == 0) + { + if (currentspace != IntPtr.Zero) + { + if (d.GeomIsSpace(currentspace)) + { +// waitForSpaceUnlock(currentspace); +// waitForSpaceUnlock(space); + d.SpaceRemove(space, currentspace); + // free up memory used by the space. + + //d.SpaceDestroy(currentspace); + resetSpaceArrayItemToZero(currentspace); + } + else + { + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + + currentspace + " Geom:" + geom); + } + } + } + } + else + { + // this is a physical object that got disabled. ;.; + if (currentspace != IntPtr.Zero && geom != IntPtr.Zero) + { + if (d.SpaceQuery(currentspace, geom)) + { + if (d.GeomIsSpace(currentspace)) + { +// waitForSpaceUnlock(currentspace); + d.SpaceRemove(currentspace, geom); + } + else + { + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + + currentspace + " Geom:" + geom); + } + } + else + { + IntPtr sGeomIsIn = d.GeomGetSpace(geom); + if (sGeomIsIn != IntPtr.Zero) + { + if (d.GeomIsSpace(sGeomIsIn)) + { +// waitForSpaceUnlock(sGeomIsIn); + d.SpaceRemove(sGeomIsIn, geom); + } + else + { + m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + + sGeomIsIn + " Geom:" + geom); + } + } + } + } + } + + // The routines in the Position and Size sections do the 'inserting' into the space, + // so all we have to do is make sure that the space that we're putting the prim into + // is in the 'main' space. + int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos); + IntPtr newspace = calculateSpaceForGeom(pos); + + if (newspace == IntPtr.Zero) + { + newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]); + d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh); + } + + return newspace; + } + + /// + /// Creates a new space at X Y + /// + /// + /// + /// A pointer to the created space + internal IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY) + { + // creating a new space for prim and inserting it into main space. + staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero); + d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space); +// waitForSpaceUnlock(space); + d.SpaceSetSublevel(space, 1); + d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]); + + return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]; + } + + /// + /// Calculates the space the prim should be in by its position + /// + /// + /// a pointer to the space. This could be a new space or reused space. + internal IntPtr calculateSpaceForGeom(Vector3 pos) + { + int[] xyspace = calculateSpaceArrayItemFromPos(pos); + //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString()); + return staticPrimspace[xyspace[0], xyspace[1]]; + } + + /// + /// Holds the space allocation logic + /// + /// + /// an array item based on the position + internal int[] calculateSpaceArrayItemFromPos(Vector3 pos) + { + int[] returnint = new int[2]; + + returnint[0] = (int) (pos.X * spacesPerMeterX); + + if (returnint[0] > spaceGridMaxX) + returnint[0] = spaceGridMaxX; + if (returnint[0] < 0) + returnint[0] = 0; + + returnint[1] = (int)(pos.Y * spacesPerMeterY); + if (returnint[1] > spaceGridMaxY) + returnint[1] = spaceGridMaxY; + if (returnint[1] < 0) + returnint[1] = 0; + + return returnint; + } + + #endregion + + /// + /// Routine to figure out if we need to mesh this prim with our mesher + /// + /// + /// + internal bool needsMeshing(PrimitiveBaseShape pbs) + { + // most of this is redundant now as the mesher will return null if it cant mesh a prim + // but we still need to check for sculptie meshing being enabled so this is the most + // convenient place to do it for now... + + // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f) + // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString()); + int iPropertiesNotSupportedDefault = 0; + + if (pbs.SculptEntry && !meshSculptedPrim) + { +#if SPAM + m_log.Warn("NonMesh"); +#endif + return false; + } + + // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim + if (!forceSimplePrimMeshing && !pbs.SculptEntry) + { + if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) + || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 + && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) + { + + if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 + && pbs.ProfileHollow == 0 + && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 + && pbs.PathBegin == 0 && pbs.PathEnd == 0 + && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 + && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 + && pbs.PathShearX == 0 && pbs.PathShearY == 0) + { +#if SPAM + m_log.Warn("NonMesh"); +#endif + return false; + } + } + } + + if (pbs.ProfileHollow != 0) + iPropertiesNotSupportedDefault++; + + if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) + iPropertiesNotSupportedDefault++; + + if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) + iPropertiesNotSupportedDefault++; + + if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0) + iPropertiesNotSupportedDefault++; + + if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100)) + iPropertiesNotSupportedDefault++; + + if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0)) + iPropertiesNotSupportedDefault++; + + if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight) + iPropertiesNotSupportedDefault++; + + if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X)) + iPropertiesNotSupportedDefault++; + + if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1) + iPropertiesNotSupportedDefault++; + + // test for torus + if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square) + { + if (pbs.PathCurve == (byte)Extrusion.Curve1) + { + iPropertiesNotSupportedDefault++; + } + } + else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) + { + if (pbs.PathCurve == (byte)Extrusion.Straight) + { + iPropertiesNotSupportedDefault++; + } + + // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits + else if (pbs.PathCurve == (byte)Extrusion.Curve1) + { + iPropertiesNotSupportedDefault++; + } + } + else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) + { + if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2) + { + iPropertiesNotSupportedDefault++; + } + } + else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) + { + if (pbs.PathCurve == (byte)Extrusion.Straight) + { + iPropertiesNotSupportedDefault++; + } + else if (pbs.PathCurve == (byte)Extrusion.Curve1) + { + iPropertiesNotSupportedDefault++; + } + } + + if (pbs.SculptEntry && meshSculptedPrim) + iPropertiesNotSupportedDefault++; + + if (iPropertiesNotSupportedDefault == 0) + { +#if SPAM + m_log.Warn("NonMesh"); +#endif + return false; + } +#if SPAM + m_log.Debug("Mesh"); +#endif + return true; + } + + /// + /// Called after our prim properties are set Scale, position etc. + /// + /// + /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex + /// This assures us that we have no race conditions + /// + /// + public override void AddPhysicsActorTaint(PhysicsActor actor) + { + if (actor is OdePrim) + { + OdePrim taintedprim = ((OdePrim)actor); + lock (_taintedPrims) + _taintedPrims.Add(taintedprim); + } + else if (actor is OdeCharacter) + { + OdeCharacter taintedchar = ((OdeCharacter)actor); + lock (_taintedActors) + { + _taintedActors.Add(taintedchar); + if (taintedchar.bad) + m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid); + } + } + } + + /// + /// This is our main simulate loop + /// + /// + /// It's thread locked by a Mutex in the scene. + /// It holds Collisions, it instructs ODE to step through the physical reactions + /// It moves the objects around in memory + /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup) + /// + /// + /// The number of frames simulated over that period. + public override float Simulate(float timeStep) + { + if (!_worldInitialized) return 11f; + + int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0; + int tempTick = 0, tempTick2 = 0; + + if (framecount >= int.MaxValue) + framecount = 0; + + framecount++; + + float fps = 0; + + float timeLeft = timeStep; + + //m_log.Info(timeStep.ToString()); +// step_time += timeSte +// +// // If We're loaded down by something else, +// // or debugging with the Visual Studio project on pause +// // skip a few frames to catch up gracefully. +// // without shooting the physicsactors all over the place +// +// if (step_time >= m_SkipFramesAtms) +// { +// // Instead of trying to catch up, it'll do 5 physics frames only +// step_time = ODE_STEPSIZE; +// m_physicsiterations = 5; +// } +// else +// { +// m_physicsiterations = 10; +// } + + // We change _collisionEventPrimChanges to avoid locking _collisionEventPrim itself and causing potential + // deadlock if the collision event tries to lock something else later on which is already locked by a + // caller that is adding or removing the collision event. + lock (m_collisionEventActorsChanges) + { + foreach (KeyValuePair kvp in m_collisionEventActorsChanges) + { + if (kvp.Value == null) + m_collisionEventActors.Remove(kvp.Key); + else + m_collisionEventActors[kvp.Key] = kvp.Value; + } + + m_collisionEventActorsChanges.Clear(); + } + + if (SupportsNINJAJoints) + { + DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks + CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks + } + + lock (OdeLock) + { + // Process 10 frames if the sim is running normal.. + // process 5 frames if the sim is running slow + //try + //{ + //d.WorldSetQuickStepNumIterations(world, m_physicsiterations); + //} + //catch (StackOverflowException) + //{ + // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim."); + // ode.drelease(world); + //base.TriggerPhysicsBasedRestart(); + //} + + // Figure out the Frames Per Second we're going at. + //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size + + fps = (timeStep / ODE_STEPSIZE) * 1000; + // HACK: Using a time dilation of 1.0 to debug rubberbanding issues + //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f); + + while (timeLeft > 0.0f) + { + try + { + if (CollectStats) + tempTick = Util.EnvironmentTickCount(); + + lock (_taintedActors) + { + foreach (OdeCharacter character in _taintedActors) + character.ProcessTaints(); + + _taintedActors.Clear(); + } + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEAvatarTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + + lock (_taintedPrims) + { + foreach (OdePrim prim in _taintedPrims) + { + if (prim.m_taintremove) + { +// Console.WriteLine("Simulate calls RemovePrimThreadLocked for {0}", prim.Name); + RemovePrimThreadLocked(prim); + } + else + { +// Console.WriteLine("Simulate calls ProcessTaints for {0}", prim.Name); + prim.ProcessTaints(); + } + + prim.m_collisionscore = 0; + + // This loop can block up the Heartbeat for a very long time on large regions. + // We need to let the Watchdog know that the Heartbeat is not dead + // NOTE: This is currently commented out, but if things like OAR loading are + // timing the heartbeat out we will need to uncomment it + //Watchdog.UpdateThread(); + } + + if (SupportsNINJAJoints) + SimulatePendingNINJAJoints(); + + _taintedPrims.Clear(); + } + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEPrimTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + + // Move characters + foreach (OdeCharacter actor in _characters) + actor.Move(defects); + + if (defects.Count != 0) + { + foreach (OdeCharacter actor in defects) + { + m_log.ErrorFormat( + "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when moving", + actor.Name, actor.LocalID, PhysicsSceneName); + + RemoveCharacter(actor); + actor.DestroyOdeStructures(); + } + + defects.Clear(); + } + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEAvatarForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + + // Move other active objects + foreach (OdePrim prim in _activeprims) + { + prim.m_collisionscore = 0; + prim.Move(timeStep); + } + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEPrimForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + + //if ((framecount % m_randomizeWater) == 0) + // randomizeWater(waterlevel); + + //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests(); + m_rayCastManager.ProcessQueuedRequests(); + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODERaycastingFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + + collision_optimized(); + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEOtherCollisionFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + + foreach (PhysicsActor obj in m_collisionEventActors.Values) + { +// m_log.DebugFormat("[PHYSICS]: Assessing {0} {1} for collision events", obj.SOPName, obj.LocalID); + + switch ((ActorTypes)obj.PhysicsActorType) + { + case ActorTypes.Agent: + OdeCharacter cobj = (OdeCharacter)obj; + cobj.AddCollisionFrameTime(100); + cobj.SendCollisions(); + break; + + case ActorTypes.Prim: + OdePrim pobj = (OdePrim)obj; + pobj.SendCollisions(); + break; + } + } + +// if (m_global_contactcount > 0) +// m_log.DebugFormat( +// "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount); + + m_global_contactcount = 0; + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODECollisionNotificationFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + + d.WorldQuickStep(world, ODE_STEPSIZE); + + if (CollectStats) + m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); + + d.JointGroupEmpty(contactgroup); + } + catch (Exception e) + { + m_log.ErrorFormat("[ODE SCENE]: {0}, {1}, {2}", e.Message, e.TargetSite, e); + } + + timeLeft -= ODE_STEPSIZE; + } + + if (CollectStats) + tempTick = Util.EnvironmentTickCount(); + + foreach (OdeCharacter actor in _characters) + { + if (actor.bad) + m_log.ErrorFormat("[ODE SCENE]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); + + actor.UpdatePositionAndVelocity(defects); + } + + if (defects.Count != 0) + { + foreach (OdeCharacter actor in defects) + { + m_log.ErrorFormat( + "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when updating position and velocity", + actor.Name, actor.LocalID, PhysicsSceneName); + + RemoveCharacter(actor); + actor.DestroyOdeStructures(); + } + + defects.Clear(); + } + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEAvatarUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + + //if (timeStep < 0.2f) + + foreach (OdePrim prim in _activeprims) + { + if (prim.IsPhysical && (d.BodyIsEnabled(prim.Body) || !prim._zeroFlag)) + { + prim.UpdatePositionAndVelocity(); + + if (SupportsNINJAJoints) + SimulateActorPendingJoints(prim); + } + } + + if (CollectStats) + m_stats[ODEPrimUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); + + //DumpJointInfo(); + + // Finished with all sim stepping. If requested, dump world state to file for debugging. + // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed? + // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots? + if (physics_logging && (physics_logging_interval > 0) && (framecount % physics_logging_interval == 0)) + { + string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename + string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file + + if (physics_logging_append_existing_logfile) + { + string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------"; + TextWriter fwriter = File.AppendText(fname); + fwriter.WriteLine(header); + fwriter.Close(); + } + + d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); + } + + latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun); + + // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics + // has a max of 100 ms to run theoretically. + // If the main loop stalls, it calls Simulate later which makes the tick count ms larger. + // If Physics stalls, it takes longer which makes the tick count ms larger. + + if (latertickcount < 100) + { + m_timeDilation = 1.0f; + } + else + { + m_timeDilation = 100f / latertickcount; + //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f); + } + + tickCountFrameRun = Util.EnvironmentTickCount(); + + if (CollectStats) + m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick); + } + + return fps; + } + + /// + /// Simulate pending NINJA joints. + /// + /// + /// Called by the main Simulate() loop if NINJA joints are active. Should not be called from anywhere else. + /// + private void SimulatePendingNINJAJoints() + { + // Create pending joints, if possible + + // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating + // a joint requires specifying the body id of both involved bodies + if (pendingJoints.Count > 0) + { + List successfullyProcessedPendingJoints = new List(); + //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints"); + foreach (PhysicsJoint joint in pendingJoints) + { + //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams); + string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries); + List jointBodies = new List(); + bool allJointBodiesAreReady = true; + foreach (string jointParam in jointParams) + { + if (jointParam == "NULL") + { + //DoJointErrorMessage(joint, "attaching NULL joint to world"); + jointBodies.Add(IntPtr.Zero); + } + else + { + //DoJointErrorMessage(joint, "looking for prim name: " + jointParam); + bool foundPrim = false; + lock (_prims) + { + foreach (OdePrim prim in _prims) // FIXME: inefficient + { + if (prim.SOPName == jointParam) + { + //DoJointErrorMessage(joint, "found for prim name: " + jointParam); + if (prim.IsPhysical && prim.Body != IntPtr.Zero) + { + jointBodies.Add(prim.Body); + foundPrim = true; + break; + } + else + { + DoJointErrorMessage(joint, "prim name " + jointParam + + " exists but is not (yet) physical; deferring joint creation. " + + "IsPhysical property is " + prim.IsPhysical + + " and body is " + prim.Body); + foundPrim = false; + break; + } + } + } + } + if (foundPrim) + { + // all is fine + } + else + { + allJointBodiesAreReady = false; + break; + } + } + } + + if (allJointBodiesAreReady) + { + //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams); + if (jointBodies[0] == jointBodies[1]) + { + DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams); + } + else + { + switch (joint.Type) + { + case PhysicsJointType.Ball: + { + IntPtr odeJoint; + //DoJointErrorMessage(joint, "ODE creating ball joint "); + odeJoint = d.JointCreateBall(world, IntPtr.Zero); + //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); + d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); + //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position); + d.JointSetBallAnchor(odeJoint, + joint.Position.X, + joint.Position.Y, + joint.Position.Z); + //DoJointErrorMessage(joint, "ODE joint setting OK"); + //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: "); + //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment")); + //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: "); + //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment")); + + if (joint is OdePhysicsJoint) + { + ((OdePhysicsJoint)joint).jointID = odeJoint; + } + else + { + DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); + } + } + break; + case PhysicsJointType.Hinge: + { + IntPtr odeJoint; + //DoJointErrorMessage(joint, "ODE creating hinge joint "); + odeJoint = d.JointCreateHinge(world, IntPtr.Zero); + //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); + d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); + //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position); + d.JointSetHingeAnchor(odeJoint, + joint.Position.X, + joint.Position.Y, + joint.Position.Z); + // We use the orientation of the x-axis of the joint's coordinate frame + // as the axis for the hinge. + + // Therefore, we must get the joint's coordinate frame based on the + // joint.Rotation field, which originates from the orientation of the + // joint's proxy object in the scene. + + // The joint's coordinate frame is defined as the transformation matrix + // that converts a vector from joint-local coordinates into world coordinates. + // World coordinates are defined as the XYZ coordinate system of the sim, + // as shown in the top status-bar of the viewer. + + // Once we have the joint's coordinate frame, we extract its X axis (AtAxis) + // and use that as the hinge axis. + + //joint.Rotation.Normalize(); + Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation); + + // Now extract the X axis of the joint's coordinate frame. + + // Do not try to use proxyFrame.AtAxis or you will become mired in the + // tar pit of transposed, inverted, and generally messed-up orientations. + // (In other words, Matrix4.AtAxis() is borked.) + // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness + + // Instead, compute the X axis of the coordinate frame by transforming + // the (1,0,0) vector. At least that works. + + //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame); + Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame); + //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis); + //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis); + d.JointSetHingeAxis(odeJoint, + jointAxis.X, + jointAxis.Y, + jointAxis.Z); + //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f); + if (joint is OdePhysicsJoint) + { + ((OdePhysicsJoint)joint).jointID = odeJoint; + } + else + { + DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); + } + } + break; + } + successfullyProcessedPendingJoints.Add(joint); + } + } + else + { + DoJointErrorMessage(joint, "joint could not yet be created; still pending"); + } + } + + foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints) + { + //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams); + //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending"); + InternalRemovePendingJoint(successfullyProcessedJoint); + //DoJointErrorMessage(successfullyProcessedJoint, "adding to active"); + InternalAddActiveJoint(successfullyProcessedJoint); + //DoJointErrorMessage(successfullyProcessedJoint, "done"); + } + } + } + + /// + /// Simulate the joint proxies of a NINJA actor. + /// + /// + /// Called as part of the Simulate() loop if NINJA physics is active. Must only be called from there. + /// + /// + private void SimulateActorPendingJoints(OdePrim actor) + { + // If an actor moved, move its joint proxy objects as well. + // There seems to be an event PhysicsActor.OnPositionUpdate that could be used + // for this purpose but it is never called! So we just do the joint + // movement code here. + + if (actor.SOPName != null && + joints_connecting_actor.ContainsKey(actor.SOPName) && + joints_connecting_actor[actor.SOPName] != null && + joints_connecting_actor[actor.SOPName].Count > 0) + { + foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName]) + { + if (affectedJoint.IsInPhysicsEngine) + { + DoJointMoved(affectedJoint); + } + else + { + DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams); + } + } + } + } + + public override void GetResults() + { + } + + public override bool IsThreaded + { + // for now we won't be multithreaded + get { return false; } + } + + public override void SetTerrain(float[] heightMap) + { + if (m_worldOffset != Vector3.Zero && m_parentScene != null) + { + if (m_parentScene is OdeScene) + { + ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset); + } + } + else + { + SetTerrain(heightMap, m_worldOffset); + } + } + + private void SetTerrain(float[] heightMap, Vector3 pOffset) + { + int startTime = Util.EnvironmentTickCount(); + m_log.DebugFormat("[ODE SCENE]: Setting terrain for {0} with offset {1}", PhysicsSceneName, pOffset); + + + float[] _heightmap; + + // ok im lasy this are just a aliases + uint regionsizeX = m_regionWidth; + uint regionsizeY = m_regionHeight; + + // map is rotated + uint heightmapWidth = regionsizeY + 2; + uint heightmapHeight = regionsizeX + 2; + + uint heightmapWidthSamples = heightmapWidth + 1; + uint heightmapHeightSamples = heightmapHeight + 1; + + _heightmap = new float[heightmapWidthSamples * heightmapHeightSamples]; + + + const float scale = 1.0f; + const float offset = 0.0f; + const float thickness = 10f; + const int wrap = 0; + + + float hfmin = float.MaxValue; + float hfmax = float.MinValue; + float val; + uint xx; + uint yy; + + uint maxXX = regionsizeX - 1; + uint maxYY = regionsizeY - 1; + + // flipping map adding one margin all around so things don't fall in edges + + uint xt = 0; + xx = 0; + + + for (uint x = 0; x < heightmapWidthSamples; x++) + { + if (x > 1 && xx < maxXX) + xx++; + yy = 0; + for (uint y = 0; y < heightmapHeightSamples; y++) + { + if (y > 1 && y < maxYY) + yy += regionsizeX; + + val = heightMap[yy + xx]; + if (val < 0.0f) + val = 0.0f; + _heightmap[xt + y] = val; + + if (hfmin > val) + hfmin = val; + if (hfmax < val) + hfmax = val; + } + xt += heightmapHeightSamples; + } + + lock (OdeLock) + { + IntPtr GroundGeom = IntPtr.Zero; + if (RegionTerrain.TryGetValue(pOffset, out GroundGeom)) + { + RegionTerrain.Remove(pOffset); + if (GroundGeom != IntPtr.Zero) + { + if (TerrainHeightFieldHeights.ContainsKey(GroundGeom)) + { + TerrainHeightFieldHeights.Remove(GroundGeom); + } + d.SpaceRemove(space, GroundGeom); + d.GeomDestroy(GroundGeom); + } + + } + IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); + d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, + heightmapWidth, heightmapHeight, + (int)heightmapWidthSamples, (int)heightmapHeightSamples, + scale, offset, thickness, wrap); + + d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); + GroundGeom = d.CreateHeightfield(space, HeightmapData, 1); + if (GroundGeom != IntPtr.Zero) + { + d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land)); + d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space)); + + } + geom_name_map[GroundGeom] = "Terrain"; + + d.Matrix3 R = new d.Matrix3(); + + Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f); + Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f); + + q1 = q1 * q2; + Vector3 v3; + float angle; + q1.GetAxisAngle(out v3, out angle); + + d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); + d.GeomSetRotation(GroundGeom, ref R); + d.GeomSetPosition(GroundGeom, pOffset.X + regionsizeX * 0.5f, pOffset.Y + regionsizeY * 0.5f, 0f); + IntPtr testGround = IntPtr.Zero; + if (RegionTerrain.TryGetValue(pOffset, out testGround)) + { + RegionTerrain.Remove(pOffset); + } + RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); + TerrainHeightFieldHeights.Add(GroundGeom,_heightmap); + } + + m_log.DebugFormat( + "[ODE SCENE]: Setting terrain for {0} took {1}ms", PhysicsSceneName, Util.EnvironmentTickCountSubtract(startTime)); + } + + public override void DeleteTerrain() + { + } + + internal float GetWaterLevel() + { + return waterlevel; + } + + public override bool SupportsCombining() + { + return m_suportCombine; + } + + public override void SetWaterLevel(float baseheight) + { + waterlevel = baseheight; +// randomizeWater(waterlevel); + } + +/* + private void randomizeWater(float baseheight) + { + uint heightmapWidth = m_regionWidth + 2; + uint heightmapHeight = m_regionHeight + 2; + uint heightmapWidthSamples = m_regionWidth + 2; + uint heightmapHeightSamples = m_regionHeight + 2; + float scale = 1.0f; + float offset = 0.0f; + float thickness = 2.9f; + int wrap = 0; + + for (int i = 0; i < (258 * 258); i++) + { + _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f); + // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f)); + } + + lock (OdeLock) + { + if (WaterGeom != IntPtr.Zero) + { + d.SpaceRemove(space, WaterGeom); + } + IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); + d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight, + (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale, + offset, thickness, wrap); + d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight); + WaterGeom = d.CreateHeightfield(space, HeightmapData, 1); + if (WaterGeom != IntPtr.Zero) + { + d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water)); + d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space)); + } + + geom_name_map[WaterGeom] = "Water"; + + d.Matrix3 R = new d.Matrix3(); + + Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f); + Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f); + //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1)); + + q1 = q1 * q2; + //q1 = q1 * q3; + Vector3 v3; + float angle; + q1.GetAxisAngle(out v3, out angle); + + d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); + d.GeomSetRotation(WaterGeom, ref R); + d.GeomSetPosition(WaterGeom, 128, 128, 0); + } + } +*/ + public override void Dispose() + { + _worldInitialized = false; + + m_rayCastManager.Dispose(); + m_rayCastManager = null; + + lock (OdeLock) + { + lock (_prims) + { + foreach (OdePrim prm in _prims) + { + RemovePrim(prm); + } + } + + //foreach (OdeCharacter act in _characters) + //{ + //RemoveAvatar(act); + //} + d.WorldDestroy(world); + //d.CloseODE(); + } + + } + + public override Dictionary GetTopColliders() + { + Dictionary topColliders; + + lock (_prims) + { + List orderedPrims = new List(_prims); + orderedPrims.OrderByDescending(p => p.CollisionScore); + topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore); + + foreach (OdePrim p in _prims) + p.CollisionScore = 0; + } + + return topColliders; + } + + public override bool SupportsRayCast() + { + return true; + } + + public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod) + { + if (retMethod != null) + { + m_rayCastManager.QueueRequest(position, direction, length, retMethod); + } + } + + public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod) + { + if (retMethod != null) + { + m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); + } + } + + public override List RaycastWorld(Vector3 position, Vector3 direction, float length, int Count) + { + ContactResult[] ourResults = null; + RayCallback retMethod = delegate(List results) + { + ourResults = new ContactResult[results.Count]; + results.CopyTo(ourResults, 0); + }; + int waitTime = 0; + m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); + while (ourResults == null && waitTime < 1000) + { + Thread.Sleep(1); + waitTime++; + } + if (ourResults == null) + return new List (); + return new List(ourResults); + } + +#if USE_DRAWSTUFF + // Keyboard callback + public void command(int cmd) + { + IntPtr geom; + d.Mass mass; + d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f); + + + + Char ch = Char.ToLower((Char)cmd); + switch ((Char)ch) + { + case 'w': + try + { + Vector3 rotate = (new Vector3(1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD)); + + xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z; + ds.SetViewpoint(ref xyz, ref hpr); + } + catch (ArgumentException) + { hpr.X = 0; } + break; + + case 'a': + hpr.X++; + ds.SetViewpoint(ref xyz, ref hpr); + break; + + case 's': + try + { + Vector3 rotate2 = (new Vector3(-1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD)); + + xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z; + ds.SetViewpoint(ref xyz, ref hpr); + } + catch (ArgumentException) + { hpr.X = 0; } + break; + case 'd': + hpr.X--; + ds.SetViewpoint(ref xyz, ref hpr); + break; + case 'r': + xyz.Z++; + ds.SetViewpoint(ref xyz, ref hpr); + break; + case 'f': + xyz.Z--; + ds.SetViewpoint(ref xyz, ref hpr); + break; + case 'e': + xyz.Y++; + ds.SetViewpoint(ref xyz, ref hpr); + break; + case 'q': + xyz.Y--; + ds.SetViewpoint(ref xyz, ref hpr); + break; + } + } + + public void step(int pause) + { + + ds.SetColor(1.0f, 1.0f, 0.0f); + ds.SetTexture(ds.Texture.Wood); + lock (_prims) + { + foreach (OdePrim prm in _prims) + { + //IntPtr body = d.GeomGetBody(prm.prim_geom); + if (prm.prim_geom != IntPtr.Zero) + { + d.Vector3 pos; + d.GeomCopyPosition(prm.prim_geom, out pos); + //d.BodyCopyPosition(body, out pos); + + d.Matrix3 R; + d.GeomCopyRotation(prm.prim_geom, out R); + //d.BodyCopyRotation(body, out R); + + + d.Vector3 sides = new d.Vector3(); + sides.X = prm.Size.X; + sides.Y = prm.Size.Y; + sides.Z = prm.Size.Z; + + ds.DrawBox(ref pos, ref R, ref sides); + } + } + } + ds.SetColor(1.0f, 0.0f, 0.0f); + + foreach (OdeCharacter chr in _characters) + { + if (chr.Shell != IntPtr.Zero) + { + IntPtr body = d.GeomGetBody(chr.Shell); + + d.Vector3 pos; + d.GeomCopyPosition(chr.Shell, out pos); + //d.BodyCopyPosition(body, out pos); + + d.Matrix3 R; + d.GeomCopyRotation(chr.Shell, out R); + //d.BodyCopyRotation(body, out R); + + ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f); + d.Vector3 sides = new d.Vector3(); + sides.X = 0.5f; + sides.Y = 0.5f; + sides.Z = 0.5f; + + ds.DrawBox(ref pos, ref R, ref sides); + } + } + } + + public void start(int unused) + { + ds.SetViewpoint(ref xyz, ref hpr); + } +#endif + + public override Dictionary GetStats() + { + if (!CollectStats) + return null; + + Dictionary returnStats; + + lock (OdeLock) + { + returnStats = new Dictionary(m_stats); + + // FIXME: This is a SUPER DUMB HACK until we can establish stats that aren't subject to a division by + // 3 from the SimStatsReporter. + returnStats[ODETotalAvatarsStatName] = _characters.Count * 3; + returnStats[ODETotalPrimsStatName] = _prims.Count * 3; + returnStats[ODEActivePrimsStatName] = _activeprims.Count * 3; + + InitializeExtraStats(); + } + + returnStats[ODEOtherCollisionFrameMsStatName] + = returnStats[ODEOtherCollisionFrameMsStatName] + - returnStats[ODENativeSpaceCollisionFrameMsStatName] + - returnStats[ODENativeGeomCollisionFrameMsStatName]; + + return returnStats; + } + + private void InitializeExtraStats() + { + m_stats[ODETotalFrameMsStatName] = 0; + m_stats[ODEAvatarTaintMsStatName] = 0; + m_stats[ODEPrimTaintMsStatName] = 0; + m_stats[ODEAvatarForcesFrameMsStatName] = 0; + m_stats[ODEPrimForcesFrameMsStatName] = 0; + m_stats[ODERaycastingFrameMsStatName] = 0; + m_stats[ODENativeStepFrameMsStatName] = 0; + m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0; + m_stats[ODENativeGeomCollisionFrameMsStatName] = 0; + m_stats[ODEOtherCollisionFrameMsStatName] = 0; + m_stats[ODECollisionNotificationFrameMsStatName] = 0; + m_stats[ODEAvatarContactsStatsName] = 0; + m_stats[ODEPrimContactsStatName] = 0; + m_stats[ODEAvatarUpdateFrameMsStatName] = 0; + m_stats[ODEPrimUpdateFrameMsStatName] = 0; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs b/OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs new file mode 100644 index 0000000..6dc22bd --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs @@ -0,0 +1,151 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Region.PhysicsModule.ODE; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Tests.Common; +using log4net; +using System.Reflection; + +namespace OpenSim.Region.PhysicsModule.ODE.Tests +{ + [TestFixture] + public class ODETestClass : OpenSimTestCase + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + //private OpenSim.Region.PhysicsModule.ODE.OdePlugin cbt; + private PhysicsScene pScene; + + [SetUp] + public void Initialize() + { + IConfigSource openSimINI = new IniConfigSource(); + IConfig startupConfig = openSimINI.AddConfig("Startup"); + startupConfig.Set("physics", "OpenDynamicsEngine"); + startupConfig.Set("DecodedSculptMapPath", "j2kDecodeCache"); + + Vector3 regionExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); + + //PhysicsScene pScene = physicsPluginManager.GetPhysicsScene( + // "BulletSim", "Meshmerizer", openSimINI, "BSTestRegion", regionExtent); + RegionInfo info = new RegionInfo(); + info.RegionName = "ODETestRegion"; + info.RegionSizeX = info.RegionSizeY = info.RegionSizeZ = Constants.RegionSize; + OpenSim.Region.Framework.Scenes.Scene scene = new OpenSim.Region.Framework.Scenes.Scene(info); + + //IMesher mesher = new OpenSim.Region.PhysicsModules.Meshing.Meshmerizer(); + //INonSharedRegionModule mod = mesher as INonSharedRegionModule; + //mod.Initialise(openSimINI); + //mod.AddRegion(scene); + //mod.RegionLoaded(scene); + + pScene = new OdeScene(); + Console.WriteLine("HERE " + (pScene == null ? "Null" : "Not null")); + INonSharedRegionModule mod = (pScene as INonSharedRegionModule); + Console.WriteLine("HERE " + (mod == null ? "Null" : "Not null")); + mod.Initialise(openSimINI); + mod.AddRegion(scene); + mod.RegionLoaded(scene); + + // Loading ODEPlugin + //cbt = new OdePlugin(); + // Getting Physics Scene + //ps = cbt.GetScene("test"); + // Initializing Physics Scene. + //ps.Initialise(imp.GetMesher(TopConfig), null, Vector3.Zero); + float[] _heightmap = new float[(int)Constants.RegionSize * (int)Constants.RegionSize]; + for (int i = 0; i < ((int)Constants.RegionSize * (int)Constants.RegionSize); i++) + { + _heightmap[i] = 21f; + } + pScene.SetTerrain(_heightmap); + } + + [TearDown] + public void Terminate() + { + pScene.DeleteTerrain(); + pScene.Dispose(); + + } + + [Test] + public void CreateAndDropPhysicalCube() + { + PrimitiveBaseShape newcube = PrimitiveBaseShape.CreateBox(); + Vector3 position = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 128f); + Vector3 size = new Vector3(0.5f, 0.5f, 0.5f); + Quaternion rot = Quaternion.Identity; + PhysicsActor prim = pScene.AddPrimShape("CoolShape", newcube, position, size, rot, true, 0); + OdePrim oprim = (OdePrim)prim; + OdeScene pscene = (OdeScene)pScene; + + Assert.That(oprim.m_taintadd); + + prim.LocalID = 5; + + for (int i = 0; i < 58; i++) + { + pScene.Simulate(0.133f); + + Assert.That(oprim.prim_geom != (IntPtr)0); + + Assert.That(oprim.m_targetSpace != (IntPtr)0); + + //Assert.That(oprim.m_targetSpace == pscene.space); + m_log.Info("TargetSpace: " + oprim.m_targetSpace + " - SceneMainSpace: " + pscene.space); + + Assert.That(!oprim.m_taintadd); + m_log.Info("Prim Position (" + oprim.LocalID + "): " + prim.Position); + + // Make sure we're above the ground + //Assert.That(prim.Position.Z > 20f); + //m_log.Info("PrimCollisionScore (" + oprim.m_localID + "): " + oprim.m_collisionscore); + + // Make sure we've got a Body + Assert.That(oprim.Body != (IntPtr)0); + //m_log.Info( + } + + // Make sure we're not somewhere above the ground + Assert.That(prim.Position.Z < 21.5f); + + pScene.RemovePrim(prim); + Assert.That(oprim.m_taintremove); + pScene.Simulate(0.133f); + Assert.That(oprim.Body == (IntPtr)0); + } + } +} diff --git a/OpenSim/Region/PhysicsModules/Ode/drawstuff.cs b/OpenSim/Region/PhysicsModules/Ode/drawstuff.cs new file mode 100644 index 0000000..87ca446 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/Ode/drawstuff.cs @@ -0,0 +1,98 @@ +/* + * Copyright ODE + * Ode.NET - .NET bindings for ODE + * Jason Perkins (starkos@industriousone.com) + * Licensed under the New BSD + * Part of the OpenDynamicsEngine +Open Dynamics Engine +Copyright (c) 2001-2007, Russell L. Smith. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +Neither the names of ODE's copyright owner nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + */ + +using System; +using System.Runtime.InteropServices; +using Ode.NET; + +namespace Drawstuff.NET +{ +#if dDOUBLE + using dReal = System.Double; +#else + using dReal = System.Single; +#endif + + public static class ds + { + public const int VERSION = 2; + + public enum Texture + { + None, + Wood + } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void CallbackFunction(int arg); + + [StructLayout(LayoutKind.Sequential)] + public struct Functions + { + public int version; + public CallbackFunction start; + public CallbackFunction step; + public CallbackFunction command; + public CallbackFunction stop; + public string path_to_textures; + } + + [DllImport("drawstuff", EntryPoint = "dsDrawBox")] + public static extern void DrawBox(ref d.Vector3 pos, ref d.Matrix3 R, ref d.Vector3 sides); + + [DllImport("drawstuff", EntryPoint = "dsDrawCapsule")] + public static extern void DrawCapsule(ref d.Vector3 pos, ref d.Matrix3 R, dReal length, dReal radius); + + [DllImport("drawstuff", EntryPoint = "dsDrawConvex")] + public static extern void DrawConvex(ref d.Vector3 pos, ref d.Matrix3 R, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons); + + [DllImport("drawstuff", EntryPoint = "dsSetColor")] + public static extern void SetColor(float red, float green, float blue); + + [DllImport("drawstuff", EntryPoint = "dsSetTexture")] + public static extern void SetTexture(Texture texture); + + [DllImport("drawstuff", EntryPoint = "dsSetViewpoint")] + public static extern void SetViewpoint(ref d.Vector3 xyz, ref d.Vector3 hpr); + + [DllImport("drawstuff", EntryPoint = "dsSimulationLoop")] + public static extern void SimulationLoop(int argc, string[] argv, int window_width, int window_height, ref Functions fn); + } +} diff --git a/OpenSim/Region/PhysicsModules/POS/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/POS/AssemblyInfo.cs new file mode 100644 index 0000000..e3a3e35 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/POS/AssemblyInfo.cs @@ -0,0 +1,62 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Reflection; +using System.Runtime.InteropServices; +using Mono.Addins; + +// Information about this assembly is defined by the following +// attributes. +// +// change them to the information which is associated with the assembly +// you compile. + +[assembly : AssemblyTitle("POSPlugin")] +[assembly : AssemblyDescription("")] +[assembly : AssemblyConfiguration("")] +[assembly : AssemblyCompany("http://opensimulator.org")] +[assembly : AssemblyProduct("POSPlugin")] +[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] +[assembly : AssemblyTrademark("")] +[assembly : AssemblyCulture("")] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. + +[assembly : ComVisible(false)] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all values by your own or you can build default build and revision +// numbers with the '*' character (the default): + +[assembly : AssemblyVersion("0.8.2.*")] + +[assembly: Addin("OpenSim.Region.PhysicsModule.POS", OpenSim.VersionInfo.VersionNumber)] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Region/PhysicsModules/POS/POSCharacter.cs b/OpenSim/Region/PhysicsModules/POS/POSCharacter.cs new file mode 100644 index 0000000..32469d9 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/POS/POSCharacter.cs @@ -0,0 +1,341 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +namespace OpenSim.Region.PhysicsModule.POS +{ + public class POSCharacter : PhysicsActor + { + private Vector3 _position; + public Vector3 _velocity; + public Vector3 _target_velocity = Vector3.Zero; + public Vector3 _size = Vector3.Zero; + private Vector3 _acceleration; + private Vector3 m_rotationalVelocity = Vector3.Zero; + private bool flying; + private bool isColliding; + + public POSCharacter() + { + } + + public override int PhysicsActorType + { + get { return (int) ActorTypes.Agent; } + set { return; } + } + + public override Vector3 RotationalVelocity + { + get { return m_rotationalVelocity; } + set { m_rotationalVelocity = value; } + } + + public override bool SetAlwaysRun + { + get { return false; } + set { return; } + } + + public override uint LocalID + { + set { return; } + } + + public override bool Grabbed + { + set { return; } + } + + public override bool Selected + { + set { return; } + } + + public override float Buoyancy + { + get { return 0f; } + set { return; } + } + + public override bool FloatOnWater + { + set { return; } + } + + public override bool IsPhysical + { + get { return false; } + set { return; } + } + + public override bool ThrottleUpdates + { + get { return false; } + set { return; } + } + + public override bool Flying + { + get { return flying; } + set { flying = value; } + } + + public override bool IsColliding + { + get { return isColliding; } + set { isColliding = value; } + } + + public override bool CollidingGround + { + get { return false; } + set { return; } + } + + public override bool CollidingObj + { + get { return false; } + set { return; } + } + + public override bool Stopped + { + get { return false; } + } + + public override Vector3 Position + { + get { return _position; } + set { _position = value; } + } + + public override Vector3 Size + { + get { return _size; } + set + { + _size = value; + _size.Z = _size.Z / 2.0f; + } + } + + public override float Mass + { + get { return 0f; } + } + + public override Vector3 Force + { + get { return Vector3.Zero; } + set { return; } + } + + public override int VehicleType + { + get { return 0; } + set { return; } + } + + public override void VehicleFloatParam(int param, float value) + { + + } + + public override void VehicleVectorParam(int param, Vector3 value) + { + + } + + public override void VehicleRotationParam(int param, Quaternion rotation) + { + + } + + public override void VehicleFlags(int param, bool remove) { } + + public override void SetVolumeDetect(int param) + { + + } + + public override Vector3 CenterOfMass + { + get { return Vector3.Zero; } + } + + public override Vector3 GeometricCenter + { + get { return Vector3.Zero; } + } + + public override PrimitiveBaseShape Shape + { + set { return; } + } + + public override Vector3 Velocity + { + get { return _velocity; } + set { _target_velocity = value; } + } + + public override Vector3 Torque + { + get { return Vector3.Zero; } + set { return; } + } + + public override float CollisionScore + { + get { return 0f; } + set { } + } + + public override Quaternion Orientation + { + get { return Quaternion.Identity; } + set { } + } + + public override Vector3 Acceleration + { + get { return _acceleration; } + set { _acceleration = value; } + } + + public override bool Kinematic + { + get { return true; } + set { } + } + + public override void link(PhysicsActor obj) + { + } + + public override void delink() + { + } + + public override void LockAngularMotion(Vector3 axis) + { + } + + public override void AddForce(Vector3 force, bool pushforce) + { + } + + public override void AddAngularForce(Vector3 force, bool pushforce) + { + } + + public override void SetMomentum(Vector3 momentum) + { + } + + public override void CrossingFailure() + { + } + + public override Vector3 PIDTarget + { + set { return; } + } + + public override bool PIDActive + { + get { return false; } + set { return; } + } + + public override float PIDTau + { + set { return; } + } + + public override float PIDHoverHeight + { + set { return; } + } + + public override bool PIDHoverActive + { + set { return; } + } + + public override PIDHoverType PIDHoverType + { + set { return; } + } + + public override float PIDHoverTau + { + set { return; } + } + + public override Quaternion APIDTarget + { + set { return; } + } + + public override bool APIDActive + { + set { return; } + } + + public override float APIDStrength + { + set { return; } + } + + public override float APIDDamping + { + set { return; } + } + + + public override void SubscribeEvents(int ms) + { + } + + public override void UnSubscribeEvents() + { + } + + public override bool SubscribedEvents() + { + return false; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/POS/POSPrim.cs b/OpenSim/Region/PhysicsModules/POS/POSPrim.cs new file mode 100644 index 0000000..8aae716 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/POS/POSPrim.cs @@ -0,0 +1,336 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; + +namespace OpenSim.Region.PhysicsModule.POS +{ + public class POSPrim : PhysicsActor + { + private Vector3 _position; + private Vector3 _velocity; + private Vector3 _acceleration; + private Vector3 _size; + private Vector3 m_rotationalVelocity = Vector3.Zero; + private Quaternion _orientation; + private bool iscolliding; + + public POSPrim() + { + } + + public override int PhysicsActorType + { + get { return (int) ActorTypes.Prim; } + set { return; } + } + + public override Vector3 RotationalVelocity + { + get { return m_rotationalVelocity; } + set { m_rotationalVelocity = value; } + } + + public override bool IsPhysical + { + get { return false; } + set { return; } + } + + public override bool ThrottleUpdates + { + get { return false; } + set { return; } + } + + public override bool IsColliding + { + get { return iscolliding; } + set { iscolliding = value; } + } + + public override bool CollidingGround + { + get { return false; } + set { return; } + } + + public override bool CollidingObj + { + get { return false; } + set { return; } + } + + public override bool Stopped + { + get { return false; } + } + + public override Vector3 Position + { + get { return _position; } + set { _position = value; } + } + + public override Vector3 Size + { + get { return _size; } + set { _size = value; } + } + + public override float Mass + { + get { return 0f; } + } + + public override Vector3 Force + { + get { return Vector3.Zero; } + set { return; } + } + + public override int VehicleType + { + get { return 0; } + set { return; } + } + + public override void VehicleFloatParam(int param, float value) + { + + } + + public override void VehicleVectorParam(int param, Vector3 value) + { + + } + + public override void VehicleRotationParam(int param, Quaternion rotation) + { + + } + + public override void VehicleFlags(int param, bool remove) { } + + public override void SetVolumeDetect(int param) + { + + } + + public override Vector3 CenterOfMass + { + get { return Vector3.Zero; } + } + + public override Vector3 GeometricCenter + { + get { return Vector3.Zero; } + } + + public override PrimitiveBaseShape Shape + { + set { return; } + } + + public override float Buoyancy + { + get { return 0f; } + set { return; } + } + + public override bool FloatOnWater + { + set { return; } + } + + public override Vector3 Velocity + { + get { return _velocity; } + set { _velocity = value; } + } + + public override float CollisionScore + { + get { return 0f; } + set { } + } + + public override Quaternion Orientation + { + get { return _orientation; } + set { _orientation = value; } + } + + public override Vector3 Acceleration + { + get { return _acceleration; } + set { _acceleration = value; } + } + + public override bool Kinematic + { + get { return true; } + set { } + } + + public override void AddForce(Vector3 force, bool pushforce) + { + } + + public override void AddAngularForce(Vector3 force, bool pushforce) + { + } + + public override Vector3 Torque + { + get { return Vector3.Zero; } + set { return; } + } + + public override void SetMomentum(Vector3 momentum) + { + } + + public override bool Flying + { + get { return false; } + set { } + } + + public override bool SetAlwaysRun + { + get { return false; } + set { return; } + } + + public override uint LocalID + { + set { return; } + } + + public override bool Grabbed + { + set { return; } + } + + public override void link(PhysicsActor obj) + { + } + + public override void delink() + { + } + + public override void LockAngularMotion(Vector3 axis) + { + } + + public override bool Selected + { + set { return; } + } + + public override void CrossingFailure() + { + } + + public override Vector3 PIDTarget + { + set { return; } + } + + public override bool PIDActive + { + get { return false; } + set { return; } + } + + public override float PIDTau + { + set { return; } + } + + public override float PIDHoverHeight + { + set { return; } + } + + public override bool PIDHoverActive + { + set { return; } + } + + public override PIDHoverType PIDHoverType + { + set { return; } + } + + public override float PIDHoverTau + { + set { return; } + } + + public override Quaternion APIDTarget + { + set { return; } + } + + public override bool APIDActive + { + set { return; } + } + + public override float APIDStrength + { + set { return; } + } + + public override float APIDDamping + { + set { return; } + } + + + public override void SubscribeEvents(int ms) + { + } + + public override void UnSubscribeEvents() + { + } + + public override bool SubscribedEvents() + { + return false; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/POS/POSScene.cs b/OpenSim/Region/PhysicsModules/POS/POSScene.cs new file mode 100644 index 0000000..6375f18 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/POS/POSScene.cs @@ -0,0 +1,323 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using Nini.Config; +using OpenMetaverse; +using Mono.Addins; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.PhysicsModule.POS +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "POSPhysicsScene")] + public class POSScene : PhysicsScene, INonSharedRegionModule + { + private List _characters = new List(); + private List _prims = new List(); + private float[] _heightMap; + private const float gravity = -9.8f; + + private bool m_Enabled = false; + //protected internal string sceneIdentifier; + + #region INonSharedRegionModule + public string Name + { + get { return "POS"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Initialise(IConfigSource source) + { + // TODO: Move this out of Startup + IConfig config = source.Configs["Startup"]; + if (config != null) + { + string physics = config.GetString("physics", string.Empty); + if (physics == Name) + m_Enabled = true; + } + + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + EngineType = Name; + PhysicsSceneName = EngineType + "/" + scene.RegionInfo.RegionName; + + scene.RegisterModuleInterface(this); + base.Initialise(scene.PhysicsRequestAsset, + (scene.Heightmap != null ? scene.Heightmap.GetFloatsSerialised() : new float[Constants.RegionSize * Constants.RegionSize]), + (float)scene.RegionInfo.RegionSettings.WaterHeight); + + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + } + #endregion + + public override void Dispose() + { + } + + public override PhysicsActor AddAvatar( + string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) + { + POSCharacter act = new POSCharacter(); + act.Position = position; + act.Flying = isFlying; + _characters.Add(act); + return act; + } + + public override void RemovePrim(PhysicsActor prim) + { + POSPrim p = (POSPrim) prim; + if (_prims.Contains(p)) + { + _prims.Remove(p); + } + } + + public override void RemoveAvatar(PhysicsActor character) + { + POSCharacter act = (POSCharacter) character; + if (_characters.Contains(act)) + { + _characters.Remove(act); + } + } + +/* + public override PhysicsActor AddPrim(Vector3 position, Vector3 size, Quaternion rotation) + { + return null; + } +*/ + + public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, + Vector3 size, Quaternion rotation, bool isPhysical, uint localid) + { + POSPrim prim = new POSPrim(); + prim.Position = position; + prim.Orientation = rotation; + prim.Size = size; + _prims.Add(prim); + return prim; + } + + private bool isColliding(POSCharacter c, POSPrim p) + { + Vector3 rotatedPos = new Vector3(c.Position.X - p.Position.X, c.Position.Y - p.Position.Y, + c.Position.Z - p.Position.Z) * Quaternion.Inverse(p.Orientation); + Vector3 avatarSize = new Vector3(c.Size.X, c.Size.Y, c.Size.Z) * Quaternion.Inverse(p.Orientation); + + return (Math.Abs(rotatedPos.X) < (p.Size.X*0.5 + Math.Abs(avatarSize.X)) && + Math.Abs(rotatedPos.Y) < (p.Size.Y*0.5 + Math.Abs(avatarSize.Y)) && + Math.Abs(rotatedPos.Z) < (p.Size.Z*0.5 + Math.Abs(avatarSize.Z))); + } + + private bool isCollidingWithPrim(POSCharacter c) + { + foreach (POSPrim p in _prims) + { + if (isColliding(c, p)) + { + return true; + } + } + + return false; + } + + public override void AddPhysicsActorTaint(PhysicsActor prim) + { + } + + public override float Simulate(float timeStep) + { + float fps = 0; + for (int i = 0; i < _characters.Count; ++i) + { + fps++; + POSCharacter character = _characters[i]; + + float oldposX = character.Position.X; + float oldposY = character.Position.Y; + float oldposZ = character.Position.Z; + + if (!character.Flying) + { + character._target_velocity.Z += gravity * timeStep; + } + + Vector3 characterPosition = character.Position; + + characterPosition.X += character._target_velocity.X * timeStep; + characterPosition.Y += character._target_velocity.Y * timeStep; + + characterPosition.X = Util.Clamp(character.Position.X, 0.01f, Constants.RegionSize - 0.01f); + characterPosition.Y = Util.Clamp(character.Position.Y, 0.01f, Constants.RegionSize - 0.01f); + + bool forcedZ = false; + + float terrainheight = _heightMap[(int)character.Position.Y * Constants.RegionSize + (int)character.Position.X]; + if (character.Position.Z + (character._target_velocity.Z * timeStep) < terrainheight + 2) + { + characterPosition.Z = terrainheight + character.Size.Z; + forcedZ = true; + } + else + { + characterPosition.Z += character._target_velocity.Z*timeStep; + } + + /// this is it -- the magic you've all been waiting for! Ladies and gentlemen -- + /// Completely Bogus Collision Detection!!! + /// better known as the CBCD algorithm + + if (isCollidingWithPrim(character)) + { + characterPosition.Z = oldposZ; // first try Z axis + if (isCollidingWithPrim(character)) + { + characterPosition.Z = oldposZ + character.Size.Z / 4.4f; // try harder + if (isCollidingWithPrim(character)) + { + characterPosition.Z = oldposZ + character.Size.Z / 2.2f; // try very hard + if (isCollidingWithPrim(character)) + { + characterPosition.X = oldposX; + characterPosition.Y = oldposY; + characterPosition.Z = oldposZ; + + characterPosition.X += character._target_velocity.X * timeStep; + if (isCollidingWithPrim(character)) + { + characterPosition.X = oldposX; + } + + characterPosition.Y += character._target_velocity.Y * timeStep; + if (isCollidingWithPrim(character)) + { + characterPosition.Y = oldposY; + } + } + else + { + forcedZ = true; + } + } + else + { + forcedZ = true; + } + } + else + { + forcedZ = true; + } + } + + characterPosition.X = Util.Clamp(character.Position.X, 0.01f, Constants.RegionSize - 0.01f); + characterPosition.Y = Util.Clamp(character.Position.Y, 0.01f, Constants.RegionSize - 0.01f); + + character.Position = characterPosition; + + character._velocity.X = (character.Position.X - oldposX)/timeStep; + character._velocity.Y = (character.Position.Y - oldposY)/timeStep; + + if (forcedZ) + { + character._velocity.Z = 0; + character._target_velocity.Z = 0; + ((PhysicsActor)character).IsColliding = true; + character.RequestPhysicsterseUpdate(); + } + else + { + ((PhysicsActor)character).IsColliding = false; + character._velocity.Z = (character.Position.Z - oldposZ)/timeStep; + } + } + return fps; + } + + public override void GetResults() + { + } + + public override bool IsThreaded + { + // for now we won't be multithreaded + get { return (false); } + } + + public override void SetTerrain(float[] heightMap) + { + _heightMap = heightMap; + } + + public override void DeleteTerrain() + { + } + + public override void SetWaterLevel(float baseheight) + { + } + + public override Dictionary GetTopColliders() + { + Dictionary returncolliders = new Dictionary(); + return returncolliders; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/SharedBase/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/SharedBase/AssemblyInfo.cs new file mode 100644 index 0000000..33f60e4 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/SharedBase/AssemblyInfo.cs @@ -0,0 +1,58 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Reflection; +using System.Runtime.InteropServices; + +// Information about this assembly is defined by the following +// attributes. +// +// change them to the information which is associated with the assembly +// you compile. + +[assembly : AssemblyTitle("PhysicsManager")] +[assembly : AssemblyDescription("")] +[assembly : AssemblyConfiguration("")] +[assembly : AssemblyCompany("http://opensimulator.org")] +[assembly : AssemblyProduct("PhysicsManager")] +[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] +[assembly : AssemblyTrademark("")] +[assembly : AssemblyCulture("")] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. + +[assembly : ComVisible(false)] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all values by your own or you can build default build and revision +// numbers with the '*' character (the default): + +[assembly : AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/PhysicsModules/SharedBase/CollisionLocker.cs b/OpenSim/Region/PhysicsModules/SharedBase/CollisionLocker.cs new file mode 100644 index 0000000..6e658b5 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/SharedBase/CollisionLocker.cs @@ -0,0 +1,73 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; + +namespace OpenSim.Region.PhysicsModules.SharedBase +{ + public class CollisionLocker + { + private List worldlock = new List(); + + public CollisionLocker() + { + + } + + public void dlock(IntPtr world) + { + lock (worldlock) + { + worldlock.Add(world); + } + + } + + public void dunlock(IntPtr world) + { + lock (worldlock) + { + worldlock.Remove(world); + } + } + + public bool lockquery() + { + return (worldlock.Count > 0); + } + + public void drelease(IntPtr world) + { + lock (worldlock) + { + if (worldlock.Contains(world)) + worldlock.Remove(world); + } + } + } +} diff --git a/OpenSim/Region/PhysicsModules/SharedBase/IMesher.cs b/OpenSim/Region/PhysicsModules/SharedBase/IMesher.cs new file mode 100644 index 0000000..5c75307 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/SharedBase/IMesher.cs @@ -0,0 +1,71 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenSim.Framework; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModules.SharedBase +{ + public interface IMesher + { + IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); + IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); + IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache); + } + + // Values for level of detail to be passed to the mesher. + // Values origionally chosen for the LOD of sculpties (the sqrt(width*heigth) of sculpt texture) + // Lower level of detail reduces the number of vertices used to represent the meshed shape. + public enum LevelOfDetail + { + High = 32, + Medium = 16, + Low = 8, + VeryLow = 4 + } + + public interface IVertex + { + } + + public interface IMesh + { + List getVertexList(); + int[] getIndexListAsInt(); + int[] getIndexListAsIntLocked(); + float[] getVertexListAsFloat(); + float[] getVertexListAsFloatLocked(); + void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount); + void getVertexListAsPtrToFloatArray(out IntPtr vertexList, out int vertexStride, out int vertexCount); + void releaseSourceMeshData(); + void releasePinned(); + void Append(IMesh newMesh); + void TransformLinear(float[,] matrix, float[] offset); + } +} diff --git a/OpenSim/Region/PhysicsModules/SharedBase/IPhysicsParameters.cs b/OpenSim/Region/PhysicsModules/SharedBase/IPhysicsParameters.cs new file mode 100755 index 0000000..fb0c9e2 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/SharedBase/IPhysicsParameters.cs @@ -0,0 +1,73 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenSim.Framework; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModules.SharedBase +{ + public struct PhysParameterEntry + { + // flags to say to apply to all or no instances (I wish one could put consts into interfaces) + public const uint APPLY_TO_ALL = 0xfffffff3; + public const uint APPLY_TO_NONE = 0xfffffff4; + + // values that denote true and false values + public const float NUMERIC_TRUE = 1f; + public const float NUMERIC_FALSE = 0f; + + public string name; + public string desc; + + public PhysParameterEntry(string n, string d) + { + name = n; + desc = d; + } + } + + // Interface for a physics scene that implements the runtime setting and getting of physics parameters + public interface IPhysicsParameters + { + // Get the list of parameters this physics engine supports + PhysParameterEntry[] GetParameterList(); + + // Set parameter on a specific or all instances. + // Return 'false' if not able to set the parameter. + bool SetPhysicsParameter(string parm, string value, uint localID); + + // Get parameter. + // Return 'false' if not able to get the parameter. + bool GetPhysicsParameter(string parm, out string value); + + // Get parameter from a particular object + // TODO: + // bool GetPhysicsParameter(string parm, out string value, uint localID); + } +} diff --git a/OpenSim/Region/PhysicsModules/SharedBase/NullPhysicsScene.cs b/OpenSim/Region/PhysicsModules/SharedBase/NullPhysicsScene.cs new file mode 100644 index 0000000..432708c --- /dev/null +++ b/OpenSim/Region/PhysicsModules/SharedBase/NullPhysicsScene.cs @@ -0,0 +1,117 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Collections.Generic; +using System.Reflection; +using log4net; +using Nini.Config; +using OpenSim.Framework; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModules.SharedBase +{ + class NullPhysicsScene : PhysicsScene + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private static int m_workIndicator; + + public override PhysicsActor AddAvatar( + string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) + { + m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : AddAvatar({0})", position); + return PhysicsActor.Null; + } + + public override void RemoveAvatar(PhysicsActor actor) + { + } + + public override void RemovePrim(PhysicsActor prim) + { + } + public override void SetWaterLevel(float baseheight) + { + + } + +/* + public override PhysicsActor AddPrim(Vector3 position, Vector3 size, Quaternion rotation) + { + m_log.InfoFormat("NullPhysicsScene : AddPrim({0},{1})", position, size); + return PhysicsActor.Null; + } +*/ + + public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, + Vector3 size, Quaternion rotation, bool isPhysical, uint localid) + { + m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : AddPrim({0},{1})", position, size); + return PhysicsActor.Null; + } + + public override void AddPhysicsActorTaint(PhysicsActor prim) + { + } + + public override float Simulate(float timeStep) + { + m_workIndicator = (m_workIndicator + 1) % 10; + + return 0f; + } + + public override void GetResults() + { + m_log.Info("[PHYSICS]: NullPhysicsScene : GetResults()"); + } + + public override void SetTerrain(float[] heightMap) + { + m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : SetTerrain({0} items)", heightMap.Length); + } + + public override void DeleteTerrain() + { + } + + public override bool IsThreaded + { + get { return false; } + } + + public override void Dispose() + { + } + + public override Dictionary GetTopColliders() + { + Dictionary returncolliders = new Dictionary(); + return returncolliders; + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs new file mode 100644 index 0000000..c04ff58 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs @@ -0,0 +1,584 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using log4net; +using System; +using System.Collections.Generic; +using System.Reflection; +using OpenSim.Framework; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModules.SharedBase +{ + public delegate void PositionUpdate(Vector3 position); + public delegate void VelocityUpdate(Vector3 velocity); + public delegate void OrientationUpdate(Quaternion orientation); + + public enum ActorTypes : int + { + Unknown = 0, + Agent = 1, + Prim = 2, + Ground = 3 + } + + public enum PIDHoverType + { + Ground, + GroundAndWater, + Water, + Absolute + } + + public struct ContactPoint + { + public Vector3 Position; + public Vector3 SurfaceNormal; + public float PenetrationDepth; + + public ContactPoint(Vector3 position, Vector3 surfaceNormal, float penetrationDepth) + { + Position = position; + SurfaceNormal = surfaceNormal; + PenetrationDepth = penetrationDepth; + } + } + + /// + /// Used to pass collision information to OnCollisionUpdate listeners. + /// + public class CollisionEventUpdate : EventArgs + { + /// + /// Number of collision events in this update. + /// + public int Count { get { return m_objCollisionList.Count; } } + + public bool CollisionsOnPreviousFrame { get; private set; } + + public Dictionary m_objCollisionList; + + public CollisionEventUpdate(Dictionary objCollisionList) + { + m_objCollisionList = objCollisionList; + } + + public CollisionEventUpdate() + { + m_objCollisionList = new Dictionary(); + } + + public void AddCollider(uint localID, ContactPoint contact) + { + if (!m_objCollisionList.ContainsKey(localID)) + { + m_objCollisionList.Add(localID, contact); + } + else + { + if (m_objCollisionList[localID].PenetrationDepth < contact.PenetrationDepth) + m_objCollisionList[localID] = contact; + } + } + + /// + /// Clear added collision events. + /// + public void Clear() + { + m_objCollisionList.Clear(); + } + } + + public abstract class PhysicsActor + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public delegate void RequestTerseUpdate(); + public delegate void CollisionUpdate(EventArgs e); + public delegate void OutOfBounds(Vector3 pos); + +// disable warning: public events +#pragma warning disable 67 + public event PositionUpdate OnPositionUpdate; + public event VelocityUpdate OnVelocityUpdate; + public event OrientationUpdate OnOrientationUpdate; + public event RequestTerseUpdate OnRequestTerseUpdate; + + /// + /// Subscribers to this event must synchronously handle the dictionary of collisions received, since the event + /// object is reused in subsequent physics frames. + /// + public event CollisionUpdate OnCollisionUpdate; + + public event OutOfBounds OnOutOfBounds; +#pragma warning restore 67 + + public static PhysicsActor Null + { + get { return new NullPhysicsActor(); } + } + + public abstract bool Stopped { get; } + + public abstract Vector3 Size { get; set; } + + public virtual byte PhysicsShapeType { get; set; } + + public abstract PrimitiveBaseShape Shape { set; } + + uint m_baseLocalID; + public virtual uint LocalID + { + set { m_baseLocalID = value; } + get { return m_baseLocalID; } + } + + public abstract bool Grabbed { set; } + + public abstract bool Selected { set; } + + /// + /// Name of this actor. + /// + /// + /// XXX: Bizarrely, this cannot be "Terrain" or "Water" right now unless it really is simulating terrain or + /// water. This is not a problem due to the formatting of names given by prims and avatars. + /// + public string Name { get; protected set; } + + /// + /// This is being used by ODE joint code. + /// + public string SOPName; + + public abstract void CrossingFailure(); + + public abstract void link(PhysicsActor obj); + + public abstract void delink(); + + public abstract void LockAngularMotion(Vector3 axis); + + public virtual void RequestPhysicsterseUpdate() + { + // Make a temporary copy of the event to avoid possibility of + // a race condition if the last subscriber unsubscribes + // immediately after the null check and before the event is raised. + RequestTerseUpdate handler = OnRequestTerseUpdate; + + if (handler != null) + { + handler(); + } + } + + public virtual void RaiseOutOfBounds(Vector3 pos) + { + // Make a temporary copy of the event to avoid possibility of + // a race condition if the last subscriber unsubscribes + // immediately after the null check and before the event is raised. + OutOfBounds handler = OnOutOfBounds; + + if (handler != null) + { + handler(pos); + } + } + + public virtual void SendCollisionUpdate(EventArgs e) + { + CollisionUpdate handler = OnCollisionUpdate; + +// m_log.DebugFormat("[PHYSICS ACTOR]: Sending collision for {0}", LocalID); + + if (handler != null) + handler(e); + } + + public virtual void SetMaterial (int material) { } + public virtual float Density { get; set; } + public virtual float GravModifier { get; set; } + public virtual float Friction { get; set; } + public virtual float Restitution { get; set; } + + /// + /// Position of this actor. + /// + /// + /// Setting this directly moves the actor to a given position. + /// Getting this retrieves the position calculated by physics scene updates, using factors such as velocity and + /// collisions. + /// + public abstract Vector3 Position { get; set; } + + public abstract float Mass { get; } + public abstract Vector3 Force { get; set; } + + public abstract int VehicleType { get; set; } + public abstract void VehicleFloatParam(int param, float value); + public abstract void VehicleVectorParam(int param, Vector3 value); + public abstract void VehicleRotationParam(int param, Quaternion rotation); + public abstract void VehicleFlags(int param, bool remove); + + /// + /// Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more + /// + public abstract void SetVolumeDetect(int param); + + public abstract Vector3 GeometricCenter { get; } + public abstract Vector3 CenterOfMass { get; } + + /// + /// The desired velocity of this actor. + /// + /// + /// Setting this provides a target velocity for physics scene updates. + /// Getting this returns the last set target. Fetch Velocity to get the current velocity. + /// + protected Vector3 m_targetVelocity; + public virtual Vector3 TargetVelocity + { + get { return m_targetVelocity; } + set { + m_targetVelocity = value; + Velocity = m_targetVelocity; + } + } + + public abstract Vector3 Velocity { get; set; } + + public abstract Vector3 Torque { get; set; } + public abstract float CollisionScore { get; set;} + public abstract Vector3 Acceleration { get; set; } + public abstract Quaternion Orientation { get; set; } + public abstract int PhysicsActorType { get; set; } + public abstract bool IsPhysical { get; set; } + public abstract bool Flying { get; set; } + public abstract bool SetAlwaysRun { get; set; } + public abstract bool ThrottleUpdates { get; set; } + public abstract bool IsColliding { get; set; } + public abstract bool CollidingGround { get; set; } + public abstract bool CollidingObj { get; set; } + public abstract bool FloatOnWater { set; } + public abstract Vector3 RotationalVelocity { get; set; } + public abstract bool Kinematic { get; set; } + public abstract float Buoyancy { get; set; } + + // Used for MoveTo + public abstract Vector3 PIDTarget { set; } + public abstract bool PIDActive { get; set; } + public abstract float PIDTau { set; } + + // Used for llSetHoverHeight and maybe vehicle height + // Hover Height will override MoveTo target's Z + public abstract bool PIDHoverActive { set;} + public abstract float PIDHoverHeight { set;} + public abstract PIDHoverType PIDHoverType { set;} + public abstract float PIDHoverTau { set;} + + // For RotLookAt + public abstract Quaternion APIDTarget { set;} + public abstract bool APIDActive { set;} + public abstract float APIDStrength { set;} + public abstract float APIDDamping { set;} + + public abstract void AddForce(Vector3 force, bool pushforce); + public abstract void AddAngularForce(Vector3 force, bool pushforce); + public abstract void SetMomentum(Vector3 momentum); + public abstract void SubscribeEvents(int ms); + public abstract void UnSubscribeEvents(); + public abstract bool SubscribedEvents(); + + // Extendable interface for new, physics engine specific operations + public virtual object Extension(string pFunct, params object[] pParams) + { + // A NOP of the physics engine does not implement this feature + return null; + } + } + + public class NullPhysicsActor : PhysicsActor + { + public override bool Stopped + { + get{ return false; } + } + + public override Vector3 Position + { + get { return Vector3.Zero; } + set { return; } + } + + public override bool SetAlwaysRun + { + get { return false; } + set { return; } + } + + public override uint LocalID + { + set { return; } + } + + public override bool Grabbed + { + set { return; } + } + + public override bool Selected + { + set { return; } + } + + public override float Buoyancy + { + get { return 0f; } + set { return; } + } + + public override bool FloatOnWater + { + set { return; } + } + + public override bool CollidingGround + { + get { return false; } + set { return; } + } + + public override bool CollidingObj + { + get { return false; } + set { return; } + } + + public override Vector3 Size + { + get { return Vector3.Zero; } + set { return; } + } + + public override float Mass + { + get { return 0f; } + } + + public override Vector3 Force + { + get { return Vector3.Zero; } + set { return; } + } + + public override int VehicleType + { + get { return 0; } + set { return; } + } + + public override void VehicleFloatParam(int param, float value) + { + + } + + public override void VehicleVectorParam(int param, Vector3 value) + { + + } + + public override void VehicleRotationParam(int param, Quaternion rotation) + { + + } + + public override void VehicleFlags(int param, bool remove) + { + + } + + public override void SetVolumeDetect(int param) + { + + } + + public override void SetMaterial(int material) + { + + } + + public override Vector3 CenterOfMass + { + get { return Vector3.Zero; } + } + + public override Vector3 GeometricCenter + { + get { return Vector3.Zero; } + } + + public override PrimitiveBaseShape Shape + { + set { return; } + } + + public override Vector3 Velocity + { + get { return Vector3.Zero; } + set { return; } + } + + public override Vector3 Torque + { + get { return Vector3.Zero; } + set { return; } + } + + public override float CollisionScore + { + get { return 0f; } + set { } + } + + public override void CrossingFailure() + { + } + + public override Quaternion Orientation + { + get { return Quaternion.Identity; } + set { } + } + + public override Vector3 Acceleration + { + get { return Vector3.Zero; } + set { } + } + + public override bool IsPhysical + { + get { return false; } + set { return; } + } + + public override bool Flying + { + get { return false; } + set { return; } + } + + public override bool ThrottleUpdates + { + get { return false; } + set { return; } + } + + public override bool IsColliding + { + get { return false; } + set { return; } + } + + public override int PhysicsActorType + { + get { return (int) ActorTypes.Unknown; } + set { return; } + } + + public override bool Kinematic + { + get { return true; } + set { return; } + } + + public override void link(PhysicsActor obj) + { + } + + public override void delink() + { + } + + public override void LockAngularMotion(Vector3 axis) + { + } + + public override void AddForce(Vector3 force, bool pushforce) + { + } + + public override void AddAngularForce(Vector3 force, bool pushforce) + { + + } + + public override Vector3 RotationalVelocity + { + get { return Vector3.Zero; } + set { return; } + } + + public override Vector3 PIDTarget { set { return; } } + + public override bool PIDActive + { + get { return false; } + set { return; } + } + + public override float PIDTau { set { return; } } + + public override float PIDHoverHeight { set { return; } } + public override bool PIDHoverActive { set { return; } } + public override PIDHoverType PIDHoverType { set { return; } } + public override float PIDHoverTau { set { return; } } + + public override Quaternion APIDTarget { set { return; } } + public override bool APIDActive { set { return; } } + public override float APIDStrength { set { return; } } + public override float APIDDamping { set { return; } } + + public override void SetMomentum(Vector3 momentum) + { + } + + public override void SubscribeEvents(int ms) + { + + } + public override void UnSubscribeEvents() + { + + } + public override bool SubscribedEvents() + { + return false; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsJoint.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsJoint.cs new file mode 100644 index 0000000..ce2bf05 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsJoint.cs @@ -0,0 +1,55 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenSim.Framework; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModules.SharedBase +{ + public enum PhysicsJointType : int + { + Ball = 0, + Hinge = 1 + } + + public class PhysicsJoint + { + public virtual bool IsInPhysicsEngine { get { return false; } } // set internally to indicate if this joint has already been passed to the physics engine or is still pending + public PhysicsJointType Type; + public string RawParams; + public List BodyNames = new List(); + public Vector3 Position; // global coords + public Quaternion Rotation; // global coords + public string ObjectNameInScene; // proxy object in scene that represents the joint position/orientation + public string TrackedBodyName; // body name that this joint is attached to (ObjectNameInScene will follow TrackedBodyName) + public Quaternion LocalRotation; // joint orientation relative to one of the involved bodies, the tracked body + public int ErrorMessageCount; // total # of error messages printed for this joint since its creation. if too many, further error messages are suppressed to prevent flooding. + public const int maxErrorMessages = 100; // no more than this # of error messages will be printed for each joint + } +} diff --git a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsScene.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsScene.cs new file mode 100644 index 0000000..32691fc --- /dev/null +++ b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsScene.cs @@ -0,0 +1,358 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; + +using log4net; +using Nini.Config; + +using OpenSim.Framework; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModules.SharedBase +{ + public delegate void physicsCrash(); + + public delegate void RaycastCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal); + public delegate void RayCallback(List list); + + public delegate void JointMoved(PhysicsJoint joint); + public delegate void JointDeactivated(PhysicsJoint joint); + public delegate void JointErrorMessage(PhysicsJoint joint, string message); // this refers to an "error message due to a problem", not "amount of joint constraint violation" + + public enum RayFilterFlags : ushort + { + // the flags + water = 0x01, + land = 0x02, + agent = 0x04, + nonphysical = 0x08, + physical = 0x10, + phantom = 0x20, + volumedtc = 0x40, + + // ray cast colision control (may only work for meshs) + ContactsUnImportant = 0x2000, + BackFaceCull = 0x4000, + ClosestHit = 0x8000, + + // some combinations + LSLPhantom = phantom | volumedtc, + PrimsNonPhantom = nonphysical | physical, + PrimsNonPhantomAgents = nonphysical | physical | agent, + + AllPrims = nonphysical | phantom | volumedtc | physical, + AllButLand = agent | nonphysical | physical | phantom | volumedtc, + + ClosestAndBackCull = ClosestHit | BackFaceCull, + + All = 0x3f + } + + public delegate void RequestAssetDelegate(UUID assetID, AssetReceivedDelegate callback); + public delegate void AssetReceivedDelegate(AssetBase asset); + + /// + /// Contact result from a raycast. + /// + public struct ContactResult + { + public Vector3 Pos; + public float Depth; + public uint ConsumerID; + public Vector3 Normal; + } + + public abstract class PhysicsScene + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// A unique identifying string for this instance of the physics engine. + /// Useful in debug messages to distinguish one OdeScene instance from another. + /// Usually set to include the region name that the physics engine is acting for. + /// + public string PhysicsSceneName { get; protected set; } + + /// + /// A string identifying the family of this physics engine. Most common values returned + /// are "OpenDynamicsEngine" and "BulletSim" but others are possible. + /// + public string EngineType { get; protected set; } + + // The only thing that should register for this event is the SceneGraph + // Anything else could cause problems. + public event physicsCrash OnPhysicsCrash; + + public static PhysicsScene Null + { + get { return new NullPhysicsScene(); } + } + + public RequestAssetDelegate RequestAssetMethod { get; set; } + + protected void Initialise(RequestAssetDelegate m, float[] terrain, float waterHeight) + { + RequestAssetMethod = m; + SetTerrain(terrain); + SetWaterLevel(waterHeight); + + } + + public virtual void TriggerPhysicsBasedRestart() + { + physicsCrash handler = OnPhysicsCrash; + if (handler != null) + { + OnPhysicsCrash(); + } + } + + /// + /// Add an avatar + /// + /// + /// + /// + /// + /// + /// + public abstract PhysicsActor AddAvatar( + string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying); + + /// + /// Add an avatar + /// + /// + /// + /// + /// + /// + /// + /// + public virtual PhysicsActor AddAvatar( + uint localID, string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying) + { + PhysicsActor ret = AddAvatar(avName, position, velocity, size, isFlying); + + if (ret != null) + ret.LocalID = localID; + + return ret; + } + + /// + /// Remove an avatar. + /// + /// + public abstract void RemoveAvatar(PhysicsActor actor); + + /// + /// Remove a prim. + /// + /// + public abstract void RemovePrim(PhysicsActor prim); + + public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, + Vector3 size, Quaternion rotation, bool isPhysical, uint localid); + + public virtual PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, + Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, byte shapetype, uint localid) + { + return AddPrimShape(primName, pbs, position, size, rotation, isPhysical, localid); + } + + public virtual float TimeDilation + { + get { return 1.0f; } + } + + public virtual bool SupportsNINJAJoints + { + get { return false; } + } + + public virtual PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position, + Quaternion rotation, string parms, List bodyNames, string trackedBodyName, Quaternion localRotation) + { return null; } + + public virtual void RequestJointDeletion(string objectNameInScene) + { return; } + + public virtual void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor) + { return; } + + public virtual void DumpJointInfo() + { return; } + + public event JointMoved OnJointMoved; + + protected virtual void DoJointMoved(PhysicsJoint joint) + { + // We need this to allow subclasses (but not other classes) to invoke the event; C# does + // not allow subclasses to invoke the parent class event. + if (OnJointMoved != null) + { + OnJointMoved(joint); + } + } + + public event JointDeactivated OnJointDeactivated; + + protected virtual void DoJointDeactivated(PhysicsJoint joint) + { + // We need this to allow subclasses (but not other classes) to invoke the event; C# does + // not allow subclasses to invoke the parent class event. + if (OnJointDeactivated != null) + { + OnJointDeactivated(joint); + } + } + + public event JointErrorMessage OnJointErrorMessage; + + protected virtual void DoJointErrorMessage(PhysicsJoint joint, string message) + { + // We need this to allow subclasses (but not other classes) to invoke the event; C# does + // not allow subclasses to invoke the parent class event. + if (OnJointErrorMessage != null) + { + OnJointErrorMessage(joint, message); + } + } + + public virtual Vector3 GetJointAnchor(PhysicsJoint joint) + { return Vector3.Zero; } + + public virtual Vector3 GetJointAxis(PhysicsJoint joint) + { return Vector3.Zero; } + + public abstract void AddPhysicsActorTaint(PhysicsActor prim); + + /// + /// Perform a simulation of the current physics scene over the given timestep. + /// + /// + /// The number of frames simulated over that period. + public abstract float Simulate(float timeStep); + + /// + /// Get statistics about this scene. + /// + /// This facility is currently experimental and subject to change. + /// + /// A dictionary where the key is the statistic name. If no statistics are supplied then returns null. + /// + public virtual Dictionary GetStats() { return null; } + + public abstract void GetResults(); + + public abstract void SetTerrain(float[] heightMap); + + public abstract void SetWaterLevel(float baseheight); + + public abstract void DeleteTerrain(); + + public abstract void Dispose(); + + public abstract Dictionary GetTopColliders(); + + public abstract bool IsThreaded { get; } + + /// + /// True if the physics plugin supports raycasting against the physics scene + /// + public virtual bool SupportsRayCast() + { + return false; + } + + public virtual bool SupportsCombining() + { + return false; + } + + public virtual void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) {} + + public virtual void UnCombine(PhysicsScene pScene) {} + + /// + /// Queue a raycast against the physics scene. + /// The provided callback method will be called when the raycast is complete + /// + /// Many physics engines don't support collision testing at the same time as + /// manipulating the physics scene, so we queue the request up and callback + /// a custom method when the raycast is complete. + /// This allows physics engines that give an immediate result to callback immediately + /// and ones that don't, to callback when it gets a result back. + /// + /// ODE for example will not allow you to change the scene while collision testing or + /// it asserts, 'opteration not valid for locked space'. This includes adding a ray to the scene. + /// + /// This is named RayCastWorld to not conflict with modrex's Raycast method. + /// + /// Origin of the ray + /// Direction of the ray + /// Length of ray in meters + /// Method to call when the raycast is complete + public virtual void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod) + { + if (retMethod != null) + retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero); + } + + public virtual void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod) + { + if (retMethod != null) + retMethod(new List()); + } + + public virtual List RaycastWorld(Vector3 position, Vector3 direction, float length, int Count) + { + return new List(); + } + + public virtual object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter) + { + return null; + } + + public virtual bool SupportsRaycastWorldFiltered() + { + return false; + } + + // Extendable interface for new, physics engine specific operations + public virtual object Extension(string pFunct, params object[] pParams) + { + // A NOP if the extension thing is not implemented by the physics engine + return null; + } + } +} diff --git a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsSensor.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsSensor.cs new file mode 100644 index 0000000..da9c96c --- /dev/null +++ b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsSensor.cs @@ -0,0 +1,78 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Timers; +using OpenMetaverse; + +namespace OpenSim.Region.PhysicsModules.SharedBase +{ + [Flags] + public enum SenseType : uint + { + NONE = 0, + AGENT = 1, + ACTIVE = 2, + PASSIVE = 3, + SCRIPTED = 4 + } + + public abstract class PhysicsSensor + { + public static PhysicsSensor Null + { + get { return new NullPhysicsSensor(); } + } + public abstract Vector3 Position { get; set; } + public abstract void TimerCallback (object obj, ElapsedEventArgs eea); + public abstract float radianarc {get; set;} + public abstract string targetname {get; set;} + public abstract Guid targetKey{get;set;} + public abstract SenseType sensetype { get;set;} + public abstract float range { get;set;} + public abstract float rateSeconds { get;set;} + } + + public class NullPhysicsSensor : PhysicsSensor + { + public override Vector3 Position + { + get { return Vector3.Zero; } + set { return; } + } + public override void TimerCallback(object obj, ElapsedEventArgs eea) + { + // don't do squat + } + public override float radianarc { get { return 0f; } set { } } + public override string targetname { get { return ""; } set { } } + public override Guid targetKey { get { return Guid.Empty; } set { } } + public override SenseType sensetype { get { return SenseType.NONE; } set { } } + public override float range { get { return 0; } set { } } + public override float rateSeconds { get { return 0; } set { } } + } +} diff --git a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsVector.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsVector.cs new file mode 100644 index 0000000..76a82fa --- /dev/null +++ b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsVector.cs @@ -0,0 +1,186 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenSim.Region.PhysicsModules.SharedBase +{ + /*public class PhysicsVector + { + public float X; + public float Y; + public float Z; + + public Vector3() + { + } + + public Vector3(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + + public Vector3(Vector3 pv) : this(pv.X, pv.Y, pv.Z) + { + } + + public void setValues(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + + public static readonly PhysicsVector Zero = new PhysicsVector(0f, 0f, 0f); + + public override string ToString() + { + return "<" + X + "," + Y + "," + Z + ">"; + } + + /// + /// These routines are the easiest way to store XYZ values in an Vector3 without requiring 3 calls. + /// + /// + public byte[] GetBytes() + { + byte[] byteArray = new byte[12]; + + Buffer.BlockCopy(BitConverter.GetBytes(X), 0, byteArray, 0, 4); + Buffer.BlockCopy(BitConverter.GetBytes(Y), 0, byteArray, 4, 4); + Buffer.BlockCopy(BitConverter.GetBytes(Z), 0, byteArray, 8, 4); + + if (!BitConverter.IsLittleEndian) + { + Array.Reverse(byteArray, 0, 4); + Array.Reverse(byteArray, 4, 4); + Array.Reverse(byteArray, 8, 4); + } + + return byteArray; + } + + public void FromBytes(byte[] byteArray, int pos) + { + byte[] conversionBuffer = null; + if (!BitConverter.IsLittleEndian) + { + // Big endian architecture + if (conversionBuffer == null) + conversionBuffer = new byte[12]; + + Buffer.BlockCopy(byteArray, pos, conversionBuffer, 0, 12); + + Array.Reverse(conversionBuffer, 0, 4); + Array.Reverse(conversionBuffer, 4, 4); + Array.Reverse(conversionBuffer, 8, 4); + + X = BitConverter.ToSingle(conversionBuffer, 0); + Y = BitConverter.ToSingle(conversionBuffer, 4); + Z = BitConverter.ToSingle(conversionBuffer, 8); + } + else + { + // Little endian architecture + X = BitConverter.ToSingle(byteArray, pos); + Y = BitConverter.ToSingle(byteArray, pos + 4); + Z = BitConverter.ToSingle(byteArray, pos + 8); + } + } + + // Operations + public static PhysicsVector operator +(Vector3 a, Vector3 b) + { + return new PhysicsVector(a.X + b.X, a.Y + b.Y, a.Z + b.Z); + } + + public static PhysicsVector operator -(Vector3 a, Vector3 b) + { + return new PhysicsVector(a.X - b.X, a.Y - b.Y, a.Z - b.Z); + } + + public static PhysicsVector cross(Vector3 a, Vector3 b) + { + return new PhysicsVector(a.Y*b.Z - a.Z*b.Y, a.Z*b.X - a.X*b.Z, a.X*b.Y - a.Y*b.X); + } + + public float length() + { + return (float) Math.Sqrt(X*X + Y*Y + Z*Z); + } + + public static float GetDistanceTo(Vector3 a, Vector3 b) + { + float dx = a.X - b.X; + float dy = a.Y - b.Y; + float dz = a.Z - b.Z; + return (float) Math.Sqrt(dx * dx + dy * dy + dz * dz); + } + + public static PhysicsVector operator /(Vector3 v, float f) + { + return new PhysicsVector(v.X/f, v.Y/f, v.Z/f); + } + + public static PhysicsVector operator *(Vector3 v, float f) + { + return new PhysicsVector(v.X*f, v.Y*f, v.Z*f); + } + + public static PhysicsVector operator *(float f, Vector3 v) + { + return v*f; + } + + public static bool isFinite(Vector3 v) + { + if (v == null) + return false; + if (Single.IsInfinity(v.X) || Single.IsNaN(v.X)) + return false; + if (Single.IsInfinity(v.Y) || Single.IsNaN(v.Y)) + return false; + if (Single.IsInfinity(v.Z) || Single.IsNaN(v.Z)) + return false; + + return true; + } + + public virtual bool IsIdentical(Vector3 v, float tolerance) + { + PhysicsVector diff = this - v; + float d = diff.length(); + if (d <= tolerance) + return true; + + return false; + } + + }*/ +} diff --git a/OpenSim/Region/PhysicsModules/SharedBase/VehicleConstants.cs b/OpenSim/Region/PhysicsModules/SharedBase/VehicleConstants.cs new file mode 100644 index 0000000..63a8cb8 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/SharedBase/VehicleConstants.cs @@ -0,0 +1,121 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenSim.Region.PhysicsModules.SharedBase +{ + public enum Vehicle : int + { + /// + /// Turns off Vehicle Support + /// + TYPE_NONE = 0, + + /// + /// No Angular motor, High Left right friction, No Hover, Linear Deflection 1, no angular deflection + /// no vertical attractor, No banking, Identity rotation frame + /// + TYPE_SLED = 1, + + /// + /// Needs Motors to be driven by timer or control events High left/right friction, No angular friction + /// Linear Motor wins in a second, decays in 60 seconds. Angular motor wins in a second, decays in 8/10ths of a second + /// linear deflection 2 seconds + /// Vertical Attractor locked UP + /// + TYPE_CAR = 2, + TYPE_BOAT = 3, + TYPE_AIRPLANE = 4, + TYPE_BALLOON = 5, + LINEAR_FRICTION_TIMESCALE = 16, + /// + /// vector of timescales for exponential decay of angular velocity about three axis + /// + ANGULAR_FRICTION_TIMESCALE = 17, + /// + /// linear velocity vehicle will try for + /// + LINEAR_MOTOR_DIRECTION = 18, + + /// + /// Offset from center of mass where linear motor forces are added + /// + LINEAR_MOTOR_OFFSET = 20, + /// + /// angular velocity that vehicle will try for + /// + ANGULAR_MOTOR_DIRECTION = 19, + HOVER_HEIGHT = 24, + HOVER_EFFICIENCY = 25, + HOVER_TIMESCALE = 26, + BUOYANCY = 27, + LINEAR_DEFLECTION_EFFICIENCY = 28, + LINEAR_DEFLECTION_TIMESCALE = 29, + LINEAR_MOTOR_TIMESCALE = 30, + LINEAR_MOTOR_DECAY_TIMESCALE = 31, + + /// + /// slide between 0 and 1 + /// + ANGULAR_DEFLECTION_EFFICIENCY = 32, + ANGULAR_DEFLECTION_TIMESCALE = 33, + ANGULAR_MOTOR_TIMESCALE = 34, + ANGULAR_MOTOR_DECAY_TIMESCALE = 35, + VERTICAL_ATTRACTION_EFFICIENCY = 36, + VERTICAL_ATTRACTION_TIMESCALE = 37, + BANKING_EFFICIENCY = 38, + BANKING_MIX = 39, + BANKING_TIMESCALE = 40, + REFERENCE_FRAME = 44, + BLOCK_EXIT = 45, + ROLL_FRAME = 46 + + } + + [Flags] + public enum VehicleFlag + { + NO_DEFLECTION_UP = 1, + LIMIT_ROLL_ONLY = 2, + HOVER_WATER_ONLY = 4, + HOVER_TERRAIN_ONLY = 8, + HOVER_GLOBAL_HEIGHT = 16, + HOVER_UP_ONLY = 32, + LIMIT_MOTOR_UP = 64, + MOUSELOOK_STEER = 128, + MOUSELOOK_BANK = 256, + CAMERA_DECOUPLED = 512, + NO_X = 1024, + NO_Y = 2048, + NO_Z = 4096, + LOCK_HOVER_HEIGHT = 8192, + NO_DEFLECTION = 16392, + LOCK_ROTATION = 32784 + } + +} diff --git a/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs b/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs deleted file mode 100644 index 085eb59..0000000 --- a/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenSim.Region.RegionCombinerModule")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("http://opensimulator.org")] -[assembly: AssemblyProduct("OpenSim")] -[assembly: AssemblyCopyright("OpenSimulator developers")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("73c166d2-c9d8-4ab8-af4e-89c41b4b58a9")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerClientEventForwarder.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerClientEventForwarder.cs deleted file mode 100644 index 721d396..0000000 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerClientEventForwarder.cs +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using OpenMetaverse; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.RegionCombinerModule -{ -public class RegionCombinerClientEventForwarder - { - private Scene m_rootScene; - private Dictionary m_virtScene = new Dictionary(); - private Dictionary m_forwarders = new Dictionary(); - - public RegionCombinerClientEventForwarder(RegionConnections rootScene) - { - m_rootScene = rootScene.RegionScene; - } - - public void AddSceneToEventForwarding(Scene virtualScene) - { - lock (m_virtScene) - { - if (m_virtScene.ContainsKey(virtualScene.RegionInfo.originRegionID)) - { - m_virtScene[virtualScene.RegionInfo.originRegionID] = virtualScene; - } - else - { - m_virtScene.Add(virtualScene.RegionInfo.originRegionID, virtualScene); - } - } - - lock (m_forwarders) - { - // TODO: Fix this to unregister if this happens - if (m_forwarders.ContainsKey(virtualScene.RegionInfo.originRegionID)) - m_forwarders.Remove(virtualScene.RegionInfo.originRegionID); - - RegionCombinerIndividualEventForwarder forwarder = - new RegionCombinerIndividualEventForwarder(m_rootScene, virtualScene); - m_forwarders.Add(virtualScene.RegionInfo.originRegionID, forwarder); - - virtualScene.EventManager.OnNewClient += forwarder.ClientConnect; - virtualScene.EventManager.OnClientClosed += forwarder.ClientClosed; - } - } - - public void RemoveSceneFromEventForwarding (Scene virtualScene) - { - lock (m_forwarders) - { - RegionCombinerIndividualEventForwarder forwarder = m_forwarders[virtualScene.RegionInfo.originRegionID]; - virtualScene.EventManager.OnNewClient -= forwarder.ClientConnect; - virtualScene.EventManager.OnClientClosed -= forwarder.ClientClosed; - m_forwarders.Remove(virtualScene.RegionInfo.originRegionID); - } - lock (m_virtScene) - { - if (m_virtScene.ContainsKey(virtualScene.RegionInfo.originRegionID)) - { - m_virtScene.Remove(virtualScene.RegionInfo.originRegionID); - } - } - } - } -} \ No newline at end of file diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs deleted file mode 100644 index f424e7f..0000000 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.CoreModules.Avatar.Attachments; -using OpenSim.Region.CoreModules.Avatar.Gods; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.RegionCombinerModule -{ - public class RegionCombinerIndividualEventForwarder - { - private Scene m_rootScene; - private Scene m_virtScene; - - public RegionCombinerIndividualEventForwarder(Scene rootScene, Scene virtScene) - { - m_rootScene = rootScene; - m_virtScene = virtScene; - } - - public void ClientConnect(IClientAPI client) - { - m_virtScene.UnSubscribeToClientPrimEvents(client); - m_virtScene.UnSubscribeToClientPrimRezEvents(client); - m_virtScene.UnSubscribeToClientInventoryEvents(client); - ((AttachmentsModule)m_virtScene.AttachmentsModule).UnsubscribeFromClientEvents(client); - //m_virtScene.UnSubscribeToClientTeleportEvents(client); - m_virtScene.UnSubscribeToClientScriptEvents(client); - - IGodsModule virtGodsModule = m_virtScene.RequestModuleInterface(); - if (virtGodsModule != null) - ((GodsModule)virtGodsModule).UnsubscribeFromClientEvents(client); - - m_virtScene.UnSubscribeToClientNetworkEvents(client); - - m_rootScene.SubscribeToClientPrimEvents(client); - client.OnAddPrim += LocalAddNewPrim; - client.OnRezObject += LocalRezObject; - - m_rootScene.SubscribeToClientInventoryEvents(client); - ((AttachmentsModule)m_rootScene.AttachmentsModule).SubscribeToClientEvents(client); - //m_rootScene.SubscribeToClientTeleportEvents(client); - m_rootScene.SubscribeToClientScriptEvents(client); - - IGodsModule rootGodsModule = m_virtScene.RequestModuleInterface(); - if (rootGodsModule != null) - ((GodsModule)rootGodsModule).UnsubscribeFromClientEvents(client); - - m_rootScene.SubscribeToClientNetworkEvents(client); - } - - public void ClientClosed(UUID clientid, Scene scene) - { - } - - /// - /// Fixes position based on the region the Rez event came in on - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - private void LocalRezObject(IClientAPI remoteclient, UUID itemid, Vector3 rayend, Vector3 raystart, - UUID raytargetid, byte bypassraycast, bool rayendisintersection, bool rezselected, bool removeitem, - UUID fromtaskid) - { - int differenceX = (int)m_virtScene.RegionInfo.RegionLocX - (int)m_rootScene.RegionInfo.RegionLocX; - int differenceY = (int)m_virtScene.RegionInfo.RegionLocY - (int)m_rootScene.RegionInfo.RegionLocY; - rayend.X += differenceX * (int)Constants.RegionSize; - rayend.Y += differenceY * (int)Constants.RegionSize; - raystart.X += differenceX * (int)Constants.RegionSize; - raystart.Y += differenceY * (int)Constants.RegionSize; - - m_rootScene.RezObject(remoteclient, itemid, rayend, raystart, raytargetid, bypassraycast, - rayendisintersection, rezselected, removeitem, fromtaskid); - } - /// - /// Fixes position based on the region the AddPrimShape event came in on - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - private void LocalAddNewPrim(UUID ownerid, UUID groupid, Vector3 rayend, Quaternion rot, - PrimitiveBaseShape shape, byte bypassraycast, Vector3 raystart, UUID raytargetid, - byte rayendisintersection) - { - int differenceX = (int)m_virtScene.RegionInfo.RegionLocX - (int)m_rootScene.RegionInfo.RegionLocX; - int differenceY = (int)m_virtScene.RegionInfo.RegionLocY - (int)m_rootScene.RegionInfo.RegionLocY; - rayend.X += differenceX * (int)Constants.RegionSize; - rayend.Y += differenceY * (int)Constants.RegionSize; - raystart.X += differenceX * (int)Constants.RegionSize; - raystart.Y += differenceY * (int)Constants.RegionSize; - m_rootScene.AddNewPrim(ownerid, groupid, rayend, rot, shape, bypassraycast, raystart, raytargetid, - rayendisintersection); - } - } -} \ No newline at end of file diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs deleted file mode 100644 index a133e51..0000000 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.CoreModules.World.Land; - -namespace OpenSim.Region.RegionCombinerModule -{ -public class RegionCombinerLargeLandChannel : ILandChannel - { - // private static readonly ILog m_log = - // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private RegionData RegData; - private ILandChannel RootRegionLandChannel; - private readonly List RegionConnections; - - #region ILandChannel Members - - public RegionCombinerLargeLandChannel(RegionData regData, ILandChannel rootRegionLandChannel, - List regionConnections) - { - RegData = regData; - RootRegionLandChannel = rootRegionLandChannel; - RegionConnections = regionConnections; - } - - public List ParcelsNearPoint(Vector3 position) - { - //m_log.DebugFormat("[LANDPARCELNEARPOINT]: {0}>", position); - return RootRegionLandChannel.ParcelsNearPoint(position - RegData.Offset); - } - - public List AllParcels() - { - return RootRegionLandChannel.AllParcels(); - } - - public void Clear(bool setupDefaultParcel) - { - RootRegionLandChannel.Clear(setupDefaultParcel); - } - - public ILandObject GetLandObject(int x, int y) - { - //m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y); - - if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) - { - return RootRegionLandChannel.GetLandObject(x, y); - } - else - { - int offsetX = (x / (int)Constants.RegionSize); - int offsetY = (y / (int)Constants.RegionSize); - offsetX *= (int)Constants.RegionSize; - offsetY *= (int)Constants.RegionSize; - - foreach (RegionData regionData in RegionConnections) - { - if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) - { - return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); - } - } - ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); - obj.LandData.Name = "NO LAND"; - return obj; - } - } - - public ILandObject GetLandObject(int localID) - { - return RootRegionLandChannel.GetLandObject(localID); - } - - public ILandObject GetLandObject(float x, float y) - { - //m_log.DebugFormat("[BIGLANDTESTFLOAT]: <{0},{1}>", x, y); - - if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) - { - return RootRegionLandChannel.GetLandObject(x, y); - } - else - { - int offsetX = (int)(x/(int) Constants.RegionSize); - int offsetY = (int)(y/(int) Constants.RegionSize); - offsetX *= (int) Constants.RegionSize; - offsetY *= (int) Constants.RegionSize; - - foreach (RegionData regionData in RegionConnections) - { - if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) - { - return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); - } - } - - ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); - obj.LandData.Name = "NO LAND"; - return obj; - } - } - - public bool IsForcefulBansAllowed() - { - return RootRegionLandChannel.IsForcefulBansAllowed(); - } - - public void UpdateLandObject(int localID, LandData data) - { - RootRegionLandChannel.UpdateLandObject(localID, data); - } - - public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) - { - RootRegionLandChannel.Join(start_x, start_y, end_x, end_y, attempting_user_id); - } - - public void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) - { - RootRegionLandChannel.Subdivide(start_x, start_y, end_x, end_y, attempting_user_id); - } - - public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient) - { - RootRegionLandChannel.ReturnObjectsInParcel(localID, returnType, agentIDs, taskIDs, remoteClient); - } - - public void setParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel) - { - RootRegionLandChannel.setParcelObjectMaxOverride(overrideDel); - } - - public void setSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel) - { - RootRegionLandChannel.setSimulatorObjectMaxOverride(overrideDel); - } - - public void SetParcelOtherCleanTime(IClientAPI remoteClient, int localID, int otherCleanTime) - { - RootRegionLandChannel.SetParcelOtherCleanTime(remoteClient, localID, otherCleanTime); - } - - #endregion - } -} \ No newline at end of file diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs deleted file mode 100644 index 905540d..0000000 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs +++ /dev/null @@ -1,1076 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using log4net; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Client; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Framework.Console; -using OpenSim.Region.Physics.Manager; -using Mono.Addins; - -namespace OpenSim.Region.RegionCombinerModule -{ - public class RegionCombinerModule : ISharedRegionModule, IRegionCombinerModule - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - public string Name - { - get { return "RegionCombinerModule"; } - } - - public Type ReplaceableInterface - { - get { return null; } - } - - /// - /// Is this module enabled? - /// - private bool m_combineContiguousRegions = false; - - /// - /// This holds the root regions for the megaregions. - /// - /// - /// Usually there is only ever one megaregion (and hence only one entry here). - /// - private Dictionary m_regions = new Dictionary(); - - /// - /// The scenes that comprise the megaregion. - /// - private Dictionary m_startingScenes = new Dictionary(); - - public void Initialise(IConfigSource source) - { - IConfig myConfig = source.Configs["Startup"]; - m_combineContiguousRegions = myConfig.GetBoolean("CombineContiguousRegions", false); - - MainConsole.Instance.Commands.AddCommand( - "RegionCombinerModule", false, "fix-phantoms", "fix-phantoms", - "Fixes phantom objects after an import to a megaregion or a change from a megaregion back to normal regions", - FixPhantoms); - } - - public void Close() - { - } - - public void AddRegion(Scene scene) - { - if (m_combineContiguousRegions) - scene.RegisterModuleInterface(this); - } - - public void RemoveRegion(Scene scene) - { - lock (m_startingScenes) - m_startingScenes.Remove(scene.RegionInfo.originRegionID); - } - - public void RegionLoaded(Scene scene) - { - lock (m_startingScenes) - m_startingScenes.Add(scene.RegionInfo.originRegionID, scene); - - if (m_combineContiguousRegions) - { - RegionLoadedDoWork(scene); - - scene.EventManager.OnNewPresence += NewPresence; - } - } - - public bool IsRootForMegaregion(UUID regionId) - { - lock (m_regions) - return m_regions.ContainsKey(regionId); - } - - public Vector2 GetSizeOfMegaregion(UUID regionId) - { - lock (m_regions) - { - if (m_regions.ContainsKey(regionId)) - { - RegionConnections rootConn = m_regions[regionId]; - - return new Vector2((float)rootConn.XEnd, (float)rootConn.YEnd); - } - } - - throw new Exception(string.Format("Region with id {0} not found", regionId)); - } - - private void NewPresence(ScenePresence presence) - { - if (presence.IsChildAgent) - { - byte[] throttleData; - - try - { - throttleData = presence.ControllingClient.GetThrottlesPacked(1); - } - catch (NotImplementedException) - { - return; - } - - if (throttleData == null) - return; - - if (throttleData.Length == 0) - return; - - if (throttleData.Length != 28) - return; - - byte[] adjData; - int pos = 0; - - if (!BitConverter.IsLittleEndian) - { - byte[] newData = new byte[7 * 4]; - Buffer.BlockCopy(throttleData, 0, newData, 0, 7 * 4); - - for (int i = 0; i < 7; i++) - Array.Reverse(newData, i * 4, 4); - - adjData = newData; - } - else - { - adjData = throttleData; - } - - // 0.125f converts from bits to bytes - int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; - int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; - int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; - int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; - int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; - int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; - int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); - // State is a subcategory of task that we allocate a percentage to - - - //int total = resend + land + wind + cloud + task + texture + asset; - - byte[] data = new byte[7 * 4]; - int ii = 0; - - Buffer.BlockCopy(Utils.FloatToBytes(resend), 0, data, ii, 4); ii += 4; - Buffer.BlockCopy(Utils.FloatToBytes(land * 50), 0, data, ii, 4); ii += 4; - Buffer.BlockCopy(Utils.FloatToBytes(wind), 0, data, ii, 4); ii += 4; - Buffer.BlockCopy(Utils.FloatToBytes(cloud), 0, data, ii, 4); ii += 4; - Buffer.BlockCopy(Utils.FloatToBytes(task), 0, data, ii, 4); ii += 4; - Buffer.BlockCopy(Utils.FloatToBytes(texture), 0, data, ii, 4); ii += 4; - Buffer.BlockCopy(Utils.FloatToBytes(asset), 0, data, ii, 4); - - try - { - presence.ControllingClient.SetChildAgentThrottle(data); - } - catch (NotImplementedException) - { - return; - } - } - } - - private void RegionLoadedDoWork(Scene scene) - { -/* - // For testing on a single instance - if (scene.RegionInfo.RegionLocX == 1004 && scene.RegionInfo.RegionLocY == 1000) - return; - // -*/ - - // Give each region a standard set of non-infinite borders - Border northBorder = new Border(); - northBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, (int)Constants.RegionSize); //<--- - northBorder.CrossDirection = Cardinals.N; - scene.NorthBorders[0] = northBorder; - - Border southBorder = new Border(); - southBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, 0); //---> - southBorder.CrossDirection = Cardinals.S; - scene.SouthBorders[0] = southBorder; - - Border eastBorder = new Border(); - eastBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, (int)Constants.RegionSize); //<--- - eastBorder.CrossDirection = Cardinals.E; - scene.EastBorders[0] = eastBorder; - - Border westBorder = new Border(); - westBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, 0); //---> - westBorder.CrossDirection = Cardinals.W; - scene.WestBorders[0] = westBorder; - - RegionConnections newConn = new RegionConnections(); - newConn.ConnectedRegions = new List(); - newConn.RegionScene = scene; - newConn.RegionLandChannel = scene.LandChannel; - newConn.RegionId = scene.RegionInfo.originRegionID; - newConn.X = scene.RegionInfo.RegionLocX; - newConn.Y = scene.RegionInfo.RegionLocY; - newConn.XEnd = (int)Constants.RegionSize; - newConn.YEnd = (int)Constants.RegionSize; - - lock (m_regions) - { - bool connectedYN = false; - - foreach (RegionConnections rootConn in m_regions.Values) - { - #region commented - /* - // If we're one region over +x +y - //xxy - //xxx - //xxx - if ((((int)conn.X * (int)Constants.RegionSize) + conn.XEnd - == (regionConnections.X * (int)Constants.RegionSize)) - && (((int)conn.Y * (int)Constants.RegionSize) - conn.YEnd - == (regionConnections.Y * (int)Constants.RegionSize))) - { - Vector3 offset = Vector3.Zero; - offset.X = (((regionConnections.X * (int) Constants.RegionSize)) - - ((conn.X * (int) Constants.RegionSize))); - offset.Y = (((regionConnections.Y * (int) Constants.RegionSize)) - - ((conn.Y * (int) Constants.RegionSize))); - - Vector3 extents = Vector3.Zero; - extents.Y = regionConnections.YEnd + conn.YEnd; - extents.X = conn.XEnd + conn.XEnd; - - m_log.DebugFormat("Scene: {0} to the northwest of Scene{1}. Offset: {2}. Extents:{3}", - conn.RegionScene.RegionInfo.RegionName, - regionConnections.RegionScene.RegionInfo.RegionName, - offset, extents); - - scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents); - - connectedYN = true; - break; - } - */ - - /* - //If we're one region over x +y - //xxx - //xxx - //xyx - if ((((int)conn.X * (int)Constants.RegionSize) - == (regionConnections.X * (int)Constants.RegionSize)) - && (((int)conn.Y * (int)Constants.RegionSize) - conn.YEnd - == (regionConnections.Y * (int)Constants.RegionSize))) - { - Vector3 offset = Vector3.Zero; - offset.X = (((regionConnections.X * (int)Constants.RegionSize)) - - ((conn.X * (int)Constants.RegionSize))); - offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) - - ((conn.Y * (int)Constants.RegionSize))); - - Vector3 extents = Vector3.Zero; - extents.Y = regionConnections.YEnd + conn.YEnd; - extents.X = conn.XEnd; - - m_log.DebugFormat("Scene: {0} to the north of Scene{1}. Offset: {2}. Extents:{3}", - conn.RegionScene.RegionInfo.RegionName, - regionConnections.RegionScene.RegionInfo.RegionName, offset, extents); - - scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents); - connectedYN = true; - break; - } - */ - - /* - // If we're one region over -x +y - //xxx - //xxx - //yxx - if ((((int)conn.X * (int)Constants.RegionSize) - conn.XEnd - == (regionConnections.X * (int)Constants.RegionSize)) - && (((int)conn.Y * (int)Constants.RegionSize) - conn.YEnd - == (regionConnections.Y * (int)Constants.RegionSize))) - { - Vector3 offset = Vector3.Zero; - offset.X = (((regionConnections.X * (int)Constants.RegionSize)) - - ((conn.X * (int)Constants.RegionSize))); - offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) - - ((conn.Y * (int)Constants.RegionSize))); - - Vector3 extents = Vector3.Zero; - extents.Y = regionConnections.YEnd + conn.YEnd; - extents.X = conn.XEnd + conn.XEnd; - - m_log.DebugFormat("Scene: {0} to the northeast of Scene. Offset: {2}. Extents:{3}", - conn.RegionScene.RegionInfo.RegionName, - regionConnections.RegionScene.RegionInfo.RegionName, offset, extents); - - scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents); - - - connectedYN = true; - break; - } - */ - - /* - // If we're one region over -x y - //xxx - //yxx - //xxx - if ((((int)conn.X * (int)Constants.RegionSize) - conn.XEnd - == (regionConnections.X * (int)Constants.RegionSize)) - && (((int)conn.Y * (int)Constants.RegionSize) - == (regionConnections.Y * (int)Constants.RegionSize))) - { - Vector3 offset = Vector3.Zero; - offset.X = (((regionConnections.X * (int)Constants.RegionSize)) - - ((conn.X * (int)Constants.RegionSize))); - offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) - - ((conn.Y * (int)Constants.RegionSize))); - - Vector3 extents = Vector3.Zero; - extents.Y = regionConnections.YEnd; - extents.X = conn.XEnd + conn.XEnd; - - m_log.DebugFormat("Scene: {0} to the east of Scene{1} Offset: {2}. Extents:{3}", - conn.RegionScene.RegionInfo.RegionName, - regionConnections.RegionScene.RegionInfo.RegionName, offset, extents); - - scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents); - - connectedYN = true; - break; - } - */ - - /* - // If we're one region over -x -y - //yxx - //xxx - //xxx - if ((((int)conn.X * (int)Constants.RegionSize) - conn.XEnd - == (regionConnections.X * (int)Constants.RegionSize)) - && (((int)conn.Y * (int)Constants.RegionSize) + conn.YEnd - == (regionConnections.Y * (int)Constants.RegionSize))) - { - Vector3 offset = Vector3.Zero; - offset.X = (((regionConnections.X * (int)Constants.RegionSize)) - - ((conn.X * (int)Constants.RegionSize))); - offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) - - ((conn.Y * (int)Constants.RegionSize))); - - Vector3 extents = Vector3.Zero; - extents.Y = regionConnections.YEnd + conn.YEnd; - extents.X = conn.XEnd + conn.XEnd; - - m_log.DebugFormat("Scene: {0} to the northeast of Scene{1} Offset: {2}. Extents:{3}", - conn.RegionScene.RegionInfo.RegionName, - regionConnections.RegionScene.RegionInfo.RegionName, offset, extents); - - scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents); - - connectedYN = true; - break; - } - */ - #endregion - - // If we're one region over +x y - //xxx - //xxy - //xxx - - if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY >= newConn.PosY) - { - connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene); - break; - } - - // If we're one region over x +y - //xyx - //xxx - //xxx - if (rootConn.PosX >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY) - { - connectedYN = DoWorkForOneRegionOverXPlusY(rootConn, newConn, scene); - break; - } - - // If we're one region over +x +y - //xxy - //xxx - //xxx - if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY) - { - connectedYN = DoWorkForOneRegionOverPlusXPlusY(rootConn, newConn, scene); - break; - - } - } - - // If !connectYN means that this region is a root region - if (!connectedYN) - { - DoWorkForRootRegion(newConn, scene); - } - } - - // Set up infinite borders around the entire AABB of the combined ConnectedRegions - AdjustLargeRegionBounds(); - } - - private bool DoWorkForOneRegionOverPlusXY(RegionConnections rootConn, RegionConnections newConn, Scene scene) - { - Vector3 offset = Vector3.Zero; - offset.X = newConn.PosX - rootConn.PosX; - offset.Y = newConn.PosY - rootConn.PosY; - - Vector3 extents = Vector3.Zero; - extents.Y = rootConn.YEnd; - extents.X = rootConn.XEnd + newConn.XEnd; - - rootConn.UpdateExtents(extents); - - m_log.DebugFormat( - "[REGION COMBINER MODULE]: Root region {0} is to the west of region {1}, Offset: {2}, Extents: {3}", - rootConn.RegionScene.RegionInfo.RegionName, - newConn.RegionScene.RegionInfo.RegionName, offset, extents); - - scene.BordersLocked = true; - rootConn.RegionScene.BordersLocked = true; - - RegionData ConnectedRegion = new RegionData(); - ConnectedRegion.Offset = offset; - ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; - ConnectedRegion.RegionScene = scene; - rootConn.ConnectedRegions.Add(ConnectedRegion); - - // Inform root region Physics about the extents of this region - rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); - - // Inform Child region that it needs to forward it's terrain to the root region - scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); - - // Extend the borders as appropriate - lock (rootConn.RegionScene.EastBorders) - rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize; - - lock (rootConn.RegionScene.NorthBorders) - rootConn.RegionScene.NorthBorders[0].BorderLine.Y += (int)Constants.RegionSize; - - lock (rootConn.RegionScene.SouthBorders) - rootConn.RegionScene.SouthBorders[0].BorderLine.Y += (int)Constants.RegionSize; - - lock (scene.WestBorders) - { - scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - rootConn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West - - // Trigger auto teleport to root region - scene.WestBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX; - scene.WestBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY; - } - - // Reset Terrain.. since terrain loads before we get here, we need to load - // it again so it loads in the root region - - scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); - - // Unlock borders - rootConn.RegionScene.BordersLocked = false; - scene.BordersLocked = false; - - // Create a client event forwarder and add this region's events to the root region. - if (rootConn.ClientEventForwarder != null) - rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); - - return true; - } - - private bool DoWorkForOneRegionOverXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene) - { - Vector3 offset = Vector3.Zero; - offset.X = newConn.PosX - rootConn.PosX; - offset.Y = newConn.PosY - rootConn.PosY; - - Vector3 extents = Vector3.Zero; - extents.Y = newConn.YEnd + rootConn.YEnd; - extents.X = rootConn.XEnd; - rootConn.UpdateExtents(extents); - - scene.BordersLocked = true; - rootConn.RegionScene.BordersLocked = true; - - RegionData ConnectedRegion = new RegionData(); - ConnectedRegion.Offset = offset; - ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; - ConnectedRegion.RegionScene = scene; - rootConn.ConnectedRegions.Add(ConnectedRegion); - - m_log.DebugFormat( - "[REGION COMBINER MODULE]: Root region {0} is to the south of region {1}, Offset: {2}, Extents: {3}", - rootConn.RegionScene.RegionInfo.RegionName, - newConn.RegionScene.RegionInfo.RegionName, offset, extents); - - rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); - scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); - - lock (rootConn.RegionScene.NorthBorders) - rootConn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize; - - lock (rootConn.RegionScene.EastBorders) - rootConn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize; - - lock (rootConn.RegionScene.WestBorders) - rootConn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize; - - lock (scene.SouthBorders) - { - scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - rootConn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south - scene.SouthBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX; - scene.SouthBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY; - } - - // Reset Terrain.. since terrain normally loads first. - //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); - scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); - //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); - - scene.BordersLocked = false; - rootConn.RegionScene.BordersLocked = false; - - if (rootConn.ClientEventForwarder != null) - rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); - - return true; - } - - private bool DoWorkForOneRegionOverPlusXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene) - { - Vector3 offset = Vector3.Zero; - offset.X = newConn.PosX - rootConn.PosX; - offset.Y = newConn.PosY - rootConn.PosY; - - Vector3 extents = Vector3.Zero; - - // We do not want to inflate the extents for regions strictly to the NE of the root region, since this - // would double count regions strictly to the north and east that have already been added. -// extents.Y = regionConnections.YEnd + conn.YEnd; -// extents.X = regionConnections.XEnd + conn.XEnd; -// conn.UpdateExtents(extents); - - extents.Y = rootConn.YEnd; - extents.X = rootConn.XEnd; - - scene.BordersLocked = true; - rootConn.RegionScene.BordersLocked = true; - - RegionData ConnectedRegion = new RegionData(); - ConnectedRegion.Offset = offset; - ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; - ConnectedRegion.RegionScene = scene; - - rootConn.ConnectedRegions.Add(ConnectedRegion); - - m_log.DebugFormat( - "[REGION COMBINER MODULE]: Region {0} is to the southwest of Scene {1}, Offset: {2}, Extents: {3}", - rootConn.RegionScene.RegionInfo.RegionName, - newConn.RegionScene.RegionInfo.RegionName, offset, extents); - - rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); - scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); - - lock (rootConn.RegionScene.NorthBorders) - { - if (rootConn.RegionScene.NorthBorders.Count == 1)// && 2) - { - //compound border - // already locked above - rootConn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize; - - lock (rootConn.RegionScene.EastBorders) - rootConn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize; - - lock (rootConn.RegionScene.WestBorders) - rootConn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize; - } - } - - lock (scene.SouthBorders) - { - scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - rootConn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south - scene.SouthBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX; - scene.SouthBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY; - } - - lock (rootConn.RegionScene.EastBorders) - { - if (rootConn.RegionScene.EastBorders.Count == 1)// && conn.RegionScene.EastBorders.Count == 2) - { - - rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize; - - lock (rootConn.RegionScene.NorthBorders) - rootConn.RegionScene.NorthBorders[0].BorderLine.Y += (int)Constants.RegionSize; - - lock (rootConn.RegionScene.SouthBorders) - rootConn.RegionScene.SouthBorders[0].BorderLine.Y += (int)Constants.RegionSize; - } - } - - lock (scene.WestBorders) - { - scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - rootConn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West - scene.WestBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX; - scene.WestBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY; - } - - /* - else - { - conn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize; - conn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize; - conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize; - scene.SouthBorders[0].BorderLine.Z += (int)Constants.RegionSize; //auto teleport south - } - */ - - - // Reset Terrain.. since terrain normally loads first. - //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); - scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); - //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); - scene.BordersLocked = false; - rootConn.RegionScene.BordersLocked = false; - - if (rootConn.ClientEventForwarder != null) - rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); - - return true; - - //scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset,extents); - } - - private void DoWorkForRootRegion(RegionConnections rootConn, Scene scene) - { - m_log.DebugFormat("[REGION COMBINER MODULE]: Adding root region {0}", scene.RegionInfo.RegionName); - - RegionData rdata = new RegionData(); - rdata.Offset = Vector3.Zero; - rdata.RegionId = scene.RegionInfo.originRegionID; - rdata.RegionScene = scene; - // save it's land channel - rootConn.RegionLandChannel = scene.LandChannel; - - // Substitue our landchannel - RegionCombinerLargeLandChannel lnd = new RegionCombinerLargeLandChannel(rdata, scene.LandChannel, - rootConn.ConnectedRegions); - - scene.LandChannel = lnd; - - // Forward the permissions modules of each of the connected regions to the root region - lock (m_regions) - { - foreach (RegionData r in rootConn.ConnectedRegions) - { - ForwardPermissionRequests(rootConn, r.RegionScene); - } - - // Create the root region's Client Event Forwarder - rootConn.ClientEventForwarder = new RegionCombinerClientEventForwarder(rootConn); - - // Sets up the CoarseLocationUpdate forwarder for this root region - scene.EventManager.OnNewPresence += SetCoarseLocationDelegate; - - // Adds this root region to a dictionary of regions that are connectable - m_regions.Add(scene.RegionInfo.originRegionID, rootConn); - } - } - - private void SetCoarseLocationDelegate(ScenePresence presence) - { - presence.SetSendCoarseLocationMethod(SendCoarseLocationUpdates); - } - - // This delegate was refactored for non-combined regions. - // This combined region version will not use the pre-compiled lists of locations and ids - private void SendCoarseLocationUpdates(UUID sceneId, ScenePresence presence, List coarseLocations, List avatarUUIDs) - { - RegionConnections connectiondata = null; - lock (m_regions) - { - if (m_regions.ContainsKey(sceneId)) - connectiondata = m_regions[sceneId]; - else - return; - } - - List CoarseLocations = new List(); - List AvatarUUIDs = new List(); - - connectiondata.RegionScene.ForEachRootScenePresence(delegate(ScenePresence sp) - { - if (sp.UUID != presence.UUID) - { - CoarseLocations.Add(sp.AbsolutePosition); - AvatarUUIDs.Add(sp.UUID); - } - }); - - DistributeCoarseLocationUpdates(CoarseLocations, AvatarUUIDs, connectiondata, presence); - } - - private void DistributeCoarseLocationUpdates(List locations, List uuids, - RegionConnections connectiondata, ScenePresence rootPresence) - { - RegionData[] rdata = connectiondata.ConnectedRegions.ToArray(); - //List clients = new List(); - Dictionary updates = new Dictionary(); - - // Root Region entry - RegionCoarseLocationStruct rootupdatedata = new RegionCoarseLocationStruct(); - rootupdatedata.Locations = new List(); - rootupdatedata.Uuids = new List(); - rootupdatedata.Offset = Vector2.Zero; - - rootupdatedata.UserAPI = rootPresence.ControllingClient; - - if (rootupdatedata.UserAPI != null) - updates.Add(Vector2.Zero, rootupdatedata); - - //Each Region needs an entry or we will end up with dead minimap dots - foreach (RegionData regiondata in rdata) - { - Vector2 offset = new Vector2(regiondata.Offset.X, regiondata.Offset.Y); - RegionCoarseLocationStruct updatedata = new RegionCoarseLocationStruct(); - updatedata.Locations = new List(); - updatedata.Uuids = new List(); - updatedata.Offset = offset; - - if (offset == Vector2.Zero) - updatedata.UserAPI = rootPresence.ControllingClient; - else - updatedata.UserAPI = LocateUsersChildAgentIClientAPI(offset, rootPresence.UUID, rdata); - - if (updatedata.UserAPI != null) - updates.Add(offset, updatedata); - } - - // go over the locations and assign them to an IClientAPI - for (int i = 0; i < locations.Count; i++) - //{locations[i]/(int) Constants.RegionSize; - { - Vector3 pPosition = new Vector3((int)locations[i].X / (int)Constants.RegionSize, - (int)locations[i].Y / (int)Constants.RegionSize, locations[i].Z); - Vector2 offset = new Vector2(pPosition.X*(int) Constants.RegionSize, - pPosition.Y*(int) Constants.RegionSize); - - if (!updates.ContainsKey(offset)) - { - // This shouldn't happen - RegionCoarseLocationStruct updatedata = new RegionCoarseLocationStruct(); - updatedata.Locations = new List(); - updatedata.Uuids = new List(); - updatedata.Offset = offset; - - if (offset == Vector2.Zero) - updatedata.UserAPI = rootPresence.ControllingClient; - else - updatedata.UserAPI = LocateUsersChildAgentIClientAPI(offset, rootPresence.UUID, rdata); - - updates.Add(offset,updatedata); - } - - updates[offset].Locations.Add(locations[i]); - updates[offset].Uuids.Add(uuids[i]); - } - - // Send out the CoarseLocationupdates from their respective client connection based on where the avatar is - foreach (Vector2 offset in updates.Keys) - { - if (updates[offset].UserAPI != null) - { - updates[offset].UserAPI.SendCoarseLocationUpdate(updates[offset].Uuids,updates[offset].Locations); - } - } - } - - /// - /// Locates a the Client of a particular region in an Array of RegionData based on offset - /// - /// - /// - /// - /// IClientAPI or null - private IClientAPI LocateUsersChildAgentIClientAPI(Vector2 offset, UUID uUID, RegionData[] rdata) - { - IClientAPI returnclient = null; - foreach (RegionData r in rdata) - { - if (r.Offset.X == offset.X && r.Offset.Y == offset.Y) - { - return r.RegionScene.SceneGraph.GetControllingClient(uUID); - } - } - - return returnclient; - } - - public void PostInitialise() - { - } - -// /// -// /// TODO: -// /// -// /// -// public void UnCombineRegion(RegionData rdata) -// { -// lock (m_regions) -// { -// if (m_regions.ContainsKey(rdata.RegionId)) -// { -// // uncombine root region and virtual regions -// } -// else -// { -// foreach (RegionConnections r in m_regions.Values) -// { -// foreach (RegionData rd in r.ConnectedRegions) -// { -// if (rd.RegionId == rdata.RegionId) -// { -// // uncombine virtual region -// } -// } -// } -// } -// } -// } - - // Create a set of infinite borders around the whole aabb of the combined island. - private void AdjustLargeRegionBounds() - { - lock (m_regions) - { - foreach (RegionConnections rconn in m_regions.Values) - { - Vector3 offset = Vector3.Zero; - rconn.RegionScene.BordersLocked = true; - foreach (RegionData rdata in rconn.ConnectedRegions) - { - if (rdata.Offset.X > offset.X) offset.X = rdata.Offset.X; - if (rdata.Offset.Y > offset.Y) offset.Y = rdata.Offset.Y; - } - - lock (rconn.RegionScene.NorthBorders) - { - Border northBorder = null; - // If we don't already have an infinite border, create one. - if (!TryGetInfiniteBorder(rconn.RegionScene.NorthBorders, out northBorder)) - { - northBorder = new Border(); - rconn.RegionScene.NorthBorders.Add(northBorder); - } - - northBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, - offset.Y + (int) Constants.RegionSize); //<--- - northBorder.CrossDirection = Cardinals.N; - } - - lock (rconn.RegionScene.SouthBorders) - { - Border southBorder = null; - // If we don't already have an infinite border, create one. - if (!TryGetInfiniteBorder(rconn.RegionScene.SouthBorders, out southBorder)) - { - southBorder = new Border(); - rconn.RegionScene.SouthBorders.Add(southBorder); - } - southBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, 0); //---> - southBorder.CrossDirection = Cardinals.S; - } - - lock (rconn.RegionScene.EastBorders) - { - Border eastBorder = null; - // If we don't already have an infinite border, create one. - if (!TryGetInfiniteBorder(rconn.RegionScene.EastBorders, out eastBorder)) - { - eastBorder = new Border(); - rconn.RegionScene.EastBorders.Add(eastBorder); - } - eastBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, offset.X + (int)Constants.RegionSize); - //<--- - eastBorder.CrossDirection = Cardinals.E; - } - - lock (rconn.RegionScene.WestBorders) - { - Border westBorder = null; - // If we don't already have an infinite border, create one. - if (!TryGetInfiniteBorder(rconn.RegionScene.WestBorders, out westBorder)) - { - westBorder = new Border(); - rconn.RegionScene.WestBorders.Add(westBorder); - - } - westBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, 0); //---> - westBorder.CrossDirection = Cardinals.W; - } - - rconn.RegionScene.BordersLocked = false; - } - } - } - - /// - /// Try and get an Infinite border out of a listT of borders - /// - /// - /// - /// - public static bool TryGetInfiniteBorder(List borders, out Border oborder) - { - // Warning! Should be locked before getting here! - foreach (Border b in borders) - { - if (b.BorderLine.X == float.MinValue && b.BorderLine.Y == float.MaxValue) - { - oborder = b; - return true; - } - } - - oborder = null; - return false; - } - - public RegionData GetRegionFromPosition(Vector3 pPosition) - { - pPosition = pPosition/(int) Constants.RegionSize; - int OffsetX = (int) pPosition.X; - int OffsetY = (int) pPosition.Y; - - lock (m_regions) - { - foreach (RegionConnections regConn in m_regions.Values) - { - foreach (RegionData reg in regConn.ConnectedRegions) - { - if (reg.Offset.X == OffsetX && reg.Offset.Y == OffsetY) - return reg; - } - } - } - - return new RegionData(); - } - - public void ForwardPermissionRequests(RegionConnections BigRegion, Scene VirtualRegion) - { - if (BigRegion.PermissionModule == null) - BigRegion.PermissionModule = new RegionCombinerPermissionModule(BigRegion.RegionScene); - - VirtualRegion.Permissions.OnBypassPermissions += BigRegion.PermissionModule.BypassPermissions; - VirtualRegion.Permissions.OnSetBypassPermissions += BigRegion.PermissionModule.SetBypassPermissions; - VirtualRegion.Permissions.OnPropagatePermissions += BigRegion.PermissionModule.PropagatePermissions; - VirtualRegion.Permissions.OnGenerateClientFlags += BigRegion.PermissionModule.GenerateClientFlags; - VirtualRegion.Permissions.OnAbandonParcel += BigRegion.PermissionModule.CanAbandonParcel; - VirtualRegion.Permissions.OnReclaimParcel += BigRegion.PermissionModule.CanReclaimParcel; - VirtualRegion.Permissions.OnDeedParcel += BigRegion.PermissionModule.CanDeedParcel; - VirtualRegion.Permissions.OnDeedObject += BigRegion.PermissionModule.CanDeedObject; - VirtualRegion.Permissions.OnIsGod += BigRegion.PermissionModule.IsGod; - VirtualRegion.Permissions.OnDuplicateObject += BigRegion.PermissionModule.CanDuplicateObject; - VirtualRegion.Permissions.OnDeleteObject += BigRegion.PermissionModule.CanDeleteObject; //MAYBE FULLY IMPLEMENTED - VirtualRegion.Permissions.OnEditObject += BigRegion.PermissionModule.CanEditObject; //MAYBE FULLY IMPLEMENTED - VirtualRegion.Permissions.OnEditParcelProperties += BigRegion.PermissionModule.CanEditParcelProperties; //MAYBE FULLY IMPLEMENTED - VirtualRegion.Permissions.OnInstantMessage += BigRegion.PermissionModule.CanInstantMessage; - VirtualRegion.Permissions.OnInventoryTransfer += BigRegion.PermissionModule.CanInventoryTransfer; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnIssueEstateCommand += BigRegion.PermissionModule.CanIssueEstateCommand; //FULLY IMPLEMENTED - VirtualRegion.Permissions.OnMoveObject += BigRegion.PermissionModule.CanMoveObject; //MAYBE FULLY IMPLEMENTED - VirtualRegion.Permissions.OnObjectEntry += BigRegion.PermissionModule.CanObjectEntry; - VirtualRegion.Permissions.OnReturnObjects += BigRegion.PermissionModule.CanReturnObjects; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnRezObject += BigRegion.PermissionModule.CanRezObject; //MAYBE FULLY IMPLEMENTED - VirtualRegion.Permissions.OnRunConsoleCommand += BigRegion.PermissionModule.CanRunConsoleCommand; - VirtualRegion.Permissions.OnRunScript += BigRegion.PermissionModule.CanRunScript; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnCompileScript += BigRegion.PermissionModule.CanCompileScript; - VirtualRegion.Permissions.OnSellParcel += BigRegion.PermissionModule.CanSellParcel; - VirtualRegion.Permissions.OnTakeObject += BigRegion.PermissionModule.CanTakeObject; - VirtualRegion.Permissions.OnTakeCopyObject += BigRegion.PermissionModule.CanTakeCopyObject; - VirtualRegion.Permissions.OnTerraformLand += BigRegion.PermissionModule.CanTerraformLand; - VirtualRegion.Permissions.OnLinkObject += BigRegion.PermissionModule.CanLinkObject; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnDelinkObject += BigRegion.PermissionModule.CanDelinkObject; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnBuyLand += BigRegion.PermissionModule.CanBuyLand; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnViewNotecard += BigRegion.PermissionModule.CanViewNotecard; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnViewScript += BigRegion.PermissionModule.CanViewScript; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnEditNotecard += BigRegion.PermissionModule.CanEditNotecard; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnEditScript += BigRegion.PermissionModule.CanEditScript; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnCreateObjectInventory += BigRegion.PermissionModule.CanCreateObjectInventory; //NOT IMPLEMENTED HERE - VirtualRegion.Permissions.OnEditObjectInventory += BigRegion.PermissionModule.CanEditObjectInventory;//MAYBE FULLY IMPLEMENTED - VirtualRegion.Permissions.OnCopyObjectInventory += BigRegion.PermissionModule.CanCopyObjectInventory; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnDeleteObjectInventory += BigRegion.PermissionModule.CanDeleteObjectInventory; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnResetScript += BigRegion.PermissionModule.CanResetScript; - VirtualRegion.Permissions.OnCreateUserInventory += BigRegion.PermissionModule.CanCreateUserInventory; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnCopyUserInventory += BigRegion.PermissionModule.CanCopyUserInventory; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnEditUserInventory += BigRegion.PermissionModule.CanEditUserInventory; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnDeleteUserInventory += BigRegion.PermissionModule.CanDeleteUserInventory; //NOT YET IMPLEMENTED - VirtualRegion.Permissions.OnTeleport += BigRegion.PermissionModule.CanTeleport; //NOT YET IMPLEMENTED - } - - #region console commands - - public void FixPhantoms(string module, string[] cmdparams) - { - List scenes = new List(m_startingScenes.Values); - - foreach (Scene s in scenes) - { - MainConsole.Instance.OutputFormat("Fixing phantoms for {0}", s.RegionInfo.RegionName); - - s.ForEachSOG(so => so.AbsolutePosition = so.AbsolutePosition); - } - } - - #endregion - } -} diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerPermissionModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerPermissionModule.cs deleted file mode 100644 index 7c662c9..0000000 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerPermissionModule.cs +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.RegionCombinerModule -{ - public class RegionCombinerPermissionModule - { - private Scene m_rootScene; - - public RegionCombinerPermissionModule(Scene RootScene) - { - m_rootScene = RootScene; - } - - #region Permission Override - - public bool BypassPermissions() - { - return m_rootScene.Permissions.BypassPermissions(); - } - - public void SetBypassPermissions(bool value) - { - m_rootScene.Permissions.SetBypassPermissions(value); - } - - public bool PropagatePermissions() - { - return m_rootScene.Permissions.PropagatePermissions(); - } - - public uint GenerateClientFlags(UUID userid, UUID objectidid) - { - return m_rootScene.Permissions.GenerateClientFlags(userid,objectidid); - } - - public bool CanAbandonParcel(UUID user, ILandObject parcel, Scene scene) - { - return m_rootScene.Permissions.CanAbandonParcel(user,parcel); - } - - public bool CanReclaimParcel(UUID user, ILandObject parcel, Scene scene) - { - return m_rootScene.Permissions.CanReclaimParcel(user, parcel); - } - - public bool CanDeedParcel(UUID user, ILandObject parcel, Scene scene) - { - return m_rootScene.Permissions.CanDeedParcel(user, parcel); - } - - public bool CanDeedObject(UUID user, UUID @group, Scene scene) - { - return m_rootScene.Permissions.CanDeedObject(user,@group); - } - - public bool IsGod(UUID user, Scene requestfromscene) - { - return m_rootScene.Permissions.IsGod(user); - } - - public bool CanDuplicateObject(int objectcount, UUID objectid, UUID owner, Scene scene, Vector3 objectposition) - { - return m_rootScene.Permissions.CanDuplicateObject(objectcount, objectid, owner, objectposition); - } - - public bool CanDeleteObject(UUID objectid, UUID deleter, Scene scene) - { - return m_rootScene.Permissions.CanDeleteObject(objectid, deleter); - } - - public bool CanEditObject(UUID objectid, UUID editorid, Scene scene) - { - return m_rootScene.Permissions.CanEditObject(objectid, editorid); - } - - public bool CanEditParcelProperties(UUID user, ILandObject parcel, GroupPowers g, Scene scene) - { - return m_rootScene.Permissions.CanEditParcelProperties(user, parcel, g); - } - - public bool CanInstantMessage(UUID user, UUID target, Scene startscene) - { - return m_rootScene.Permissions.CanInstantMessage(user, target); - } - - public bool CanInventoryTransfer(UUID user, UUID target, Scene startscene) - { - return m_rootScene.Permissions.CanInventoryTransfer(user, target); - } - - public bool CanIssueEstateCommand(UUID user, Scene requestfromscene, bool ownercommand) - { - return m_rootScene.Permissions.CanIssueEstateCommand(user, ownercommand); - } - - public bool CanMoveObject(UUID objectid, UUID moverid, Scene scene) - { - return m_rootScene.Permissions.CanMoveObject(objectid, moverid); - } - - public bool CanObjectEntry(UUID objectid, bool enteringregion, Vector3 newpoint, Scene scene) - { - return m_rootScene.Permissions.CanObjectEntry(objectid, enteringregion, newpoint); - } - - public bool CanReturnObjects(ILandObject land, UUID user, List objects, Scene scene) - { - return m_rootScene.Permissions.CanReturnObjects(land, user, objects); - } - - public bool CanRezObject(int objectcount, UUID owner, Vector3 objectposition, Scene scene) - { - return m_rootScene.Permissions.CanRezObject(objectcount, owner, objectposition); - } - - public bool CanRunConsoleCommand(UUID user, Scene requestfromscene) - { - return m_rootScene.Permissions.CanRunConsoleCommand(user); - } - - public bool CanRunScript(UUID script, UUID objectid, UUID user, Scene scene) - { - return m_rootScene.Permissions.CanRunScript(script, objectid, user); - } - - public bool CanCompileScript(UUID owneruuid, int scripttype, Scene scene) - { - return m_rootScene.Permissions.CanCompileScript(owneruuid, scripttype); - } - - public bool CanSellParcel(UUID user, ILandObject parcel, Scene scene) - { - return m_rootScene.Permissions.CanSellParcel(user, parcel); - } - - public bool CanTakeObject(UUID objectid, UUID stealer, Scene scene) - { - return m_rootScene.Permissions.CanTakeObject(objectid, stealer); - } - - public bool CanTakeCopyObject(UUID objectid, UUID userid, Scene inscene) - { - return m_rootScene.Permissions.CanTakeObject(objectid, userid); - } - - public bool CanTerraformLand(UUID user, Vector3 position, Scene requestfromscene) - { - return m_rootScene.Permissions.CanTerraformLand(user, position); - } - - public bool CanLinkObject(UUID user, UUID objectid) - { - return m_rootScene.Permissions.CanLinkObject(user, objectid); - } - - public bool CanDelinkObject(UUID user, UUID objectid) - { - return m_rootScene.Permissions.CanDelinkObject(user, objectid); - } - - public bool CanBuyLand(UUID user, ILandObject parcel, Scene scene) - { - return m_rootScene.Permissions.CanBuyLand(user, parcel); - } - - public bool CanViewNotecard(UUID script, UUID objectid, UUID user, Scene scene) - { - return m_rootScene.Permissions.CanViewNotecard(script, objectid, user); - } - - public bool CanViewScript(UUID script, UUID objectid, UUID user, Scene scene) - { - return m_rootScene.Permissions.CanViewScript(script, objectid, user); - } - - public bool CanEditNotecard(UUID notecard, UUID objectid, UUID user, Scene scene) - { - return m_rootScene.Permissions.CanEditNotecard(notecard, objectid, user); - } - - public bool CanEditScript(UUID script, UUID objectid, UUID user, Scene scene) - { - return m_rootScene.Permissions.CanEditScript(script, objectid, user); - } - - public bool CanCreateObjectInventory(int invtype, UUID objectid, UUID userid) - { - return m_rootScene.Permissions.CanCreateObjectInventory(invtype, objectid, userid); - } - - public bool CanEditObjectInventory(UUID objectid, UUID editorid, Scene scene) - { - return m_rootScene.Permissions.CanEditObjectInventory(objectid, editorid); - } - - public bool CanCopyObjectInventory(UUID itemid, UUID objectid, UUID userid) - { - return m_rootScene.Permissions.CanCopyObjectInventory(itemid, objectid, userid); - } - - public bool CanDeleteObjectInventory(UUID itemid, UUID objectid, UUID userid) - { - return m_rootScene.Permissions.CanDeleteObjectInventory(itemid, objectid, userid); - } - - public bool CanResetScript(UUID prim, UUID script, UUID user, Scene scene) - { - return m_rootScene.Permissions.CanResetScript(prim, script, user); - } - - public bool CanCreateUserInventory(int invtype, UUID userid) - { - return m_rootScene.Permissions.CanCreateUserInventory(invtype, userid); - } - - public bool CanCopyUserInventory(UUID itemid, UUID userid) - { - return m_rootScene.Permissions.CanCopyUserInventory(itemid, userid); - } - - public bool CanEditUserInventory(UUID itemid, UUID userid) - { - return m_rootScene.Permissions.CanEditUserInventory(itemid, userid); - } - - public bool CanDeleteUserInventory(UUID itemid, UUID userid) - { - return m_rootScene.Permissions.CanDeleteUserInventory(itemid, userid); - } - - public bool CanTeleport(UUID userid, Scene scene) - { - return m_rootScene.Permissions.CanTeleport(userid); - } - - #endregion - } -} diff --git a/OpenSim/Region/RegionCombinerModule/RegionConnections.cs b/OpenSim/Region/RegionCombinerModule/RegionConnections.cs deleted file mode 100644 index fba51d2..0000000 --- a/OpenSim/Region/RegionCombinerModule/RegionConnections.cs +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.RegionCombinerModule -{ - public class RegionConnections - { - /// - /// Root Region ID - /// - public UUID RegionId; - - /// - /// Root Region Scene - /// - public Scene RegionScene; - - /// - /// LargeLandChannel for combined region - /// - public ILandChannel RegionLandChannel; - - /// - /// The x map co-ordinate for this region (where each co-ordinate is a Constants.RegionSize block). - /// - public uint X; - - /// - /// The y co-ordinate for this region (where each cor-odinate is a Constants.RegionSize block). - /// - public uint Y; - - /// - /// The X meters position of this connection. - /// - public uint PosX { get { return X * Constants.RegionSize; } } - - /// - /// The Y meters co-ordinate of this connection. - /// - public uint PosY { get { return Y * Constants.RegionSize; } } - - /// - /// The size of the megaregion in meters. - /// - public uint XEnd; - - /// - /// The size of the megaregion in meters. - /// - public uint YEnd; - - public List ConnectedRegions; - public RegionCombinerPermissionModule PermissionModule; - public RegionCombinerClientEventForwarder ClientEventForwarder; - - public void UpdateExtents(Vector3 extents) - { - XEnd = (uint)extents.X; - YEnd = (uint)extents.Y; - } - } -} \ No newline at end of file diff --git a/OpenSim/Region/RegionCombinerModule/RegionCourseLocation.cs b/OpenSim/Region/RegionCombinerModule/RegionCourseLocation.cs deleted file mode 100644 index 224ac99..0000000 --- a/OpenSim/Region/RegionCombinerModule/RegionCourseLocation.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using OpenMetaverse; -using OpenSim.Framework; - -namespace OpenSim.Region.RegionCombinerModule -{ - - struct RegionCoarseLocationStruct - { - public List Locations; - public List Uuids; - public IClientAPI UserAPI; - public Vector2 Offset; - } -} \ No newline at end of file diff --git a/OpenSim/Region/RegionCombinerModule/RegionData.cs b/OpenSim/Region/RegionCombinerModule/RegionData.cs deleted file mode 100644 index bd0e398..0000000 --- a/OpenSim/Region/RegionCombinerModule/RegionData.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using OpenMetaverse; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.RegionCombinerModule -{ - public class RegionData - { - public UUID RegionId; - public Scene RegionScene; - public Vector3 Offset; - } -} \ No newline at end of file diff --git a/OpenSim/Region/RegionCombinerModule/Resources/RegionCombinerModule.addin.xml b/OpenSim/Region/RegionCombinerModule/Resources/RegionCombinerModule.addin.xml deleted file mode 100644 index 13cb8b6..0000000 --- a/OpenSim/Region/RegionCombinerModule/Resources/RegionCombinerModule.addin.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs b/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs index e4ca635..a7fa502 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/ICompiler.cs @@ -34,7 +34,36 @@ namespace OpenSim.Region.ScriptEngine.Interfaces { public interface ICompiler { - void PerformScriptCompile(string source, string asset, UUID ownerID, out string assembly, out Dictionary, KeyValuePair> linemap); + /// + /// Performs the script compile. + /// + /// + /// + /// + /// + /// If set to true then always recompile the script, even if we have a DLL already cached. + /// + /// + /// + void PerformScriptCompile( + string source, string asset, UUID ownerID, + out string assembly, out Dictionary, KeyValuePair> linemap); + + /// + /// Performs the script compile. + /// + /// + /// + /// + /// + /// If set to true then always recompile the script, even if we have a DLL already cached. + /// + /// + /// + void PerformScriptCompile( + string source, string asset, UUID ownerID, bool alwaysRecompile, + out string assembly, out Dictionary, KeyValuePair> linemap); + string[] GetWarnings(); } } diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs index 2027ca6..b9970bf 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs @@ -26,9 +26,11 @@ */ using System; +using System.Threading; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; namespace OpenSim.Region.ScriptEngine.Interfaces { @@ -38,11 +40,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces /// Initialize the API /// /// - /// Each API has an identifier, which is used to load the - /// proper runtime assembly at load time. - /// /param> - /// - /// - void Initialize(IScriptEngine engine, SceneObjectPart part, TaskInventoryItem item); + /// Each API has an identifier, which is used to load the proper runtime assembly at load time. + /// /param> + /// /param> + /// /param> + /// /param> + void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item); } -} \ No newline at end of file +} diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs index 17c2708..6355669 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs @@ -25,16 +25,17 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -using log4net; using System; -using OpenSim.Region.ScriptEngine.Shared; +using System.Reflection; +using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; -using OpenMetaverse; -using Nini.Config; using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.Shared; using Amib.Threading; -using OpenSim.Framework; +using log4net; +using Nini.Config; +using OpenMetaverse; namespace OpenSim.Region.ScriptEngine.Interfaces { @@ -76,6 +77,40 @@ namespace OpenSim.Region.ScriptEngine.Interfaces IConfigSource ConfigSource { get; } string ScriptEngineName { get; } string ScriptEnginePath { get; } + + /// + /// Return the name of the class that will be used for all running scripts. + /// + /// + /// Each class goes in its own assembly so we don't need to otherwise distinguish the class name. + /// + string ScriptClassName { get; } + + /// + /// Return the name of the base class that will be used for all running scripts. + /// + string ScriptBaseClassName { get; } + + /// + /// Assemblies that need to be referenced when compiling scripts. + /// + /// + /// These are currently additional to those always referenced by the compiler, BUT THIS MAY CHANGE IN THE + /// FUTURE. + /// This can be null if there are no additional assemblies. + /// + string[] ScriptReferencedAssemblies { get; } + + /// + /// Parameters for the generated script's constructor. + /// + /// + /// Can be null if there are no parameters + /// + ParameterInfo[] ScriptBaseClassParameters { get; } + IScriptApi GetApi(UUID itemID, string name); + + void SleepScript(UUID itemID, int delay); } } diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index 2f5b526..e4297c4 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs @@ -28,9 +28,12 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Threading; +using System.Diagnostics; using OpenMetaverse; using log4net; using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Interfaces; @@ -49,8 +52,13 @@ namespace OpenSim.Region.ScriptEngine.Interfaces public interface IScriptWorkItem { bool Cancel(); - void Abort(); - bool Wait(TimeSpan t); + bool Abort(); + + /// + /// Wait for the work item to complete. + /// + /// The number of milliseconds to wait. Must be >= -1 (Timeout.Infinite). + bool Wait(int t); } /// @@ -86,24 +94,35 @@ namespace OpenSim.Region.ScriptEngine.Interfaces bool ShuttingDown { get; set; } /// + /// When stopping the script: should it remain stopped permanently (i.e., save !Running in its state)? + /// + bool StayStopped { get; set; } + + /// /// Script state /// string State { get; set; } /// + /// If true then the engine is responsible for persisted state. If false then some other component may + /// persist state (e.g. attachments persisting in assets). + /// + bool StatePersistedHere { get; } + + /// /// Time the script was last started /// DateTime TimeStarted { get; } /// - /// Tick the last measurement period was started. + /// Collects information about how long the script was executed. /// - long MeasurementPeriodTickStart { get; } + MetricsCollectorTime ExecutionTime { get; } /// - /// Ticks spent executing in the last measurement period. + /// Scene part in which this script instance is contained. /// - long MeasurementPeriodExecutionTime { get; } + SceneObjectPart Part { get; } IScriptEngine Engine { get; } UUID AppDomain { get; set; } @@ -124,6 +143,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces uint LocalID { get; } UUID AssetID { get; } + + /// + /// Inventory item containing the script used. + /// + TaskInventoryItem ScriptTask { get; } + Queue EventQueue { get; } /// @@ -139,6 +164,9 @@ namespace OpenSim.Region.ScriptEngine.Interfaces void ClearQueue(); int StartParam { get; set; } + WaitHandle CoopWaitHandle { get; } + Stopwatch ExecutionTimer { get; } + void RemoveState(); void Init(); @@ -154,8 +182,9 @@ namespace OpenSim.Region.ScriptEngine.Interfaces /// /// How many milliseconds we will wait for an existing script event to finish before /// forcibly aborting that event. + /// If true then the event queue is also cleared /// true if the script was successfully stopped, false otherwise - bool Stop(int timeout); + bool Stop(int timeout, bool clearEventQueue = false); void SetState(string state); @@ -204,7 +233,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces void SetVars(Dictionary vars); DetectParams GetDetectParams(int idx); UUID GetDetectID(int idx); - void SaveState(string assembly); + void SaveState(); void DestroyScriptInstance(); IScriptApi GetApi(string name); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs index 47a9cdc..036cb5d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs @@ -28,7 +28,9 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Reflection; using System.Threading; +using log4net; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Monitoring; @@ -45,15 +47,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public class AsyncCommandManager { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static Thread cmdHandlerThread; private static int cmdHandlerThreadCycleSleepms; - private static List m_Scenes = new List(); + /// + /// Lock for reading/writing static components of AsyncCommandManager. + /// + /// + /// This lock exists so that multiple threads from different engines and/or different copies of the same engine + /// are prevented from running non-thread safe code (e.g. read/write of lists) concurrently. + /// + private static object staticLock = new object(); + private static List m_ScriptEngines = new List(); public IScriptEngine m_ScriptEngine; - private IScene m_Scene; private static Dictionary m_Dataserver = new Dictionary(); @@ -70,67 +81,99 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public Dataserver DataserverPlugin { - get { return m_Dataserver[m_ScriptEngine]; } + get + { + lock (staticLock) + return m_Dataserver[m_ScriptEngine]; + } } public Timer TimerPlugin { - get { return m_Timer[m_ScriptEngine]; } + get + { + lock (staticLock) + return m_Timer[m_ScriptEngine]; + } } public HttpRequest HttpRequestPlugin { - get { return m_HttpRequest[m_ScriptEngine]; } + get + { + lock (staticLock) + return m_HttpRequest[m_ScriptEngine]; + } } public Listener ListenerPlugin { - get { return m_Listener[m_ScriptEngine]; } + get + { + lock (staticLock) + return m_Listener[m_ScriptEngine]; + } } public SensorRepeat SensorRepeatPlugin { - get { return m_SensorRepeat[m_ScriptEngine]; } + get + { + lock (staticLock) + return m_SensorRepeat[m_ScriptEngine]; + } } public XmlRequest XmlRequestPlugin { - get { return m_XmlRequest[m_ScriptEngine]; } + get + { + lock (staticLock) + return m_XmlRequest[m_ScriptEngine]; + } } public IScriptEngine[] ScriptEngines { - get { return m_ScriptEngines.ToArray(); } + get + { + lock (staticLock) + return m_ScriptEngines.ToArray(); + } } public AsyncCommandManager(IScriptEngine _ScriptEngine) { m_ScriptEngine = _ScriptEngine; - m_Scene = m_ScriptEngine.World; - - if (m_Scenes.Count == 0) - ReadConfig(); - - if (!m_Scenes.Contains(m_Scene)) - m_Scenes.Add(m_Scene); - if (!m_ScriptEngines.Contains(m_ScriptEngine)) - m_ScriptEngines.Add(m_ScriptEngine); - - // Create instances of all plugins - if (!m_Dataserver.ContainsKey(m_ScriptEngine)) - m_Dataserver[m_ScriptEngine] = new Dataserver(this); - if (!m_Timer.ContainsKey(m_ScriptEngine)) - m_Timer[m_ScriptEngine] = new Timer(this); - if (!m_HttpRequest.ContainsKey(m_ScriptEngine)) - m_HttpRequest[m_ScriptEngine] = new HttpRequest(this); - if (!m_Listener.ContainsKey(m_ScriptEngine)) - m_Listener[m_ScriptEngine] = new Listener(this); - if (!m_SensorRepeat.ContainsKey(m_ScriptEngine)) - m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this); - if (!m_XmlRequest.ContainsKey(m_ScriptEngine)) - m_XmlRequest[m_ScriptEngine] = new XmlRequest(this); - - StartThread(); + + // If there is more than one scene in the simulator or multiple script engines are used on the same region + // then more than one thread could arrive at this block of code simultaneously. However, it cannot be + // executed concurrently both because concurrent list operations are not thread-safe and because of other + // race conditions such as the later check of cmdHandlerThread == null. + lock (staticLock) + { + if (m_ScriptEngines.Count == 0) + ReadConfig(); + + if (!m_ScriptEngines.Contains(m_ScriptEngine)) + m_ScriptEngines.Add(m_ScriptEngine); + + // Create instances of all plugins + if (!m_Dataserver.ContainsKey(m_ScriptEngine)) + m_Dataserver[m_ScriptEngine] = new Dataserver(this); + if (!m_Timer.ContainsKey(m_ScriptEngine)) + m_Timer[m_ScriptEngine] = new Timer(this); + if (!m_HttpRequest.ContainsKey(m_ScriptEngine)) + m_HttpRequest[m_ScriptEngine] = new HttpRequest(this); + if (!m_Listener.ContainsKey(m_ScriptEngine)) + m_Listener[m_ScriptEngine] = new Listener(this); + if (!m_SensorRepeat.ContainsKey(m_ScriptEngine)) + m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this); + if (!m_XmlRequest.ContainsKey(m_ScriptEngine)) + m_XmlRequest[m_ScriptEngine] = new XmlRequest(this); + + StartThread(); + } } private static void StartThread() @@ -139,7 +182,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { // Start the thread that will be doing the work cmdHandlerThread - = Watchdog.StartThread( + = WorkManager.StartThread( CmdHandlerThreadLoop, "AsyncLSLCmdHandlerThread", ThreadPriority.Normal, true, true); } } @@ -179,42 +222,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { try { - while (true) - { - Thread.Sleep(cmdHandlerThreadCycleSleepms); + Thread.Sleep(cmdHandlerThreadCycleSleepms); - DoOneCmdHandlerPass(); + DoOneCmdHandlerPass(); - Watchdog.UpdateThread(); - } + Watchdog.UpdateThread(); } - catch + catch (Exception e) { + m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e); } } } private static void DoOneCmdHandlerPass() { - // Check HttpRequests - m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); + lock (staticLock) + { + // Check HttpRequests + m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); - // Check XMLRPCRequests - m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); + // Check XMLRPCRequests + m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); - foreach (IScriptEngine s in m_ScriptEngines) - { - // Check Listeners - m_Listener[s].CheckListeners(); + foreach (IScriptEngine s in m_ScriptEngines) + { + // Check Listeners + m_Listener[s].CheckListeners(); - // Check timers - m_Timer[s].CheckTimerEvents(); + // Check timers + m_Timer[s].CheckTimerEvents(); - // Check Sensors - m_SensorRepeat[s].CheckSenseRepeaterEvents(); + // Check Sensors + m_SensorRepeat[s].CheckSenseRepeaterEvents(); - // Check dataserver - m_Dataserver[s].ExpireRequests(); + // Check dataserver + m_Dataserver[s].ExpireRequests(); + } } } @@ -225,19 +269,44 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID) { +// m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID); + + lock (staticLock) + { + // Remove dataserver events + m_Dataserver[engine].RemoveEvents(localID, itemID); + + // Remove from: Timers + m_Timer[engine].UnSetTimerEvents(localID, itemID); + + // Remove from: HttpRequest + IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface(); + if (iHttpReq != null) + iHttpReq.StopHttpRequestsForScript(itemID); + + IWorldComm comms = engine.World.RequestModuleInterface(); + if (comms != null) + comms.DeleteListener(itemID); + + IXMLRPC xmlrpc = engine.World.RequestModuleInterface(); + if (xmlrpc != null) + { + xmlrpc.DeleteChannels(itemID); + xmlrpc.CancelSRDRequests(itemID); + } + + // Remove Sensors + m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID); + } + } + + public static void StateChange(IScriptEngine engine, uint localID, UUID itemID) + { // Remove a specific script // Remove dataserver events m_Dataserver[engine].RemoveEvents(localID, itemID); - // Remove from: Timers - m_Timer[engine].UnSetTimerEvents(localID, itemID); - - // Remove from: HttpRequest - IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface(); - if (iHttpReq != null) - iHttpReq.StopHttpRequest(localID, itemID); - IWorldComm comms = engine.World.RequestModuleInterface(); if (comms != null) comms.DeleteListener(itemID); @@ -248,9 +317,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api xmlrpc.DeleteChannels(itemID); xmlrpc.CancelSRDRequests(itemID); } - // Remove Sensors m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID); + } /// @@ -260,10 +329,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine) { - if (m_SensorRepeat.ContainsKey(engine)) - return m_SensorRepeat[engine]; - else - return null; + lock (staticLock) + { + if (m_SensorRepeat.ContainsKey(engine)) + return m_SensorRepeat[engine]; + else + return null; + } } /// @@ -273,10 +345,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public static Dataserver GetDataserverPlugin(IScriptEngine engine) { - if (m_Dataserver.ContainsKey(engine)) - return m_Dataserver[engine]; - else - return null; + lock (staticLock) + { + if (m_Dataserver.ContainsKey(engine)) + return m_Dataserver[engine]; + else + return null; + } } /// @@ -286,10 +361,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public static Timer GetTimerPlugin(IScriptEngine engine) { - if (m_Timer.ContainsKey(engine)) - return m_Timer[engine]; - else - return null; + lock (staticLock) + { + if (m_Timer.ContainsKey(engine)) + return m_Timer[engine]; + else + return null; + } } /// @@ -299,38 +377,44 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public static Listener GetListenerPlugin(IScriptEngine engine) { - if (m_Listener.ContainsKey(engine)) - return m_Listener[engine]; - else - return null; + lock (staticLock) + { + if (m_Listener.ContainsKey(engine)) + return m_Listener[engine]; + else + return null; + } } public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID) { List data = new List(); - Object[] listeners = m_Listener[engine].GetSerializationData(itemID); - if (listeners.Length > 0) + lock (staticLock) { - data.Add("listener"); - data.Add(listeners.Length); - data.AddRange(listeners); - } + Object[] listeners = m_Listener[engine].GetSerializationData(itemID); + if (listeners.Length > 0) + { + data.Add("listener"); + data.Add(listeners.Length); + data.AddRange(listeners); + } - Object[] timers=m_Timer[engine].GetSerializationData(itemID); - if (timers.Length > 0) - { - data.Add("timer"); - data.Add(timers.Length); - data.AddRange(timers); - } + Object[] timers=m_Timer[engine].GetSerializationData(itemID); + if (timers.Length > 0) + { + data.Add("timer"); + data.Add(timers.Length); + data.AddRange(timers); + } - Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID); - if (sensors.Length > 0) - { - data.Add("sensor"); - data.Add(sensors.Length); - data.AddRange(sensors); + Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID); + if (sensors.Length > 0) + { + data.Add("sensor"); + data.Add(sensors.Length); + data.AddRange(sensors); + } } return data.ToArray(); @@ -355,41 +439,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api idx+=len; + lock (staticLock) + { switch (type) { - case "listener": - m_Listener[engine].CreateFromData(localID, itemID, - hostID, item); - break; - case "timer": - m_Timer[engine].CreateFromData(localID, itemID, - hostID, item); - break; - case "sensor": - m_SensorRepeat[engine].CreateFromData(localID, - itemID, hostID, item); - break; + case "listener": + m_Listener[engine].CreateFromData(localID, itemID, + hostID, item); + break; + case "timer": + m_Timer[engine].CreateFromData(localID, itemID, + hostID, item); + break; + case "sensor": + m_SensorRepeat[engine].CreateFromData(localID, + itemID, hostID, item); + break; + } } } } } - - #region Check llRemoteData channels - - #endregion - - #region Check llListeners - - #endregion - - /// - /// If set to true then threads and stuff should try to make a graceful exit - /// - public bool PleaseShutdown - { - get { return _PleaseShutdown; } - set { _PleaseShutdown = value; } - } - private bool _PleaseShutdown = false; } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 1ab107a..4eda443 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -28,6 +28,9 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; using System.Runtime.Remoting.Lifetime; using System.Text; using System.Threading; @@ -35,7 +38,9 @@ using System.Text.RegularExpressions; using Nini.Config; using log4net; using OpenMetaverse; +using OpenMetaverse.Assets; using OpenMetaverse.Packets; +using OpenMetaverse.Rendering; using OpenSim; using OpenSim.Framework; @@ -45,7 +50,8 @@ using OpenSim.Region.CoreModules.World.Terrain; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes.Animation; -using OpenSim.Region.Physics.Manager; +using OpenSim.Region.Framework.Scenes.Scripting; +using OpenSim.Region.PhysicsModules.SharedBase; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; @@ -66,6 +72,8 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; using System.Reflection; +using System.Linq; +using PermissionMask = OpenSim.Framework.PermissionMask; namespace OpenSim.Region.ScriptEngine.Shared.Api { @@ -83,15 +91,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public int LlRequestAgentDataCacheTimeoutMs { get; set; } + protected IScriptEngine m_ScriptEngine; protected SceneObjectPart m_host; /// + /// Used for script sleeps when we are using co-operative script termination. + /// + /// null if co-operative script termination is not active + /// /// The item that hosts this script /// protected TaskInventoryItem m_item; - protected bool throwErrorOnNotImplemented = true; + protected bool throwErrorOnNotImplemented = false; protected AsyncCommandManager AsyncCommands = null; protected float m_ScriptDelayFactor = 1.0f; protected float m_ScriptDistanceFactor = 1.0f; @@ -108,49 +123,260 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected IUrlModule m_UrlModule = null; protected Dictionary m_userInfoCache = new Dictionary(); protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp. + protected int m_sleepMsOnSetTexture = 200; + protected int m_sleepMsOnSetLinkTexture = 200; + protected int m_sleepMsOnScaleTexture = 200; + protected int m_sleepMsOnOffsetTexture = 200; + protected int m_sleepMsOnRotateTexture = 200; + protected int m_sleepMsOnSetPos = 200; + protected int m_sleepMsOnSetRot = 200; + protected int m_sleepMsOnSetLocalRot = 200; + protected int m_sleepMsOnPreloadSound = 1000; + protected int m_sleepMsOnMakeExplosion = 100; + protected int m_sleepMsOnMakeFountain = 100; + protected int m_sleepMsOnMakeSmoke = 100; + protected int m_sleepMsOnMakeFire = 100; + protected int m_sleepMsOnRezAtRoot = 100; + protected int m_sleepMsOnInstantMessage = 2000; + protected int m_sleepMsOnEmail = 20000; + protected int m_sleepMsOnCreateLink = 1000; + protected int m_sleepMsOnGiveInventory = 3000; + protected int m_sleepMsOnRequestAgentData = 100; + protected int m_sleepMsOnRequestInventoryData = 1000; + protected int m_sleepMsOnSetDamage = 5000; + protected int m_sleepMsOnTextBox = 1000; + protected int m_sleepMsOnAdjustSoundVolume = 100; + protected int m_sleepMsOnEjectFromLand = 5000; + protected int m_sleepMsOnAddToLandPassList = 100; + protected int m_sleepMsOnDialog = 1000; + protected int m_sleepMsOnRemoteLoadScript = 3000; + protected int m_sleepMsOnRemoteLoadScriptPin = 3000; + protected int m_sleepMsOnOpenRemoteDataChannel = 1000; + protected int m_sleepMsOnSendRemoteData = 3000; + protected int m_sleepMsOnRemoteDataReply = 3000; + protected int m_sleepMsOnCloseRemoteDataChannel = 1000; + protected int m_sleepMsOnSetPrimitiveParams = 200; + protected int m_sleepMsOnSetLinkPrimitiveParams = 200; + protected int m_sleepMsOnXorBase64Strings = 300; + protected int m_sleepMsOnSetParcelMusicURL = 2000; + protected int m_sleepMsOnGetPrimMediaParams = 1000; + protected int m_sleepMsOnGetLinkMedia = 1000; + protected int m_sleepMsOnSetPrimMediaParams = 1000; + protected int m_sleepMsOnSetLinkMedia = 1000; + protected int m_sleepMsOnClearPrimMedia = 1000; + protected int m_sleepMsOnClearLinkMedia = 1000; + protected int m_sleepMsOnRequestSimulatorData = 1000; + protected int m_sleepMsOnLoadURL = 10000; + protected int m_sleepMsOnParcelMediaCommandList = 2000; + protected int m_sleepMsOnParcelMediaQuery = 2000; + protected int m_sleepMsOnModPow = 1000; + protected int m_sleepMsOnSetPrimURL = 2000; + protected int m_sleepMsOnRefreshPrimURL = 20000; + protected int m_sleepMsOnMapDestination = 1000; + protected int m_sleepMsOnAddToLandBanList = 100; + protected int m_sleepMsOnRemoveFromLandPassList = 100; + protected int m_sleepMsOnRemoveFromLandBanList = 100; + protected int m_sleepMsOnResetLandBanList = 100; + protected int m_sleepMsOnResetLandPassList = 100; + protected int m_sleepMsOnGetParcelPrimOwners = 2000; + protected int m_sleepMsOnGetNumberOfNotecardLines = 100; + protected int m_sleepMsOnGetNotecardLine = 100; + protected string m_internalObjectHost = "lsl.opensim.local"; + protected bool m_restrictEmail = false; protected ISoundModule m_SoundModule = null; - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) + protected float m_avatarHeightCorrection = 0.2f; + protected bool m_useSimpleBoxesInGetBoundingBox = false; + protected bool m_addStatsInGetBoundingBox = false; + + //LSL Avatar Bounding Box (lABB), lower (1) and upper (2), + //standing (Std), Groundsitting (Grs), Sitting (Sit), + //along X, Y and Z axes, constants (0) and coefficients (1) + protected float m_lABB1StdX0 = -0.275f; + protected float m_lABB2StdX0 = 0.275f; + protected float m_lABB1StdY0 = -0.35f; + protected float m_lABB2StdY0 = 0.35f; + protected float m_lABB1StdZ0 = -0.1f; + protected float m_lABB1StdZ1 = -0.5f; + protected float m_lABB2StdZ0 = 0.1f; + protected float m_lABB2StdZ1 = 0.5f; + protected float m_lABB1GrsX0 = -0.3875f; + protected float m_lABB2GrsX0 = 0.3875f; + protected float m_lABB1GrsY0 = -0.5f; + protected float m_lABB2GrsY0 = 0.5f; + protected float m_lABB1GrsZ0 = -0.05f; + protected float m_lABB1GrsZ1 = -0.375f; + protected float m_lABB2GrsZ0 = 0.5f; + protected float m_lABB2GrsZ1 = 0.0f; + protected float m_lABB1SitX0 = -0.5875f; + protected float m_lABB2SitX0 = 0.1875f; + protected float m_lABB1SitY0 = -0.35f; + protected float m_lABB2SitY0 = 0.35f; + protected float m_lABB1SitZ0 = -0.35f; + protected float m_lABB1SitZ1 = -0.375f; + protected float m_lABB2SitZ0 = -0.25f; + protected float m_lABB2SitZ1 = 0.25f; + + protected float m_primSafetyCoeffX = 2.414214f; + protected float m_primSafetyCoeffY = 2.414214f; + protected float m_primSafetyCoeffZ = 1.618034f; + protected bool m_useCastRayV3 = false; + protected float m_floatToleranceInCastRay = 0.00001f; + protected float m_floatTolerance2InCastRay = 0.001f; + protected DetailLevel m_primLodInCastRay = DetailLevel.Medium; + protected DetailLevel m_sculptLodInCastRay = DetailLevel.Medium; + protected DetailLevel m_meshLodInCastRay = DetailLevel.Highest; + protected DetailLevel m_avatarLodInCastRay = DetailLevel.Medium; + protected int m_maxHitsInCastRay = 16; + protected int m_maxHitsPerPrimInCastRay = 16; + protected int m_maxHitsPerObjectInCastRay = 16; + protected bool m_detectExitsInCastRay = false; + protected bool m_filterPartsInCastRay = false; + protected bool m_doAttachmentsInCastRay = false; + protected int m_msThrottleInCastRay = 200; + protected int m_msPerRegionInCastRay = 40; + protected int m_msPerAvatarInCastRay = 10; + protected int m_msMinInCastRay = 2; + protected int m_msMaxInCastRay = 40; + protected static List m_castRayCalls = new List(); + protected bool m_useMeshCacheInCastRay = true; + protected static Dictionary m_cachedMeshes = new Dictionary(); + + //An array of HTTP/1.1 headers that are not allowed to be used + //as custom headers by llHTTPRequest. + private string[] HttpStandardHeaders = + { + "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", + "Accept-Ranges", "Age", "Allow", "Authorization", "Cache-Control", + "Connection", "Content-Encoding", "Content-Language", + "Content-Length", "Content-Location", "Content-MD5", + "Content-Range", "Content-Type", "Date", "ETag", "Expect", + "Expires", "From", "Host", "If-Match", "If-Modified-Since", + "If-None-Match", "If-Range", "If-Unmodified-Since", "Last-Modified", + "Location", "Max-Forwards", "Pragma", "Proxy-Authenticate", + "Proxy-Authorization", "Range", "Referer", "Retry-After", "Server", + "TE", "Trailer", "Transfer-Encoding", "Upgrade", "User-Agent", + "Vary", "Via", "Warning", "WWW-Authenticate" + }; + + public void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item) { - m_ScriptEngine = ScriptEngine; + m_ScriptEngine = scriptEngine; m_host = host; m_item = item; - LoadLimits(); // read script limits from config. + LoadConfig(); m_TransferModule = m_ScriptEngine.World.RequestModuleInterface(); m_UrlModule = m_ScriptEngine.World.RequestModuleInterface(); m_SoundModule = m_ScriptEngine.World.RequestModuleInterface(); - AsyncCommands = new AsyncCommandManager(ScriptEngine); + AsyncCommands = new AsyncCommandManager(m_ScriptEngine); } - /* load configuration items that affect script, object and run-time behavior. */ - private void LoadLimits() + /// + /// Load configuration items that affect script, object and run-time behavior. */ + /// + private void LoadConfig() { - m_ScriptDelayFactor = - m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); - m_ScriptDistanceFactor = - m_ScriptEngine.Config.GetFloat("ScriptDistanceLimitFactor", 1.0f); - m_MinTimerInterval = - m_ScriptEngine.Config.GetFloat("MinTimerInterval", 0.5f); - m_automaticLinkPermission = - m_ScriptEngine.Config.GetBoolean("AutomaticLinkPermission", false); - m_notecardLineReadCharsMax = - m_ScriptEngine.Config.GetInt("NotecardLineReadCharsMax", 255); + LlRequestAgentDataCacheTimeoutMs = 20000; + + IConfig seConfig = m_ScriptEngine.Config; + + if (seConfig != null) + { + m_ScriptDelayFactor = + seConfig.GetFloat("ScriptDelayFactor", m_ScriptDelayFactor); + m_ScriptDistanceFactor = + seConfig.GetFloat("ScriptDistanceLimitFactor", m_ScriptDistanceFactor); + m_MinTimerInterval = + seConfig.GetFloat("MinTimerInterval", m_MinTimerInterval); + m_automaticLinkPermission = + seConfig.GetBoolean("AutomaticLinkPermission", m_automaticLinkPermission); + m_notecardLineReadCharsMax = + seConfig.GetInt("NotecardLineReadCharsMax", m_notecardLineReadCharsMax); + + // Rezzing an object with a velocity can create recoil. This feature seems to have been + // removed from recent versions of SL. The code computes recoil (vel*mass) and scales + // it by this factor. May be zero to turn off recoil all together. + m_recoilScaleFactor = m_ScriptEngine.Config.GetFloat("RecoilScaleFactor", m_recoilScaleFactor); + } + if (m_notecardLineReadCharsMax > 65535) m_notecardLineReadCharsMax = 65535; + // load limits for particular subsystems. - IConfig SMTPConfig; - if ((SMTPConfig = m_ScriptEngine.ConfigSource.Configs["SMTP"]) != null) { - // there's an smtp config, so load in the snooze time. - EMAIL_PAUSE_TIME = SMTPConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME); - } - // Rezzing an object with a velocity can create recoil. This feature seems to have been - // removed from recent versions of SL. The code computes recoil (vel*mass) and scales - // it by this factor. May be zero to turn off recoil all together. - m_recoilScaleFactor = m_ScriptEngine.Config.GetFloat("RecoilScaleFactor", m_recoilScaleFactor); + IConfigSource seConfigSource = m_ScriptEngine.ConfigSource; + + if (seConfigSource != null) + { + IConfig lslConfig = seConfigSource.Configs["LL-Functions"]; + if (lslConfig != null) + { + m_restrictEmail = lslConfig.GetBoolean("RestrictEmail", m_restrictEmail); + m_avatarHeightCorrection = lslConfig.GetFloat("AvatarHeightCorrection", m_avatarHeightCorrection); + m_useSimpleBoxesInGetBoundingBox = lslConfig.GetBoolean("UseSimpleBoxesInGetBoundingBox", m_useSimpleBoxesInGetBoundingBox); + m_addStatsInGetBoundingBox = lslConfig.GetBoolean("AddStatsInGetBoundingBox", m_addStatsInGetBoundingBox); + m_lABB1StdX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingXconst", m_lABB1StdX0); + m_lABB2StdX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingXconst", m_lABB2StdX0); + m_lABB1StdY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingYconst", m_lABB1StdY0); + m_lABB2StdY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingYconst", m_lABB2StdY0); + m_lABB1StdZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZconst", m_lABB1StdZ0); + m_lABB1StdZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZcoeff", m_lABB1StdZ1); + m_lABB2StdZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZconst", m_lABB2StdZ0); + m_lABB2StdZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZcoeff", m_lABB2StdZ1); + m_lABB1GrsX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingXconst", m_lABB1GrsX0); + m_lABB2GrsX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingXconst", m_lABB2GrsX0); + m_lABB1GrsY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingYconst", m_lABB1GrsY0); + m_lABB2GrsY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingYconst", m_lABB2GrsY0); + m_lABB1GrsZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZconst", m_lABB1GrsZ0); + m_lABB1GrsZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZcoeff", m_lABB1GrsZ1); + m_lABB2GrsZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZconst", m_lABB2GrsZ0); + m_lABB2GrsZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZcoeff", m_lABB2GrsZ1); + m_lABB1SitX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingXconst", m_lABB1SitX0); + m_lABB2SitX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingXconst", m_lABB2SitX0); + m_lABB1SitY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingYconst", m_lABB1SitY0); + m_lABB2SitY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingYconst", m_lABB2SitY0); + m_lABB1SitZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZconst", m_lABB1SitZ0); + m_lABB1SitZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZcoeff", m_lABB1SitZ1); + m_lABB2SitZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZconst", m_lABB2SitZ0); + m_lABB2SitZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZcoeff", m_lABB2SitZ1); + m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX); + m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY); + m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ); + m_useCastRayV3 = lslConfig.GetBoolean("UseLlCastRayV3", m_useCastRayV3); + m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay); + m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay); + m_primLodInCastRay = (DetailLevel)lslConfig.GetInt("PrimDetailLevelInLlCastRay", (int)m_primLodInCastRay); + m_sculptLodInCastRay = (DetailLevel)lslConfig.GetInt("SculptDetailLevelInLlCastRay", (int)m_sculptLodInCastRay); + m_meshLodInCastRay = (DetailLevel)lslConfig.GetInt("MeshDetailLevelInLlCastRay", (int)m_meshLodInCastRay); + m_avatarLodInCastRay = (DetailLevel)lslConfig.GetInt("AvatarDetailLevelInLlCastRay", (int)m_avatarLodInCastRay); + m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay); + m_maxHitsPerPrimInCastRay = lslConfig.GetInt("MaxHitsPerPrimInLlCastRay", m_maxHitsPerPrimInCastRay); + m_maxHitsPerObjectInCastRay = lslConfig.GetInt("MaxHitsPerObjectInLlCastRay", m_maxHitsPerObjectInCastRay); + m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay); + m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay); + m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay); + m_msThrottleInCastRay = lslConfig.GetInt("ThrottleTimeInMsInLlCastRay", m_msThrottleInCastRay); + m_msPerRegionInCastRay = lslConfig.GetInt("AvailableTimeInMsPerRegionInLlCastRay", m_msPerRegionInCastRay); + m_msPerAvatarInCastRay = lslConfig.GetInt("AvailableTimeInMsPerAvatarInLlCastRay", m_msPerAvatarInCastRay); + m_msMinInCastRay = lslConfig.GetInt("RequiredAvailableTimeInMsInLlCastRay", m_msMinInCastRay); + m_msMaxInCastRay = lslConfig.GetInt("MaximumAvailableTimeInMsInLlCastRay", m_msMaxInCastRay); + m_useMeshCacheInCastRay = lslConfig.GetBoolean("UseMeshCacheInLlCastRay", m_useMeshCacheInCastRay); + } + + IConfig smtpConfig = seConfigSource.Configs["SMTP"]; + if (smtpConfig != null) + { + // there's an smtp config, so load in the snooze time. + EMAIL_PAUSE_TIME = smtpConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME); + + m_internalObjectHost = smtpConfig.GetString("internal_object_host", m_internalObjectHost); + } + } + m_sleepMsOnEmail = EMAIL_PAUSE_TIME * 1000; } public override Object InitializeLifetimeService() @@ -171,9 +397,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api delay = (int)((float)delay * m_ScriptDelayFactor); if (delay == 0) return; - System.Threading.Thread.Sleep(delay); + + Sleep(delay); + } + + protected virtual void Sleep(int delay) + { + if (m_item == null) // Some unit tests don't set this + { + Thread.Sleep(delay); + return; + } + + m_ScriptEngine.SleepScript(m_item.ItemID, delay); } + /// + /// Check for co-operative termination. + /// + /// If called with 0, then just the check is performed with no wait. + public Scene World { get { return m_ScriptEngine.World; } @@ -209,7 +452,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if ((item = GetScriptByName(name)) != UUID.Zero) m_ScriptEngine.ResetScript(item); else - ShoutError("llResetOtherScript: script "+name+" not found"); + Error("llResetOtherScript", "Can't find script '" + name + "'"); } public LSL_Integer llGetScriptState(string name) @@ -223,7 +466,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return m_ScriptEngine.GetScriptState(item) ?1:0; } - ShoutError("llGetScriptState: script "+name+" not found"); + Error("llGetScriptState", "Can't find script '" + name + "'"); // If we didn't find it, then it's safe to // assume it is not running. @@ -246,7 +489,78 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else { - ShoutError("llSetScriptState: script "+name+" not found"); + Error("llSetScriptState", "Can't find script '" + name + "'"); + } + } + + /// + /// Get a given link entity from a linkset (linked objects and any sitting avatars). + /// + /// + /// If there are any ScenePresence's in the linkset (i.e. because they are sat upon one of the prims), then + /// these are counted as extra entities that correspond to linknums beyond the number of prims in the linkset. + /// The ScenePresences receive linknums in the order in which they sat. + /// + /// + /// The link entity. null if not found. + /// + /// + /// + /// Can be either a non-negative integer or ScriptBaseClass.LINK_THIS (-4). + /// If ScriptBaseClass.LINK_THIS then the entity containing the script is returned. + /// If the linkset has one entity and a linknum of zero is given, then the single entity is returned. If any + /// positive integer is given in this case then null is returned. + /// If the linkset has more than one entity and a linknum greater than zero but equal to or less than the number + /// of entities, then the entity which corresponds to that linknum is returned. + /// Otherwise, if a positive linknum is given which is greater than the number of entities in the linkset, then + /// null is returned. + /// + public ISceneEntity GetLinkEntity(SceneObjectPart part, int linknum) + { + if (linknum < 0) + { + if (linknum == ScriptBaseClass.LINK_THIS) + return part; + else + return null; + } + + int actualPrimCount = part.ParentGroup.PrimCount; + List sittingAvatars = part.ParentGroup.GetSittingAvatars(); + int adjustedPrimCount = actualPrimCount + sittingAvatars.Count; + + // Special case for a single prim. In this case the linknum is zero. However, this will not match a single + // prim that has any avatars sat upon it (in which case the root prim is link 1). + if (linknum == 0) + { + if (actualPrimCount == 1 && sittingAvatars.Count == 0) + return part; + + return null; + } + // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but + // here we must match 1 (ScriptBaseClass.LINK_ROOT). + else if (linknum == ScriptBaseClass.LINK_ROOT && actualPrimCount == 1) + { + if (sittingAvatars.Count > 0) + return part.ParentGroup.RootPart; + else + return null; + } + else if (linknum <= adjustedPrimCount) + { + if (linknum <= actualPrimCount) + { + return part.ParentGroup.GetLinkNumPart(linknum); + } + else + { + return sittingAvatars[linknum - actualPrimCount - 1]; + } + } + else + { + return null; } } @@ -301,77 +615,52 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - protected UUID InventoryKey(string name, int type) + public List GetLinkEntities(int linkType) { - TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name); - - if (item != null && item.Type == type) - return item.AssetID; - else - return UUID.Zero; + return GetLinkEntities(m_host, linkType); } - /// - /// accepts a valid UUID, -or- a name of an inventory item. - /// Returns a valid UUID or UUID.Zero if key invalid and item not found - /// in prim inventory. - /// - /// - /// - protected UUID KeyOrName(string k) + public List GetLinkEntities(SceneObjectPart part, int linkType) { - UUID key; + List ret; - // if we can parse the string as a key, use it. - // else try to locate the name in inventory of object. found returns key, - // not found returns UUID.Zero - if (!UUID.TryParse(k, out key)) + switch (linkType) { - TaskInventoryItem item = m_host.Inventory.GetInventoryItem(k); + case ScriptBaseClass.LINK_SET: + return new List(part.ParentGroup.Parts); - if (item != null) - key = item.AssetID; - else - key = UUID.Zero; - } + case ScriptBaseClass.LINK_ROOT: + return new List() { part.ParentGroup.RootPart }; - return key; - } + case ScriptBaseClass.LINK_ALL_OTHERS: + ret = new List(part.ParentGroup.Parts); - /// - /// Return the UUID of the asset matching the specified key or name - /// and asset type. - /// - /// - /// - /// - protected UUID KeyOrName(string k, AssetType type) - { - UUID key; + if (ret.Contains(part)) + ret.Remove(part); - if (!UUID.TryParse(k, out key)) - { - TaskInventoryItem item = m_host.Inventory.GetInventoryItem(k); - if (item != null && item.Type == (int)type) - key = item.AssetID; - } - else - { - lock (m_host.TaskInventory) - { - foreach (KeyValuePair item in m_host.TaskInventory) - { - if (item.Value.Type == (int)type && item.Value.Name == k) - { - key = item.Value.ItemID; - break; - } - } - } - } + return ret; + + case ScriptBaseClass.LINK_ALL_CHILDREN: + ret = new List(part.ParentGroup.Parts); + + if (ret.Contains(part.ParentGroup.RootPart)) + ret.Remove(part.ParentGroup.RootPart); + + return ret; + + case ScriptBaseClass.LINK_THIS: + return new List() { part }; + + default: + if (linkType < 0) + return new List(); + ISceneEntity target = GetLinkEntity(part, linkType); + if (target == null) + return new List(); - return key; + return new List() { target }; + } } //These are the implementations of the various ll-functions used by the LSL scripts. @@ -430,10 +719,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Float llFrand(double mag) { m_host.AddScriptLPS(1); - lock (Util.RandomClass) - { - return Util.RandomClass.NextDouble() * mag; - } + + return Util.RandomClass.NextDouble() * mag; } public LSL_Integer llFloor(double f) @@ -837,7 +1124,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (channelID == 0) { - LSLError("Cannot use llRegionSay() on channel 0"); + Error("llRegionSay", "Cannot use on channel 0"); return; } @@ -846,6 +1133,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); + World.SimChat(Utils.StringToBytes(text), + ChatTypeEnum.Region, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false); + IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); if (wComm != null) wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text); @@ -866,6 +1156,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID TargetID; UUID.TryParse(target, out TargetID); + World.SimChatToAgent(TargetID, Utils.StringToBytes(msg), + channel, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, true); + IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); if (wComm != null) wComm.DeliverMessageTo(TargetID, channel, m_host.AbsolutePosition, m_host.Name, m_host.UUID, msg); @@ -1255,12 +1548,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } if ((status & ScriptBaseClass.STATUS_BLOCK_GRAB) == ScriptBaseClass.STATUS_BLOCK_GRAB) - { - if (value != 0) - m_host.SetBlockGrab(true); - else - m_host.SetBlockGrab(false); - } + m_host.BlockGrab = value != 0; + + if ((status & ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT) == ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT) + m_host.ParentGroup.BlockGrabOverride = value != 0; if ((status & ScriptBaseClass.STATUS_DIE_AT_EDGE) == ScriptBaseClass.STATUS_DIE_AT_EDGE) { @@ -1321,10 +1612,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return 0; case ScriptBaseClass.STATUS_BLOCK_GRAB: - if (m_host.GetBlockGrab()) - return 1; - else - return 0; + return m_host.BlockGrab ? 1 : 0; + + case ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT: + return m_host.ParentGroup.BlockGrabOverride ? 1 : 0; case ScriptBaseClass.STATUS_DIE_AT_EDGE: if (m_host.GetDieAtEdge()) @@ -1427,6 +1718,73 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.SetFaceColorAlpha(face, color, null); } + public void llSetContentType(LSL_Key id, LSL_Integer type) + { + m_host.AddScriptLPS(1); + + if (m_UrlModule == null) + return; + + // Make sure the content type is text/plain to start with + m_UrlModule.HttpContentType(new UUID(id), "text/plain"); + + // Is the object owner online and in the region + ScenePresence agent = World.GetScenePresence(m_host.ParentGroup.OwnerID); + if (agent == null || agent.IsChildAgent) + return; // Fail if the owner is not in the same region + + // Is it the embeded browser? + string userAgent = m_UrlModule.GetHttpHeader(new UUID(id), "user-agent"); + if (userAgent.IndexOf("SecondLife") < 0) + return; // Not the embedded browser. Is this check good enough? + + // Use the IP address of the client and check against the request + // seperate logins from the same IP will allow all of them to get non-text/plain as long + // as the owner is in the region. Same as SL! + string logonFromIPAddress = agent.ControllingClient.RemoteEndPoint.Address.ToString(); + string requestFromIPAddress = m_UrlModule.GetHttpHeader(new UUID(id), "remote_addr"); + //m_log.Debug("IP from header='" + requestFromIPAddress + "' IP from endpoint='" + logonFromIPAddress + "'"); + if (requestFromIPAddress == null || requestFromIPAddress.Trim() == "") + return; + if (logonFromIPAddress == null || logonFromIPAddress.Trim() == "") + return; + + // If the request isnt from the same IP address then the request cannot be from the owner + if (!requestFromIPAddress.Trim().Equals(logonFromIPAddress.Trim())) + return; + + switch (type) + { + case ScriptBaseClass.CONTENT_TYPE_HTML: + m_UrlModule.HttpContentType(new UUID(id), "text/html"); + break; + case ScriptBaseClass.CONTENT_TYPE_XML: + m_UrlModule.HttpContentType(new UUID(id), "application/xml"); + break; + case ScriptBaseClass.CONTENT_TYPE_XHTML: + m_UrlModule.HttpContentType(new UUID(id), "application/xhtml+xml"); + break; + case ScriptBaseClass.CONTENT_TYPE_ATOM: + m_UrlModule.HttpContentType(new UUID(id), "application/atom+xml"); + break; + case ScriptBaseClass.CONTENT_TYPE_JSON: + m_UrlModule.HttpContentType(new UUID(id), "application/json"); + break; + case ScriptBaseClass.CONTENT_TYPE_LLSD: + m_UrlModule.HttpContentType(new UUID(id), "application/llsd+xml"); + break; + case ScriptBaseClass.CONTENT_TYPE_FORM: + m_UrlModule.HttpContentType(new UUID(id), "application/x-www-form-urlencoded"); + break; + case ScriptBaseClass.CONTENT_TYPE_RSS: + m_UrlModule.HttpContentType(new UUID(id), "application/rss+xml"); + break; + default: + m_UrlModule.HttpContentType(new UUID(id), "text/plain"); + break; + } + } + public void SetTexGen(SceneObjectPart part, int face,int style) { Primitive.TextureEntry tex = part.Shape.Textures; @@ -1522,7 +1880,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (tex.FaceTextures[i] != null) { tex.FaceTextures[i].Shiny = sval; - tex.FaceTextures[i].Bump = bump;; + tex.FaceTextures[i].Bump = bump; } tex.DefaultTexture.Shiny = sval; tex.DefaultTexture.Bump = bump; @@ -1631,7 +1989,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f); tex.DefaultTexture.RGBA = texcolor; } - + part.UpdateTextureEntry(tex.GetBytes()); return; } @@ -1703,9 +2061,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api part.Shape.LightColorR = Util.Clip((float)color.x, 0.0f, 1.0f); part.Shape.LightColorG = Util.Clip((float)color.y, 0.0f, 1.0f); part.Shape.LightColorB = Util.Clip((float)color.z, 0.0f, 1.0f); - part.Shape.LightIntensity = intensity; - part.Shape.LightRadius = radius; - part.Shape.LightFalloff = falloff; + part.Shape.LightIntensity = Util.Clip((float)intensity, 0.0f, 1.0f); + part.Shape.LightRadius = Util.Clip((float)radius, 0.1f, 20.0f); + part.Shape.LightFalloff = Util.Clip((float)falloff, 0.01f, 2.0f); } else { @@ -1752,7 +2110,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api rgb.x = texcolor.R; rgb.y = texcolor.G; rgb.z = texcolor.B; - + return rgb; } else @@ -1765,7 +2123,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); SetTexture(m_host, texture, face); - ScriptSleep(200); + ScriptSleep(m_sleepMsOnSetTexture); } public void llSetLinkTexture(int linknumber, string texture, int face) @@ -1777,19 +2135,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api foreach (SceneObjectPart part in parts) SetTexture(part, texture, face); - ScriptSleep(200); + ScriptSleep(m_sleepMsOnSetLinkTexture); } protected void SetTexture(SceneObjectPart part, string texture, int face) { UUID textureID = new UUID(); - textureID = InventoryKey(texture, (int)AssetType.Texture); - if (textureID == UUID.Zero) - { - if (!UUID.TryParse(texture, out textureID)) - return; - } + textureID = ScriptUtils.GetAssetIdFromItemName(m_host, texture, (int)AssetType.Texture); + if (textureID == UUID.Zero) + { + if (!UUID.TryParse(texture, out textureID)) + return; + } Primitive.TextureEntry tex = part.Shape.Textures; @@ -1821,7 +2179,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); ScaleTexture(m_host, u, v, face); - ScriptSleep(200); + ScriptSleep(m_sleepMsOnScaleTexture); } protected void ScaleTexture(SceneObjectPart part, double u, double v, int face) @@ -1857,7 +2215,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); OffsetTexture(m_host, u, v, face); - ScriptSleep(200); + ScriptSleep(m_sleepMsOnOffsetTexture); } protected void OffsetTexture(SceneObjectPart part, double u, double v, int face) @@ -1893,7 +2251,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); RotateTexture(m_host, rotation, face); - ScriptSleep(200); + ScriptSleep(m_sleepMsOnRotateTexture); } protected void RotateTexture(SceneObjectPart part, double rotation, int face) @@ -1968,7 +2326,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api SetPos(m_host, pos, true); - ScriptSleep(200); + ScriptSleep(m_sleepMsOnSetPos); } /// @@ -1986,8 +2344,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND. // // This workaround is to prevent silent failure of this function. - // According to the specification on the SL Wiki, providing a position outside of the - if (pos.x < 0 || pos.x > Constants.RegionSize || pos.y < 0 || pos.y > Constants.RegionSize) + // According to the specification on the SL Wiki, providing a position outside of the + if (pos.x < 0 || pos.x > World.RegionInfo.RegionSizeX || pos.y < 0 || pos.y > World.RegionInfo.RegionSizeY) { return 0; } @@ -1997,9 +2355,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.ParentGroup.IsAttachment || // return FALSE if attachment ( pos.x < -10.0 || // return FALSE if more than 10 meters into a west-adjacent region. - pos.x > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a east-adjacent region. + pos.x > (World.RegionInfo.RegionSizeX + 10) || // return FALSE if more than 10 meters into a east-adjacent region. pos.y < -10.0 || // return FALSE if more than 10 meters into a south-adjacent region. - pos.y > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a north-adjacent region. + pos.y > (World.RegionInfo.RegionSizeY + 10) || // return FALSE if more than 10 meters into a north-adjacent region. pos.z > Constants.RegionHeight // return FALSE if altitude than 4096m ) ) @@ -2151,14 +2509,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - ScriptSleep(200); + ScriptSleep(m_sleepMsOnSetRot); } public void llSetLocalRot(LSL_Rotation rot) { m_host.AddScriptLPS(1); SetRot(m_host, rot); - ScriptSleep(200); + ScriptSleep(m_sleepMsOnSetLocalRot); } protected void SetRot(SceneObjectPart part, Quaternion rot) @@ -2195,7 +2553,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { return llGetRootRotation(); } - + m_host.AddScriptLPS(1); Quaternion q = m_host.GetWorldRotation(); return new LSL_Rotation(q.X, q.Y, q.Z, q.W); @@ -2214,23 +2572,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) q = avatar.CameraRotation; // Mouselook else - q = avatar.Rotation; // Currently infrequently updated so may be inaccurate + q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate } else q = part.ParentGroup.GroupRotation; // Likely never get here but just in case } else q = part.ParentGroup.GroupRotation; // just the group rotation - return new LSL_Rotation(q.X, q.Y, q.Z, q.W); + + return new LSL_Rotation(q); } - q = part.GetWorldRotation(); - return new LSL_Rotation(q.X, q.Y, q.Z, q.W); + + return new LSL_Rotation(part.GetWorldRotation()); } public LSL_Rotation llGetLocalRot() { m_host.AddScriptLPS(1); - return new LSL_Rotation(m_host.RotationOffset.X, m_host.RotationOffset.Y, m_host.RotationOffset.Z, m_host.RotationOffset.W); + + return new LSL_Rotation(m_host.RotationOffset); } public void llSetForce(LSL_Vector force, int local) @@ -2260,6 +2620,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return force; } + public void llSetVelocity(LSL_Vector velocity, int local) + { + m_host.AddScriptLPS(1); + + if (!m_host.ParentGroup.IsDeleted) + { + if (local != 0) + velocity *= llGetRot(); + + m_host.ParentGroup.RootPart.Velocity = velocity; + } + } + + public void llSetAngularVelocity(LSL_Vector angularVelocity, int local) + { + m_host.AddScriptLPS(1); + + if (!m_host.ParentGroup.IsDeleted) + { + if (local != 0) + angularVelocity *= llGetRot(); + + m_host.ParentGroup.RootPart.AngularVelocity = angularVelocity; + } + } + public LSL_Integer llTarget(LSL_Vector position, double range) { m_host.AddScriptLPS(1); @@ -2325,8 +2711,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llGetTorque() { m_host.AddScriptLPS(1); - Vector3 torque = m_host.ParentGroup.GetTorque(); - return new LSL_Vector(torque.X,torque.Y,torque.Z); + + return new LSL_Vector(m_host.ParentGroup.GetTorque()); } public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local) @@ -2345,26 +2731,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_host.ParentGroup.IsAttachment) { ScenePresence avatar = m_host.ParentGroup.Scene.GetScenePresence(m_host.ParentGroup.AttachedAvatar); - vel = avatar.Velocity; + vel = avatar.GetWorldVelocity(); } else { vel = m_host.Velocity; } - return new LSL_Vector(vel.X, vel.Y, vel.Z); + return new LSL_Vector(vel); } public LSL_Vector llGetAccel() { m_host.AddScriptLPS(1); - return new LSL_Vector(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z); + + return new LSL_Vector(m_host.Acceleration); } public LSL_Vector llGetOmega() { m_host.AddScriptLPS(1); - return new LSL_Vector(m_host.AngularVelocity.X, m_host.AngularVelocity.Y, m_host.AngularVelocity.Z); + + return new LSL_Vector(m_host.AngularVelocity); } public LSL_Float llGetTimeOfDay() @@ -2403,9 +2791,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llSound(string sound, double volume, int queue, int loop) { m_host.AddScriptLPS(1); - // This function has been deprecated - // see http://www.lslwiki.net/lslwiki/wakka.php?wakka=llSound - Deprecated("llSound"); + Deprecated("llSound", "Use llPlaySound instead"); } // Xantor 20080528 PlaySound updated so it accepts an objectinventory name -or- a key to a sound @@ -2417,9 +2803,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // send the sound, once, to all clients in range if (m_SoundModule != null) { - m_SoundModule.SendSound(m_host.UUID, - KeyOrName(sound, AssetType.Sound), volume, false, 0, - 0, false, false); + m_SoundModule.SendSound( + m_host.UUID, + ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), + volume, false, m_host.SoundQueueing ? (byte)SoundFlags.Queue : (byte)SoundFlags.None, + 0, false, false); } } @@ -2428,7 +2816,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); if (m_SoundModule != null) { - m_SoundModule.LoopSound(m_host.UUID, KeyOrName(sound), + m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), volume, 20, false); } } @@ -2438,7 +2826,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); if (m_SoundModule != null) { - m_SoundModule.LoopSound(m_host.UUID, KeyOrName(sound), + m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), volume, 20, true); } } @@ -2460,7 +2848,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_SoundModule != null) { m_SoundModule.SendSound(m_host.UUID, - KeyOrName(sound, AssetType.Sound), volume, false, 0, + ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0, 0, true, false); } } @@ -2472,7 +2860,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_SoundModule != null) { m_SoundModule.SendSound(m_host.UUID, - KeyOrName(sound, AssetType.Sound), volume, true, 0, 0, + ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, true, 0, 0, false, false); } } @@ -2489,8 +2877,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); if (m_SoundModule != null) - m_SoundModule.PreloadSound(m_host.UUID, KeyOrName(sound), 0); - ScriptSleep(1000); + m_SoundModule.PreloadSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), 0); + ScriptSleep(m_sleepMsOnPreloadSound); } /// @@ -2723,70 +3111,68 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return src.ToLower(); } - public LSL_Integer llGiveMoney(string destination, int amount) + public void llGiveMoney(string destination, int amount) { - m_host.AddScriptLPS(1); - - if (m_item.PermsGranter == UUID.Zero) - return 0; - - if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0) + Util.FireAndForget(x => { - LSLError("No permissions to give money"); - return 0; - } + m_host.AddScriptLPS(1); - UUID toID = new UUID(); + if (m_item.PermsGranter == UUID.Zero) + return; - if (!UUID.TryParse(destination, out toID)) - { - LSLError("Bad key in llGiveMoney"); - return 0; - } + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0) + { + Error("llGiveMoney", "No permissions to give money"); + return; + } - IMoneyModule money = World.RequestModuleInterface(); + UUID toID = new UUID(); - if (money == null) - { - NotImplemented("llGiveMoney"); - return 0; - } + if (!UUID.TryParse(destination, out toID)) + { + Error("llGiveMoney", "Bad key in llGiveMoney"); + return; + } - bool result = money.ObjectGiveMoney( - m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount); + IMoneyModule money = World.RequestModuleInterface(); - if (result) - return 1; + if (money == null) + { + NotImplemented("llGiveMoney"); + return; + } - return 0; + money.ObjectGiveMoney( + m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount); + }, null, "LSL_Api.llGiveMoney"); } public void llMakeExplosion(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset) { m_host.AddScriptLPS(1); - Deprecated("llMakeExplosion"); - ScriptSleep(100); + Deprecated("llMakeExplosion", "Use llParticleSystem instead"); + ScriptSleep(m_sleepMsOnMakeExplosion); } public void llMakeFountain(int particles, double scale, double vel, double lifetime, double arc, int bounce, string texture, LSL_Vector offset, double bounce_offset) { m_host.AddScriptLPS(1); - Deprecated("llMakeFountain"); - ScriptSleep(100); + Deprecated("llMakeFountain", "Use llParticleSystem instead"); + ScriptSleep(m_sleepMsOnMakeFountain); } public void llMakeSmoke(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset) { m_host.AddScriptLPS(1); - Deprecated("llMakeSmoke"); - ScriptSleep(100); + Deprecated("llMakeSmoke", "Use llParticleSystem instead"); + ScriptSleep(m_sleepMsOnMakeSmoke); } public void llMakeFire(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset) { m_host.AddScriptLPS(1); - Deprecated("llMakeFire"); - ScriptSleep(100); + Deprecated("llMakeFire", "Use llParticleSystem instead"); + ScriptSleep(m_sleepMsOnMakeFire); } public void llRezAtRoot(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param) @@ -2807,54 +3193,57 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (item == null) { - llSay(0, "Could not find object " + inventory); + Error("llRezAtRoot", "Can't find object '" + inventory + "'"); return; } if (item.InvType != (int)InventoryType.Object) { - llSay(0, "Unable to create requested object. Object is missing from database."); + Error("llRezAtRoot", "Can't create requested object; object is missing from database"); return; } // need the magnitude later // float velmag = (float)Util.GetMagnitude(llvel); - SceneObjectGroup new_group = World.RezObject(m_host, item, pos, rot, vel, param); + List new_groups = World.RezObject(m_host, item, pos, rot, vel, param); // If either of these are null, then there was an unknown error. - if (new_group == null) + if (new_groups == null) return; - // objects rezzed with this method are die_at_edge by default. - new_group.RootPart.SetDieAtEdge(true); + foreach (SceneObjectGroup group in new_groups) + { + // objects rezzed with this method are die_at_edge by default. + group.RootPart.SetDieAtEdge(true); - new_group.ResumeScripts(); + group.ResumeScripts(); - m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams( - "object_rez", new Object[] { - new LSL_String( - new_group.RootPart.UUID.ToString()) }, - new DetectParams[0])); + m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams( + "object_rez", new Object[] { + new LSL_String( + group.RootPart.UUID.ToString()) }, + new DetectParams[0])); - float groupmass = new_group.GetMass(); + float groupmass = group.GetMass(); - PhysicsActor pa = new_group.RootPart.PhysActor; + PhysicsActor pa = group.RootPart.PhysActor; - //Recoil. - if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero) - { - Vector3 recoil = -vel * groupmass * m_recoilScaleFactor; - if (recoil != Vector3.Zero) + //Recoil. + if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero) { - llApplyImpulse(recoil, 0); + Vector3 recoil = -vel * groupmass * m_recoilScaleFactor; + if (recoil != Vector3.Zero) + { + llApplyImpulse(recoil, 0); + } } + // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) } - // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) - }); + }, null, "LSL_Api.llRezAtRoot"); //ScriptSleep((int)((groupmass * velmag) / 10)); - ScriptSleep(100); + ScriptSleep(m_sleepMsOnRezAtRoot); } public void llRezObject(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param) @@ -2868,26 +3257,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Determine where we are looking from LSL_Vector from = llGetPos(); - // Work out the normalised vector from the source to the target - LSL_Vector delta = llVecNorm(target - from); - LSL_Vector angle = new LSL_Vector(0,0,0); - - // Calculate the yaw - // subtracting PI_BY_TWO is required to compensate for the odd SL co-ordinate system - angle.x = llAtan2(delta.z, delta.y) - ScriptBaseClass.PI_BY_TWO; + // normalized direction to target + LSL_Vector dir = llVecNorm(target - from); + // use vertical to help compute left axis + LSL_Vector up = new LSL_Vector(0.0, 0.0, 1.0); + // find normalized left axis parallel to horizon + LSL_Vector left = llVecNorm(LSL_Vector.Cross(up, dir)); + // make up orthogonal to left and dir + up = LSL_Vector.Cross(dir, left); - // Calculate pitch - angle.y = llAtan2(delta.x, llSqrt((delta.y * delta.y) + (delta.z * delta.z))); + // compute rotation based on orthogonal axes + LSL_Rotation rot = new LSL_Rotation(0.0, 0.707107, 0.0, 0.707107) * llAxes2Rot(dir, left, up); - // we need to convert from a vector describing - // the angles of rotation in radians into rotation value - LSL_Rotation rot = llEuler2Rot(angle); - // Per discussion with Melanie, for non-physical objects llLookAt appears to simply // set the rotation of the object, copy that behavior PhysicsActor pa = m_host.PhysActor; - if (strength == 0 || pa == null || !pa.IsPhysical) + if (m_host.ParentGroup.IsAttachment || strength == 0 || pa == null || !pa.IsPhysical) { llSetRot(rot); } @@ -2900,7 +3286,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llStopLookAt() { m_host.AddScriptLPS(1); -// NotImplemented("llStopLookAt"); m_host.StopLookAt(); } @@ -2917,7 +3302,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { // m_log.Info("llSleep snoozing " + sec + "s."); m_host.AddScriptLPS(1); - Thread.Sleep((int)(sec * 1000)); + + Sleep((int)(sec * 1000)); } public LSL_Float llGetMass() @@ -2950,6 +3336,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + public LSL_Float llGetMassMKS() + { + // this is what the wiki says it does! + // http://wiki.secondlife.com/wiki/LlGetMassMKS + return llGetMass() * 100.0; + } + public void llCollisionFilter(string name, string id, int accept) { m_host.AddScriptLPS(1); @@ -2958,7 +3351,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!UUID.TryParse(id, out objectID)) objectID = UUID.Zero; - + if (objectID == UUID.Zero && name == "") return; @@ -3026,7 +3419,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; if (attachmentsModule != null) - return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, false); + return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true, true); else return false; } @@ -3039,7 +3432,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void DetachFromAvatar() { - Util.FireAndForget(DetachWrapper, m_host); + Util.FireAndForget(DetachWrapper, m_host, "LSL_Api.DetachFromAvatar"); } private void DetachWrapper(object o) @@ -3083,13 +3476,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llTakeCamera(string avatar) { m_host.AddScriptLPS(1); - Deprecated("llTakeCamera"); + Deprecated("llTakeCamera", "Use llSetCameraParams instead"); } public void llReleaseCamera(string avatar) { m_host.AddScriptLPS(1); - Deprecated("llReleaseCamera"); + Deprecated("llReleaseCamera", "Use llClearCameraParams instead"); } public LSL_String llGetOwner() @@ -3112,14 +3505,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // TODO: figure out values for client, fromSession, and imSessionID // client.SendInstantMessage(m_host.UUID, fromSession, message, user, imSessionID, m_host.Name, AgentManager.InstantMessageDialog.MessageFromAgent, (uint)Util.UnixTimeSinceEpoch()); - UUID friendTransactionID = UUID.Random(); - - //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID); GridInstantMessage msg = new GridInstantMessage(); - msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid; + msg.fromAgentID = new Guid(m_host.OwnerID.ToString()); // fromAgentID.Guid; msg.toAgentID = new Guid(user); // toAgentID.Guid; - msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here + msg.imSessionID = new Guid(m_host.UUID.ToString()); // This is the item we're mucking with here // m_log.Debug("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message); // m_log.Debug("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString()); msg.timestamp = (uint)Util.UnixTimeSinceEpoch();// timestamp; @@ -3142,20 +3532,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api msg.ParentEstateID = 0; //ParentEstateID; msg.Position = new Vector3(m_host.AbsolutePosition); msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid; - msg.binaryBucket + + Vector3 pos = m_host.AbsolutePosition; + msg.binaryBucket = Util.StringToBytes256( - "{0}/{1}/{2}/{3}", - World.RegionInfo.RegionName, - (int)Math.Floor(m_host.AbsolutePosition.X), - (int)Math.Floor(m_host.AbsolutePosition.Y), - (int)Math.Floor(m_host.AbsolutePosition.Z)); + "{0}/{1}/{2}/{3}", + World.RegionInfo.RegionName, + (int)Math.Floor(pos.X), + (int)Math.Floor(pos.Y), + (int)Math.Floor(pos.Z)); if (m_TransferModule != null) { m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); } - - ScriptSleep(2000); + + ScriptSleep(m_sleepMsOnInstantMessage); } public void llEmail(string address, string subject, string message) @@ -3164,12 +3556,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface(); if (emailModule == null) { - ShoutError("llEmail: email module not configured"); + Error("llEmail", "Email module not configured"); return; } + //Restrict email destination to the avatars registered email address? + //The restriction only applies if the destination address is not local. + if (m_restrictEmail == true && address.Contains(m_internalObjectHost) == false) + { + UserAccount account = + World.UserAccountService.GetUserAccount( + World.RegionInfo.ScopeID, + m_host.OwnerID); + + if (account == null) + { + Error("llEmail", "Can't find user account for '" + m_host.OwnerID.ToString() + "'"); + return; + } + + if (String.IsNullOrEmpty(account.Email)) + { + Error("llEmail", "User account has not registered an email address."); + return; + } + + address = account.Email; + } + emailModule.SendEmail(m_host.UUID, address, subject, message); - llSleep(EMAIL_PAUSE_TIME); + ScriptSleep(m_sleepMsOnEmail); } public void llGetNextEmail(string address, string subject) @@ -3178,7 +3594,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface(); if (emailModule == null) { - ShoutError("llGetNextEmail: email module not configured"); + Error("llGetNextEmail", "Email module not configured"); return; } Email email; @@ -3263,23 +3679,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api catch (NotImplementedException) { // Currently not implemented in DotNetEngine only XEngine - NotImplemented("llMinEventDelay in DotNetEngine"); + NotImplemented("llMinEventDelay", "In DotNetEngine"); } } - /// - /// llSoundPreload is deprecated. In SL this appears to do absolutely nothing - /// and is documented to have no delay. - /// public void llSoundPreload(string sound) { m_host.AddScriptLPS(1); + Deprecated("llSoundPreload", "Use llPreloadSound instead"); } public void llRotLookAt(LSL_Rotation target, double strength, double damping) { m_host.AddScriptLPS(1); - + // Per discussion with Melanie, for non-physical objects llLookAt appears to simply // set the rotation of the object, copy that behavior PhysicsActor pa = m_host.PhysActor; @@ -3321,7 +3734,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (presence != null) { // Do NOT try to parse UUID, animations cannot be triggered by ID - UUID animID = InventoryKey(anim, (int)AssetType.Animation); + UUID animID = ScriptUtils.GetAssetIdFromItemName(m_host, anim, (int)AssetType.Animation); if (animID == UUID.Zero) presence.Animator.AddAnimation(anim, m_host.UUID); else @@ -3343,7 +3756,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (presence != null) { - UUID animID = KeyOrName(anim); + UUID animID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, anim); if (animID == UUID.Zero) presence.Animator.RemoveAnimation(anim); @@ -3371,6 +3784,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected void TargetOmega(SceneObjectPart part, LSL_Vector axis, double spinrate, double gain) { + PhysicsActor pa = part.PhysActor; + if ( ( pa == null || !pa.IsPhysical ) && gain == 0.0d ) + spinrate = 0.0d; part.UpdateAngularVelocity(axis * spinrate); } @@ -3415,11 +3831,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api implicitPerms = ScriptBaseClass.PERMISSION_TAKE_CONTROLS | ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION | ScriptBaseClass.PERMISSION_CONTROL_CAMERA | + ScriptBaseClass.PERMISSION_TRACK_CAMERA | ScriptBaseClass.PERMISSION_ATTACH; } else { - if (m_host.ParentGroup.GetSittingAvatars().Contains(agentID)) + if (m_host.ParentGroup.GetSittingAvatars().SingleOrDefault(sp => sp.UUID == agentID) != null) { // When agent is sitting, certain permissions are implicit if requested from sitting agent implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION | @@ -3451,10 +3868,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } ScenePresence presence = World.GetScenePresence(agentID); + if (presence != null) { // If permissions are being requested from an NPC and were not implicitly granted above then - // auto grant all reuqested permissions if the script is owned by the NPC or the NPCs owner + // auto grant all requested permissions if the script is owned by the NPC or the NPCs owner INPCModule npcModule = World.RequestModuleInterface(); if (npcModule != null && npcModule.IsNPC(agentID, World)) { @@ -3570,22 +3988,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llCreateLink(string target, int parent) { m_host.AddScriptLPS(1); - UUID targetID; - - if (!UUID.TryParse(target, out targetID)) - return; if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 && !m_automaticLinkPermission) { - ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!"); + Error("llCreateLink", "PERMISSION_CHANGE_LINKS permission not set"); return; } - IClientAPI client = null; - ScenePresence sp = World.GetScenePresence(m_item.PermsGranter); - if (sp != null) - client = sp.ControllingClient; + CreateLink(target, parent); + } + + public void CreateLink(string target, int parent) + { + UUID targetID; + + if (!UUID.TryParse(target, out targetID)) + return; SceneObjectPart targetPart = World.GetSceneObjectPart((UUID)targetID); @@ -3620,10 +4039,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api parentPrim.HasGroupChanged = true; parentPrim.ScheduleGroupForFullUpdate(); + IClientAPI client = null; + ScenePresence sp = World.GetScenePresence(m_host.OwnerID); + if (sp != null) + client = sp.ControllingClient; + if (client != null) parentPrim.SendPropertiesToClient(client); - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnCreateLink); } public void llBreakLink(int linknum) @@ -3633,10 +4057,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 && !m_automaticLinkPermission) { - ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!"); + Error("llBreakLink", "PERMISSION_CHANGE_LINKS permission not set"); return; } + BreakLink(linknum); + } + + public void BreakLink(int linknum) + { if (linknum < ScriptBaseClass.LINK_THIS) return; @@ -3712,6 +4141,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llBreakAllLinks() { m_host.AddScriptLPS(1); + + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 + && !m_automaticLinkPermission) + { + Error("llBreakAllLinks", "PERMISSION_CHANGE_LINKS permission not set"); + return; + } + + BreakAllLinks(); + } + + public void BreakAllLinks() + { SceneObjectGroup parentPrim = m_host.ParentGroup; if (parentPrim.AttachmentPoint != 0) return; // Fail silently if attached @@ -3732,47 +4174,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - if (linknum < 0) - { - if (linknum == ScriptBaseClass.LINK_THIS) - return m_host.UUID.ToString(); - else - return ScriptBaseClass.NULL_KEY; - } - - int actualPrimCount = m_host.ParentGroup.PrimCount; - List sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars(); - int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count; - - // Special case for a single prim. In this case the linknum is zero. However, this will not match a single - // prim that has any avatars sat upon it (in which case the root prim is link 1). - if (linknum == 0) - { - if (actualPrimCount == 1 && sittingAvatarIds.Count == 0) - return m_host.UUID.ToString(); + ISceneEntity entity = GetLinkEntity(m_host, linknum); - return ScriptBaseClass.NULL_KEY; - } - // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but - // here we must match 1 (ScriptBaseClass.LINK_ROOT). - else if (linknum == 1 && actualPrimCount == 1) - { - if (sittingAvatarIds.Count > 0) - return m_host.ParentGroup.RootPart.UUID.ToString(); - else - return ScriptBaseClass.NULL_KEY; - } - else if (linknum <= adjustedPrimCount) - { - if (linknum <= actualPrimCount) - return m_host.ParentGroup.GetLinkNumPart(linknum).UUID.ToString(); - else - return sittingAvatarIds[linknum - actualPrimCount - 1].ToString(); - } + if (entity != null) + return entity.UUID.ToString(); else - { return ScriptBaseClass.NULL_KEY; - } } /// @@ -3818,55 +4225,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - if (linknum < 0) - { - if (linknum == ScriptBaseClass.LINK_THIS) - return m_host.Name; - else - return ScriptBaseClass.NULL_KEY; - } - - int actualPrimCount = m_host.ParentGroup.PrimCount; - List sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars(); - int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count; - - // Special case for a single prim. In this case the linknum is zero. However, this will not match a single - // prim that has any avatars sat upon it (in which case the root prim is link 1). - if (linknum == 0) - { - if (actualPrimCount == 1 && sittingAvatarIds.Count == 0) - return m_host.Name; + ISceneEntity entity = GetLinkEntity(m_host, linknum); - return ScriptBaseClass.NULL_KEY; - } - // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but - // here we must match 1 (ScriptBaseClass.LINK_ROOT). - else if (linknum == 1 && actualPrimCount == 1) - { - if (sittingAvatarIds.Count > 0) - return m_host.ParentGroup.RootPart.Name; - else - return ScriptBaseClass.NULL_KEY; - } - else if (linknum <= adjustedPrimCount) - { - if (linknum <= actualPrimCount) - { - return m_host.ParentGroup.GetLinkNumPart(linknum).Name; - } - else - { - ScenePresence sp = World.GetScenePresence(sittingAvatarIds[linknum - actualPrimCount - 1]); - if (sp != null) - return sp.Name; - else - return ScriptBaseClass.NULL_KEY; - } - } + if (entity != null) + return entity.Name; else - { return ScriptBaseClass.NULL_KEY; - } } public LSL_Integer llGetInventoryNumber(int type) @@ -3931,7 +4295,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!UUID.TryParse(destination, out destId)) { - llSay(0, "Could not parse key " + destination); + Error("llGiveInventory", "Can't parse destination key '" + destination + "'"); return; } @@ -3939,8 +4303,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (item == null) { - llSay(0, String.Format("Could not find object '{0}'", inventory)); - throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory)); + Error("llGiveInventory", "Can't find inventory object '" + inventory + "'"); + return; } UUID objId = item.ItemID; @@ -3964,15 +4328,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (account == null) { - llSay(0, "Can't find destination "+destId.ToString()); - return; + GridUserInfo info = World.GridUserService.GetGridUserInfo(destId.ToString()); + if(info == null || info.Online == false) + { + Error("llGiveInventory", "Can't find destination '" + destId.ToString() + "'"); + return; + } } } // destination is an avatar - InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId); + string message; + InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId, out message); if (agentItem == null) + { + llSay(0, message); return; + } if (m_TransferModule != null) { @@ -3991,7 +4363,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); } - ScriptSleep(3000); + ScriptSleep(m_sleepMsOnGiveInventory); } } @@ -4054,87 +4426,98 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UserAccount account; UserInfoCacheEntry ce; - if (!m_userInfoCache.TryGetValue(uuid, out ce)) + + lock (m_userInfoCache) { - account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, uuid); - if (account == null) + if (!m_userInfoCache.TryGetValue(uuid, out ce)) { - m_userInfoCache[uuid] = null; // Cache negative - return UUID.Zero.ToString(); - } - + account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, uuid); + if (account == null) + { + m_userInfoCache[uuid] = null; // Cache negative + return UUID.Zero.ToString(); + } - PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() }); - if (pinfos != null && pinfos.Length > 0) - { - foreach (PresenceInfo p in pinfos) + PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() }); + if (pinfos != null && pinfos.Length > 0) { - if (p.RegionID != UUID.Zero) + foreach (PresenceInfo p in pinfos) { - pinfo = p; + if (p.RegionID != UUID.Zero) + { + pinfo = p; + } } } - } - - ce = new UserInfoCacheEntry(); - ce.time = Util.EnvironmentTickCount(); - ce.account = account; - ce.pinfo = pinfo; - } - else - { - if (ce == null) - return UUID.Zero.ToString(); - account = ce.account; - pinfo = ce.pinfo; - } + ce = new UserInfoCacheEntry(); + ce.time = Util.EnvironmentTickCount(); + ce.account = account; + ce.pinfo = pinfo; - if (Util.EnvironmentTickCount() < ce.time || (Util.EnvironmentTickCount() - ce.time) >= 20000) - { - PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() }); - if (pinfos != null && pinfos.Length > 0) + m_userInfoCache[uuid] = ce; + } + else { - foreach (PresenceInfo p in pinfos) + if (ce == null) + return UUID.Zero.ToString(); + + account = ce.account; + + if (Util.EnvironmentTickCount() < ce.time || (Util.EnvironmentTickCount() - ce.time) + >= LlRequestAgentDataCacheTimeoutMs) { - if (p.RegionID != UUID.Zero) + PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() }); + if (pinfos != null && pinfos.Length > 0) + { + foreach (PresenceInfo p in pinfos) + { + if (p.RegionID != UUID.Zero) + { + pinfo = p; + } + } + } + else { - pinfo = p; + pinfo = null; } + + ce.time = Util.EnvironmentTickCount(); + ce.pinfo = pinfo; + } + else + { + pinfo = ce.pinfo; } } - else - pinfo = null; - - ce.time = Util.EnvironmentTickCount(); - ce.pinfo = pinfo; } string reply = String.Empty; switch (data) { - case 1: // DATA_ONLINE (0|1) + case ScriptBaseClass.DATA_ONLINE: if (pinfo != null && pinfo.RegionID != UUID.Zero) reply = "1"; else reply = "0"; break; - case 2: // DATA_NAME (First Last) + case ScriptBaseClass.DATA_NAME: // (First Last) reply = account.FirstName + " " + account.LastName; break; - case 3: // DATA_BORN (YYYY-MM-DD) + case ScriptBaseClass.DATA_BORN: // (YYYY-MM-DD) DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0); born = born.AddSeconds(account.Created); reply = born.ToString("yyyy-MM-dd"); break; - case 4: // DATA_RATING (0,0,0,0,0,0) + case ScriptBaseClass.DATA_RATING: // (0,0,0,0,0,0) reply = "0,0,0,0,0,0"; break; - case 7: // DATA_USERLEVEL (integer) + case 7: // DATA_USERLEVEL (integer). This is not available in LL and so has no constant. reply = account.UserLevel.ToString(); break; - case 8: // DATA_PAYINFO (0|1|2|3) + case ScriptBaseClass.DATA_PAYINFO: // (0|1|2|3) reply = "0"; break; default: @@ -4150,7 +4533,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api AsyncCommands. DataserverPlugin.DataserverReply(rq.ToString(), reply); - ScriptSleep(100); + ScriptSleep(m_sleepMsOnRequestAgentData); return tid.ToString(); } @@ -4166,10 +4549,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, item.AssetID.ToString()); - Vector3 region = new Vector3( - World.RegionInfo.RegionLocX * Constants.RegionSize, - World.RegionInfo.RegionLocY * Constants.RegionSize, - 0); + Vector3 region = new Vector3(World.RegionInfo.WorldLocX, World.RegionInfo.WorldLocY, 0); World.AssetService.Get(item.AssetID.ToString(), this, delegate(string i, object sender, AssetBase a) @@ -4186,12 +4566,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api reply); }); - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnRequestInventoryData); return tid.ToString(); } } - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnRequestInventoryData); return String.Empty; } @@ -4211,14 +4591,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (presence != null) { // agent must be over the owners land - if (m_host.OwnerID == World.LandChannel.GetLandObject( - presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) + if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID) { World.TeleportClientHome(agentId, presence.ControllingClient); } } } - ScriptSleep(5000); + + ScriptSleep(m_sleepMsOnSetDamage); } public void llTeleportAgent(string agent, string destination, LSL_Vector targetPos, LSL_Vector targetLookAt) @@ -4238,8 +4618,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api destination = World.RegionInfo.RegionName; // agent must be over the owners land - if (m_host.OwnerID == World.LandChannel.GetLandObject( - presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) + if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID) { DoLLTeleport(presence, destination, targetPos, targetLookAt); } @@ -4259,7 +4638,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); UUID agentId = new UUID(); - ulong regionHandle = Utils.UIntsToLong((uint)global_coords.x, (uint)global_coords.y); + ulong regionHandle = Util.RegionWorldLocToHandle((uint)global_coords.x, (uint)global_coords.y); if (UUID.TryParse(agent, out agentId)) { @@ -4270,8 +4649,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (presence.GodLevel >= 200) return; // agent must be over the owners land - if (m_host.OwnerID == World.LandChannel.GetLandObject( - presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) + if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID) { World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation); } @@ -4288,7 +4666,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api private void DoLLTeleport(ScenePresence sp, string destination, Vector3 targetPos, Vector3 targetLookAt) { - UUID assetID = KeyOrName(destination); + UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, destination); // The destinaion is not an asset ID and also doesn't name a landmark. // Use it as a sim name @@ -4321,22 +4699,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID av = new UUID(); if (!UUID.TryParse(agent,out av)) { - LSLError("First parameter to llDialog needs to be a key"); + Error("llTextBox", "First parameter must be a key"); return; } if (message == string.Empty) { - ShoutError("Trying to use llTextBox with empty message."); + Error("llTextBox", "Empty message"); } else if (message.Length > 512) { - ShoutError("Trying to use llTextBox with message over 512 characters."); + Error("llTextBox", "Message more than 512 characters"); } else { dm.SendTextBoxToUser(av, message, chatChannel, m_host.Name, m_host.UUID, m_host.OwnerID); - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnTextBox); } } @@ -4353,9 +4731,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llCollisionSound(string impact_sound, double impact_volume) { m_host.AddScriptLPS(1); - + // TODO: Parameter check logic required. - m_host.CollisionSound = KeyOrName(impact_sound, AssetType.Sound); + m_host.CollisionSound = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, impact_sound, AssetType.Sound); m_host.CollisionSoundVolume = (float)impact_volume; } @@ -4475,7 +4853,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (pushrestricted) { - ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y); + ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos); // We didn't find the parcel but region is push restricted so assume it is NOT ok if (targetlandObj == null) @@ -4490,7 +4868,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else { - ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y); + ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos); if (targetlandObj == null) { // We didn't find the parcel but region isn't push restricted so assume it's ok @@ -4520,6 +4898,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } + if (pushAllowed) { float distance = (PusheePos - m_host.AbsolutePosition).Length(); @@ -4548,17 +4927,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api applied_linear_impulse *= scaling_factor; } + if (pusheeIsAvatar) { if (pusheeav != null) { - if (pusheeav.PhysicsActor != null) + PhysicsActor pa = pusheeav.PhysicsActor; + + if (pa != null) { if (local != 0) { applied_linear_impulse *= m_host.GetWorldRotation(); } - pusheeav.PhysicsActor.AddForce(applied_linear_impulse, true); + + pa.AddForce(applied_linear_impulse, true); } } } @@ -4666,6 +5049,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api s = Math.Cos(angle * 0.5); t = Math.Sin(angle * 0.5); // temp value to avoid 2 more sin() calcs + axis = LSL_Vector.Norm(axis); x = axis.x * t; y = axis.y * t; z = axis.z * t; @@ -4673,41 +5057,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return new LSL_Rotation(x,y,z,s); } - - // Xantor 29/apr/2008 - // converts a Quaternion to X,Y,Z axis rotations + /// + /// Returns the axis of rotation for a quaternion + /// + /// + /// public LSL_Vector llRot2Axis(LSL_Rotation rot) { m_host.AddScriptLPS(1); - double x,y,z; - - if (rot.s > 1) // normalization needed - { - double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y + - rot.z * rot.z + rot.s * rot.s); - rot.x /= length; - rot.y /= length; - rot.z /= length; - rot.s /= length; + if (Math.Abs(rot.s) > 1) // normalization needed + rot.Normalize(); - } - - // double angle = 2 * Math.Acos(rot.s); double s = Math.Sqrt(1 - rot.s * rot.s); if (s < 0.001) { - x = 1; - y = z = 0; + return new LSL_Vector(1, 0, 0); } else { - x = rot.x / s; // normalise axis - y = rot.y / s; - z = rot.z / s; + double invS = 1.0 / s; + if (rot.s < 0) invS = -invS; + return new LSL_Vector(rot.x * invS, rot.y * invS, rot.z * invS); } - - return new LSL_Vector(x,y,z); } @@ -4716,18 +5088,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - if (rot.s > 1) // normalization needed - { - double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y + - rot.z * rot.z + rot.s * rot.s); - - rot.x /= length; - rot.y /= length; - rot.z /= length; - rot.s /= length; - } + if (Math.Abs(rot.s) > 1) // normalization needed + rot.Normalize(); double angle = 2 * Math.Acos(rot.s); + if (angle > Math.PI) + angle = 2 * Math.PI - angle; return angle; } @@ -4907,8 +5273,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llGetCenterOfMass() { m_host.AddScriptLPS(1); - Vector3 center = m_host.GetGeometricCenter(); - return new LSL_Vector(center.X,center.Y,center.Z); + + return new LSL_Vector(m_host.GetCenterOfMass()); } public LSL_List llListSort(LSL_List src, int stride, int ascending) @@ -5043,10 +5409,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // SL spits out an empty string for types other than key & string // At the time of patching, LSL_Key is currently LSL_String, // so the OR check may be a little redundant, but it's being done - // for completion and should LSL_Key ever be implemented + // for completion and should LSL_Key ever be implemented // as it's own struct + // NOTE: 3rd case is needed because a NULL_KEY comes through as + // type 'obj' and wrongly returns "" else if (!(src.Data[index] is LSL_String || - src.Data[index] is LSL_Key)) + src.Data[index] is LSL_Key || + src.Data[index].ToString() == "00000000-0000-0000-0000-000000000000")) { return ""; } @@ -5179,8 +5548,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - return string.Join(", ", - (new List(src.Data)).ConvertAll(o => + return string.Join(", ", + (new List(src.Data)).ConvertAll(o => { return o.ToString(); }).ToArray()); @@ -5254,7 +5623,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_List llListRandomize(LSL_List src, int stride) { LSL_List result; - Random rand = new Random(); + BetterRandom rand = new BetterRandom(); int chunkk; int[] chunks; @@ -5270,24 +5639,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // If not, then return the src list. This also // traps those cases where stride > length. - if (src.Length != stride && src.Length%stride == 0) + if (src.Length != stride && src.Length % stride == 0) { chunkk = src.Length/stride; chunks = new int[chunkk]; for (int i = 0; i < chunkk; i++) + { chunks[i] = i; + } // Knuth shuffle the chunkk index - for (int i = chunkk - 1; i >= 1; i--) + for (int i = chunkk - 1; i > 0; i--) { // Elect an unrandomized chunk to swap int index = rand.Next(i + 1); - int tmp; // and swap position with first unrandomized chunk - tmp = chunks[i]; + int tmp = chunks[i]; chunks[i] = chunks[index]; chunks[index] = tmp; } @@ -5300,7 +5670,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { for (int j = 0; j < stride; j++) { - result.Add(src.Data[chunks[i]*stride+j]); + result.Add(src.Data[chunks[i] * stride + j]); } } } @@ -5417,7 +5787,72 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llGetRegionCorner() { m_host.AddScriptLPS(1); - return new LSL_Vector(World.RegionInfo.RegionLocX * Constants.RegionSize, World.RegionInfo.RegionLocY * Constants.RegionSize, 0); + return new LSL_Vector(World.RegionInfo.WorldLocX, World.RegionInfo.WorldLocY, 0); + } + + public LSL_String llGetEnv(LSL_String name) + { + m_host.AddScriptLPS(1); + if (name == "agent_limit") + { + return World.RegionInfo.RegionSettings.AgentLimit.ToString(); + } + else if (name == "dynamic_pathfinding") + { + return "0"; + } + else if (name == "estate_id") + { + return World.RegionInfo.EstateSettings.EstateID.ToString(); + } + else if (name == "estate_name") + { + return World.RegionInfo.EstateSettings.EstateName; + } + else if (name == "frame_number") + { + return World.Frame.ToString(); + } + else if (name == "region_cpu_ratio") + { + return "1"; + } + else if (name == "region_idle") + { + return "0"; + } + else if (name == "region_product_name") + { + if (World.RegionInfo.RegionType != String.Empty) + return World.RegionInfo.RegionType; + else + return ""; + } + else if (name == "region_product_sku") + { + return "OpenSim"; + } + else if (name == "region_start_time") + { + return World.UnixStartTime.ToString(); + } + else if (name == "sim_channel") + { + return "OpenSim"; + } + else if (name == "sim_version") + { + return World.GetSimulatorVersion(); + } + else if (name == "simulator_hostname") + { + IUrlModule UrlModule = World.RequestModuleInterface(); + return UrlModule.ExternalHostNameForLSL; + } + else + { + return ""; + } } /// @@ -5429,8 +5864,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index) { - LSL_List pref = null; - LSL_List suff = null; + LSL_List pref; + LSL_List suff; m_host.AddScriptLPS(1); @@ -5564,7 +5999,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSL_Float mag; if (dir.x > 0) { - mag = (Constants.RegionSize - pos.x) / dir.x; + mag = (World.RegionInfo.RegionSizeX - pos.x) / dir.x; } else { @@ -5575,7 +6010,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api edge.y = pos.y + (dir.y * mag); - if (edge.y > Constants.RegionSize || edge.y < 0) + if (edge.y > World.RegionInfo.RegionSizeY || edge.y < 0) { // Y goes out of bounds first edge.y = dir.y / Math.Abs(dir.y); @@ -5704,12 +6139,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llGetAgentLanguage(string id) { - // This should only return a value if the avatar is in the same region - //ckrinke 1-30-09 : This needs to parse the XMLRPC language field supplied - //by the client at login. Currently returning only en-us until our I18N - //effort gains momentum + // This should only return a value if the avatar is in the same region, but eh. idc. m_host.AddScriptLPS(1); - return "en-us"; + if (World.AgentPreferencesService == null) + { + Error("llGetAgentLanguage", "No AgentPreferencesService present"); + } + else + { + UUID key = new UUID(); + if (UUID.TryParse(id, out key)) + { + return new LSL_String(World.AgentPreferencesService.GetLang(key)); + } + } + return new LSL_String("en-us"); } /// /// http://wiki.secondlife.com/wiki/LlGetAgentList @@ -5739,12 +6183,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } ILandObject land; - Vector3 pos; UUID id = UUID.Zero; + if (parcel || parcelOwned) { - pos = m_host.ParentGroup.RootPart.GetWorldPosition(); - land = World.LandChannel.GetLandObject(pos.X, pos.Y); + land = World.LandChannel.GetLandObject(m_host.ParentGroup.RootPart.GetWorldPosition()); if (land == null) { id = UUID.Zero; @@ -5770,8 +6213,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (!regionWide) { - pos = ssp.AbsolutePosition; - land = World.LandChannel.GetLandObject(pos.X, pos.Y); + land = World.LandChannel.GetLandObject(ssp.AbsolutePosition); if (land != null) { if (parcelOwned && land.LandData.OwnerID == id || @@ -5800,7 +6242,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); m_host.AdjustSoundGain(volume); - ScriptSleep(100); + ScriptSleep(m_sleepMsOnAdjustSoundVolume); } public void llSetSoundRadius(double radius) @@ -5881,7 +6323,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_SoundModule != null) { m_SoundModule.TriggerSoundLimited(m_host.UUID, - KeyOrName(sound, AssetType.Sound), volume, + ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, bottom_south_west, top_north_east); } } @@ -5896,7 +6338,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (presence != null) { // agent must be over the owners land - ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition); if (land == null) return; @@ -5906,7 +6348,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - ScriptSleep(5000); + ScriptSleep(m_sleepMsOnEjectFromLand); } public LSL_Integer llOverMyLand(string id) @@ -5918,19 +6360,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ScenePresence presence = World.GetScenePresence(key); if (presence != null) // object is an avatar { - if (m_host.OwnerID - == World.LandChannel.GetLandObject( - presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) + if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID) return 1; } else // object is not an avatar { SceneObjectPart obj = World.GetSceneObjectPart(key); + if (obj != null) - if (m_host.OwnerID - == World.LandChannel.GetLandObject( - obj.AbsolutePosition.X, obj.AbsolutePosition.Y).LandData.OwnerID) + { + if (m_host.OwnerID == World.LandChannel.GetLandObject(obj.AbsolutePosition).LandData.OwnerID) return 1; + } } } @@ -5962,8 +6403,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else { - agentSize = new LSL_Vector(0.45, 0.6, avatar.Appearance.AvatarHeight); + agentSize = GetAgentSize(avatar); } + return agentSize; } @@ -5991,10 +6433,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (UUID.TryParse(id, out key)) { ScenePresence av = World.GetScenePresence(key); + List sittingAvatars = m_host.ParentGroup.GetSittingAvatars(); if (av != null) { - if (llAvatarOnSitTarget() == id) + if (sittingAvatars.Contains(av)) { // if the avatar is sitting on this object, then // we can unsit them. We don't want random scripts unsitting random people @@ -6008,8 +6451,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // if the land is group owned and the object is group owned by the same group // or // if the object is owned by a person with estate access. - - ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y); + ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition); if (parcel != null) { if (m_host.OwnerID == parcel.LandData.OwnerID || @@ -6021,14 +6463,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - } - } public LSL_Vector llGroundSlope(LSL_Vector offset) { m_host.AddScriptLPS(1); + //Get the slope normal. This gives us the equation of the plane tangent to the slope. LSL_Vector vsn = llGroundNormal(offset); @@ -6039,7 +6480,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api vsl.Normalize(); //Normalization might be overkill here - return new LSL_Vector(vsl.X, vsl.Y, vsl.Z); + vsn.x = vsl.X; + vsn.y = vsl.Y; + vsn.z = vsl.Z; + + return vsn; } public LSL_Vector llGroundNormal(LSL_Vector offset) @@ -6089,7 +6534,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api //I believe the crossproduct of two normalized vectors is a normalized vector so //this normalization may be overkill - return new LSL_Vector(vsn.X, vsn.Y, vsn.Z); + return new LSL_Vector(vsn); } public LSL_Vector llGroundContour(LSL_Vector offset) @@ -6105,11 +6550,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return m_host.ParentGroup.AttachmentPoint; } - public LSL_Integer llGetFreeMemory() + public virtual LSL_Integer llGetFreeMemory() { m_host.AddScriptLPS(1); - // Make scripts designed for LSO happy - return 16384; + // Make scripts designed for Mono happy + return 65536; } public LSL_Integer llGetFreeURLs() @@ -6176,7 +6621,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api PSYS_SRC_TARGET_KEY = 20, PSYS_SRC_OMEGA = 21, PSYS_SRC_ANGLE_BEGIN = 22, - PSYS_SRC_ANGLE_END = 23 + PSYS_SRC_ANGLE_END = 23, + PSYS_PART_BLEND_FUNC_SOURCE = 24, + PSYS_PART_BLEND_FUNC_DEST = 25, + PSYS_PART_START_GLOW = 26, + PSYS_PART_END_GLOW = 27 } internal Primitive.ParticleSystem.ParticleDataFlags ConvertUINTtoFlags(uint flags) @@ -6202,6 +6651,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ps.BurstRate = 0.1f; ps.PartMaxAge = 10.0f; ps.BurstPartCount = 1; + ps.BlendFuncSource = ScriptBaseClass.PSYS_PART_BF_SOURCE_ALPHA; + ps.BlendFuncDest = ScriptBaseClass.PSYS_PART_BF_ONE_MINUS_SOURCE_ALPHA; + ps.PartStartGlow = 0.0f; + ps.PartEndGlow = 0.0f; + return ps; } @@ -6213,17 +6667,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api foreach (SceneObjectPart part in parts) { - SetParticleSystem(part, rules); + SetParticleSystem(part, rules, "llLinkParticleSystem"); } } public void llParticleSystem(LSL_List rules) { m_host.AddScriptLPS(1); - SetParticleSystem(m_host, rules); + SetParticleSystem(m_host, rules, "llParticleSystem"); } - private void SetParticleSystem(SceneObjectPart part, LSL_List rules) + private void SetParticleSystem(SceneObjectPart part, LSL_List rules, string originFunc) { if (rules.Length == 0) { @@ -6236,65 +6690,156 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSL_Vector tempv = new LSL_Vector(); float tempf = 0; + int tmpi = 0; for (int i = 0; i < rules.Length; i += 2) { - switch (rules.GetLSLIntegerItem(i)) + int psystype; + try + { + psystype = rules.GetLSLIntegerItem(i); + } + catch (InvalidCastException) + { + Error(originFunc, string.Format("Error running particle system params index #{0}: particle system parameter type must be integer", i)); + return; + } + switch (psystype) { case (int)ScriptBaseClass.PSYS_PART_FLAGS: - prules.PartDataFlags = (Primitive.ParticleSystem.ParticleDataFlags)(uint)rules.GetLSLIntegerItem(i + 1); + try + { + prules.PartDataFlags = (Primitive.ParticleSystem.ParticleDataFlags)(uint)rules.GetLSLIntegerItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_PART_FLAGS: arg #{0} - parameter 1 must be integer", i + 1)); + return; + } break; case (int)ScriptBaseClass.PSYS_PART_START_COLOR: - tempv = rules.GetVector3Item(i + 1); + try + { + tempv = rules.GetVector3Item(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_PART_START_COLOR: arg #{0} - parameter 1 must be vector", i + 1)); + return; + } prules.PartStartColor.R = (float)tempv.x; prules.PartStartColor.G = (float)tempv.y; prules.PartStartColor.B = (float)tempv.z; break; case (int)ScriptBaseClass.PSYS_PART_START_ALPHA: - tempf = (float)rules.GetLSLFloatItem(i + 1); + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_PART_START_ALPHA: arg #{0} - parameter 1 must be float", i + 1)); + return; + } prules.PartStartColor.A = tempf; break; case (int)ScriptBaseClass.PSYS_PART_END_COLOR: - tempv = rules.GetVector3Item(i + 1); + try + { + tempv = rules.GetVector3Item(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_PART_END_COLOR: arg #{0} - parameter 1 must be vector", i + 1)); + return; + } prules.PartEndColor.R = (float)tempv.x; prules.PartEndColor.G = (float)tempv.y; prules.PartEndColor.B = (float)tempv.z; break; case (int)ScriptBaseClass.PSYS_PART_END_ALPHA: - tempf = (float)rules.GetLSLFloatItem(i + 1); + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_PART_END_ALPHA: arg #{0} - parameter 1 must be float", i + 1)); + return; + } prules.PartEndColor.A = tempf; break; case (int)ScriptBaseClass.PSYS_PART_START_SCALE: - tempv = rules.GetVector3Item(i + 1); - prules.PartStartScaleX = (float)tempv.x; - prules.PartStartScaleY = (float)tempv.y; + try + { + tempv = rules.GetVector3Item(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_PART_START_SCALE: arg #{0} - parameter 1 must be vector", i + 1)); + return; + } + prules.PartStartScaleX = validParticleScale((float)tempv.x); + prules.PartStartScaleY = validParticleScale((float)tempv.y); break; case (int)ScriptBaseClass.PSYS_PART_END_SCALE: - tempv = rules.GetVector3Item(i + 1); - prules.PartEndScaleX = (float)tempv.x; - prules.PartEndScaleY = (float)tempv.y; + try + { + tempv = rules.GetVector3Item(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_PART_END_SCALE: arg #{0} - parameter 1 must be vector", i + 1)); + return; + } + prules.PartEndScaleX = validParticleScale((float)tempv.x); + prules.PartEndScaleY = validParticleScale((float)tempv.y); break; case (int)ScriptBaseClass.PSYS_PART_MAX_AGE: - tempf = (float)rules.GetLSLFloatItem(i + 1); + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_PART_MAX_AGE: arg #{0} - parameter 1 must be float", i + 1)); + return; + } prules.PartMaxAge = tempf; break; case (int)ScriptBaseClass.PSYS_SRC_ACCEL: - tempv = rules.GetVector3Item(i + 1); + try + { + tempv = rules.GetVector3Item(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_ACCEL: arg #{0} - parameter 1 must be vector", i + 1)); + return; + } prules.PartAcceleration.X = (float)tempv.x; prules.PartAcceleration.Y = (float)tempv.y; prules.PartAcceleration.Z = (float)tempv.z; break; case (int)ScriptBaseClass.PSYS_SRC_PATTERN: - int tmpi = (int)rules.GetLSLIntegerItem(i + 1); + try + { + tmpi = (int)rules.GetLSLIntegerItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_PATTERN: arg #{0} - parameter 1 must be integer", i + 1)); + return; + } prules.Pattern = (Primitive.ParticleSystem.SourcePattern)tmpi; break; @@ -6303,47 +6848,171 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // client tells the difference between the two by looking at the 0x02 bit in // the PartFlags variable. case (int)ScriptBaseClass.PSYS_SRC_INNERANGLE: - tempf = (float)rules.GetLSLFloatItem(i + 1); + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_INNERANGLE: arg #{0} - parameter 1 must be float", i + 1)); + return; + } prules.InnerAngle = (float)tempf; prules.PartFlags &= 0xFFFFFFFD; // Make sure new angle format is off. break; case (int)ScriptBaseClass.PSYS_SRC_OUTERANGLE: - tempf = (float)rules.GetLSLFloatItem(i + 1); - prules.OuterAngle = (float)tempf; - prules.PartFlags &= 0xFFFFFFFD; // Make sure new angle format is off. - break; + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_OUTERANGLE: arg #{0} - parameter 1 must be float", i + 1)); + return; + } + prules.OuterAngle = (float)tempf; + prules.PartFlags &= 0xFFFFFFFD; // Make sure new angle format is off. + break; + + case (int)ScriptBaseClass.PSYS_PART_BLEND_FUNC_SOURCE: + try + { + tmpi = (int)rules.GetLSLIntegerItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_PART_BLEND_FUNC_SOURCE: arg #{0} - parameter 1 must be integer", i + 1)); + return; + } + prules.BlendFuncSource = (byte)tmpi; + break; + + case (int)ScriptBaseClass.PSYS_PART_BLEND_FUNC_DEST: + try + { + tmpi = (int)rules.GetLSLIntegerItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_PART_BLEND_FUNC_DEST: arg #{0} - parameter 1 must be integer", i + 1)); + return; + } + prules.BlendFuncDest = (byte)tmpi; + break; + + case (int)ScriptBaseClass.PSYS_PART_START_GLOW: + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_PART_START_GLOW: arg #{0} - parameter 1 must be float", i + 1)); + return; + } + prules.PartStartGlow = (float)tempf; + break; + + case (int)ScriptBaseClass.PSYS_PART_END_GLOW: + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_PART_END_GLOW: arg #{0} - parameter 1 must be float", i + 1)); + return; + } + prules.PartEndGlow = (float)tempf; + break; case (int)ScriptBaseClass.PSYS_SRC_TEXTURE: - prules.Texture = KeyOrName(rules.GetLSLStringItem(i + 1)); + try + { + prules.Texture = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, rules.GetLSLStringItem(i + 1)); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_TEXTURE: arg #{0} - parameter 1 must be string or key", i + 1)); + return; + } break; case (int)ScriptBaseClass.PSYS_SRC_BURST_RATE: - tempf = (float)rules.GetLSLFloatItem(i + 1); + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_BURST_RATE: arg #{0} - parameter 1 must be float", i + 1)); + return; + } prules.BurstRate = (float)tempf; break; case (int)ScriptBaseClass.PSYS_SRC_BURST_PART_COUNT: - prules.BurstPartCount = (byte)(int)rules.GetLSLIntegerItem(i + 1); + try + { + prules.BurstPartCount = (byte)(int)rules.GetLSLIntegerItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_BURST_PART_COUNT: arg #{0} - parameter 1 must be integer", i + 1)); + return; + } break; case (int)ScriptBaseClass.PSYS_SRC_BURST_RADIUS: - tempf = (float)rules.GetLSLFloatItem(i + 1); + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_BURST_RADIUS: arg #{0} - parameter 1 must be float", i + 1)); + return; + } prules.BurstRadius = (float)tempf; break; case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MIN: - tempf = (float)rules.GetLSLFloatItem(i + 1); + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_BURST_SPEED_MIN: arg #{0} - parameter 1 must be float", i + 1)); + return; + } prules.BurstSpeedMin = (float)tempf; break; case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MAX: - tempf = (float)rules.GetLSLFloatItem(i + 1); + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_BURST_SPEED_MAX: arg #{0} - parameter 1 must be float", i + 1)); + return; + } prules.BurstSpeedMax = (float)tempf; break; case (int)ScriptBaseClass.PSYS_SRC_MAX_AGE: - tempf = (float)rules.GetLSLFloatItem(i + 1); + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_MAX_AGE: arg #{0} - parameter 1 must be float", i + 1)); + return; + } prules.MaxAge = (float)tempf; break; @@ -6361,20 +7030,44 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case (int)ScriptBaseClass.PSYS_SRC_OMEGA: // AL: This is an assumption, since it is the only thing that would match. - tempv = rules.GetVector3Item(i + 1); + try + { + tempv = rules.GetVector3Item(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_OMEGA: arg #{0} - parameter 1 must be vector", i + 1)); + return; + } prules.AngularVelocity.X = (float)tempv.x; prules.AngularVelocity.Y = (float)tempv.y; prules.AngularVelocity.Z = (float)tempv.z; break; case (int)ScriptBaseClass.PSYS_SRC_ANGLE_BEGIN: - tempf = (float)rules.GetLSLFloatItem(i + 1); + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_ANGLE_BEGIN: arg #{0} - parameter 1 must be float", i + 1)); + return; + } prules.InnerAngle = (float)tempf; prules.PartFlags |= 0x02; // Set new angle format. break; case (int)ScriptBaseClass.PSYS_SRC_ANGLE_END: - tempf = (float)rules.GetLSLFloatItem(i + 1); + try + { + tempf = (float)rules.GetLSLFloatItem(i + 1); + } + catch (InvalidCastException) + { + Error(originFunc, string.Format("Error running rule PSYS_SRC_ANGLE_END: arg #{0} - parameter 1 must be float", i + 1)); + return; + } prules.OuterAngle = (float)tempf; prules.PartFlags |= 0x02; // Set new angle format. break; @@ -6389,6 +7082,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api part.SendFullUpdateToAllClients(); } + private float validParticleScale(float value) + { + if (value > 4.0f) return 4.0f; + return value; + } + public void llGroundRepel(double height, int water, double tau) { m_host.AddScriptLPS(1); @@ -6460,7 +7159,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.OwnerID, m_host.Name, destID, (byte)InstantMessageDialog.TaskInventoryOffered, false, string.Format("'{0}'", category), -// We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06 +// We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06 // false, string.Format("'{0}' ( http://slurl.com/secondlife/{1}/{2}/{3}/{4} )", category, World.Name, (int)pos.X, (int)pos.Y, (int)pos.Z), folderID, false, pos, bucket, false); @@ -6575,12 +7274,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llAvatarOnLinkSitTarget(int linknum) { m_host.AddScriptLPS(1); - if(linknum == ScriptBaseClass.LINK_SET || + if(linknum == ScriptBaseClass.LINK_SET || linknum == ScriptBaseClass.LINK_ALL_CHILDREN || linknum == ScriptBaseClass.LINK_ALL_OTHERS) return UUID.Zero.ToString(); - + List parts = GetLinkParts(linknum); - if (parts.Count == 0) return UUID.Zero.ToString(); + if (parts.Count == 0) return UUID.Zero.ToString(); return parts[0].SitTargetAvatar.ToString(); } @@ -6589,7 +7288,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); UUID key; - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); + if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) { int expires = 0; @@ -6623,7 +7323,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land); } } - ScriptSleep(100); + ScriptSleep(m_sleepMsOnAddToLandPassList); } public void llSetTouchText(string text) @@ -6642,12 +7342,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); m_host.SetCameraEyeOffset(offset); + + if (m_host.ParentGroup.RootPart.GetCameraEyeOffset() == Vector3.Zero) + m_host.ParentGroup.RootPart.SetCameraEyeOffset(offset); } public void llSetCameraAtOffset(LSL_Vector offset) { m_host.AddScriptLPS(1); m_host.SetCameraAtOffset(offset); + + if (m_host.ParentGroup.RootPart.GetCameraAtOffset() == Vector3.Zero) + m_host.ParentGroup.RootPart.SetCameraAtOffset(offset); } public void llSetLinkCamera(LSL_Integer link, LSL_Vector eye, LSL_Vector at) @@ -6722,17 +7428,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID av = new UUID(); if (!UUID.TryParse(avatar,out av)) { - LSLError("First parameter to llDialog needs to be a key"); + Error("llDialog", "First parameter must be a key"); return; } if (buttons.Length < 1) { - LSLError("No less than 1 button can be shown"); + Error("llDialog", "At least 1 button must be shown"); return; } if (buttons.Length > 12) { - LSLError("No more than 12 buttons can be shown"); + Error("llDialog", "No more than 12 buttons can be shown"); return; } string[] buts = new string[buttons.Length]; @@ -6740,12 +7446,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (buttons.Data[i].ToString() == String.Empty) { - LSLError("button label cannot be blank"); + Error("llDialog", "Button label cannot be blank"); return; } if (buttons.Data[i].ToString().Length > 24) { - LSLError("button label cannot be longer than 24 characters"); + Error("llDialog", "Button label cannot be longer than 24 characters"); return; } buts[i] = buttons.Data[i].ToString(); @@ -6755,7 +7461,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api av, m_host.Name, m_host.UUID, m_host.OwnerID, message, new UUID("00000000-0000-2222-3333-100000001000"), chat_channel, buts); - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnDialog); } public void llVolumeDetect(int detect) @@ -6766,16 +7472,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.ParentGroup.ScriptSetVolumeDetect(detect != 0); } - /// - /// This is a depecated function so this just replicates the result of - /// invoking it in SL - /// public void llRemoteLoadScript(string target, string name, int running, int start_param) { m_host.AddScriptLPS(1); - // Report an error as it does in SL - ShoutError("Deprecated. Please use llRemoteLoadScriptPin instead."); - ScriptSleep(3000); + Deprecated("llRemoteLoadScript", "Use llRemoteLoadScriptPin instead"); + ScriptSleep(m_sleepMsOnRemoteLoadScript); } public void llSetRemoteScriptAccessPin(int pin) @@ -6792,7 +7493,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!UUID.TryParse(target, out destId)) { - llSay(0, "Could not parse key " + target); + Error("llRemoteLoadScriptPin", "Can't parse key '" + target + "'"); return; } @@ -6808,7 +7509,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // make sure the object is a script if (item == null || item.Type != 10) { - llSay(0, "Could not find script " + name); + Error("llRemoteLoadScriptPin", "Can't find script '" + name + "'"); return; } @@ -6816,14 +7517,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World.RezScriptFromPrim(item.ItemID, m_host, destId, pin, running, start_param); // this will cause the delay even if the script pin or permissions were wrong - seems ok - ScriptSleep(3000); + ScriptSleep(m_sleepMsOnRemoteLoadScriptPin); } public void llOpenRemoteDataChannel() { m_host.AddScriptLPS(1); IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); - if (xmlrpcMod.IsEnabled()) + if (xmlrpcMod != null && xmlrpcMod.IsEnabled()) { UUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_host.LocalId, m_item.ItemID, UUID.Zero); IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface(); @@ -6847,14 +7548,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams("remote_data", resobj, new DetectParams[0])); } - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnOpenRemoteDataChannel); } public LSL_String llSendRemoteData(string channel, string dest, int idata, string sdata) { m_host.AddScriptLPS(1); IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); - ScriptSleep(3000); + ScriptSleep(m_sleepMsOnSendRemoteData); + if (xmlrpcMod == null) + return ""; return (xmlrpcMod.SendRemoteData(m_host.LocalId, m_item.ItemID, channel, dest, idata, sdata)).ToString(); } @@ -6862,8 +7565,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); - xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata); - ScriptSleep(3000); + if (xmlrpcMod != null) + xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata); + ScriptSleep(m_sleepMsOnRemoteDataReply); } public void llCloseRemoteDataChannel(string channel) @@ -6877,8 +7581,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); - xmlrpcMod.CloseXMLRPCChannel((UUID)channel); - ScriptSleep(1000); + if (xmlrpcMod != null) + xmlrpcMod.CloseXMLRPCChannel((UUID)channel); + ScriptSleep(m_sleepMsOnCloseRemoteDataChannel); } public LSL_String llMD5String(string src, int nonce) @@ -6924,13 +7629,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { cut.y = 1f; } - if (cut.y - cut.x < 0.05f) + if (cut.y - cut.x < 0.02f) { - cut.x = cut.y - 0.05f; + cut.x = cut.y - 0.02f; if (cut.x < 0.0f) { cut.x = 0.0f; - cut.y = 0.05f; + cut.y = 0.02f; } } shapeBlock.ProfileBegin = (ushort)(50000 * cut.x); @@ -6952,12 +7657,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api hollow = 0.70f; } } - // Otherwise, hollow is limited to 95%. + // Otherwise, hollow is limited to 99%. else { - if (hollow > 0.95f) + if (hollow > 0.99f) { - hollow = 0.95f; + hollow = 0.99f; } } shapeBlock.ProfileHollow = (ushort)(50000 * hollow); @@ -7081,9 +7786,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { dimple.y = 1f; } - if (dimple.y - cut.x < 0.05f) + if (dimple.y - dimple.x < 0.02f) { - dimple.x = cut.y - 0.05f; + dimple.x = dimple.y - 0.02f; + if (dimple.x < 0.0f) + { + dimple.x = 0.0f; + dimple.y = 0.02f; + } } shapeBlock.ProfileBegin = (ushort)(50000 * dimple.x); shapeBlock.ProfileEnd = (ushort)(50000 * (1 - dimple.y)); @@ -7104,17 +7814,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api shapeBlock.PathBegin = shapeBlock.ProfileBegin; shapeBlock.PathEnd = shapeBlock.ProfileEnd; - if (holesize.x < 0.05f) + if (holesize.x < 0.01f) { - holesize.x = 0.05f; + holesize.x = 0.01f; } if (holesize.x > 1f) { holesize.x = 1f; } - if (holesize.y < 0.05f) + if (holesize.y < 0.01f) { - holesize.y = 0.05f; + holesize.y = 0.01f; } if (holesize.y > 0.5f) { @@ -7160,13 +7870,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { profilecut.y = 1f; } - if (profilecut.y - profilecut.x < 0.05f) + if (profilecut.y - profilecut.x < 0.02f) { - profilecut.x = profilecut.y - 0.05f; + profilecut.x = profilecut.y - 0.02f; if (profilecut.x < 0.0f) { profilecut.x = 0.0f; - profilecut.y = 0.05f; + profilecut.y = 0.02f; } } shapeBlock.ProfileBegin = (ushort)(50000 * profilecut.x); @@ -7234,9 +7944,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID sculptId; if (!UUID.TryParse(map, out sculptId)) - { - sculptId = InventoryKey(map, (int)AssetType.Texture); - } + sculptId = ScriptUtils.GetAssetIdFromItemName(m_host, map, (int)AssetType.Texture); if (sculptId == UUID.Zero) return; @@ -7266,45 +7974,205 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - setLinkPrimParams(ScriptBaseClass.LINK_THIS, rules, "llSetPrimitiveParams"); + SetLinkPrimParams(ScriptBaseClass.LINK_THIS, rules, "llSetPrimitiveParams"); - ScriptSleep(200); + ScriptSleep(m_sleepMsOnSetPrimitiveParams); } public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules) { m_host.AddScriptLPS(1); - setLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParams"); + SetLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParams"); - ScriptSleep(200); + ScriptSleep(m_sleepMsOnSetLinkPrimitiveParams); } public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules) { m_host.AddScriptLPS(1); - setLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParamsFast"); + SetLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParamsFast"); } - protected void setLinkPrimParams(int linknumber, LSL_List rules, string originFunc) + protected void SetLinkPrimParams(int linknumber, LSL_List rules, string originFunc) { - List parts = GetLinkParts(linknumber); + SetEntityParams(GetLinkEntities(linknumber), rules, originFunc); + } - LSL_List remaining = null; + protected void SetEntityParams(List entities, LSL_List rules, string originFunc) + { + LSL_List remaining = new LSL_List(); uint rulesParsed = 0; - foreach (SceneObjectPart part in parts) - remaining = SetPrimParams(part, rules, originFunc, ref rulesParsed); + foreach (ISceneEntity entity in entities) + { + if (entity is SceneObjectPart) + remaining = SetPrimParams((SceneObjectPart)entity, rules, originFunc, ref rulesParsed); + else + remaining = SetAgentParams((ScenePresence)entity, rules, originFunc, ref rulesParsed); + } - while (remaining != null && remaining.Length > 2) + while (remaining.Length > 2) { - linknumber = remaining.GetLSLIntegerItem(0); + int linknumber; + try + { + linknumber = remaining.GetLSLIntegerItem(0); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_LINK_TARGET: parameter 2 must be integer", rulesParsed)); + return; + } + rules = remaining.GetSublist(1, -1); - parts = GetLinkParts(linknumber); + entities = GetLinkEntities(linknumber); - foreach (SceneObjectPart part in parts) - remaining = SetPrimParams(part, rules, originFunc, ref rulesParsed); + foreach (ISceneEntity entity in entities) + { + if (entity is SceneObjectPart) + remaining = SetPrimParams((SceneObjectPart)entity, rules, originFunc, ref rulesParsed); + else + remaining = SetAgentParams((ScenePresence)entity, rules, originFunc, ref rulesParsed); + } + } + } + + public void llSetKeyframedMotion(LSL_List frames, LSL_List options) + { + SceneObjectGroup group = m_host.ParentGroup; + + if (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical) + return; + if (group.IsAttachment) + return; + + if (frames.Data.Length > 0) // We are getting a new motion + { + if (group.RootPart.KeyframeMotion != null) + group.RootPart.KeyframeMotion.Delete(); + group.RootPart.KeyframeMotion = null; + + int idx = 0; + + KeyframeMotion.PlayMode mode = KeyframeMotion.PlayMode.Forward; + KeyframeMotion.DataFormat data = KeyframeMotion.DataFormat.Translation | KeyframeMotion.DataFormat.Rotation; + + while (idx < options.Data.Length) + { + int option = (int)options.GetLSLIntegerItem(idx++); + int remain = options.Data.Length - idx; + + switch (option) + { + case ScriptBaseClass.KFM_MODE: + if (remain < 1) + break; + int modeval = (int)options.GetLSLIntegerItem(idx++); + switch(modeval) + { + case ScriptBaseClass.KFM_FORWARD: + mode = KeyframeMotion.PlayMode.Forward; + break; + case ScriptBaseClass.KFM_REVERSE: + mode = KeyframeMotion.PlayMode.Reverse; + break; + case ScriptBaseClass.KFM_LOOP: + mode = KeyframeMotion.PlayMode.Loop; + break; + case ScriptBaseClass.KFM_PING_PONG: + mode = KeyframeMotion.PlayMode.PingPong; + break; + } + break; + case ScriptBaseClass.KFM_DATA: + if (remain < 1) + break; + int dataval = (int)options.GetLSLIntegerItem(idx++); + data = (KeyframeMotion.DataFormat)dataval; + break; + } + } + + group.RootPart.KeyframeMotion = new KeyframeMotion(group, mode, data); + + idx = 0; + + int elemLength = 2; + if (data == (KeyframeMotion.DataFormat.Translation | KeyframeMotion.DataFormat.Rotation)) + elemLength = 3; + + List keyframes = new List(); + while (idx < frames.Data.Length) + { + int remain = frames.Data.Length - idx; + + if (remain < elemLength) + break; + + KeyframeMotion.Keyframe frame = new KeyframeMotion.Keyframe(); + frame.Position = null; + frame.Rotation = null; + + if ((data & KeyframeMotion.DataFormat.Translation) != 0) + { + LSL_Types.Vector3 tempv = frames.GetVector3Item(idx++); + frame.Position = new Vector3((float)tempv.x, (float)tempv.y, (float)tempv.z); + } + if ((data & KeyframeMotion.DataFormat.Rotation) != 0) + { + LSL_Types.Quaternion tempq = frames.GetQuaternionItem(idx++); + Quaternion q = new Quaternion((float)tempq.x, (float)tempq.y, (float)tempq.z, (float)tempq.s); + q.Normalize(); + frame.Rotation = q; + } + + float tempf = (float)frames.GetLSLFloatItem(idx++); + frame.TimeMS = (int)(tempf * 1000.0f); + + keyframes.Add(frame); + } + + group.RootPart.KeyframeMotion.SetKeyframes(keyframes.ToArray()); + group.RootPart.KeyframeMotion.Start(); + } + else + { + if (group.RootPart.KeyframeMotion == null) + return; + + if (options.Data.Length == 0) + { + group.RootPart.KeyframeMotion.Stop(); + return; + } + + int idx = 0; + + while (idx < options.Data.Length) + { + int option = (int)options.GetLSLIntegerItem(idx++); + + switch (option) + { + case ScriptBaseClass.KFM_COMMAND: + int cmd = (int)options.GetLSLIntegerItem(idx++); + switch (cmd) + { + case ScriptBaseClass.KFM_CMD_PLAY: + group.RootPart.KeyframeMotion.Start(); + break; + case ScriptBaseClass.KFM_CMD_STOP: + group.RootPart.KeyframeMotion.Stop(); + break; + case ScriptBaseClass.KFM_CMD_PAUSE: + group.RootPart.KeyframeMotion.Pause(); + break; + } + break; + } + } } } @@ -7331,29 +8199,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api switch (code) { - case (int)ScriptBaseClass.PRIM_POSITION: - case (int)ScriptBaseClass.PRIM_POS_LOCAL: + case ScriptBaseClass.PRIM_POSITION: + case ScriptBaseClass.PRIM_POS_LOCAL: if (remain < 1) - return null; + return new LSL_List(); - v=rules.GetVector3Item(idx++); + try + { + v = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + if(code == ScriptBaseClass.PRIM_POSITION) + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POSITION: arg #{1} - parameter 1 must be vector", rulesParsed, idx - idxStart - 1)); + else + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POS_LOCAL: arg #{1} - parameter 1 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } positionChanged = true; currentPosition = GetSetPosTarget(part, v, currentPosition); break; - case (int)ScriptBaseClass.PRIM_SIZE: + case ScriptBaseClass.PRIM_SIZE: if (remain < 1) - return null; + return new LSL_List(); v=rules.GetVector3Item(idx++); SetScale(part, v); break; - case (int)ScriptBaseClass.PRIM_ROTATION: + case ScriptBaseClass.PRIM_ROTATION: if (remain < 1) - return null; - - LSL_Rotation q = rules.GetQuaternionItem(idx++); + return new LSL_List(); + LSL_Rotation q; + try + { + q = rules.GetQuaternionItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ROTATION: arg #{1} - parameter 1 must be rotation", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } // try to let this work as in SL... if (part.ParentID == 0) { @@ -7369,11 +8256,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; - case (int)ScriptBaseClass.PRIM_TYPE: + case ScriptBaseClass.PRIM_TYPE: if (remain < 3) - return null; + return new LSL_List(); - code = (int)rules.GetLSLIntegerItem(idx++); + try + { + code = (int)rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE: arg #{1} - parameter 1 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } remain = rules.Length - idx; float hollow; @@ -7388,140 +8283,625 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api switch (code) { - case (int)ScriptBaseClass.PRIM_TYPE_BOX: + case ScriptBaseClass.PRIM_TYPE_BOX: if (remain < 6) - return null; - - face = (int)rules.GetLSLIntegerItem(idx++); - v = rules.GetVector3Item(idx++); // cut - hollow = (float)rules.GetLSLFloatItem(idx++); - twist = rules.GetVector3Item(idx++); - taper_b = rules.GetVector3Item(idx++); - topshear = rules.GetVector3Item(idx++); + return new LSL_List(); + + try + { + face = (int)rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_BOX: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + v = rules.GetVector3Item(idx++); // cut + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_BOX: arg #{1} - parameter 3 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + hollow = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_BOX: arg #{1} - parameter 4 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + twist = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_BOX: arg #{1} - parameter 5 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + taper_b = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_BOX: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + topshear = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_BOX: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, (byte)ProfileShape.Square, (byte)Extrusion.Straight); break; - case (int)ScriptBaseClass.PRIM_TYPE_CYLINDER: + case ScriptBaseClass.PRIM_TYPE_CYLINDER: if (remain < 6) - return null; - - face = (int)rules.GetLSLIntegerItem(idx++); // holeshape - v = rules.GetVector3Item(idx++); // cut - hollow = (float)rules.GetLSLFloatItem(idx++); - twist = rules.GetVector3Item(idx++); - taper_b = rules.GetVector3Item(idx++); - topshear = rules.GetVector3Item(idx++); + return new LSL_List(); + + try + { + face = (int)rules.GetLSLIntegerItem(idx++); // holeshape + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_CYLINDER: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + v = rules.GetVector3Item(idx++); // cut + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_CYLINDER: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + hollow = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_CYLINDER: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + twist = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_CYLINDER: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + taper_b = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_CYLINDER: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + topshear = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_CYLINDER: arg #{1} - parameter 8 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, (byte)ProfileShape.Circle, (byte)Extrusion.Straight); break; - case (int)ScriptBaseClass.PRIM_TYPE_PRISM: + case ScriptBaseClass.PRIM_TYPE_PRISM: if (remain < 6) - return null; - - face = (int)rules.GetLSLIntegerItem(idx++); // holeshape - v = rules.GetVector3Item(idx++); //cut - hollow = (float)rules.GetLSLFloatItem(idx++); - twist = rules.GetVector3Item(idx++); - taper_b = rules.GetVector3Item(idx++); - topshear = rules.GetVector3Item(idx++); + return new LSL_List(); + + try + { + face = (int)rules.GetLSLIntegerItem(idx++); // holeshape + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_PRISM: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + v = rules.GetVector3Item(idx++); //cut + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_PRISM: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + hollow = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_PRISM: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + twist = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_PRISM: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + taper_b = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_PRISM: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + topshear = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_PRISM: arg #{1} - parameter 8 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, (byte)ProfileShape.EquilateralTriangle, (byte)Extrusion.Straight); break; - case (int)ScriptBaseClass.PRIM_TYPE_SPHERE: + case ScriptBaseClass.PRIM_TYPE_SPHERE: if (remain < 5) - return null; - - face = (int)rules.GetLSLIntegerItem(idx++); // holeshape - v = rules.GetVector3Item(idx++); // cut - hollow = (float)rules.GetLSLFloatItem(idx++); - twist = rules.GetVector3Item(idx++); - taper_b = rules.GetVector3Item(idx++); // dimple + return new LSL_List(); + + try + { + face = (int)rules.GetLSLIntegerItem(idx++); // holeshape + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_SPHERE: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + v = rules.GetVector3Item(idx++); // cut + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_SPHERE: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + hollow = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_SPHERE: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + twist = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_SPHERE: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + taper_b = rules.GetVector3Item(idx++); // dimple + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_SPHERE: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, (byte)ProfileShape.HalfCircle, (byte)Extrusion.Curve1); break; - case (int)ScriptBaseClass.PRIM_TYPE_TORUS: + case ScriptBaseClass.PRIM_TYPE_TORUS: if (remain < 11) - return null; - - face = (int)rules.GetLSLIntegerItem(idx++); // holeshape - v = rules.GetVector3Item(idx++); //cut - hollow = (float)rules.GetLSLFloatItem(idx++); - twist = rules.GetVector3Item(idx++); - holesize = rules.GetVector3Item(idx++); - topshear = rules.GetVector3Item(idx++); - profilecut = rules.GetVector3Item(idx++); - taper_b = rules.GetVector3Item(idx++); // taper_a - revolutions = (float)rules.GetLSLFloatItem(idx++); - radiusoffset = (float)rules.GetLSLFloatItem(idx++); - skew = (float)rules.GetLSLFloatItem(idx++); + return new LSL_List(); + + try + { + face = (int)rules.GetLSLIntegerItem(idx++); // holeshape + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + v = rules.GetVector3Item(idx++); //cut + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + hollow = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + twist = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + holesize = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + topshear = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 8 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + profilecut = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 9 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + taper_b = rules.GetVector3Item(idx++); // taper_a + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 10 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + revolutions = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 11 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + radiusoffset = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 12 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + skew = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 13 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, revolutions, radiusoffset, skew, (byte)ProfileShape.Circle, (byte)Extrusion.Curve1); break; - case (int)ScriptBaseClass.PRIM_TYPE_TUBE: + case ScriptBaseClass.PRIM_TYPE_TUBE: if (remain < 11) - return null; - - face = (int)rules.GetLSLIntegerItem(idx++); // holeshape - v = rules.GetVector3Item(idx++); //cut - hollow = (float)rules.GetLSLFloatItem(idx++); - twist = rules.GetVector3Item(idx++); - holesize = rules.GetVector3Item(idx++); - topshear = rules.GetVector3Item(idx++); - profilecut = rules.GetVector3Item(idx++); - taper_b = rules.GetVector3Item(idx++); // taper_a - revolutions = (float)rules.GetLSLFloatItem(idx++); - radiusoffset = (float)rules.GetLSLFloatItem(idx++); - skew = (float)rules.GetLSLFloatItem(idx++); + return new LSL_List(); + + try + { + face = (int)rules.GetLSLIntegerItem(idx++); // holeshape + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + v = rules.GetVector3Item(idx++); //cut + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + hollow = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + twist = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + holesize = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + topshear = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 8 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + profilecut = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 9 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + taper_b = rules.GetVector3Item(idx++); // taper_a + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 10 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + revolutions = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 11 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + radiusoffset = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 12 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + skew = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 13 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, revolutions, radiusoffset, skew, (byte)ProfileShape.Square, (byte)Extrusion.Curve1); break; - case (int)ScriptBaseClass.PRIM_TYPE_RING: + case ScriptBaseClass.PRIM_TYPE_RING: if (remain < 11) - return null; - - face = (int)rules.GetLSLIntegerItem(idx++); // holeshape - v = rules.GetVector3Item(idx++); //cut - hollow = (float)rules.GetLSLFloatItem(idx++); - twist = rules.GetVector3Item(idx++); - holesize = rules.GetVector3Item(idx++); - topshear = rules.GetVector3Item(idx++); - profilecut = rules.GetVector3Item(idx++); - taper_b = rules.GetVector3Item(idx++); // taper_a - revolutions = (float)rules.GetLSLFloatItem(idx++); - radiusoffset = (float)rules.GetLSLFloatItem(idx++); - skew = (float)rules.GetLSLFloatItem(idx++); + return new LSL_List(); + + try + { + face = (int)rules.GetLSLIntegerItem(idx++); // holeshape + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + v = rules.GetVector3Item(idx++); //cut + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + hollow = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + twist = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + holesize = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + topshear = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 8 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + profilecut = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 9 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + taper_b = rules.GetVector3Item(idx++); // taper_a + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 10 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + revolutions = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 11 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + radiusoffset = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 12 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + skew = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 13 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, revolutions, radiusoffset, skew, (byte)ProfileShape.EquilateralTriangle, (byte)Extrusion.Curve1); break; - case (int)ScriptBaseClass.PRIM_TYPE_SCULPT: + case ScriptBaseClass.PRIM_TYPE_SCULPT: if (remain < 2) - return null; + return new LSL_List(); string map = rules.Data[idx++].ToString(); - face = (int)rules.GetLSLIntegerItem(idx++); // type + try + { + face = (int)rules.GetLSLIntegerItem(idx++); // type + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_SCULPT: arg #{1} - parameter 4 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } SetPrimitiveShapeParams(part, map, face, (byte)Extrusion.Curve1); break; } break; - case (int)ScriptBaseClass.PRIM_TEXTURE: + case ScriptBaseClass.PRIM_TEXTURE: if (remain < 5) - return null; + return new LSL_List(); face=(int)rules.GetLSLIntegerItem(idx++); - string tex=rules.Data[idx++].ToString(); - LSL_Vector repeats=rules.GetVector3Item(idx++); - LSL_Vector offsets=rules.GetVector3Item(idx++); - double rotation=(double)rules.GetLSLFloatItem(idx++); + string tex; + LSL_Vector repeats; + LSL_Vector offsets; + double rotation; + + tex = rules.Data[idx++].ToString(); + try + { + repeats = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXTURE: arg #{1} - parameter 3 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + offsets = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXTURE: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + rotation = (double)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXTURE: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } SetTexture(part, tex, face); ScaleTexture(part, repeats.x, repeats.y, face); @@ -7530,180 +8910,525 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; - case (int)ScriptBaseClass.PRIM_COLOR: + case ScriptBaseClass.PRIM_COLOR: if (remain < 3) - return null; + return new LSL_List(); - face=(int)rules.GetLSLIntegerItem(idx++); - LSL_Vector color=rules.GetVector3Item(idx++); - double alpha=(double)rules.GetLSLFloatItem(idx++); + LSL_Vector color; + double alpha; + + try + { + face = (int)rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_COLOR: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + color = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_COLOR: arg #{1} - parameter 3 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + alpha = (double)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_COLOR: arg #{1} - parameter 4 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } part.SetFaceColorAlpha(face, color, alpha); break; - case (int)ScriptBaseClass.PRIM_FLEXIBLE: + case ScriptBaseClass.PRIM_FLEXIBLE: if (remain < 7) - return null; - - bool flexi = rules.GetLSLIntegerItem(idx++); - int softness = rules.GetLSLIntegerItem(idx++); - float gravity = (float)rules.GetLSLFloatItem(idx++); - float friction = (float)rules.GetLSLFloatItem(idx++); - float wind = (float)rules.GetLSLFloatItem(idx++); - float tension = (float)rules.GetLSLFloatItem(idx++); - LSL_Vector force = rules.GetVector3Item(idx++); + return new LSL_List(); + bool flexi; + int softness; + float gravity; + float friction; + float wind; + float tension; + LSL_Vector force; + + try + { + flexi = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + softness = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + gravity = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 4 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + friction = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + wind = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 6 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + tension = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 7 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + force = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 8 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } SetFlexi(part, flexi, softness, gravity, friction, wind, tension, force); break; - case (int)ScriptBaseClass.PRIM_POINT_LIGHT: + case ScriptBaseClass.PRIM_POINT_LIGHT: if (remain < 5) - return null; - bool light = rules.GetLSLIntegerItem(idx++); - LSL_Vector lightcolor = rules.GetVector3Item(idx++); - float intensity = (float)rules.GetLSLFloatItem(idx++); - float radius = (float)rules.GetLSLFloatItem(idx++); - float falloff = (float)rules.GetLSLFloatItem(idx++); - - SetPointLight(part, light, lightcolor, intensity, radius, falloff); - - break; - - case (int)ScriptBaseClass.PRIM_GLOW: - if (remain < 2) - return null; - face = rules.GetLSLIntegerItem(idx++); - float glow = (float)rules.GetLSLFloatItem(idx++); - - SetGlow(part, face, glow); - - break; - - case (int)ScriptBaseClass.PRIM_BUMP_SHINY: - if (remain < 3) - return null; - face = (int)rules.GetLSLIntegerItem(idx++); - int shiny = (int)rules.GetLSLIntegerItem(idx++); - Bumpiness bump = (Bumpiness)(int)rules.GetLSLIntegerItem(idx++); - + return new LSL_List(); + bool light; + LSL_Vector lightcolor; + float intensity; + float radius; + float falloff; + + try + { + light = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POINT_LIGHT: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + lightcolor = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POINT_LIGHT: arg #{1} - parameter 3 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + intensity = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POINT_LIGHT: arg #{1} - parameter 4 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + radius = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POINT_LIGHT: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + falloff = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POINT_LIGHT: arg #{1} - parameter 6 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + SetPointLight(part, light, lightcolor, intensity, radius, falloff); + + break; + + case ScriptBaseClass.PRIM_GLOW: + if (remain < 2) + return new LSL_List(); + + float glow; + + try + { + face = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_GLOW: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + glow = (float)rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_GLOW: arg #{1} - parameter 3 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + SetGlow(part, face, glow); + + break; + + case ScriptBaseClass.PRIM_BUMP_SHINY: + if (remain < 3) + return new LSL_List(); + + int shiny; + Bumpiness bump; + + try + { + face = (int)rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_BUMP_SHINY: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + shiny = (int)rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_BUMP_SHINY: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + bump = (Bumpiness)(int)rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_BUMP_SHINY: arg #{1} - parameter 4 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + SetShiny(part, face, shiny, bump); break; - case (int)ScriptBaseClass.PRIM_FULLBRIGHT: - if (remain < 2) - return null; - face = rules.GetLSLIntegerItem(idx++); - bool st = rules.GetLSLIntegerItem(idx++); - SetFullBright(part, face , st); - break; + case ScriptBaseClass.PRIM_FULLBRIGHT: + if (remain < 2) + return new LSL_List(); + bool st; + + try + { + face = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FULLBRIGHT: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + st = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FULLBRIGHT: arg #{1} - parameter 4 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + SetFullBright(part, face , st); + break; + + case ScriptBaseClass.PRIM_MATERIAL: + if (remain < 1) + return new LSL_List(); + int mat; + + try + { + mat = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_MATERIAL: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + if (mat < 0 || mat > 7) + return new LSL_List(); - case (int)ScriptBaseClass.PRIM_MATERIAL: - if (remain < 1) - return null; - int mat = rules.GetLSLIntegerItem(idx++); - if (mat < 0 || mat > 7) - return null; + part.Material = Convert.ToByte(mat); + break; - part.Material = Convert.ToByte(mat); - break; + case ScriptBaseClass.PRIM_PHANTOM: + if (remain < 1) + return new LSL_List(); - case (int)ScriptBaseClass.PRIM_PHANTOM: - if (remain < 1) - return null; + string ph = rules.Data[idx++].ToString(); + part.ParentGroup.ScriptSetPhantomStatus(ph.Equals("1")); - string ph = rules.Data[idx++].ToString(); - m_host.ParentGroup.ScriptSetPhantomStatus(ph.Equals("1")); + break; - break; + case ScriptBaseClass.PRIM_PHYSICS: + if (remain < 1) + return new LSL_List(); + string phy = rules.Data[idx++].ToString(); + part.ScriptSetPhysicsStatus(phy.Equals("1")); + break; - case (int)ScriptBaseClass.PRIM_PHYSICS: + case ScriptBaseClass.PRIM_PHYSICS_SHAPE_TYPE: if (remain < 1) - return null; - string phy = rules.Data[idx++].ToString(); - bool physics; + return new LSL_List(); - if (phy.Equals("1")) - physics = true; - else - physics = false; + int shape_type; + + try + { + shape_type = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_PHYSICS_SHAPE_TYPE: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } - part.ScriptSetPhysicsStatus(physics); - break; + ExtraPhysicsData physdata = new ExtraPhysicsData(); + physdata.Density = part.Density; + physdata.Bounce = part.Restitution; + physdata.GravitationModifier = part.GravityModifier; + physdata.PhysShapeType = (PhysShapeType)shape_type; - case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ: + part.UpdateExtraPhysics(physdata); + + break; + + case ScriptBaseClass.PRIM_TEMP_ON_REZ: if (remain < 1) - return null; + return new LSL_List(); string temp = rules.Data[idx++].ToString(); - m_host.ParentGroup.ScriptSetTemporaryStatus(temp.Equals("1")); + part.ParentGroup.ScriptSetTemporaryStatus(temp.Equals("1")); break; - case (int)ScriptBaseClass.PRIM_TEXGEN: + case ScriptBaseClass.PRIM_TEXGEN: if (remain < 2) - return null; + return new LSL_List(); //face,type - face = rules.GetLSLIntegerItem(idx++); - int style = rules.GetLSLIntegerItem(idx++); + int style; + + try + { + face = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXGEN: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + style = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXGEN: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } SetTexGen(part, face, style); break; - case (int)ScriptBaseClass.PRIM_TEXT: + case ScriptBaseClass.PRIM_TEXT: if (remain < 3) - return null; - string primText = rules.GetLSLStringItem(idx++); - LSL_Vector primTextColor = rules.GetVector3Item(idx++); - LSL_Float primTextAlpha = rules.GetLSLFloatItem(idx++); + return new LSL_List(); + string primText; + LSL_Vector primTextColor; + LSL_Float primTextAlpha; + + try + { + primText = rules.GetLSLStringItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXT: arg #{1} - parameter 2 must be string", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + primTextColor = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXT: arg #{1} - parameter 3 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + primTextAlpha = rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXT: arg #{1} - parameter 4 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } Vector3 av3 = Util.Clip(primTextColor, 0.0f, 1.0f); part.SetText(primText, av3, Util.Clip((float)primTextAlpha, 0.0f, 1.0f)); break; - case (int)ScriptBaseClass.PRIM_NAME: + + case ScriptBaseClass.PRIM_NAME: if (remain < 1) - return null; - string primName = rules.GetLSLStringItem(idx++); - part.Name = primName; + return new LSL_List(); + try + { + string primName = rules.GetLSLStringItem(idx++); + part.Name = primName; + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NAME: arg #{1} - parameter 2 must be string", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } break; - case (int)ScriptBaseClass.PRIM_DESC: + case ScriptBaseClass.PRIM_DESC: if (remain < 1) - return null; - string primDesc = rules.GetLSLStringItem(idx++); - part.Description = primDesc; + return new LSL_List(); + try + { + string primDesc = rules.GetLSLStringItem(idx++); + part.Description = primDesc; + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_DESC: arg #{1} - parameter 2 must be string", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } break; - case (int)ScriptBaseClass.PRIM_ROT_LOCAL: + case ScriptBaseClass.PRIM_ROT_LOCAL: if (remain < 1) - return null; - SetRot(part, rules.GetQuaternionItem(idx++)); + return new LSL_List(); + LSL_Rotation rot; + try + { + rot = rules.GetQuaternionItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ROT_LOCAL: arg #{1} - parameter 2 must be rotation", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + SetRot(part, rot); break; - case (int)ScriptBaseClass.PRIM_OMEGA: + + case ScriptBaseClass.PRIM_OMEGA: if (remain < 3) - return null; - LSL_Vector axis = rules.GetVector3Item(idx++); - LSL_Float spinrate = rules.GetLSLFloatItem(idx++); - LSL_Float gain = rules.GetLSLFloatItem(idx++); + return new LSL_List(); + LSL_Vector axis; + LSL_Float spinrate; + LSL_Float gain; + + try + { + axis = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_OMEGA: arg #{1} - parameter 2 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + spinrate = rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_OMEGA: arg #{1} - parameter 3 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + try + { + gain = rules.GetLSLFloatItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_OMEGA: arg #{1} - parameter 4 must be float", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } TargetOmega(part, axis, (double)spinrate, (double)gain); break; - case (int)ScriptBaseClass.PRIM_SLICE: + + case ScriptBaseClass.PRIM_SLICE: if (remain < 1) - return null; - LSL_Vector slice = rules.GetVector3Item(idx++); + return new LSL_List(); + LSL_Vector slice; + try + { + slice = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SLICE: arg #{1} - parameter 2 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } part.UpdateSlice((float)slice.x, (float)slice.y); break; - case (int)ScriptBaseClass.PRIM_LINK_TARGET: + + case ScriptBaseClass.PRIM_LINK_TARGET: if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless. - return null; + return new LSL_List(); return rules.GetSublist(idx, -1); + + default: + Error(originFunc, string.Format("Error running rule #{0}: arg #{1} - unsupported parameter", rulesParsed, idx - idxStart)); + return new LSL_List(); } } } catch (InvalidCastException e) { - ShoutError(string.Format( - "{0} error running rule #{1}: arg #{2} ", - originFunc, rulesParsed, idx - idxStart) + e.Message); + Error(originFunc, string.Format("Error running rule #{0}: arg #{1} - ", rulesParsed, idx - idxStart) + e.Message); } finally { @@ -7723,7 +9448,118 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - return null; + + return new LSL_List(); + } + + protected LSL_List SetAgentParams(ScenePresence sp, LSL_List rules, string originFunc, ref uint rulesParsed) + { + int idx = 0; + int idxStart = 0; + + try + { + while (idx < rules.Length) + { + ++rulesParsed; + int code = rules.GetLSLIntegerItem(idx++); + + int remain = rules.Length - idx; + idxStart = idx; + + switch (code) + { + case ScriptBaseClass.PRIM_POSITION: + case ScriptBaseClass.PRIM_POS_LOCAL: + if (remain < 1) + return new LSL_List(); + + try + { + sp.OffsetPosition = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + if (code == ScriptBaseClass.PRIM_POSITION) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POSITION: arg #{1} - parameter 2 must be vector", rulesParsed, idx - idxStart - 1)); + } + else + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POS_LOCAL: arg #{1} - parameter 2 must be vector", rulesParsed, idx - idxStart - 1)); + } + return new LSL_List(); + } + break; + + case ScriptBaseClass.PRIM_ROTATION: + if (remain < 1) + return new LSL_List(); + + Quaternion inRot; + + try + { + inRot = rules.GetQuaternionItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ROTATION: arg #{1} - parameter 2 must be rotation", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + SceneObjectPart parentPart = sp.ParentPart; + + if (parentPart != null) + sp.Rotation = m_host.GetWorldRotation() * inRot; + + break; + + case ScriptBaseClass.PRIM_ROT_LOCAL: + if (remain < 1) + return new LSL_List(); + + try + { + sp.Rotation = rules.GetQuaternionItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ROT_LOCAL: arg #{1} - parameter 2 must be rotation", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + break; + + case ScriptBaseClass.PRIM_TYPE: + Error(originFunc, "PRIM_TYPE disallowed on agent"); + return new LSL_List(); + + case ScriptBaseClass.PRIM_OMEGA: + Error(originFunc, "PRIM_OMEGA disallowed on agent"); + return new LSL_List(); + + case ScriptBaseClass.PRIM_LINK_TARGET: + if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless. + return new LSL_List(); + + return rules.GetSublist(idx, -1); + + default: + Error(originFunc, + string.Format("Error running rule #{0} on agent: arg #{1} - disallowed on agent", rulesParsed, idx - idxStart)); + return new LSL_List(); + } + } + } + catch (InvalidCastException e) + { + Error( + originFunc, + string.Format("Error running rule #{0}: arg #{1} - ", rulesParsed, idx - idxStart) + e.Message); + } + + return new LSL_List(); } public LSL_String llStringToBase64(string str) @@ -7731,14 +9567,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); try { - byte[] encData_byte = new byte[str.Length]; + byte[] encData_byte; encData_byte = Util.UTF8.GetBytes(str); string encodedData = Convert.ToBase64String(encData_byte); return encodedData; } - catch (Exception e) + catch { - throw new Exception("Error in base64Encode" + e.Message); + Error("llBase64ToString", "Error encoding string"); + return String.Empty; } } @@ -7747,26 +9584,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); try { - return Util.Base64ToString(str); + byte[] b = Convert.FromBase64String(str); + return Encoding.UTF8.GetString(b); } - catch (Exception e) + catch { - throw new Exception("Error in base64Decode" + e.Message); + Error("llBase64ToString", "Error decoding string"); + return String.Empty; } } public LSL_String llXorBase64Strings(string str1, string str2) { m_host.AddScriptLPS(1); - Deprecated("llXorBase64Strings"); - ScriptSleep(300); + Deprecated("llXorBase64Strings", "Use llXorBase64 instead"); + ScriptSleep(m_sleepMsOnXorBase64Strings); return String.Empty; } public void llRemoteDataSetRegion() { m_host.AddScriptLPS(1); - Deprecated("llRemoteDataSetRegion"); + Deprecated("llRemoteDataSetRegion", "Use llOpenRemoteDataChannel instead"); } public LSL_Float llLog10(double val) @@ -7800,21 +9639,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (land.LandData.OwnerID != m_host.OwnerID) return; land.SetMusicUrl(url); - ScriptSleep(2000); + ScriptSleep(m_sleepMsOnSetParcelMusicURL); } public LSL_String llGetParcelMusicURL() { m_host.AddScriptLPS(1); - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (land.LandData.OwnerID != m_host.OwnerID) return String.Empty; @@ -7825,8 +9664,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llGetRootPosition() { m_host.AddScriptLPS(1); - return new LSL_Vector(m_host.ParentGroup.AbsolutePosition.X, m_host.ParentGroup.AbsolutePosition.Y, - m_host.ParentGroup.AbsolutePosition.Z); + + return new LSL_Vector(m_host.ParentGroup.AbsolutePosition); } /// @@ -7849,13 +9688,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) q = avatar.CameraRotation; // Mouselook else - q = avatar.Rotation; // Currently infrequently updated so may be inaccurate + q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate else q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case } else q = m_host.ParentGroup.GroupRotation; // just the group rotation - return new LSL_Rotation(q.X, q.Y, q.Z, q.W); + + return new LSL_Rotation(q); } public LSL_String llGetObjectDesc() @@ -7881,145 +9721,676 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ"); } - public LSL_Integer llGetNumberOfPrims() - { - m_host.AddScriptLPS(1); + public LSL_Integer llGetNumberOfPrims() + { + m_host.AddScriptLPS(1); + + return m_host.ParentGroup.PrimCount + m_host.ParentGroup.GetSittingAvatarsCount(); + } + + /// + /// Full implementation of llGetBoundingBox according to SL 2015-04-15. + /// http://wiki.secondlife.com/wiki/LlGetBoundingBox + /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetBoundingBox + /// Returns local bounding box of avatar without attachments + /// if target is non-seated avatar or prim/mesh in avatar attachment. + /// Returns local bounding box of object including seated avatars + /// if target is seated avatar or prim/mesh in object. + /// Uses meshing of prims for high accuracy + /// or less accurate box models for speed. + /// + public LSL_List llGetBoundingBox(string obj) + { + m_host.AddScriptLPS(1); + + // Get target avatar if non-seated avatar or attachment, or prim and object + UUID objID = UUID.Zero; + UUID.TryParse(obj, out objID); + ScenePresence agent = World.GetScenePresence(objID); + if (agent != null) + { + if (agent.ParentPart != null) + { + objID = agent.ParentPart.UUID; + agent = null; + } + } + SceneObjectGroup group = null; + SceneObjectPart target = World.GetSceneObjectPart(objID); + if (target != null) + { + group = target.ParentGroup; + if (group.IsAttachment) { + objID = group.AttachedAvatar; + agent = World.GetScenePresence(objID); + group = null; + target = null; + } + } + + // Initialize but break if no target + LSL_List result = new LSL_List(); + int groupCount = 0; + int partCount = 0; + int vertexCount = 0; + if (target == null && agent == null) + { + result.Add(new LSL_Vector()); + result.Add(new LSL_Vector()); + if (m_addStatsInGetBoundingBox) + result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); + return result; + } + Vector3 minPosition = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); + Vector3 maxPosition = new Vector3(float.MinValue, float.MinValue, float.MinValue); + + // Try to get a mesher + IRendering primMesher = null; + List renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); + if (renderers.Count > 0) + primMesher = RenderingLoader.LoadRenderer(renderers[0]); + + // Get bounding box of just avatar, seated or not + if (agent != null) + { + bool hasParent = false; + Vector3 lower; + Vector3 upper; + BoundingBoxOfScenePresence(agent, out lower, out upper); + Vector3 offset = Vector3.Zero; + + // Since local bounding box unrotated and untilted, keep it simple + AddBoundingBoxOfSimpleBox(lower, upper, offset, agent.Rotation, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + partCount++; + groupCount++; + + // Return lower and upper bounding box corners + result.Add(new LSL_Vector(minPosition)); + result.Add(new LSL_Vector(maxPosition)); + if (m_addStatsInGetBoundingBox) + result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); + return result; + } + // Get bounding box of object including seated avatars + else if (group != null) + { + // Merge bounding boxes of all parts (prims and mesh) + foreach (SceneObjectPart part in group.Parts) + { + bool hasParent = (!part.IsRoot); + // When requested or if no mesher, keep it simple + if (m_useSimpleBoxesInGetBoundingBox || primMesher == null) + { + AddBoundingBoxOfSimpleBox(part.Scale * -0.5f, part.Scale * 0.5f, part.OffsetPosition, part.RotationOffset, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + } + // Do the full mounty + else + { + Primitive omvPrim = part.Shape.ToOmvPrimitive(part.OffsetPosition, part.RotationOffset); + byte[] sculptAsset = null; + if (omvPrim.Sculpt != null) + sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); + + // When part is mesh + // Quirk: Only imports as incompletely populated faceted mesh object, so needs an own handler. + if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) + { + AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); + FacetedMesh mesh = null; + FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out mesh); + meshAsset = null; + if (mesh != null) + { + AddBoundingBoxOfFacetedMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + mesh = null; + } + } + + // When part is sculpt + // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. + else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) + { + IJ2KDecoder imgDecoder = World.RequestModuleInterface(); + if (imgDecoder != null) + { + Image sculpt = imgDecoder.DecodeToImage(sculptAsset); + if (sculpt != null) + { + SimpleMesh mesh = primMesher.GenerateSimpleSculptMesh(omvPrim, (Bitmap)sculpt, DetailLevel.Medium); + sculpt.Dispose(); + if (mesh != null) + { + AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + mesh = null; + } + } + } + } + + // When part is prim + else if (omvPrim.Sculpt == null) + { + SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); + if (mesh != null) + { + AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + mesh = null; + } + } + + // When all else fails, try fallback to simple box + else + { + AddBoundingBoxOfSimpleBox(part.Scale * -0.5f, part.Scale * 0.5f, part.OffsetPosition, part.RotationOffset, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + } + } + partCount++; + } + } + + // Merge bounding boxes of seated avatars + foreach (ScenePresence sp in group.GetSittingAvatars()) + { + Vector3 lower; + Vector3 upper; + BoundingBoxOfScenePresence(sp, out lower, out upper); + Vector3 offset = sp.OffsetPosition; + + bool hasParent = true; + // When requested or if no mesher, keep it simple + if (m_useSimpleBoxesInGetBoundingBox || primMesher == null) + { + AddBoundingBoxOfSimpleBox(lower, upper, offset, sp.Rotation, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + } + // Do the full mounty + else + { + // Prim shapes don't do center offsets, so add it here. + offset = offset + (lower + upper) * 0.5f * sp.Rotation; + Primitive omvPrim = MakeOpenMetaversePrim(upper - lower, offset, sp.Rotation, ScriptBaseClass.PRIM_TYPE_SPHERE); + SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); + AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + mesh = null; + } + partCount++; + } + + groupCount++; + + // Return lower and upper bounding box corners + result.Add(new LSL_Vector(minPosition)); + result.Add(new LSL_Vector(maxPosition)); + if (m_addStatsInGetBoundingBox) + result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); + + primMesher = null; + return result; + } + + /// + /// Helper to calculate bounding box of an avatar. + /// + private void BoundingBoxOfScenePresence(ScenePresence sp, out Vector3 lower, out Vector3 upper) + { + // Adjust from OS model + // avatar height = visual height - 0.2, bounding box height = visual height + // to SL model + // avatar height = visual height, bounding box height = visual height + 0.2 + float height = sp.Appearance.AvatarHeight + m_avatarHeightCorrection; + + // According to avatar bounding box in SL 2015-04-18: + // standing = <-0.275,-0.35,-0.1-0.5*h> : <0.275,0.35,0.1+0.5*h> + // groundsitting = <-0.3875,-0.5,-0.05-0.375*h> : <0.3875,0.5,0.5> + // sitting = <-0.5875,-0.35,-0.35-0.375*h> : <0.1875,0.35,-0.25+0.25*h> + + // When avatar is sitting + if (sp.ParentPart != null) + { + lower = new Vector3(m_lABB1SitX0, m_lABB1SitY0, m_lABB1SitZ0 + m_lABB1SitZ1 * height); + upper = new Vector3(m_lABB2SitX0, m_lABB2SitY0, m_lABB2SitZ0 + m_lABB2SitZ1 * height); + } + // When avatar is groundsitting + else if (sp.Animator.Animations.ImplicitDefaultAnimation.AnimID == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"]) + { + lower = new Vector3(m_lABB1GrsX0, m_lABB1GrsY0, m_lABB1GrsZ0 + m_lABB1GrsZ1 * height); + upper = new Vector3(m_lABB2GrsX0, m_lABB2GrsY0, m_lABB2GrsZ0 + m_lABB2GrsZ1 * height); + } + // When avatar is standing or flying + else + { + lower = new Vector3(m_lABB1StdX0, m_lABB1StdY0, m_lABB1StdZ0 + m_lABB1StdZ1 * height); + upper = new Vector3(m_lABB2StdX0, m_lABB2StdY0, m_lABB2StdZ0 + m_lABB2StdZ1 * height); + } + } + + /// + /// Helper to approximate a part with a simple box. + /// + private void AddBoundingBoxOfSimpleBox(Vector3 corner1, Vector3 corner2, Vector3 offset, Quaternion rotation, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) + { + // Parse the 8 box corners + for (int i = 0; i < 8; i++) + { + // Calculate each box corner + Vector3 position = corner1; + if ((i & 1) != 0) + position.X = corner2.X; + if ((i & 2) != 0) + position.Y = corner2.Y; + if ((i & 4) != 0) + position.Z = corner2.Z; + // Rotate part unless part is root + if (hasParent) + position = position * rotation; + position = position + offset; + // Adjust lower and upper bounding box corners if needed + lower = Vector3.Min(lower, position); + upper = Vector3.Max(upper, position); + count++; + } + } + + /// + /// Helper to parse a meshed prim and needed especially + /// for accuracy with tortured prims and sculpts. + /// + private void AddBoundingBoxOfSimpleMesh(SimpleMesh mesh, Primitive prim, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) + { + // Quirk: A meshed box contains 10 instead of the 8 necessary vertices. + if (mesh != null) + { + // Parse each vertex in mesh + foreach (Vertex vertex in mesh.Vertices) + { + Vector3 position = vertex.Position; + position = position * prim.Scale; + // Rotate part unless part is root + if (hasParent) + position = position * prim.Rotation; + position = position + prim.Position; + // Adjust lower and upper bounding box corners if needed + lower = Vector3.Min(lower, position); + upper = Vector3.Max(upper, position); + count++; + } + } + } + + /// + /// Helper to parse mesh because no method exists + /// to parse mesh assets to SimpleMesh. + /// + private void AddBoundingBoxOfFacetedMesh(FacetedMesh mesh, Primitive prim, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) + { + if (mesh != null) + { + // Parse each face in mesh + // since vertex array isn't populated. + // This parses each unique vertex 3-6 times. + foreach (Face face in mesh.Faces) + { + // Parse each vertex in face + foreach (Vertex vertex in face.Vertices) + { + Vector3 position = vertex.Position; + position = position * prim.Scale; + // Rotate part unless part is root + if (hasParent) + position = position * prim.Rotation; + position = position + prim.Position; + // Adjust lower and upper bounding box corners if needed + lower = Vector3.Min(lower, position); + upper = Vector3.Max(upper, position); + count++; + } + } + } + } + + /// + /// Helper to make up an OpenMetaverse prim + /// needed to create mesh from parts. + /// + private Primitive MakeOpenMetaversePrim(Vector3 scale, Vector3 position, Quaternion rotation, int primType) + { + // Initialize and set common parameters + Primitive prim = new OpenMetaverse.Primitive(); + prim.Scale = scale; + prim.Position = position; + prim.Rotation = rotation; + prim.PrimData.PathShearX = 0.0f; + prim.PrimData.PathShearY = 0.0f; + prim.PrimData.PathBegin = 0.0f; + prim.PrimData.PathEnd = 1.0f; + prim.PrimData.PathScaleX = 1.0f; + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.PathTaperX = 0.0f; + prim.PrimData.PathTaperY = 0.0f; + prim.PrimData.PathTwistBegin = 0.0f; + prim.PrimData.PathTwist = 0.0f; + prim.PrimData.ProfileBegin = 0.0f; + prim.PrimData.ProfileEnd = 1.0f; + prim.PrimData.ProfileHollow = 0.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)1; + prim.PrimData.ProfileHole = (HoleType)0; + prim.PrimData.PathCurve = (PathCurve)16; + prim.PrimData.PathRadiusOffset = 0.0f; + prim.PrimData.PathRevolutions = 1.0f; + prim.PrimData.PathSkew = 0.0f; + prim.PrimData.PCode = OpenMetaverse.PCode.Prim; + prim.PrimData.State = (byte)0; + + // Set type specific parameters + switch (primType) + { + // Set specific parameters for box + case ScriptBaseClass.PRIM_TYPE_BOX: + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)1; + prim.PrimData.PathCurve = (PathCurve)16; + break; + // Set specific parameters for cylinder + case ScriptBaseClass.PRIM_TYPE_CYLINDER: + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)0; + prim.PrimData.PathCurve = (PathCurve)16; + break; + // Set specific parameters for prism + case ScriptBaseClass.PRIM_TYPE_PRISM: + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)3; + prim.PrimData.PathCurve = (PathCurve)16; + break; + // Set specific parameters for sphere + case ScriptBaseClass.PRIM_TYPE_SPHERE: + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)5; + prim.PrimData.PathCurve = (PathCurve)32; + break; + // Set specific parameters for torus + case ScriptBaseClass.PRIM_TYPE_TORUS: + prim.PrimData.PathScaleY = 0.5f; + prim.PrimData.ProfileCurve = (ProfileCurve)0; + prim.PrimData.PathCurve = (PathCurve)32; + break; + // Set specific parameters for tube + case ScriptBaseClass.PRIM_TYPE_TUBE: + prim.PrimData.PathScaleY = 0.5f; + prim.PrimData.ProfileCurve = (ProfileCurve)1; + prim.PrimData.PathCurve = (PathCurve)32; + break; + // Set specific parameters for ring + case ScriptBaseClass.PRIM_TYPE_RING: + prim.PrimData.PathScaleY = 0.5f; + prim.PrimData.ProfileCurve = (ProfileCurve)3; + prim.PrimData.PathCurve = (PathCurve)32; + break; + // Set specific parameters for sculpt + case ScriptBaseClass.PRIM_TYPE_SCULPT: + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)5; + prim.PrimData.PathCurve = (PathCurve)32; + break; + // Default to specific parameters for box + default: + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)1; + prim.PrimData.PathCurve = (PathCurve)16; + break; + } + + return prim; + } + + /// + /// Implementation of llGetGeometricCenter according to SL 2015-04-30. + /// http://wiki.secondlife.com/wiki/LlGetGeometricCenter + /// Returns the average position offset of all linked parts, + /// including the root prim and seated avatars, + /// relative to the root prim in local coordinates. + /// + public LSL_Vector llGetGeometricCenter() + { + // Subtract whatever position the root prim has to make it zero + Vector3 offset = m_host.ParentGroup.RootPart.OffsetPosition * -1.0f; + + // Add all prim/part position offsets + foreach (SceneObjectPart part in m_host.ParentGroup.Parts) + offset = offset + part.OffsetPosition; + // Add all avatar/scene presence position offsets + foreach (ScenePresence sp in m_host.ParentGroup.GetSittingAvatars()) + offset = offset + sp.OffsetPosition; + + // Calculate and return the average offset + offset = offset / (float)(m_host.ParentGroup.PrimCount + m_host.ParentGroup.GetSittingAvatarsCount()); + return new LSL_Vector(offset); + } + + public LSL_List GetEntityParams(ISceneEntity entity, LSL_List rules) + { + LSL_List result = new LSL_List(); + LSL_List remaining; + + while (true) + { +// m_log.DebugFormat( +// "[LSL API]: GetEntityParams has {0} rules with scene entity named {1}", +// rules.Length, entity != null ? entity.Name : "NULL"); + + if (entity == null) + return result; + + if (entity is SceneObjectPart) + remaining = GetPrimParams((SceneObjectPart)entity, rules, ref result); + else + remaining = GetAgentParams((ScenePresence)entity, rules, ref result); + + if (remaining == null || remaining.Length < 2) + return result; + + int linknumber = remaining.GetLSLIntegerItem(0); + rules = remaining.GetSublist(1, -1); + entity = GetLinkEntity(m_host, linknumber); + } + } + + public LSL_List llGetPrimitiveParams(LSL_List rules) + { + m_host.AddScriptLPS(1); + + return GetEntityParams(m_host, rules); + } + + public LSL_List llGetLinkPrimitiveParams(int linknumber, LSL_List rules) + { + m_host.AddScriptLPS(1); + + return GetEntityParams(GetLinkEntity(m_host, linknumber), rules); + } + + public LSL_Vector GetAgentSize(ScenePresence sp) + { + return new LSL_Vector(0.45, 0.6, sp.Appearance.AvatarHeight); + } + + /// + /// Gets params for a seated avatar in a linkset. + /// + /// + /// + /// + /// + public LSL_List GetAgentParams(ScenePresence sp, LSL_List rules, ref LSL_List res) + { + int idx = 0; + while (idx < rules.Length) + { + int code = (int)rules.GetLSLIntegerItem(idx++); + int remain = rules.Length-idx; + + switch (code) + { + case (int)ScriptBaseClass.PRIM_MATERIAL: + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_MATERIAL_FLESH)); + break; + + case (int)ScriptBaseClass.PRIM_PHYSICS: + res.Add(ScriptBaseClass.FALSE); + break; + + case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ: + res.Add(ScriptBaseClass.FALSE); + break; + + case (int)ScriptBaseClass.PRIM_PHANTOM: + res.Add(ScriptBaseClass.FALSE); + break; + + case (int)ScriptBaseClass.PRIM_POSITION: + res.Add(new LSL_Vector(sp.AbsolutePosition)); + break; + + case (int)ScriptBaseClass.PRIM_SIZE: + res.Add(GetAgentSize(sp)); + break; + + case (int)ScriptBaseClass.PRIM_ROTATION: + res.Add(sp.GetWorldRotation()); + break; + + case (int)ScriptBaseClass.PRIM_TYPE: + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TYPE_BOX)); + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_HOLE_DEFAULT)); + res.Add(new LSL_Vector(0, 1, 0)); + res.Add(new LSL_Float(0)); + res.Add(new LSL_Vector(0, 0, 0)); + res.Add(new LSL_Vector(1, 1, 0)); + res.Add(new LSL_Vector(0, 0, 0)); + break; + + case (int)ScriptBaseClass.PRIM_TEXTURE: + if (remain < 1) + return new LSL_List(); + + int face = (int)rules.GetLSLIntegerItem(idx++); + if (face > 21) + break; + + res.Add(new LSL_String("")); + res.Add(ScriptBaseClass.ZERO_VECTOR); + res.Add(ScriptBaseClass.ZERO_VECTOR); + res.Add(new LSL_Float(0)); + break; + + case (int)ScriptBaseClass.PRIM_COLOR: + if (remain < 1) + return new LSL_List(); + + face = (int)rules.GetLSLIntegerItem(idx++); + if (face > 21) + break; + + res.Add(ScriptBaseClass.ZERO_VECTOR); + res.Add(new LSL_Float(0)); + break; + + case (int)ScriptBaseClass.PRIM_BUMP_SHINY: + if (remain < 1) + return new LSL_List(); + + face = (int)rules.GetLSLIntegerItem(idx++); + if (face > 21) + break; + + res.Add(ScriptBaseClass.PRIM_SHINY_NONE); + res.Add(ScriptBaseClass.PRIM_BUMP_NONE); + break; + + case (int)ScriptBaseClass.PRIM_FULLBRIGHT: + if (remain < 1) + return new LSL_List(); - return m_host.ParentGroup.PrimCount + m_host.ParentGroup.GetSittingAvatarsCount(); - } + face = (int)rules.GetLSLIntegerItem(idx++); + if (face > 21) + break; - /// - /// A partial implementation. - /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetBoundingBox - /// So far only valid for standing/flying/ground sitting avatars and single prim objects. - /// If the object has multiple prims and/or a sitting avatar then the bounding - /// box is for the root prim only. - /// - public LSL_List llGetBoundingBox(string obj) - { - m_host.AddScriptLPS(1); - UUID objID = UUID.Zero; - LSL_List result = new LSL_List(); - if (!UUID.TryParse(obj, out objID)) - { - result.Add(new LSL_Vector()); - result.Add(new LSL_Vector()); - return result; - } - ScenePresence presence = World.GetScenePresence(objID); - if (presence != null) - { - if (presence.ParentID == 0) // not sat on an object - { - LSL_Vector lower; - LSL_Vector upper; - if (presence.Animator.Animations.ImplicitDefaultAnimation.AnimID - == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"]) - { - // This is for ground sitting avatars - float height = presence.Appearance.AvatarHeight / 2.66666667f; - lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f); - upper = new LSL_Vector(0.3375f, 0.45f, 0.0f); - } - else - { - // This is for standing/flying avatars - float height = presence.Appearance.AvatarHeight / 2.0f; - lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f); - upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f); - } - result.Add(lower); - result.Add(upper); - return result; - } - else - { - // sitting on an object so we need the bounding box of that - // which should include the avatar so set the UUID to the - // UUID of the object the avatar is sat on and allow it to fall through - // to processing an object - SceneObjectPart p = World.GetSceneObjectPart(presence.ParentID); - objID = p.UUID; - } - } - SceneObjectPart part = World.GetSceneObjectPart(objID); - // Currently only works for single prims without a sitting avatar - if (part != null) - { - Vector3 halfSize = part.Scale / 2.0f; - LSL_Vector lower = (new LSL_Vector(halfSize)) * -1.0f; - LSL_Vector upper = new LSL_Vector(halfSize); - result.Add(lower); - result.Add(upper); - return result; - } + res.Add(ScriptBaseClass.FALSE); + break; - // Not found so return empty values - result.Add(new LSL_Vector()); - result.Add(new LSL_Vector()); - return result; - } + case (int)ScriptBaseClass.PRIM_FLEXIBLE: + res.Add(ScriptBaseClass.FALSE); + res.Add(new LSL_Integer(0)); + res.Add(new LSL_Float(0)); + res.Add(new LSL_Float(0)); + res.Add(new LSL_Float(0)); + res.Add(new LSL_Float(0)); + res.Add(ScriptBaseClass.ZERO_VECTOR); + break; - public LSL_Vector llGetGeometricCenter() - { - return new LSL_Vector(m_host.GetGeometricCenter().X, m_host.GetGeometricCenter().Y, m_host.GetGeometricCenter().Z); - } + case (int)ScriptBaseClass.PRIM_TEXGEN: + if (remain < 1) + return new LSL_List(); - public LSL_List llGetPrimitiveParams(LSL_List rules) - { - m_host.AddScriptLPS(1); + face = (int)rules.GetLSLIntegerItem(idx++); + if (face > 21) + break; - LSL_List result = new LSL_List(); + res.Add(ScriptBaseClass.PRIM_TEXGEN_DEFAULT); + break; - LSL_List remaining = GetPrimParams(m_host, rules, ref result); + case (int)ScriptBaseClass.PRIM_POINT_LIGHT: + res.Add(ScriptBaseClass.FALSE); + res.Add(ScriptBaseClass.ZERO_VECTOR); + res.Add(ScriptBaseClass.ZERO_VECTOR); + break; - while (remaining != null && remaining.Length > 2) - { - int linknumber = remaining.GetLSLIntegerItem(0); - rules = remaining.GetSublist(1, -1); - List parts = GetLinkParts(linknumber); + case (int)ScriptBaseClass.PRIM_GLOW: + if (remain < 1) + return new LSL_List(); - foreach (SceneObjectPart part in parts) - remaining = GetPrimParams(part, rules, ref result); - } + face = (int)rules.GetLSLIntegerItem(idx++); + if (face > 21) + break; - return result; - } + res.Add(new LSL_Float(0)); + break; - public LSL_List llGetLinkPrimitiveParams(int linknumber, LSL_List rules) - { - m_host.AddScriptLPS(1); + case (int)ScriptBaseClass.PRIM_TEXT: + res.Add(new LSL_String("")); + res.Add(ScriptBaseClass.ZERO_VECTOR); + res.Add(new LSL_Float(1)); + break; - List parts = GetLinkParts(linknumber); + case (int)ScriptBaseClass.PRIM_ROT_LOCAL: + res.Add(new LSL_Rotation(sp.Rotation)); + break; - LSL_List res = new LSL_List(); - LSL_List remaining = null; + case (int)ScriptBaseClass.PRIM_POS_LOCAL: + res.Add(new LSL_Vector(sp.OffsetPosition)); + break; - foreach (SceneObjectPart part in parts) - { - remaining = GetPrimParams(part, rules, ref res); - } + case (int)ScriptBaseClass.PRIM_SLICE: + res.Add(new LSL_Vector(0, 1, 0)); + break; - while (remaining != null && remaining.Length > 2) - { - linknumber = remaining.GetLSLIntegerItem(0); - rules = remaining.GetSublist(1, -1); - parts = GetLinkParts(linknumber); + case (int)ScriptBaseClass.PRIM_LINK_TARGET: + if(remain < 3) + return new LSL_List(); - foreach (SceneObjectPart part in parts) - remaining = GetPrimParams(part, rules, ref res); + return rules.GetSublist(idx, -1); + } } - return res; + return new LSL_List(); } public LSL_List GetPrimParams(SceneObjectPart part, LSL_List rules, ref LSL_List res) { - int idx=0; + int idx = 0; while (idx < rules.Length) { - int code=(int)rules.GetLSLIntegerItem(idx++); - int remain=rules.Length-idx; + int code = (int)rules.GetLSLIntegerItem(idx++); + int remain = rules.Length - idx; switch (code) { @@ -8049,29 +10420,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; case (int)ScriptBaseClass.PRIM_POSITION: - LSL_Vector v = new LSL_Vector(part.AbsolutePosition.X, - part.AbsolutePosition.Y, - part.AbsolutePosition.Z); + LSL_Vector v = new LSL_Vector(part.AbsolutePosition); + // For some reason, the part.AbsolutePosition.* values do not change if the // linkset is rotated; they always reflect the child prim's world position // as though the linkset is unrotated. This is incompatible behavior with SL's // implementation, so will break scripts imported from there (not to mention it // makes it more difficult to determine a child prim's actual inworld position). - if (part.ParentID != 0) - v = ((v - llGetRootPosition()) * llGetRootRotation()) + llGetRootPosition(); + if (!part.IsRoot) + { + LSL_Vector rootPos = new LSL_Vector(m_host.ParentGroup.AbsolutePosition); + v = ((v - rootPos) * llGetRootRotation()) + rootPos; + } + res.Add(v); break; case (int)ScriptBaseClass.PRIM_SIZE: - res.Add(new LSL_Vector(part.Scale.X, - part.Scale.Y, - part.Scale.Z)); + res.Add(new LSL_Vector(part.Scale)); break; case (int)ScriptBaseClass.PRIM_ROTATION: res.Add(GetPartRot(part)); break; + case (int)ScriptBaseClass.PRIM_PHYSICS_SHAPE_TYPE: + res.Add(new LSL_Integer((int)part.PhysicsShapeType)); + break; + case (int)ScriptBaseClass.PRIM_TYPE: // implementing box PrimitiveBaseShape Shape = part.Shape; @@ -8101,7 +10477,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; case ScriptBaseClass.PRIM_TYPE_SCULPT: - res.Add(Shape.SculptTexture.ToString()); + res.Add(new LSL_String(Shape.SculptTexture.ToString())); res.Add(new LSL_Integer(Shape.SculptType)); break; @@ -8133,16 +10509,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0)); // float revolutions - res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d); + res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d); // Slightly inaccurate, because an unsigned byte is being used to represent - // the entire range of floating-point values from 1.0 through 4.0 (which is how + // the entire range of floating-point values from 1.0 through 4.0 (which is how // SL does it). // - // Using these formulas to store and retrieve PathRevolutions, it is not - // possible to use all values between 1.00 and 4.00. For instance, you can't + // Using these formulas to store and retrieve PathRevolutions, it is not + // possible to use all values between 1.00 and 4.00. For instance, you can't // represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you // use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them - // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar + // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar // behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11. // In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value // such as 1.10. So, SL must store and retreive the actual user input rather @@ -8159,7 +10535,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case (int)ScriptBaseClass.PRIM_TEXTURE: if (remain < 1) - return null; + return new LSL_List(); int face = (int)rules.GetLSLIntegerItem(idx++); Primitive.TextureEntry tex = part.Shape.Textures; @@ -8199,7 +10575,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case (int)ScriptBaseClass.PRIM_COLOR: if (remain < 1) - return null; + return new LSL_List(); face=(int)rules.GetLSLIntegerItem(idx++); @@ -8228,7 +10604,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case (int)ScriptBaseClass.PRIM_BUMP_SHINY: if (remain < 1) - return null; + return new LSL_List(); face=(int)rules.GetLSLIntegerItem(idx++); @@ -8259,9 +10635,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case (int)ScriptBaseClass.PRIM_FULLBRIGHT: if (remain < 1) - return null; + return new LSL_List(); - face=(int)rules.GetLSLIntegerItem(idx++); + face = (int)rules.GetLSLIntegerItem(idx++); tex = part.Shape.Textures; if (face == ScriptBaseClass.ALL_SIDES) @@ -8301,7 +10677,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case (int)ScriptBaseClass.PRIM_TEXGEN: if (remain < 1) - return null; + return new LSL_List(); face=(int)rules.GetLSLIntegerItem(idx++); @@ -8342,7 +10718,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case (int)ScriptBaseClass.PRIM_GLOW: if (remain < 1) - return null; + return new LSL_List(); face=(int)rules.GetLSLIntegerItem(idx++); @@ -8371,7 +10747,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api res.Add(new LSL_Vector(textColor.R, textColor.G, textColor.B)); - res.Add(new LSL_Float(textColor.A)); + res.Add(new LSL_Float(1.0 - textColor.A)); break; case (int)ScriptBaseClass.PRIM_NAME: res.Add(new LSL_String(part.Name)); @@ -8380,7 +10756,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api res.Add(new LSL_String(part.Description)); break; case (int)ScriptBaseClass.PRIM_ROT_LOCAL: - res.Add(new LSL_Rotation(part.RotationOffset.X, part.RotationOffset.Y, part.RotationOffset.Z, part.RotationOffset.W)); + res.Add(new LSL_Rotation(part.RotationOffset)); break; case (int)ScriptBaseClass.PRIM_POS_LOCAL: res.Add(new LSL_Vector(GetPartLocalPos(part))); @@ -8395,27 +10771,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api )); break; case (int)ScriptBaseClass.PRIM_LINK_TARGET: - if(remain < 3) - return null; + + // TODO: Should be issuing a runtime script warning in this case. + if (remain < 2) + return new LSL_List(); return rules.GetSublist(idx, -1); } } - return null; + return new LSL_List(); } public LSL_List llGetPrimMediaParams(int face, LSL_List rules) { m_host.AddScriptLPS(1); - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnGetPrimMediaParams); return GetPrimMediaParams(m_host, face, rules); } public LSL_List llGetLinkMedia(LSL_Integer link, LSL_Integer face, LSL_List rules) { m_host.AddScriptLPS(1); - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnGetLinkMedia); if (link == ScriptBaseClass.LINK_ROOT) return GetPrimMediaParams(m_host.ParentGroup.RootPart, face, rules); else if (link == ScriptBaseClass.LINK_THIS) @@ -8535,14 +10913,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llSetPrimMediaParams(LSL_Integer face, LSL_List rules) { m_host.AddScriptLPS(1); - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnSetPrimMediaParams); return SetPrimMediaParams(m_host, face, rules); } public LSL_Integer llSetLinkMedia(LSL_Integer link, LSL_Integer face, LSL_List rules) { m_host.AddScriptLPS(1); - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnSetLinkMedia); if (link == ScriptBaseClass.LINK_ROOT) return SetPrimMediaParams(m_host.ParentGroup.RootPart, face, rules); else if (link == ScriptBaseClass.LINK_THIS) @@ -8661,14 +11039,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llClearPrimMedia(LSL_Integer face) { m_host.AddScriptLPS(1); - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnClearPrimMedia); return ClearPrimMedia(m_host, face); } public LSL_Integer llClearLinkMedia(LSL_Integer link, LSL_Integer face) { m_host.AddScriptLPS(1); - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnClearLinkMedia); if (link == ScriptBaseClass.LINK_ROOT) return ClearPrimMedia(m_host.ParentGroup.RootPart, face); else if (link == ScriptBaseClass.LINK_THIS) @@ -9307,7 +11685,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (item == null) { - llSay(0, "No item name '" + item + "'"); + Error("llGetInventoryCreator", "Can't find item '" + item + "'"); return String.Empty; } @@ -9355,7 +11733,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.DATA_SIM_POS: if (info == null) { - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnRequestSimulatorData); return UUID.Zero.ToString(); } @@ -9402,7 +11780,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.DATA_SIM_RATING: if (info == null) { - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnRequestSimulatorData); return UUID.Zero.ToString(); } int access = info.Maturity; @@ -9421,7 +11799,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api reply = "OpenSim"; break; default: - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnRequestSimulatorData); return UUID.Zero.ToString(); // Raise no event } UUID rq = UUID.Random(); @@ -9432,7 +11810,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api AsyncCommands. DataserverPlugin.DataserverReply(rq.ToString(), reply); - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnRequestSimulatorData); return tid.ToString(); } catch(Exception) @@ -9441,6 +11819,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return UUID.Zero.ToString(); } } + public LSL_String llRequestURL() { m_host.AddScriptLPS(1); @@ -9499,7 +11878,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_List llListReplaceList(LSL_List dest, LSL_List src, int start, int end) { - LSL_List pref = null; + LSL_List pref; m_host.AddScriptLPS(1); @@ -9576,7 +11955,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api dm.SendUrlToUser( new UUID(avatar_id), m_host.Name, m_host.UUID, m_host.OwnerID, false, message, url); - ScriptSleep(10000); + ScriptSleep(m_sleepMsOnLoadURL); } public void llParcelMediaCommandList(LSL_List commandList) @@ -9588,7 +11967,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // according to the docs, this command only works if script owner and land owner are the same // lets add estate owners and gods, too, and use the generic permission check. - ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia)) return; bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)? @@ -9625,7 +12004,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api presence = World.GetScenePresence(agentID); } } - else ShoutError("The argument of PARCEL_MEDIA_COMMAND_AGENT must be a key"); + else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_AGENT must be a key"); ++i; } break; @@ -9656,7 +12035,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api url = (LSL_String)commandList.Data[i + 1]; update = true; } - else ShoutError("The argument of PARCEL_MEDIA_COMMAND_URL must be a string."); + else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_URL must be a string"); ++i; } break; @@ -9669,7 +12048,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api texture = (LSL_String)commandList.Data[i + 1]; update = true; } - else ShoutError("The argument of PARCEL_MEDIA_COMMAND_TEXTURE must be a string or key."); + else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_TEXTURE must be a string or a key"); ++i; } break; @@ -9681,7 +12060,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { time = (float)(LSL_Float)commandList.Data[i + 1]; } - else ShoutError("The argument of PARCEL_MEDIA_COMMAND_TIME must be a float."); + else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_TIME must be a float"); ++i; } break; @@ -9695,7 +12074,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api update = true; } - else ShoutError("The argument of PARCEL_MEDIA_COMMAND_AUTO_ALIGN must be an integer."); + else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_AUTO_ALIGN must be an integer"); ++i; } break; @@ -9708,7 +12087,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api mediaType = (LSL_String)commandList.Data[i + 1]; update = true; } - else ShoutError("The argument of PARCEL_MEDIA_COMMAND_TYPE must be a string."); + else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_TYPE must be a string"); ++i; } break; @@ -9721,7 +12100,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api description = (LSL_String)commandList.Data[i + 1]; update = true; } - else ShoutError("The argument of PARCEL_MEDIA_COMMAND_DESC must be a string."); + else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_DESC must be a string"); ++i; } break; @@ -9737,15 +12116,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api height = (LSL_Integer)commandList.Data[i + 2]; update = true; } - else ShoutError("The second argument of PARCEL_MEDIA_COMMAND_SIZE must be an integer."); + else Error("llParcelMediaCommandList", "The second argument of PARCEL_MEDIA_COMMAND_SIZE must be an integer"); } - else ShoutError("The first argument of PARCEL_MEDIA_COMMAND_SIZE must be an integer."); + else Error("llParcelMediaCommandList", "The first argument of PARCEL_MEDIA_COMMAND_SIZE must be an integer"); i += 2; } break; default: - NotImplemented("llParcelMediaCommandList parameter not supported yet: " + Enum.Parse(typeof(ParcelMediaCommandEnum), commandList.Data[i].ToString()).ToString()); + NotImplemented("llParcelMediaCommandList", "Parameter not supported yet: " + Enum.Parse(typeof(ParcelMediaCommandEnum), commandList.Data[i].ToString()).ToString()); break; }//end switch }//end for @@ -9819,7 +12198,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api time); } } - ScriptSleep(2000); + ScriptSleep(m_sleepMsOnParcelMediaCommandList); } public LSL_List llParcelMediaQuery(LSL_List aList) @@ -9853,13 +12232,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; default: ParcelMediaCommandEnum mediaCommandEnum = ParcelMediaCommandEnum.Url; - NotImplemented("llParcelMediaQuery parameter do not supported yet: " + Enum.Parse(mediaCommandEnum.GetType() , aList.Data[i].ToString()).ToString()); + NotImplemented("llParcelMediaQuery", "Parameter not supported yet: " + Enum.Parse(mediaCommandEnum.GetType() , aList.Data[i].ToString()).ToString()); break; } } } - ScriptSleep(2000); + ScriptSleep(m_sleepMsOnParcelMediaQuery); return list; } @@ -9868,7 +12247,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); Int64 tmp = 0; Math.DivRem(Convert.ToInt64(Math.Pow(a, b)), c, out tmp); - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnModPow); return Convert.ToInt32(tmp); } @@ -9890,7 +12269,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (quick_pay_buttons.Data.Length < 4) { - LSLError("List must have at least 4 elements"); + Error("llSetPayPrice", "List must have at least 4 elements"); return; } m_host.ParentGroup.RootPart.PayPrice[0]=price; @@ -9907,21 +12286,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); if (m_item.PermsGranter == UUID.Zero) - return new LSL_Vector(); + return Vector3.Zero; if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) { - ShoutError("No permissions to track the camera"); - return new LSL_Vector(); + Error("llGetCameraPos", "No permissions to track the camera"); + return Vector3.Zero; } ScenePresence presence = World.GetScenePresence(m_host.OwnerID); if (presence != null) { - LSL_Vector pos = new LSL_Vector(presence.CameraPosition.X, presence.CameraPosition.Y, presence.CameraPosition.Z); + LSL_Vector pos = new LSL_Vector(presence.CameraPosition); return pos; } - return new LSL_Vector(); + + return Vector3.Zero; } public LSL_Rotation llGetCameraRot() @@ -9929,42 +12309,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); if (m_item.PermsGranter == UUID.Zero) - return new LSL_Rotation(); + return Quaternion.Identity; if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) { - ShoutError("No permissions to track the camera"); - return new LSL_Rotation(); + Error("llGetCameraRot", "No permissions to track the camera"); + return Quaternion.Identity; } ScenePresence presence = World.GetScenePresence(m_host.OwnerID); if (presence != null) { - return new LSL_Rotation(presence.CameraRotation.X, presence.CameraRotation.Y, presence.CameraRotation.Z, presence.CameraRotation.W); + return new LSL_Rotation(presence.CameraRotation); } - return new LSL_Rotation(); + return Quaternion.Identity; } - /// - /// The SL implementation does nothing, it is deprecated - /// This duplicates SL - /// public void llSetPrimURL(string url) { m_host.AddScriptLPS(1); - ScriptSleep(2000); + Deprecated("llSetPrimURL", "Use llSetPrimMediaParams instead"); + ScriptSleep(m_sleepMsOnSetPrimURL); } - /// - /// The SL implementation shouts an error, it is deprecated - /// This duplicates SL - /// public void llRefreshPrimURL() { m_host.AddScriptLPS(1); - ShoutError("llRefreshPrimURL - not yet supported"); - ScriptSleep(20000); + Deprecated("llRefreshPrimURL"); + ScriptSleep(m_sleepMsOnRefreshPrimURL); } public LSL_String llEscapeURL(string url) @@ -10005,14 +12378,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api avatar.ControllingClient.SendScriptTeleportRequest(m_host.Name, simname, pos, lookAt); } - ScriptSleep(1000); + ScriptSleep(m_sleepMsOnMapDestination); } public void llAddToLandBanList(string avatar, double hours) { m_host.AddScriptLPS(1); UUID key; - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) { int expires = 0; @@ -10046,14 +12419,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land); } } - ScriptSleep(100); + ScriptSleep(m_sleepMsOnAddToLandBanList); } public void llRemoveFromLandPassList(string avatar) { m_host.AddScriptLPS(1); UUID key; - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageAllowed)) { if (UUID.TryParse(avatar, out key)) @@ -10073,14 +12446,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - ScriptSleep(100); + ScriptSleep(m_sleepMsOnRemoveFromLandPassList); } public void llRemoveFromLandBanList(string avatar) { m_host.AddScriptLPS(1); UUID key; - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) { if (UUID.TryParse(avatar, out key)) @@ -10100,7 +12473,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - ScriptSleep(100); + ScriptSleep(m_sleepMsOnRemoveFromLandBanList); } public void llSetCameraParams(LSL_List rules) @@ -10128,19 +12501,84 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api SortedDictionary parameters = new SortedDictionary(); object[] data = rules.Data; - for (int i = 0; i < data.Length; ++i) { - int type = Convert.ToInt32(data[i++].ToString()); + for (int i = 0; i < data.Length; ++i) + { + int type; + try + { + type = Convert.ToInt32(data[i++].ToString()); + } + catch + { + Error("llSetCameraParams", string.Format("Invalid camera param type {0}", data[i - 1])); + return; + } if (i >= data.Length) break; // odd number of entries => ignore the last // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3) - switch (type) { + switch (type) + { case ScriptBaseClass.CAMERA_FOCUS: case ScriptBaseClass.CAMERA_FOCUS_OFFSET: case ScriptBaseClass.CAMERA_POSITION: LSL_Vector v = (LSL_Vector)data[i]; - parameters.Add(type + 1, (float)v.x); - parameters.Add(type + 2, (float)v.y); - parameters.Add(type + 3, (float)v.z); + try + { + parameters.Add(type + 1, (float)v.x); + } + catch + { + switch(type) + { + case ScriptBaseClass.CAMERA_FOCUS: + Error("llSetCameraParams", "CAMERA_FOCUS: Parameter x is invalid"); + return; + case ScriptBaseClass.CAMERA_FOCUS_OFFSET: + Error("llSetCameraParams", "CAMERA_FOCUS_OFFSET: Parameter x is invalid"); + return; + case ScriptBaseClass.CAMERA_POSITION: + Error("llSetCameraParams", "CAMERA_POSITION: Parameter x is invalid"); + return; + } + } + try + { + parameters.Add(type + 2, (float)v.y); + } + catch + { + switch(type) + { + case ScriptBaseClass.CAMERA_FOCUS: + Error("llSetCameraParams", "CAMERA_FOCUS: Parameter y is invalid"); + return; + case ScriptBaseClass.CAMERA_FOCUS_OFFSET: + Error("llSetCameraParams", "CAMERA_FOCUS_OFFSET: Parameter y is invalid"); + return; + case ScriptBaseClass.CAMERA_POSITION: + Error("llSetCameraParams", "CAMERA_POSITION: Parameter y is invalid"); + return; + } + } + try + { + parameters.Add(type + 3, (float)v.z); + } + catch + { + switch(type) + { + case ScriptBaseClass.CAMERA_FOCUS: + Error("llSetCameraParams", "CAMERA_FOCUS: Parameter z is invalid"); + return; + case ScriptBaseClass.CAMERA_FOCUS_OFFSET: + Error("llSetCameraParams", "CAMERA_FOCUS_OFFSET: Parameter z is invalid"); + return; + case ScriptBaseClass.CAMERA_POSITION: + Error("llSetCameraParams", "CAMERA_POSITION: Parameter z is invalid"); + return; + } + } break; default: // TODO: clean that up as soon as the implicit casts are in @@ -10148,7 +12586,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api parameters.Add(type, (float)((LSL_Float)data[i]).value); else if (data[i] is LSL_Integer) parameters.Add(type, (float)((LSL_Integer)data[i]).value); - else parameters.Add(type, Convert.ToSingle(data[i])); + else + { + try + { + parameters.Add(type, Convert.ToSingle(data[i])); + } + catch + { + Error("llSetCameraParams", string.Format("{0}: Parameter is invalid", type)); + } + } break; } } @@ -10264,9 +12712,60 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IHttpRequestModule httpScriptMod = m_ScriptEngine.World.RequestModuleInterface(); List param = new List(); - foreach (object o in parameters.Data) + bool ok; + Int32 flag; + + for (int i = 0; i < parameters.Data.Length; i += 2) { - param.Add(o.ToString()); + ok = Int32.TryParse(parameters.Data[i].ToString(), out flag); + if (!ok || flag < 0 || + flag > (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE) + { + Error("llHTTPRequest", "Parameter " + i.ToString() + " is an invalid flag"); + } + + param.Add(parameters.Data[i].ToString()); //Add parameter flag + + if (flag != (int)HttpRequestConstants.HTTP_CUSTOM_HEADER) + { + param.Add(parameters.Data[i+1].ToString()); //Add parameter value + } + else + { + //Parameters are in pairs and custom header takes + //arguments in pairs so adjust for header marker. + ++i; + + //Maximum of 8 headers are allowed based on the + //Second Life documentation for llHTTPRequest. + for (int count = 1; count <= 8; ++count) + { + //Enough parameters remaining for (another) header? + if (parameters.Data.Length - i < 2) + { + //There must be at least one name/value pair for custom header + if (count == 1) + Error("llHTTPRequest", "Missing name/value for custom header at parameter " + i.ToString()); + break; + } + + if (HttpStandardHeaders.Contains(parameters.Data[i].ToString(), StringComparer.OrdinalIgnoreCase)) + Error("llHTTPRequest", "Name is invalid as a custom header at parameter " + i.ToString()); + + param.Add(parameters.Data[i].ToString()); + param.Add(parameters.Data[i+1].ToString()); + + //Have we reached the end of the list of headers? + //End is marked by a string with a single digit. + if (i+2 >= parameters.Data.Length || + Char.IsDigit(parameters.Data[i].ToString()[0])) + { + break; + } + + i += 2; + } + } } Vector3 position = m_host.AbsolutePosition; @@ -10318,8 +12817,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + HttpInitialRequestStatus status; UUID reqID - = httpScriptMod.StartHttpRequest(m_host.LocalId, m_item.ItemID, url, param, httpHeaders, body); + = httpScriptMod.StartHttpRequest(m_host.LocalId, m_item.ItemID, url, param, httpHeaders, body, out status); + + if (status == HttpInitialRequestStatus.DISALLOWED_BY_FILTER) + Error("llHttpRequest", string.Format("Request to {0} disallowed by filter", url)); if (reqID != UUID.Zero) return reqID.ToString(); @@ -10342,7 +12845,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llResetLandBanList() { m_host.AddScriptLPS(1); - LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData; + LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData; if (land.OwnerID == m_host.OwnerID) { foreach (LandAccessEntry entry in land.ParcelAccessList) @@ -10353,13 +12856,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - ScriptSleep(100); + ScriptSleep(m_sleepMsOnResetLandBanList); } public void llResetLandPassList() { m_host.AddScriptLPS(1); - LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData; + LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData; if (land.OwnerID == m_host.OwnerID) { foreach (LandAccessEntry entry in land.ParcelAccessList) @@ -10370,18 +12873,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - ScriptSleep(100); + ScriptSleep(m_sleepMsOnResetLandPassList); } public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide) { m_host.AddScriptLPS(1); - + ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y); if (lo == null) return 0; - + IPrimCounts pc = lo.PrimCounts; if (sim_wide != ScriptBaseClass.FALSE) @@ -10411,7 +12914,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api else if (category == ScriptBaseClass.PARCEL_COUNT_TEMP) return 0; // counts not implemented yet } - + return 0; } @@ -10428,7 +12931,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ret.Add(new LSL_Integer(detectedParams.Value)); } } - ScriptSleep(2000); + ScriptSleep(m_sleepMsOnGetParcelPrimOwners); return ret; } @@ -10535,10 +13038,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z)); break; case ScriptBaseClass.OBJECT_ROT: - ret.Add(new LSL_Rotation((double)av.Rotation.X, (double)av.Rotation.Y, (double)av.Rotation.Z, (double)av.Rotation.W)); + ret.Add(new LSL_Rotation(av.GetWorldRotation())); break; case ScriptBaseClass.OBJECT_VELOCITY: - ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z)); + ret.Add(new LSL_Vector(av.GetWorldVelocity())); break; case ScriptBaseClass.OBJECT_OWNER: ret.Add(new LSL_String(id)); @@ -10603,6 +13106,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_TEMP_ON_REZ: ret.Add(new LSL_Integer(0)); break; + case ScriptBaseClass.OBJECT_RENDER_WEIGHT: + ret.Add(new LSL_Integer(-1)); + break; + case ScriptBaseClass.OBJECT_HOVER_HEIGHT: + ret.Add(new LSL_Float(0)); + break; + case ScriptBaseClass.OBJECT_BODY_SHAPE_TYPE: + LSL_Float shapeType; + if (av.Appearance.VisualParams[(int)AvatarAppearance.VPElement.SHAPE_MALE] != 0) + shapeType = new LSL_Float(1); + else + shapeType = new LSL_Float(0); + ret.Add(shapeType); + break; + case ScriptBaseClass.OBJECT_LAST_OWNER_ID: + ret.Add(new LSL_Key(ScriptBaseClass.NULL_KEY)); + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); @@ -10630,20 +13150,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ret.Add(new LSL_Vector(obj.AbsolutePosition.X, obj.AbsolutePosition.Y, obj.AbsolutePosition.Z)); break; case ScriptBaseClass.OBJECT_ROT: + Quaternion rot = Quaternion.Identity; + + if (obj.ParentGroup.IsAttachment) { - Quaternion rot = Quaternion.Identity; + ScenePresence sp = World.GetScenePresence(obj.ParentGroup.AttachedAvatar); + if (sp != null) + rot = sp.GetWorldRotation(); + } + else + { if (obj.ParentGroup.RootPart == obj) rot = obj.ParentGroup.GroupRotation; else rot = obj.GetWorldRotation(); - - LSL_Rotation objrot = new LSL_Rotation(rot); - ret.Add(objrot); } + + LSL_Rotation objrot = new LSL_Rotation(rot); + ret.Add(objrot); + break; case ScriptBaseClass.OBJECT_VELOCITY: - ret.Add(new LSL_Vector(obj.Velocity)); + Vector3 vel = Vector3.Zero; + + if (obj.ParentGroup.IsAttachment) + { + ScenePresence sp = World.GetScenePresence(obj.ParentGroup.AttachedAvatar); + + if (sp != null) + vel = sp.GetWorldVelocity(); + } + else + { + vel = obj.Velocity; + } + + ret.Add(vel); break; case ScriptBaseClass.OBJECT_OWNER: ret.Add(new LSL_String(obj.OwnerID.ToString())); @@ -10744,6 +13287,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_TEMP_ON_REZ: ret.Add(new LSL_Integer(obj.ParentGroup.IsTemporary ? 1 : 0)); break; + case ScriptBaseClass.OBJECT_RENDER_WEIGHT: + ret.Add(new LSL_Integer(0)); + break; + case ScriptBaseClass.OBJECT_HOVER_HEIGHT: + ret.Add(new LSL_Float(0)); + break; + case ScriptBaseClass.OBJECT_BODY_SHAPE_TYPE: + ret.Add(new LSL_Float(-1)); + break; + case ScriptBaseClass.OBJECT_LAST_OWNER_ID: + ret.Add(new LSL_Key(obj.ParentGroup.LastOwnerID.ToString())); + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); @@ -10754,7 +13309,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return ret; } } - + return new LSL_List(); } @@ -10768,25 +13323,71 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return item.ItemID; } - internal void ShoutError(string msg) + /// + /// Reports the script error in the viewer's Script Warning/Error dialog and shouts it on the debug channel. + /// + /// The name of the command that generated the error. + /// The error message to report to the user. + internal void Error(string command, string message) { - llShout(ScriptBaseClass.DEBUG_CHANNEL, msg); + string text = command + ": " + message; + if (text.Length > 1023) + { + text = text.Substring(0, 1023); + } + + World.SimChat(Utils.StringToBytes(text), ChatTypeEnum.DebugChannel, ScriptBaseClass.DEBUG_CHANNEL, + m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false); + + IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); + if (wComm != null) + { + wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, text); + } } - internal void NotImplemented(string command) + /// + /// Reports that the command is not implemented as a script error. + /// + /// The name of the command that is not implemented. + /// Additional information to report to the user. (Optional) + internal void NotImplemented(string command, string message = "") { if (throwErrorOnNotImplemented) - throw new NotImplementedException("Command not implemented: " + command); - } + { + if (message != "") + { + message = " - " + message; + } - internal void Deprecated(string command) - { - throw new ScriptException("Command deprecated: " + command); + throw new NotImplementedException("Command not implemented: " + command + message); + } + else + { + string text = "Command not implemented"; + if (message != "") + { + text = text + " - " + message; + } + + Error(command, text); + } } - internal void LSLError(string msg) + /// + /// Reports that the command is deprecated as a script error. + /// + /// The name of the command that is deprecated. + /// Additional information to report to the user. (Optional) + internal void Deprecated(string command, string message = "") { - throw new ScriptException("LSL Runtime Error: " + msg); + string text = "Command deprecated"; + if (message != "") + { + text = text + " - " + message; + } + + Error(command, text); } public delegate void AssetRequestCallback(UUID assetID, AssetBase asset); @@ -10818,20 +13419,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (assetID == UUID.Zero) { // => complain loudly, as specified by the LSL docs - ShoutError("Notecard '" + name + "' could not be found."); + Error("llGetNumberOfNotecardLines", "Can't find notecard '" + name + "'"); return UUID.Zero.ToString(); } + string reqIdentifier = UUID.Random().ToString(); + // was: UUID tid = tid = AsyncCommands. - UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, assetID.ToString()); + UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, reqIdentifier); if (NotecardCache.IsCached(assetID)) { - AsyncCommands. - DataserverPlugin.DataserverReply(assetID.ToString(), - NotecardCache.GetLines(assetID).ToString()); - ScriptSleep(100); + AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(assetID).ToString()); + + ScriptSleep(m_sleepMsOnGetNumberOfNotecardLines); return tid.ToString(); } @@ -10839,19 +13441,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (a == null || a.Type != 7) { - ShoutError("Notecard '" + name + "' could not be found."); + Error("llGetNumberOfNotecardLines", "Can't find notecard '" + name + "'"); return; } - string data = Encoding.UTF8.GetString(a.Data); - //m_log.Debug(data); - NotecardCache.Cache(id, data); - AsyncCommands. - DataserverPlugin.DataserverReply(id.ToString(), - NotecardCache.GetLines(id).ToString()); + NotecardCache.Cache(id, a.Data); + AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(id).ToString()); }); - ScriptSleep(100); + ScriptSleep(m_sleepMsOnGetNumberOfNotecardLines); return tid.ToString(); } @@ -10872,19 +13470,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (assetID == UUID.Zero) { // => complain loudly, as specified by the LSL docs - ShoutError("Notecard '" + name + "' could not be found."); + Error("llGetNotecardLine", "Can't find notecard '" + name + "'"); return UUID.Zero.ToString(); } + string reqIdentifier = UUID.Random().ToString(); + // was: UUID tid = tid = AsyncCommands. - UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, assetID.ToString()); + UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, reqIdentifier); if (NotecardCache.IsCached(assetID)) { - AsyncCommands.DataserverPlugin.DataserverReply(assetID.ToString(), - NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax)); - ScriptSleep(100); + AsyncCommands.DataserverPlugin.DataserverReply( + reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax)); + + ScriptSleep(m_sleepMsOnGetNotecardLine); return tid.ToString(); } @@ -10892,18 +13493,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (a == null || a.Type != 7) { - ShoutError("Notecard '" + name + "' could not be found."); + Error("llGetNotecardLine", "Can't find notecard '" + name + "'"); return; } string data = Encoding.UTF8.GetString(a.Data); //m_log.Debug(data); - NotecardCache.Cache(id, data); - AsyncCommands.DataserverPlugin.DataserverReply(id.ToString(), - NotecardCache.GetLine(id, line, m_notecardLineReadCharsMax)); + NotecardCache.Cache(id, a.Data); + AsyncCommands.DataserverPlugin.DataserverReply( + reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax)); }); - ScriptSleep(100); + ScriptSleep(m_sleepMsOnGetNotecardLine); return tid.ToString(); } @@ -10916,41 +13517,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (obj.OwnerID != m_host.OwnerID) return; - uint rulesParsed = 0; - LSL_List remaining = SetPrimParams(obj, rules, originFunc, ref rulesParsed); - - while ((object)remaining != null && remaining.Length > 2) - { - LSL_Integer newLink = remaining.GetLSLIntegerItem(0); - LSL_List newrules = remaining.GetSublist(1, -1); - foreach(SceneObjectPart part in GetLinkParts(obj, newLink)){ - remaining = SetPrimParams(part, newrules, originFunc, ref rulesParsed); - } - } - } - - public LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules) - { - SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim)); - - LSL_List result = new LSL_List(); - - if (obj != null && obj.OwnerID != m_host.OwnerID) - { - LSL_List remaining = GetPrimParams(obj, rules, ref result); + SetEntityParams(new List() { obj }, rules, originFunc); + } - while (remaining != null && remaining.Length > 2) - { - int linknumber = remaining.GetLSLIntegerItem(0); - rules = remaining.GetSublist(1, -1); - List parts = GetLinkParts(linknumber); + public LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules) + { + SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim)); - foreach (SceneObjectPart part in parts) - remaining = GetPrimParams(part, rules, ref result); - } - } + if (obj != null && obj.OwnerID == m_host.OwnerID) + return GetEntityParams(obj, rules); - return result; + return new LSL_List(); } public void print(string str) @@ -11036,7 +13613,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World.ForEachScenePresence(delegate(ScenePresence sp) { Vector3 ac = sp.AbsolutePosition - rayStart; - Vector3 bc = sp.AbsolutePosition - rayEnd; +// Vector3 bc = sp.AbsolutePosition - rayEnd; double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); @@ -11124,9 +13701,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api radius = Math.Abs(maxY); if (Math.Abs(maxZ) > radius) radius = Math.Abs(maxZ); - + radius = radius*1.413f; Vector3 ac = group.AbsolutePosition - rayStart; - Vector3 bc = group.AbsolutePosition - rayEnd; +// Vector3 bc = group.AbsolutePosition - rayEnd; double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); @@ -11139,11 +13716,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (d2 > 0) return; + ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart)); EntityIntersection intersection = group.TestIntersection(ray, true, false); // Miss. if (!intersection.HitTF) return; + Vector3 b1 = group.AbsolutePosition + new Vector3(minX, minY, minZ); + Vector3 b2 = group.AbsolutePosition + new Vector3(maxX, maxY, maxZ); + //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); + if (!(intersection.ipoint.X >= b1.X && intersection.ipoint.X <= b2.X && + intersection.ipoint.Y >= b1.Y && intersection.ipoint.Y <= b2.Y && + intersection.ipoint.Z >= b1.Z && intersection.ipoint.Z <= b2.Z)) + return; + ContactResult result = new ContactResult (); result.ConsumerID = group.LocalId; result.Depth = intersection.distance; @@ -11254,155 +13840,1093 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api float wv = Vector3.Dot(w, v); float d = uv * uv - uu * vv; - float cs = (uv * wv - vv * wu) / d; - if (cs < 0 || cs > 1.0) - continue; - float ct = (uv * wu - uu * wv) / d; - if (ct < 0 || (cs + ct) > 1.0) - continue; + float cs = (uv * wv - vv * wu) / d; + if (cs < 0 || cs > 1.0) + continue; + float ct = (uv * wu - uu * wv) / d; + if (ct < 0 || (cs + ct) > 1.0) + continue; + + // Add contact point + ContactResult result = new ContactResult (); + result.ConsumerID = 0; + result.Depth = Vector3.Distance(rayStart, ip); + result.Normal = n; + result.Pos = ip; + + contacts.Add(result); + } + + if (contacts.Count == 0) + return null; + + contacts.Sort(delegate(ContactResult a, ContactResult b) + { + return (int)(a.Depth - b.Depth); + }); + + return contacts[0]; + } + + public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) + { + // Use llCastRay V3 if configured + if (m_useCastRayV3) + return llCastRayV3(start, end, options); + + LSL_List list = new LSL_List(); + + m_host.AddScriptLPS(1); + + Vector3 rayStart = start; + Vector3 rayEnd = end; + Vector3 dir = rayEnd - rayStart; + + float dist = Vector3.Mag(dir); + + int count = 1; + bool detectPhantom = false; + int dataFlags = 0; + int rejectTypes = 0; + + for (int i = 0; i < options.Length; i += 2) + { + if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS) + count = options.GetLSLIntegerItem(i + 1); + else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM) + detectPhantom = (options.GetLSLIntegerItem(i + 1) > 0); + else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS) + dataFlags = options.GetLSLIntegerItem(i + 1); + else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES) + rejectTypes = options.GetLSLIntegerItem(i + 1); + } + + if (count > 16) + count = 16; + + List results = new List(); + + bool checkTerrain = !((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) == ScriptBaseClass.RC_REJECT_LAND); + bool checkAgents = !((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) == ScriptBaseClass.RC_REJECT_AGENTS); + bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL); + bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL); + + + if (World.SupportsRayCastFiltered()) + { + if (dist == 0) + return list; + + RayFilterFlags rayfilter = RayFilterFlags.ClosestAndBackCull; + if (checkTerrain) + rayfilter |= RayFilterFlags.land; +// if (checkAgents) +// rayfilter |= RayFilterFlags.agent; + if (checkPhysical) + rayfilter |= RayFilterFlags.physical; + if (checkNonPhysical) + rayfilter |= RayFilterFlags.nonphysical; + if (detectPhantom) + rayfilter |= RayFilterFlags.LSLPhantom; + + Vector3 direction = dir * ( 1/dist); + + if(rayfilter == 0) + { + list.Add(new LSL_Integer(0)); + return list; + } + + // get some more contacts to sort ??? + int physcount = 4 * count; + if (physcount > 20) + physcount = 20; + + object physresults; + physresults = World.RayCastFiltered(rayStart, direction, dist, physcount, rayfilter); + + if (physresults == null) + { + list.Add(new LSL_Integer(-3)); // timeout error + return list; + } + + results = (List)physresults; + + // for now physics doesn't detect sitted avatars so do it outside physics + if (checkAgents) + { + ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd); + foreach (ContactResult r in agentHits) + results.Add(r); + } + + // TODO: Replace this with a better solution. ObjectIntersection can only + // detect nonphysical phantoms. They are detected by virtue of being + // nonphysical (e.g. no PhysActor) so will not conflict with detecting + // physicsl phantoms as done by the physics scene + // We don't want anything else but phantoms here. + if (detectPhantom) + { + ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, false, false, true); + foreach (ContactResult r in objectHits) + results.Add(r); + } + } + else + { + if (checkAgents) + { + ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd); + foreach (ContactResult r in agentHits) + results.Add(r); + } + + if (checkPhysical || checkNonPhysical || detectPhantom) + { + ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom); + for (int iter = 0; iter < objectHits.Length; iter++) + { + // Redistance the Depth because the Scene RayCaster returns distance from center to make the rezzing code simpler. + objectHits[iter].Depth = Vector3.Distance(objectHits[iter].Pos, rayStart); + results.Add(objectHits[iter]); + } + } + } + + if (checkTerrain) + { + ContactResult? groundContact = GroundIntersection(rayStart, rayEnd); + if (groundContact != null) + results.Add((ContactResult)groundContact); + } + + results.Sort(delegate(ContactResult a, ContactResult b) + { + return a.Depth.CompareTo(b.Depth); + }); + + int values = 0; + SceneObjectGroup thisgrp = m_host.ParentGroup; + + foreach (ContactResult result in results) + { + if (result.Depth > dist) + continue; + + // physics ray can return colisions with host prim + if (m_host.LocalId == result.ConsumerID) + continue; + + UUID itemID = UUID.Zero; + int linkNum = 0; + + SceneObjectPart part = World.GetSceneObjectPart(result.ConsumerID); + // It's a prim! + if (part != null) + { + // dont detect members of same object ??? + if (part.ParentGroup == thisgrp) + continue; + + if ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) == ScriptBaseClass.RC_GET_ROOT_KEY) + itemID = part.ParentGroup.UUID; + else + itemID = part.UUID; + + linkNum = part.LinkNum; + } + else + { + ScenePresence sp = World.GetScenePresence(result.ConsumerID); + /// It it a boy? a girl? + if (sp != null) + itemID = sp.UUID; + } + + list.Add(new LSL_String(itemID.ToString())); + list.Add(new LSL_String(result.Pos.ToString())); + + if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM) + list.Add(new LSL_Integer(linkNum)); + + if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL) + list.Add(new LSL_Vector(result.Normal)); + + values++; + if (values >= count) + break; + } + + list.Add(new LSL_Integer(values)); + + return list; + } + + /// + /// Implementation of llCastRay similar to SL 2015-04-21. + /// http://wiki.secondlife.com/wiki/LlCastRay + /// Uses pure geometry, bounding shapes, meshing and no physics + /// for prims, sculpts, meshes, avatars and terrain. + /// Implements all flags, reject types and data flags. + /// Can handle both objects/groups and prims/parts, by config. + /// May sometimes be inaccurate owing to calculation precision, + /// meshing detail level and a bug in libopenmetaverse PrimMesher. + /// + public LSL_List llCastRayV3(LSL_Vector start, LSL_Vector end, LSL_List options) + { + m_host.AddScriptLPS(1); + LSL_List result = new LSL_List(); + + // Prepare throttle data + int calledMs = Environment.TickCount; + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + UUID regionId = World.RegionInfo.RegionID; + UUID userId = UUID.Zero; + int msAvailable = 0; + // Throttle per owner when attachment or "vehicle" (sat upon) + if (m_host.ParentGroup.IsAttachment || m_host.ParentGroup.GetSittingAvatars().Count > 0) + { + userId = m_host.OwnerID; + msAvailable = m_msPerAvatarInCastRay; + } + // Throttle per parcel when not attachment or vehicle + else + { + LandData land = World.GetLandData(m_host.GetWorldPosition()); + if (land != null) + msAvailable = m_msPerRegionInCastRay * land.Area / 65536; + } + // Clamp for "oversized" parcels on varregions + if (msAvailable > m_msMaxInCastRay) + msAvailable = m_msMaxInCastRay; + + // Check throttle data + int fromCalledMs = calledMs - m_msThrottleInCastRay; + lock (m_castRayCalls) + { + for (int i = m_castRayCalls.Count - 1; i >= 0; i--) + { + // Delete old calls from throttle data + if (m_castRayCalls[i].CalledMs < fromCalledMs) + m_castRayCalls.RemoveAt(i); + // Use current region (in multi-region sims) + else if (m_castRayCalls[i].RegionId == regionId) + { + // Reduce available time with recent calls + if (m_castRayCalls[i].UserId == userId) + msAvailable -= m_castRayCalls[i].UsedMs; + } + } + } + + // Return failure if not enough available time + if (msAvailable < m_msMinInCastRay) + { + result.Add(new LSL_Integer(ScriptBaseClass.RCERR_CAST_TIME_EXCEEDED)); + return result; + } + + // Initialize + List rayHits = new List(); + float tol = m_floatToleranceInCastRay; + Vector3 pos1Ray = start; + Vector3 pos2Ray = end; + + // Get input options + int rejectTypes = 0; + int dataFlags = 0; + int maxHits = 1; + bool detectPhantom = false; + for (int i = 0; i < options.Length; i += 2) + { + if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES) + rejectTypes = options.GetLSLIntegerItem(i + 1); + else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS) + dataFlags = options.GetLSLIntegerItem(i + 1); + else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS) + maxHits = options.GetLSLIntegerItem(i + 1); + else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM) + detectPhantom = (options.GetLSLIntegerItem(i + 1) != 0); + } + if (maxHits > m_maxHitsInCastRay) + maxHits = m_maxHitsInCastRay; + bool rejectAgents = ((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) != 0); + bool rejectPhysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) != 0); + bool rejectNonphysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) != 0); + bool rejectLand = ((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) != 0); + bool getNormal = ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) != 0); + bool getRootKey = ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) != 0); + bool getLinkNum = ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) != 0); + + // Calculate some basic parameters + Vector3 vecRay = pos2Ray - pos1Ray; + float rayLength = vecRay.Length(); + + // Try to get a mesher and return failure if none, degenerate ray, or max 0 hits + IRendering primMesher = null; + List renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); + if (renderers.Count < 1 || rayLength < tol || m_maxHitsInCastRay < 1) + { + result.Add(new LSL_Integer(ScriptBaseClass.RCERR_UNKNOWN)); + return result; + } + primMesher = RenderingLoader.LoadRenderer(renderers[0]); + + // Iterate over all objects/groups and prims/parts in region + World.ForEachSOG( + delegate(SceneObjectGroup group) + { + // Check group filters unless part filters are configured + bool isPhysical = (group.RootPart != null && group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical); + bool isNonphysical = !isPhysical; + bool isPhantom = group.IsPhantom || group.IsVolumeDetect; + bool isAttachment = group.IsAttachment; + bool doGroup = true; + if (isPhysical && rejectPhysical) + doGroup = false; + if (isNonphysical && rejectNonphysical) + doGroup = false; + if (isPhantom && detectPhantom) + doGroup = true; + if (m_filterPartsInCastRay) + doGroup = true; + if (isAttachment && !m_doAttachmentsInCastRay) + doGroup = false; + // Parse object/group if passed filters + if (doGroup) + { + // Iterate over all prims/parts in object/group + foreach(SceneObjectPart part in group.Parts) + { + // Check part filters if configured + if (m_filterPartsInCastRay) + { + isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical); + isNonphysical = !isPhysical; + isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) || (part.VolumeDetectActive); + bool doPart = true; + if (isPhysical && rejectPhysical) + doPart = false; + if (isNonphysical && rejectNonphysical) + doPart = false; + if (isPhantom && detectPhantom) + doPart = true; + if (!doPart) + continue; + } + + // Parse prim/part and project ray if passed filters + Vector3 scalePart = part.Scale; + Vector3 posPart = part.GetWorldPosition(); + Quaternion rotPart = part.GetWorldRotation(); + Quaternion rotPartInv = Quaternion.Inverse(rotPart); + Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; + Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; + + // Filter parts by shape bounding boxes + Vector3 shapeBoxMax = new Vector3(0.5f, 0.5f, 0.5f); + if (!part.Shape.SculptEntry) + shapeBoxMax = shapeBoxMax * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ)); + shapeBoxMax = shapeBoxMax + (new Vector3(tol, tol, tol)); + if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) + { + // Prepare data needed to check for ray hits + RayTrans rayTrans = new RayTrans(); + rayTrans.PartId = part.UUID; + rayTrans.GroupId = part.ParentGroup.UUID; + rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0; + rayTrans.ScalePart = scalePart; + rayTrans.PositionPart = posPart; + rayTrans.RotationPart = rotPart; + rayTrans.ShapeNeedsEnds = true; + rayTrans.Position1Ray = pos1Ray; + rayTrans.Position1RayProj = pos1RayProj; + rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; + + // Get detail level depending on type + int lod = 0; + // Mesh detail level + if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh) + lod = (int)m_meshLodInCastRay; + // Sculpt detail level + else if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh) + lod = (int)m_sculptLodInCastRay; + // Shape detail level + else if (!part.Shape.SculptEntry) + lod = (int)m_primLodInCastRay; + + // Try to get cached mesh if configured + ulong meshKey = 0; + FacetedMesh mesh = null; + if (m_useMeshCacheInCastRay) + { + meshKey = part.Shape.GetMeshKey(Vector3.One, (float)(4 << lod)); + lock (m_cachedMeshes) + { + m_cachedMeshes.TryGetValue(meshKey, out mesh); + } + } + + // Create mesh if no cached mesh + if (mesh == null) + { + // Make an OMV prim to be able to mesh part + Primitive omvPrim = part.Shape.ToOmvPrimitive(posPart, rotPart); + byte[] sculptAsset = null; + if (omvPrim.Sculpt != null) + sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); + + // When part is mesh, get mesh + if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) + { + AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); + FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, m_meshLodInCastRay, out mesh); + meshAsset = null; + } + + // When part is sculpt, create mesh + // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. + else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) + { + IJ2KDecoder imgDecoder = World.RequestModuleInterface(); + if (imgDecoder != null) + { + Image sculpt = imgDecoder.DecodeToImage(sculptAsset); + if (sculpt != null) + { + mesh = primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, m_sculptLodInCastRay); + sculpt.Dispose(); + } + } + } + + // When part is shape, create mesh + else if (omvPrim.Sculpt == null) + { + if ( + omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 && + omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 && + omvPrim.PrimData.PathSkew == 0.0 && + omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0 + ) + rayTrans.ShapeNeedsEnds = false; + mesh = primMesher.GenerateFacetedMesh(omvPrim, m_primLodInCastRay); + } + + // Cache mesh if configured + if (m_useMeshCacheInCastRay && mesh != null) + { + lock(m_cachedMeshes) + { + if (!m_cachedMeshes.ContainsKey(meshKey)) + m_cachedMeshes.Add(meshKey, mesh); + } + } + } + // Check mesh for ray hits + AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); + mesh = null; + } + } + } + } + ); + + // Check avatar filter + if (!rejectAgents) + { + // Iterate over all avatars in region + World.ForEachRootScenePresence( + delegate (ScenePresence sp) + { + // Get bounding box + Vector3 lower; + Vector3 upper; + BoundingBoxOfScenePresence(sp, out lower, out upper); + // Parse avatar + Vector3 scalePart = upper - lower; + Vector3 posPart = sp.AbsolutePosition; + Quaternion rotPart = sp.GetWorldRotation(); + Quaternion rotPartInv = Quaternion.Inverse(rotPart); + posPart = posPart + (lower + upper) * 0.5f * rotPart; + // Project ray + Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; + Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; + + // Filter avatars by shape bounding boxes + Vector3 shapeBoxMax = new Vector3(0.5f + tol, 0.5f + tol, 0.5f + tol); + if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) + { + // Prepare data needed to check for ray hits + RayTrans rayTrans = new RayTrans(); + rayTrans.PartId = sp.UUID; + rayTrans.GroupId = sp.ParentPart != null ? sp.ParentPart.ParentGroup.UUID : sp.UUID; + rayTrans.Link = sp.ParentPart != null ? UUID2LinkNumber(sp.ParentPart, sp.UUID) : 0; + rayTrans.ScalePart = scalePart; + rayTrans.PositionPart = posPart; + rayTrans.RotationPart = rotPart; + rayTrans.ShapeNeedsEnds = false; + rayTrans.Position1Ray = pos1Ray; + rayTrans.Position1RayProj = pos1RayProj; + rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; + + // Try to get cached mesh if configured + PrimitiveBaseShape prim = PrimitiveBaseShape.CreateSphere(); + int lod = (int)m_avatarLodInCastRay; + ulong meshKey = prim.GetMeshKey(Vector3.One, (float)(4 << lod)); + FacetedMesh mesh = null; + if (m_useMeshCacheInCastRay) + { + lock (m_cachedMeshes) + { + m_cachedMeshes.TryGetValue(meshKey, out mesh); + } + } + + // Create mesh if no cached mesh + if (mesh == null) + { + // Make OMV prim and create mesh + prim.Scale = scalePart; + Primitive omvPrim = prim.ToOmvPrimitive(posPart, rotPart); + mesh = primMesher.GenerateFacetedMesh(omvPrim, m_avatarLodInCastRay); + + // Cache mesh if configured + if (m_useMeshCacheInCastRay && mesh != null) + { + lock(m_cachedMeshes) + { + if (!m_cachedMeshes.ContainsKey(meshKey)) + m_cachedMeshes.Add(meshKey, mesh); + } + } + } + + // Check mesh for ray hits + AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); + mesh = null; + } + } + ); + } + + // Check terrain filter + if (!rejectLand) + { + // Parse terrain + + // Mesh terrain and check bounding box + Vector3 lower; + Vector3 upper; + List triangles = TrisFromHeightmapUnderRay(pos1Ray, pos2Ray, out lower, out upper); + lower.Z -= tol; + upper.Z += tol; + if ((pos1Ray.Z >= lower.Z || pos2Ray.Z >= lower.Z) && (pos1Ray.Z <= upper.Z || pos2Ray.Z <= upper.Z)) + { + // Prepare data needed to check for ray hits + RayTrans rayTrans = new RayTrans(); + rayTrans.PartId = UUID.Zero; + rayTrans.GroupId = UUID.Zero; + rayTrans.Link = 0; + rayTrans.ScalePart = new Vector3 (1.0f, 1.0f, 1.0f); + rayTrans.PositionPart = Vector3.Zero; + rayTrans.RotationPart = Quaternion.Identity; + rayTrans.ShapeNeedsEnds = true; + rayTrans.Position1Ray = pos1Ray; + rayTrans.Position1RayProj = pos1Ray; + rayTrans.VectorRayProj = vecRay; + + // Check mesh + AddRayInTris(triangles, rayTrans, ref rayHits); + triangles = null; + } + } + + // Sort hits by ascending distance + rayHits.Sort((s1, s2) => s1.Distance.CompareTo(s2.Distance)); - // Add contact point - ContactResult result = new ContactResult (); - result.ConsumerID = 0; - result.Depth = Vector3.Distance(rayStart, ip); - result.Normal = n; - result.Pos = ip; + // Check excess hits per part and group + for (int t = 0; t < 2; t++) + { + int maxHitsPerType = 0; + UUID id = UUID.Zero; + if (t == 0) + maxHitsPerType = m_maxHitsPerPrimInCastRay; + else + maxHitsPerType = m_maxHitsPerObjectInCastRay; - contacts.Add(result); + // Handle excess hits only when needed + if (maxHitsPerType < m_maxHitsInCastRay) + { + // Find excess hits + Hashtable hits = new Hashtable(); + for (int i = rayHits.Count - 1; i >= 0; i--) + { + if (t == 0) + id = rayHits[i].PartId; + else + id = rayHits[i].GroupId; + if (hits.ContainsKey(id)) + hits[id] = (int)hits[id] + 1; + else + hits[id] = 1; + } + + // Remove excess hits + for (int i = rayHits.Count - 1; i >= 0; i--) + { + if (t == 0) + id = rayHits[i].PartId; + else + id = rayHits[i].GroupId; + int hit = (int)hits[id]; + if (hit > m_maxHitsPerPrimInCastRay) + { + rayHits.RemoveAt(i); + hit--; + hits[id] = hit; + } + } + } } - if (contacts.Count == 0) - return null; + // Parse hits into result list according to data flags + int hitCount = rayHits.Count; + if (hitCount > maxHits) + hitCount = maxHits; + for (int i = 0; i < hitCount; i++) + { + RayHit rayHit = rayHits[i]; + if (getRootKey) + result.Add(new LSL_Key(rayHit.GroupId.ToString())); + else + result.Add(new LSL_Key(rayHit.PartId.ToString())); + result.Add(new LSL_Vector(rayHit.Position)); + if (getLinkNum) + result.Add(new LSL_Integer(rayHit.Link)); + if (getNormal) + result.Add(new LSL_Vector(rayHit.Normal)); + } + result.Add(new LSL_Integer(hitCount)); - contacts.Sort(delegate(ContactResult a, ContactResult b) + // Add to throttle data + stopWatch.Stop(); + CastRayCall castRayCall = new CastRayCall(); + castRayCall.RegionId = regionId; + castRayCall.UserId = userId; + castRayCall.CalledMs = calledMs; + castRayCall.UsedMs = (int)stopWatch.ElapsedMilliseconds; + lock (m_castRayCalls) { - return (int)(a.Depth - b.Depth); - }); + m_castRayCalls.Add(castRayCall); + } - return contacts[0]; + // Return hits + return result; } - public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) + /// + /// Struct for transmitting parameters required for finding llCastRay ray hits. + /// + public struct RayTrans { - LSL_List list = new LSL_List(); + public UUID PartId; + public UUID GroupId; + public int Link; + public Vector3 ScalePart; + public Vector3 PositionPart; + public Quaternion RotationPart; + public bool ShapeNeedsEnds; + public Vector3 Position1Ray; + public Vector3 Position1RayProj; + public Vector3 VectorRayProj; + } - m_host.AddScriptLPS(1); + /// + /// Struct for llCastRay ray hits. + /// + public struct RayHit + { + public UUID PartId; + public UUID GroupId; + public int Link; + public Vector3 Position; + public Vector3 Normal; + public float Distance; + } - Vector3 rayStart = start; - Vector3 rayEnd = end; - Vector3 dir = rayEnd - rayStart; + /// + /// Struct for llCastRay throttle data. + /// + public struct CastRayCall + { + public UUID RegionId; + public UUID UserId; + public int CalledMs; + public int UsedMs; + } - float dist = Vector3.Mag(dir); + /// + /// Helper to check if a ray intersects a shape bounding box. + /// + private bool RayIntersectsShapeBox(Vector3 pos1RayProj, Vector3 pos2RayProj, Vector3 shapeBoxMax) + { + // Skip if ray can't intersect bounding box; + Vector3 rayBoxProjMin = Vector3.Min(pos1RayProj, pos2RayProj); + Vector3 rayBoxProjMax = Vector3.Max(pos1RayProj, pos2RayProj); + if ( + rayBoxProjMin.X > shapeBoxMax.X || rayBoxProjMin.Y > shapeBoxMax.Y || rayBoxProjMin.Z > shapeBoxMax.Z || + rayBoxProjMax.X < -shapeBoxMax.X || rayBoxProjMax.Y < -shapeBoxMax.Y || rayBoxProjMax.Z < -shapeBoxMax.Z + ) + return false; - int count = 1; - bool detectPhantom = false; - int dataFlags = 0; - int rejectTypes = 0; + // Check if ray intersect any bounding box side + int sign = 0; + float dist = 0.0f; + Vector3 posProj = Vector3.Zero; + Vector3 vecRayProj = pos2RayProj - pos1RayProj; - for (int i = 0; i < options.Length; i += 2) + // Check both X sides unless ray is parallell to them + if (Math.Abs(vecRayProj.X) > m_floatToleranceInCastRay) { - if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS) - count = options.GetLSLIntegerItem(i + 1); - else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM) - detectPhantom = (options.GetLSLIntegerItem(i + 1) > 0); - else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS) - dataFlags = options.GetLSLIntegerItem(i + 1); - else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES) - rejectTypes = options.GetLSLIntegerItem(i + 1); + for (sign = -1; sign <= 1; sign += 2) + { + dist = ((float)sign * shapeBoxMax.X - pos1RayProj.X) / vecRayProj.X; + posProj = pos1RayProj + vecRayProj * dist; + if (Math.Abs(posProj.Y) <= shapeBoxMax.Y && Math.Abs(posProj.Z) <= shapeBoxMax.Z) + return true; + } } - if (count > 16) - count = 16; - - List results = new List(); + // Check both Y sides unless ray is parallell to them + if (Math.Abs(vecRayProj.Y) > m_floatToleranceInCastRay) + { + for (sign = -1; sign <= 1; sign += 2) + { + dist = ((float)sign * shapeBoxMax.Y - pos1RayProj.Y) / vecRayProj.Y; + posProj = pos1RayProj + vecRayProj * dist; + if (Math.Abs(posProj.X) <= shapeBoxMax.X && Math.Abs(posProj.Z) <= shapeBoxMax.Z) + return true; + } + } - bool checkTerrain = !((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) == ScriptBaseClass.RC_REJECT_LAND); - bool checkAgents = !((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) == ScriptBaseClass.RC_REJECT_AGENTS); - bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL); - bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL); + // Check both Z sides unless ray is parallell to them + if (Math.Abs(vecRayProj.Z) > m_floatToleranceInCastRay) + { + for (sign = -1; sign <= 1; sign += 2) + { + dist = ((float)sign * shapeBoxMax.Z - pos1RayProj.Z) / vecRayProj.Z; + posProj = pos1RayProj + vecRayProj * dist; + if (Math.Abs(posProj.X) <= shapeBoxMax.X && Math.Abs(posProj.Y) <= shapeBoxMax.Y) + return true; + } + } + // No hits on bounding box so return false + return false; + } - if (checkTerrain) + /// + /// Helper to parse FacetedMesh for ray hits. + /// + private void AddRayInFacetedMesh(FacetedMesh mesh, RayTrans rayTrans, ref List rayHits) + { + if (mesh != null) { - ContactResult? groundContact = GroundIntersection(rayStart, rayEnd); - if (groundContact != null) - results.Add((ContactResult)groundContact); + foreach (Face face in mesh.Faces) + { + for (int i = 0; i < face.Indices.Count; i += 3) + { + Tri triangle = new Tri(); + triangle.p1 = face.Vertices[face.Indices[i]].Position; + triangle.p2 = face.Vertices[face.Indices[i + 1]].Position; + triangle.p3 = face.Vertices[face.Indices[i + 2]].Position; + AddRayInTri(triangle, rayTrans, ref rayHits); + } + } } + } - if (checkAgents) + /// + /// Helper to parse Tri (triangle) List for ray hits. + /// + private void AddRayInTris(List triangles, RayTrans rayTrans, ref List rayHits) + { + foreach (Tri triangle in triangles) { - ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd); - foreach (ContactResult r in agentHits) - results.Add(r); + AddRayInTri(triangle, rayTrans, ref rayHits); } + } - if (checkPhysical || checkNonPhysical || detectPhantom) + /// + /// Helper to add ray hit in a Tri (triangle). + /// + private void AddRayInTri(Tri triProj, RayTrans rayTrans, ref List rayHits) + { + // Check for hit in triangle + Vector3 posHitProj; + Vector3 normalProj; + if (HitRayInTri(triProj, rayTrans.Position1RayProj, rayTrans.VectorRayProj, out posHitProj, out normalProj)) { - ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom); - foreach (ContactResult r in objectHits) - results.Add(r); + // Hack to circumvent ghost face bug in PrimMesher by removing hits in (ghost) face plane through shape center + if (Math.Abs(Vector3.Dot(posHitProj, normalProj)) < m_floatToleranceInCastRay && !rayTrans.ShapeNeedsEnds) + return; + + // Transform hit and normal to region coordinate system + Vector3 posHit = rayTrans.PositionPart + (posHitProj * rayTrans.ScalePart) * rayTrans.RotationPart; + Vector3 normal = Vector3.Normalize((normalProj * rayTrans.ScalePart) * rayTrans.RotationPart); + + // Remove duplicate hits at triangle intersections + float distance = Vector3.Distance(rayTrans.Position1Ray, posHit); + for (int i = rayHits.Count - 1; i >= 0; i--) + { + if (rayHits[i].PartId != rayTrans.PartId) + break; + if (Math.Abs(rayHits[i].Distance - distance) < m_floatTolerance2InCastRay) + return; + } + + // Build result data set + RayHit rayHit = new RayHit(); + rayHit.PartId = rayTrans.PartId; + rayHit.GroupId = rayTrans.GroupId; + rayHit.Link = rayTrans.Link; + rayHit.Position = posHit; + rayHit.Normal = normal; + rayHit.Distance = distance; + rayHits.Add(rayHit); } + } - results.Sort(delegate(ContactResult a, ContactResult b) - { - return a.Depth.CompareTo(b.Depth); - }); + /// + /// Helper to find ray hit in triangle + /// + bool HitRayInTri(Tri triProj, Vector3 pos1RayProj, Vector3 vecRayProj, out Vector3 posHitProj, out Vector3 normalProj) + { + float tol = m_floatToleranceInCastRay; + posHitProj = Vector3.Zero; - int values = 0; - SceneObjectGroup thisgrp = m_host.ParentGroup; + // Calculate triangle edge vectors + Vector3 vec1Proj = triProj.p2 - triProj.p1; + Vector3 vec2Proj = triProj.p3 - triProj.p2; + Vector3 vec3Proj = triProj.p1 - triProj.p3; - foreach (ContactResult result in results) - { - if (result.Depth > dist) - continue; + // Calculate triangle normal + normalProj = Vector3.Cross(vec1Proj, vec2Proj); - // physics ray can return colisions with host prim - if (m_host.LocalId == result.ConsumerID) - continue; + // Skip if degenerate triangle or ray parallell with triangle plane + float divisor = Vector3.Dot(vecRayProj, normalProj); + if (Math.Abs(divisor) < tol) + return false; - UUID itemID = UUID.Zero; - int linkNum = 0; + // Skip if exit and not configured to detect + if (divisor > tol && !m_detectExitsInCastRay) + return false; - SceneObjectPart part = World.GetSceneObjectPart(result.ConsumerID); - // It's a prim! - if (part != null) - { - // dont detect members of same object ??? - if (part.ParentGroup == thisgrp) - continue; + // Skip if outside ray ends + float distanceProj = Vector3.Dot(triProj.p1 - pos1RayProj, normalProj) / divisor; + if (distanceProj < -tol || distanceProj > 1 + tol) + return false; - if ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) == ScriptBaseClass.RC_GET_ROOT_KEY) - itemID = part.ParentGroup.UUID; - else - itemID = part.UUID; + // Calculate hit position in triangle + posHitProj = pos1RayProj + vecRayProj * distanceProj; - linkNum = part.LinkNum; + // Skip if outside triangle bounding box + Vector3 triProjMin = Vector3.Min(Vector3.Min(triProj.p1, triProj.p2), triProj.p3); + Vector3 triProjMax = Vector3.Max(Vector3.Max(triProj.p1, triProj.p2), triProj.p3); + if ( + posHitProj.X < triProjMin.X - tol || posHitProj.Y < triProjMin.Y - tol || posHitProj.Z < triProjMin.Z - tol || + posHitProj.X > triProjMax.X + tol || posHitProj.Y > triProjMax.Y + tol || posHitProj.Z > triProjMax.Z + tol + ) + return false; + + // Skip if outside triangle + if ( + Vector3.Dot(Vector3.Cross(vec1Proj, normalProj), posHitProj - triProj.p1) > tol || + Vector3.Dot(Vector3.Cross(vec2Proj, normalProj), posHitProj - triProj.p2) > tol || + Vector3.Dot(Vector3.Cross(vec3Proj, normalProj), posHitProj - triProj.p3) > tol + ) + return false; + + // Return hit + return true; + } + + /// + /// Helper to parse selected parts of HeightMap into a Tri (triangle) List and calculate bounding box. + /// + private List TrisFromHeightmapUnderRay(Vector3 posStart, Vector3 posEnd, out Vector3 lower, out Vector3 upper) + { + // Get bounding X-Y rectangle of terrain under ray + lower = Vector3.Min(posStart, posEnd); + upper = Vector3.Max(posStart, posEnd); + lower.X = (float)Math.Floor(lower.X); + lower.Y = (float)Math.Floor(lower.Y); + float zLower = float.MaxValue; + upper.X = (float)Math.Ceiling(upper.X); + upper.Y = (float)Math.Ceiling(upper.Y); + float zUpper = float.MinValue; + + // Initialize Tri (triangle) List + List triangles = new List(); + + // Set parsing lane direction to major ray X-Y axis + Vector3 vec = posEnd - posStart; + float xAbs = Math.Abs(vec.X); + float yAbs = Math.Abs(vec.Y); + bool bigX = true; + if (yAbs > xAbs) + { + bigX = false; + vec = vec / yAbs; + } + else if (xAbs > yAbs || xAbs > 0.0f) + vec = vec / xAbs; + else + vec = new Vector3(1.0f, 1.0f, 0.0f); + + // Simplify by start parsing in lower end of lane + if ((bigX && vec.X < 0.0f) || (!bigX && vec.Y < 0.0f)) + { + Vector3 posTemp = posStart; + posStart = posEnd; + posEnd = posTemp; + vec = vec * -1.0f; + } + + // First 1x1 rectangle under ray + float xFloorOld = 0.0f; + float yFloorOld = 0.0f; + Vector3 pos = posStart; + float xFloor = (float)Math.Floor(pos.X); + float yFloor = (float)Math.Floor(pos.Y); + AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper); + + // Parse every remaining 1x1 rectangle under ray + while (pos != posEnd) + { + // Next 1x1 rectangle under ray + xFloorOld = xFloor; + yFloorOld = yFloor; + pos = pos + vec; + + // Clip position to 1x1 rectangle border + xFloor = (float)Math.Floor(pos.X); + yFloor = (float)Math.Floor(pos.Y); + if (bigX && pos.X > xFloor) + { + pos.Y -= vec.Y * (pos.X - xFloor); + pos.X = xFloor; } - else + else if (!bigX && pos.Y > yFloor) { - ScenePresence sp = World.GetScenePresence(result.ConsumerID); - /// It it a boy? a girl? - if (sp != null) - itemID = sp.UUID; + pos.X -= vec.X * (pos.Y - yFloor); + pos.Y = yFloor; } - list.Add(new LSL_String(itemID.ToString())); - list.Add(new LSL_String(result.Pos.ToString())); + // Last 1x1 rectangle under ray + if ((bigX && pos.X >= posEnd.X) || (!bigX && pos.Y >= posEnd.Y)) + { + pos = posEnd; + xFloor = (float)Math.Floor(pos.X); + yFloor = (float)Math.Floor(pos.Y); + } - if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM) - list.Add(new LSL_Integer(linkNum)); + // Add new 1x1 rectangle in lane + if ((bigX && xFloor != xFloorOld) || (!bigX && yFloor != yFloorOld)) + AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper); + // Add last 1x1 rectangle in old lane at lane shift + if (bigX && yFloor != yFloorOld) + AddTrisFromHeightmap(xFloor, yFloorOld, ref triangles, ref zLower, ref zUpper); + if (!bigX && xFloor != xFloorOld) + AddTrisFromHeightmap(xFloorOld, yFloor, ref triangles, ref zLower, ref zUpper); + } - if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL) - list.Add(new LSL_Vector(result.Normal.X, result.Normal.Y, result.Normal.Z)); + // Finalize bounding box Z + lower.Z = zLower; + upper.Z = zUpper; - values++; - if (values >= count) - break; - } + // Done and returning Tri (triangle)List + return triangles; + } - list.Add(new LSL_Integer(values)); + /// + /// Helper to add HeightMap squares into Tri (triangle) List and adjust bounding box. + /// + private void AddTrisFromHeightmap(float xPos, float yPos, ref List triangles, ref float zLower, ref float zUpper) + { + int xInt = (int)xPos; + int yInt = (int)yPos; + + // Corner 1 of 1x1 rectangle + int x = Util.Clamp(xInt+1, 0, World.Heightmap.Width - 1); + int y = Util.Clamp(yInt+1, 0, World.Heightmap.Height - 1); + Vector3 pos1 = new Vector3(x, y, (float)World.Heightmap[x, y]); + // Adjust bounding box + zLower = Math.Min(zLower, pos1.Z); + zUpper = Math.Max(zUpper, pos1.Z); + + // Corner 2 of 1x1 rectangle + x = Util.Clamp(xInt, 0, World.Heightmap.Width - 1); + y = Util.Clamp(yInt+1, 0, World.Heightmap.Height - 1); + Vector3 pos2 = new Vector3(x, y, (float)World.Heightmap[x, y]); + // Adjust bounding box + zLower = Math.Min(zLower, pos2.Z); + zUpper = Math.Max(zUpper, pos2.Z); + + // Corner 3 of 1x1 rectangle + x = Util.Clamp(xInt, 0, World.Heightmap.Width - 1); + y = Util.Clamp(yInt, 0, World.Heightmap.Height - 1); + Vector3 pos3 = new Vector3(x, y, (float)World.Heightmap[x, y]); + // Adjust bounding box + zLower = Math.Min(zLower, pos3.Z); + zUpper = Math.Max(zUpper, pos3.Z); + + // Corner 4 of 1x1 rectangle + x = Util.Clamp(xInt+1, 0, World.Heightmap.Width - 1); + y = Util.Clamp(yInt, 0, World.Heightmap.Height - 1); + Vector3 pos4 = new Vector3(x, y, (float)World.Heightmap[x, y]); + // Adjust bounding box + zLower = Math.Min(zLower, pos4.Z); + zUpper = Math.Max(zUpper, pos4.Z); + + // Add triangle 1 + Tri triangle1 = new Tri(); + triangle1.p1 = pos1; + triangle1.p2 = pos2; + triangle1.p3 = pos3; + triangles.Add(triangle1); + + // Add triangle 2 + Tri triangle2 = new Tri(); + triangle2.p1 = pos3; + triangle2.p2 = pos4; + triangle2.p3 = pos1; + triangles.Add(triangle2); + } - return list; + /// + /// Helper to get link number for a UUID. + /// + private int UUID2LinkNumber(SceneObjectPart part, UUID id) + { + SceneObjectGroup group = part.ParentGroup; + if (group != null) + { + // Parse every link for UUID + int linkCount = group.PrimCount + group.GetSittingAvatarsCount(); + for (int link = linkCount; link > 0; link--) + { + ISceneEntity entity = GetLinkEntity(part, link); + // Return link number if UUID match + if (entity != null && entity.UUID == id) + return link; + } + } + // Return link number 0 if no links or UUID matches + return 0; } public LSL_Integer llManageEstateAccess(int action, string avatar) @@ -11477,8 +15001,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llGetMemoryLimit() { m_host.AddScriptLPS(1); - // The value returned for LSO scripts in SL - return 16384; + // The value returned for Mono scripts in SL + return 65536; } public LSL_Integer llSetMemoryLimit(LSL_Integer limit) @@ -11491,15 +15015,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llGetSPMaxMemory() { m_host.AddScriptLPS(1); - // The value returned for LSO scripts in SL - return 16384; + // The value returned for Mono scripts in SL + return 65536; } - public LSL_Integer llGetUsedMemory() + public virtual LSL_Integer llGetUsedMemory() { m_host.AddScriptLPS(1); - // The value returned for LSO scripts in SL - return 16384; + // The value returned for Mono scripts in SL + return 65536; } public void llScriptProfiler(LSL_Integer flags) @@ -11514,16 +15038,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // them from this region as they are completed // - public void llGetEnv(LSL_String name) - { - m_host.AddScriptLPS(1); - NotImplemented("llGetEnv"); - } - public void llSetSoundQueueing(int queue) { m_host.AddScriptLPS(1); - NotImplemented("llSetSoundQueueing"); + + if (m_SoundModule != null) + m_SoundModule.SetSoundQueueing(m_host.UUID, queue == ScriptBaseClass.TRUE.value); } public void llCollisionSprite(string impact_sprite) @@ -11538,6 +15058,79 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api NotImplemented("llGodLikeRezObject"); } + public LSL_String llTransferLindenDollars(string destination, int amount) + { + UUID txn = UUID.Random(); + + Util.FireAndForget(delegate(object x) + { + int replycode = 0; + string replydata = destination + "," + amount.ToString(); + + try + { + TaskInventoryItem item = m_item; + if (item == null) + { + replydata = "SERVICE_ERROR"; + return; + } + + m_host.AddScriptLPS(1); + + if (item.PermsGranter == UUID.Zero) + { + replydata = "MISSING_PERMISSION_DEBIT"; + return; + } + + if ((item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0) + { + replydata = "MISSING_PERMISSION_DEBIT"; + return; + } + + UUID toID = new UUID(); + + if (!UUID.TryParse(destination, out toID)) + { + replydata = "INVALID_AGENT"; + return; + } + + IMoneyModule money = World.RequestModuleInterface(); + + if (money == null) + { + replydata = "TRANSFERS_DISABLED"; + return; + } + + bool result = money.ObjectGiveMoney( + m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount); + + if (result) + { + replycode = 1; + return; + } + + replydata = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + } + finally + { + m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams( + "transaction_result", new Object[] { + new LSL_String(txn.ToString()), + new LSL_Integer(replycode), + new LSL_String(replydata) }, + new DetectParams[0])); + } + }, null, "LSL_Api.llTransferLindenDollars"); + + return txn.ToString(); + } + #endregion } @@ -11549,12 +15142,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public DateTime lastRef; } - protected static Dictionary m_Notecards = + private static Dictionary m_Notecards = new Dictionary(); - public static void Cache(UUID assetID, string text) + public static void Cache(UUID assetID, byte[] text) { - CacheCheck(); + CheckCache(); lock (m_Notecards) { @@ -11563,7 +15156,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api Notecard nc = new Notecard(); nc.lastRef = DateTime.Now; - nc.text = SLUtil.ParseNotecardToList(text).ToArray(); + try + { + nc.text = SLUtil.ParseNotecardToArray(text); + } + catch(SLUtil.NotANotecardFormatException) + { + nc.text = new string[0]; + } m_Notecards[assetID] = nc; } } @@ -11639,13 +15239,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return line; } - public static void CacheCheck() + public static void CheckCache() { - foreach (UUID key in new List(m_Notecards.Keys)) + lock (m_Notecards) { - Notecard nc = m_Notecards[key]; - if (nc.lastRef.AddSeconds(30) < DateTime.Now) - m_Notecards.Remove(key); + foreach (UUID key in new List(m_Notecards.Keys)) + { + Notecard nc = m_Notecards[key]; + if (nc.lastRef.AddSeconds(30) < DateTime.Now) + m_Notecards.Remove(key); + } } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs index ceb4660..e5e43f8 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; using System.Collections; using System.Collections.Generic; using System.Runtime.Remoting.Lifetime; +using System.Threading; using OpenMetaverse; using Nini.Config; using OpenSim; @@ -61,9 +62,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal bool m_LSFunctionsEnabled = false; internal IScriptModuleComms m_comms = null; - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) + public void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item) { - m_ScriptEngine = ScriptEngine; + m_ScriptEngine = scriptEngine; m_host = host; if (m_ScriptEngine.Config.GetBoolean("AllowLightShareFunctions", false)) @@ -92,10 +94,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api get { return m_ScriptEngine.World; } } - // - //Dumps an error message on the debug console. - // - + /// + /// Dumps an error message on the debug console. + /// internal void LSShoutError(string message) { if (message.Length > 1023) @@ -264,175 +265,445 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api int idx = 0; while (idx < rules.Length) { - uint rule = (uint)rules.GetLSLIntegerItem(idx); + uint rule; + + try + { + rule = (uint)rules.GetLSLIntegerItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule type: arg #{0} - parameter type must be integer", idx)); + } + LSL_Types.Quaternion iQ; LSL_Types.Vector3 iV; switch (rule) { case (int)ScriptBaseClass.WL_SUN_MOON_POSITION: idx++; - wl.sunMoonPosition = (float)rules.GetLSLFloatItem(idx); + try + { + wl.sunMoonPosition = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_SUN_MOON_POSITION: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_AMBIENT: idx++; - iQ = rules.GetQuaternionItem(idx); + try + { + iQ = rules.GetQuaternionItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_AMBIENT: arg #{0} - parameter 1 must be rotation", idx)); + } wl.ambient = new Vector4((float)iQ.x, (float)iQ.y, (float)iQ.z, (float)iQ.s); break; case (int)ScriptBaseClass.WL_BIG_WAVE_DIRECTION: idx++; - iV = rules.GetVector3Item(idx); + try + { + iV = rules.GetVector3Item(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_BIG_WAVE_DIRECTION: arg #{0} - parameter 1 must be vector", idx)); + } wl.bigWaveDirection = new Vector2((float)iV.x, (float)iV.y); break; case (int)ScriptBaseClass.WL_BLUE_DENSITY: idx++; - iQ = rules.GetQuaternionItem(idx); + try + { + iQ = rules.GetQuaternionItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_BLUE_DENSITY: arg #{0} - parameter 1 must be rotation", idx)); + } wl.blueDensity = new Vector4((float)iQ.x, (float)iQ.y, (float)iQ.z, (float)iQ.s); break; case (int)ScriptBaseClass.WL_BLUR_MULTIPLIER: idx++; - wl.blurMultiplier = (float)rules.GetLSLFloatItem(idx); + try + { + wl.blurMultiplier = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_BLUR_MULTIPLIER: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_CLOUD_COLOR: idx++; - iQ = rules.GetQuaternionItem(idx); + try + { + iQ = rules.GetQuaternionItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_CLOUD_COLOR: arg #{0} - parameter 1 must be rotation", idx)); + } wl.cloudColor = new Vector4((float)iQ.x, (float)iQ.y, (float)iQ.z, (float)iQ.s); break; case (int)ScriptBaseClass.WL_CLOUD_COVERAGE: idx++; - wl.cloudCoverage = (float)rules.GetLSLFloatItem(idx); + try + { + wl.cloudCoverage = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_CLOUD_COVERAGE: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_CLOUD_DETAIL_XY_DENSITY: idx++; - iV = rules.GetVector3Item(idx); + try + { + iV = rules.GetVector3Item(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_CLOUD_DETAIL_XY_DENSITY: arg #{0} - parameter 1 must be vector", idx)); + } wl.cloudDetailXYDensity = iV; break; case (int)ScriptBaseClass.WL_CLOUD_SCALE: idx++; - wl.cloudScale = (float)rules.GetLSLFloatItem(idx); + try + { + wl.cloudScale = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_CLOUD_SCALE: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_CLOUD_SCROLL_X: idx++; - wl.cloudScrollX = (float)rules.GetLSLFloatItem(idx); + try + { + wl.cloudScrollX = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_CLOUD_SCROLL_X: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_CLOUD_SCROLL_X_LOCK: idx++; - wl.cloudScrollXLock = rules.GetLSLIntegerItem(idx).value == 1 ? true : false; + try + { + wl.cloudScrollXLock = rules.GetLSLIntegerItem(idx).value == 1 ? true : false; + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_CLOUD_SCROLL_Y_LOCK: arg #{0} - parameter 1 must be integer", idx)); + } break; case (int)ScriptBaseClass.WL_CLOUD_SCROLL_Y: idx++; - wl.cloudScrollY = (float)rules.GetLSLFloatItem(idx); + try + { + wl.cloudScrollY = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_CLOUD_SCROLL_Y: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_CLOUD_SCROLL_Y_LOCK: idx++; - wl.cloudScrollYLock = rules.GetLSLIntegerItem(idx).value == 1 ? true : false; + try + { + wl.cloudScrollYLock = rules.GetLSLIntegerItem(idx).value == 1 ? true : false; + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_CLOUD_SCROLL_Y_LOCK: arg #{0} - parameter 1 must be integer", idx)); + } break; case (int)ScriptBaseClass.WL_CLOUD_XY_DENSITY: idx++; - iV = rules.GetVector3Item(idx); + try + { + iV = rules.GetVector3Item(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_CLOUD_XY_DENSITY: arg #{0} - parameter 1 must be vector", idx)); + } wl.cloudXYDensity = iV; break; case (int)ScriptBaseClass.WL_DENSITY_MULTIPLIER: idx++; - wl.densityMultiplier = (float)rules.GetLSLFloatItem(idx); + try + { + wl.densityMultiplier = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_DENSITY_MULTIPLIER: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_DISTANCE_MULTIPLIER: idx++; - wl.distanceMultiplier = (float)rules.GetLSLFloatItem(idx); + try + { + wl.distanceMultiplier = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_DISTANCE_MULTIPLIER: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_DRAW_CLASSIC_CLOUDS: idx++; - wl.drawClassicClouds = rules.GetLSLIntegerItem(idx).value == 1 ? true : false; + try + { + wl.drawClassicClouds = rules.GetLSLIntegerItem(idx).value == 1 ? true : false; + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_DRAW_CLASSIC_CLOUDS: arg #{0} - parameter 1 must be integer", idx)); + } break; case (int)ScriptBaseClass.WL_EAST_ANGLE: idx++; - wl.eastAngle = (float)rules.GetLSLFloatItem(idx); + try + { + wl.eastAngle = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_EAST_ANGLE: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_FRESNEL_OFFSET: idx++; - wl.fresnelOffset = (float)rules.GetLSLFloatItem(idx); + try + { + wl.fresnelOffset = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_FRESNEL_OFFSET: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_FRESNEL_SCALE: idx++; - wl.fresnelScale = (float)rules.GetLSLFloatItem(idx); + try + { + wl.fresnelScale = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_FRESNEL_SCALE: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_HAZE_DENSITY: idx++; - wl.hazeDensity = (float)rules.GetLSLFloatItem(idx); + try + { + wl.hazeDensity = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_HAZE_DENSITY: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_HAZE_HORIZON: idx++; - wl.hazeHorizon = (float)rules.GetLSLFloatItem(idx); + try + { + wl.hazeHorizon = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_HAZE_HORIZON: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_HORIZON: idx++; - iQ = rules.GetQuaternionItem(idx); + try + { + iQ = rules.GetQuaternionItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_HORIZON: arg #{0} - parameter 1 must be rotation", idx)); + } wl.horizon = new Vector4((float)iQ.x, (float)iQ.y, (float)iQ.z, (float)iQ.s); break; case (int)ScriptBaseClass.WL_LITTLE_WAVE_DIRECTION: idx++; - iV = rules.GetVector3Item(idx); + try + { + iV = rules.GetVector3Item(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_LITTLE_WAVE_DIRECTION: arg #{0} - parameter 1 must be vector", idx)); + } wl.littleWaveDirection = new Vector2((float)iV.x, (float)iV.y); break; case (int)ScriptBaseClass.WL_MAX_ALTITUDE: idx++; - wl.maxAltitude = (ushort)rules.GetLSLIntegerItem(idx).value; + try + { + wl.maxAltitude = (ushort)rules.GetLSLIntegerItem(idx).value; + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_MAX_ALTITUDE: arg #{0} - parameter 1 must be integer", idx)); + } break; case (int)ScriptBaseClass.WL_NORMAL_MAP_TEXTURE: idx++; - wl.normalMapTexture = new UUID(rules.GetLSLStringItem(idx).m_string); + try + { + wl.normalMapTexture = new UUID(rules.GetLSLStringItem(idx).m_string); + } + catch (ArgumentException) + { + throw new InvalidCastException(string.Format("Error running rule WL_NORMAL_MAP_TEXTURE: arg #{0} - parameter 1 must be key", idx)); + } break; case (int)ScriptBaseClass.WL_REFLECTION_WAVELET_SCALE: idx++; - iV = rules.GetVector3Item(idx); + try + { + iV = rules.GetVector3Item(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_REFLECTION_WAVELET_SCALE: arg #{0} - parameter 1 must be vector", idx)); + } wl.reflectionWaveletScale = iV; break; case (int)ScriptBaseClass.WL_REFRACT_SCALE_ABOVE: idx++; - wl.refractScaleAbove = (float)rules.GetLSLFloatItem(idx); + try + { + wl.refractScaleAbove = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_REFRACT_SCALE_ABOVE: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_REFRACT_SCALE_BELOW: idx++; - wl.refractScaleBelow = (float)rules.GetLSLFloatItem(idx); + try + { + wl.refractScaleBelow = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_REFRACT_SCALE_BELOW: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_SCENE_GAMMA: idx++; - wl.sceneGamma = (float)rules.GetLSLFloatItem(idx); + try + { + wl.sceneGamma = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_SCENE_GAMMA: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_STAR_BRIGHTNESS: idx++; - wl.starBrightness = (float)rules.GetLSLFloatItem(idx); + try + { + wl.starBrightness = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_STAR_BRIGHTNESS: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_SUN_GLOW_FOCUS: idx++; - wl.sunGlowFocus = (float)rules.GetLSLFloatItem(idx); + try + { + wl.sunGlowFocus = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_SUN_GLOW_FOCUS: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_SUN_GLOW_SIZE: idx++; - wl.sunGlowSize = (float)rules.GetLSLFloatItem(idx); + try + { + wl.sunGlowSize = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_SUN_GLOW_SIZE: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_SUN_MOON_COLOR: idx++; iQ = rules.GetQuaternionItem(idx); - wl.sunMoonColor = new Vector4((float)iQ.x, (float)iQ.y, (float)iQ.z, (float)iQ.s); + try + { + wl.sunMoonColor = new Vector4((float)iQ.x, (float)iQ.y, (float)iQ.z, (float)iQ.s); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_SUN_MOON_COLOR: arg #{0} - parameter 1 must be rotation", idx)); + } break; case (int)ScriptBaseClass.WL_UNDERWATER_FOG_MODIFIER: idx++; - wl.underwaterFogModifier = (float)rules.GetLSLFloatItem(idx); + try + { + wl.underwaterFogModifier = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_UNDERWATER_FOG_MODIFIER: arg #{0} - parameter 1 must be float", idx)); + } break; case (int)ScriptBaseClass.WL_WATER_COLOR: idx++; - iV = rules.GetVector3Item(idx); + try + { + iV = rules.GetVector3Item(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_WATER_COLOR: arg #{0} - parameter 1 must be vector", idx)); + } wl.waterColor = iV; break; case (int)ScriptBaseClass.WL_WATER_FOG_DENSITY_EXPONENT: idx++; - wl.waterFogDensityExponent = (float)rules.GetLSLFloatItem(idx); + try + { + wl.waterFogDensityExponent = (float)rules.GetLSLFloatItem(idx); + } + catch (InvalidCastException) + { + throw new InvalidCastException(string.Format("Error running rule WL_WATER_FOG_DENSITY_EXPONENT: arg #{0} - parameter 1 must be float", idx)); + } break; } idx++; } return wl; } + /// /// Set the current Windlight scene /// @@ -445,16 +716,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSShoutError("LightShare functions are not enabled."); return 0; } - if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) + + if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID)) { - LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); - return 0; + ScenePresence sp = World.GetScenePresence(m_host.OwnerID); + + if (sp == null || sp.GodLevel < 200) + { + LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); + return 0; + } } + int success = 0; m_host.AddScriptLPS(1); + if (LightShareModule.EnableWindlight) { - RegionLightShareData wl = getWindlightProfileFromRules(rules); + RegionLightShareData wl; + try + { + wl = getWindlightProfileFromRules(rules); + } + catch(InvalidCastException e) + { + LSShoutError(e.Message); + return 0; + } wl.valid = true; m_host.ParentGroup.Scene.StoreWindlightProfile(wl); success = 1; @@ -464,8 +752,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSShoutError("Windlight module is disabled"); return 0; } + return success; } + public void lsClearWindlightScene() { if (!m_LSFunctionsEnabled) @@ -473,17 +763,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSShoutError("LightShare functions are not enabled."); return; } - if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) + + if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID)) { - LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); - return; + ScenePresence sp = World.GetScenePresence(m_host.OwnerID); + + if (sp == null || sp.GodLevel < 200) + { + LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); + return; + } } m_host.ParentGroup.Scene.RegionInfo.WindlightSettings.valid = false; if (m_host.ParentGroup.Scene.SimulationDataService != null) m_host.ParentGroup.Scene.SimulationDataService.RemoveRegionWindlightSettings(m_host.ParentGroup.Scene.RegionInfo.RegionID); + m_host.ParentGroup.Scene.EventManager.TriggerOnSaveNewWindlightProfile(); } + /// /// Set the current Windlight scene to a target avatar /// @@ -496,16 +794,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSShoutError("LightShare functions are not enabled."); return 0; } - if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) + + if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID)) { - LSShoutError("lsSetWindlightSceneTargeted can only be used by estate managers or owners."); - return 0; + ScenePresence sp = World.GetScenePresence(m_host.OwnerID); + + if (sp == null || sp.GodLevel < 200) + { + LSShoutError("lsSetWindlightSceneTargeted can only be used by estate managers or owners."); + return 0; + } } + int success = 0; m_host.AddScriptLPS(1); + if (LightShareModule.EnableWindlight) - { - RegionLightShareData wl = getWindlightProfileFromRules(rules); + { + RegionLightShareData wl; + try + { + wl = getWindlightProfileFromRules(rules); + } + catch(InvalidCastException e) + { + LSShoutError(e.Message); + return 0; + } World.EventManager.TriggerOnSendNewWindlightProfileTargeted(wl, new UUID(target.m_string)); success = 1; } @@ -514,8 +829,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSShoutError("Windlight module is disabled"); return 0; } + return success; - } - + } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs index 8f34833..1458c95 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; using System.Collections; using System.Collections.Generic; using System.Runtime.Remoting.Lifetime; +using System.Threading; +using log4net; using OpenMetaverse; using Nini.Config; using OpenSim; @@ -55,15 +57,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api [Serializable] public class MOD_Api : MarshalByRefObject, IMOD_Api, IScriptApi { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + internal IScriptEngine m_ScriptEngine; internal SceneObjectPart m_host; internal TaskInventoryItem m_item; internal bool m_MODFunctionsEnabled = false; internal IScriptModuleComms m_comms = null; - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) + public void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item) { - m_ScriptEngine = ScriptEngine; + m_ScriptEngine = scriptEngine; m_host = host; m_item = item; @@ -107,8 +112,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (message.Length > 1023) message = message.Substring(0, 1023); - World.SimChat(Utils.StringToBytes(message), - ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, true); + World.SimChat( + Utils.StringToBytes(message), + ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, + m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false); IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message); @@ -122,6 +129,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// string result of the invocation public void modInvokeN(string fname, params object[] parms) { +// m_log.DebugFormat( +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); + Type returntype = m_comms.LookupReturnType(fname); if (returntype != typeof(string)) MODError(String.Format("return type mismatch for {0}",fname)); @@ -131,6 +144,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String modInvokeS(string fname, params object[] parms) { +// m_log.DebugFormat( +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); + Type returntype = m_comms.LookupReturnType(fname); if (returntype != typeof(string)) MODError(String.Format("return type mismatch for {0}",fname)); @@ -141,6 +160,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer modInvokeI(string fname, params object[] parms) { +// m_log.DebugFormat( +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); + Type returntype = m_comms.LookupReturnType(fname); if (returntype != typeof(int)) MODError(String.Format("return type mismatch for {0}",fname)); @@ -151,6 +176,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Float modInvokeF(string fname, params object[] parms) { +// m_log.DebugFormat( +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); + Type returntype = m_comms.LookupReturnType(fname); if (returntype != typeof(float)) MODError(String.Format("return type mismatch for {0}",fname)); @@ -161,6 +192,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Key modInvokeK(string fname, params object[] parms) { +// m_log.DebugFormat( +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); + Type returntype = m_comms.LookupReturnType(fname); if (returntype != typeof(UUID)) MODError(String.Format("return type mismatch for {0}",fname)); @@ -171,6 +208,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector modInvokeV(string fname, params object[] parms) { +// m_log.DebugFormat( +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); + Type returntype = m_comms.LookupReturnType(fname); if (returntype != typeof(OpenMetaverse.Vector3)) MODError(String.Format("return type mismatch for {0}",fname)); @@ -181,6 +224,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Rotation modInvokeR(string fname, params object[] parms) { +// m_log.DebugFormat( +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); + Type returntype = m_comms.LookupReturnType(fname); if (returntype != typeof(OpenMetaverse.Quaternion)) MODError(String.Format("return type mismatch for {0}",fname)); @@ -191,6 +240,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_List modInvokeL(string fname, params object[] parms) { +// m_log.DebugFormat( +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); + Type returntype = m_comms.LookupReturnType(fname); if (returntype != typeof(object[])) MODError(String.Format("return type mismatch for {0}",fname)); @@ -211,6 +266,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { llist[i] = new LSL_Float((float)result[i]); } + else if (result[i] is double) + { + llist[i] = new LSL_Float((double)result[i]); + } else if (result[i] is UUID) { llist[i] = new LSL_Key(result[i].ToString()); @@ -248,13 +307,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return ""; } +// m_log.DebugFormat( +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); + Type[] signature = m_comms.LookupTypeSignature(fname); if (signature.Length != parms.Length) MODError(String.Format("wrong number of parameters to function {0}",fname)); object[] convertedParms = new object[parms.Length]; for (int i = 0; i < parms.Length; i++) - convertedParms[i] = ConvertFromLSL(parms[i],signature[i], fname); + convertedParms[i] = ConvertFromLSL(parms[i], signature[i], fname); // now call the function, the contract with the function is that it will always return // non-null but don't trust it completely @@ -351,7 +416,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (type == typeof(object[])) { - object[] plist = (lslparm as LSL_List).Data; + object[] plist = ((LSL_List)lslparm).Data; object[] result = new object[plist.Length]; for (int i = 0; i < plist.Length; i++) { @@ -379,7 +444,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - MODError(String.Format("{1}: parameter type mismatch; expecting {0}",type.Name, fname)); + MODError(String.Format("{0}: parameter type mismatch; expecting {1}, type(parm)={2}", fname, type.Name, lslparm.GetType())); return null; } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index dcc85c4..e799714 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -62,6 +62,8 @@ using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; +using PermissionMask = OpenSim.Framework.PermissionMask; +using OpenSim.Services.Connectors.Hypergrid; namespace OpenSim.Region.ScriptEngine.Shared.Api { @@ -142,16 +144,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected IUrlModule m_UrlModule = null; - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) + public void Initialize( + IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item) { - m_ScriptEngine = ScriptEngine; + m_ScriptEngine = scriptEngine; m_host = host; m_item = item; m_UrlModule = m_ScriptEngine.World.RequestModuleInterface(); if (m_ScriptEngine.Config.GetBoolean("AllowOSFunctions", false)) + { m_OSFunctionsEnabled = true; + // m_log.Warn("[OSSL] OSSL FUNCTIONS ENABLED"); + } m_ScriptDelayFactor = m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); @@ -245,11 +251,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message); } + // Returns of the function is allowed. Throws a script exception if not allowed. public void CheckThreatLevel(ThreatLevel level, string function) { if (!m_OSFunctionsEnabled) OSSLError(String.Format("{0} permission denied. All OS functions are disabled.", function)); // throws + string reasonWhyNot = CheckThreatLevelTest(level, function); + if (!String.IsNullOrEmpty(reasonWhyNot)) + { + OSSLError(reasonWhyNot); + } + } + + // Check to see if function is allowed. Returns an empty string if function permitted + // or a string explaining why this function can't be used. + private string CheckThreatLevelTest(ThreatLevel level, string function) + { if (!m_FunctionPerms.ContainsKey(function)) { FunctionPerms perms = new FunctionPerms(); @@ -329,10 +347,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { // Allow / disallow by threat level if (level > m_MaxThreatLevel) - OSSLError( + return String.Format( "{0} permission denied. Allowed threat level is {1} but function threat level is {2}.", - function, m_MaxThreatLevel, level)); + function, m_MaxThreatLevel, level); } else { @@ -342,7 +360,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_FunctionPerms[function].AllowedOwners.Contains(m_host.OwnerID)) { // prim owner is in the list of allowed owners - return; + return String.Empty; } UUID ownerID = m_item.OwnerID; @@ -350,22 +368,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api //OSSL only may be used if object is in the same group as the parcel if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_GROUP_MEMBER")) { - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (land.LandData.GroupID == m_item.GroupID && land.LandData.GroupID != UUID.Zero) { - return; + return String.Empty; } } //Only Parcelowners may use the function if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_OWNER")) { - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (land.LandData.OwnerID == ownerID) { - return; + return String.Empty; } } @@ -375,7 +393,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api //Only Estate Managers may use the function if (World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(ownerID) && World.RegionInfo.EstateSettings.EstateOwner != ownerID) { - return; + return String.Empty; } } @@ -384,25 +402,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (World.RegionInfo.EstateSettings.EstateOwner == ownerID) { - return; + return String.Empty; } } if (!m_FunctionPerms[function].AllowedCreators.Contains(m_item.CreatorID)) - OSSLError( + return( 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.", function)); if (m_item.CreatorID != ownerID) { if ((m_item.CurrentPermissions & (uint)PermissionMask.Modify) != 0) - OSSLError( - String.Format("{0} permission denied. Script permissions error.", - function)); + return String.Format("{0} permission denied. Script permissions error.", function); } } } + return String.Empty; } internal void OSSLDeprecated(string function, string replacement) @@ -437,7 +454,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - if (x > ((int)Constants.RegionSize - 1) || x < 0 || y > ((int)Constants.RegionSize - 1) || y < 0) + if (x > (World.RegionInfo.RegionSizeX - 1) || x < 0 || y > (World.RegionInfo.RegionSizeY - 1) || y < 0) OSSLError("osSetTerrainHeight: Coordinate out of bounds"); if (World.Permissions.CanTerraformLand(m_host.OwnerID, new Vector3(x, y, 0))) @@ -467,7 +484,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api private LSL_Float GetTerrainHeight(int x, int y) { m_host.AddScriptLPS(1); - if (x > ((int)Constants.RegionSize - 1) || x < 0 || y > ((int)Constants.RegionSize - 1) || y < 0) + if (x > (World.RegionInfo.RegionSizeX - 1) || x < 0 || y > (World.RegionInfo.RegionSizeY - 1) || y < 0) OSSLError("osGetTerrainHeight: Coordinate out of bounds"); return World.Heightmap[x, y]; @@ -777,9 +794,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // We will launch the teleport on a new thread so that when the script threads are terminated // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting. - Util.FireAndForget(o => World.RequestTeleportLocation( - presence.ControllingClient, regionName, position, - lookat, (uint)TPFlags.ViaLocation)); + Util.FireAndForget( + o => World.RequestTeleportLocation( + presence.ControllingClient, regionName, position, + lookat, (uint)TPFlags.ViaLocation), + null, "OSSL_Api.TeleportAgentByRegionCoords"); ScriptSleep(5000); @@ -801,7 +820,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api private void TeleportAgent(string agent, int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat, bool relaxRestrictions) { - ulong regionHandle = Util.UIntsToLong(((uint)regionX * (uint)Constants.RegionSize), ((uint)regionY * (uint)Constants.RegionSize)); + // ulong regionHandle = Util.UIntsToLong(((uint)regionX * (uint)Constants.RegionSize), ((uint)regionY * (uint)Constants.RegionSize)); + ulong regionHandle = Util.RegionLocToHandle((uint)regionX, (uint)regionY); m_host.AddScriptLPS(1); UUID agentId = new UUID(); @@ -822,9 +842,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // We will launch the teleport on a new thread so that when the script threads are terminated // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting. - Util.FireAndForget(o => World.RequestTeleportLocation( - presence.ControllingClient, regionHandle, - position, lookat, (uint)TPFlags.ViaLocation)); + Util.FireAndForget( + o => World.RequestTeleportLocation( + presence.ControllingClient, regionHandle, + position, lookat, (uint)TPFlags.ViaLocation), + null, "OSSL_Api.TeleportAgentByRegionName"); ScriptSleep(5000); @@ -859,6 +881,59 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api TeleportAgent(m_host.OwnerID.ToString(), regionX, regionY, position, lookat, true); } + /// + /// Allows a script IN the target prim to force an avatar to sit on it using normal methods + /// as if called by the client. + /// Silent fail if agent (or target if overloaded) not found. + /// Does work if passed key (or keys if overloaded). + /// + /// + public void osForceOtherSit(string avatar) + { + CheckThreatLevel(ThreatLevel.VeryHigh, "osForceOtherSit"); + + m_host.AddScriptLPS(1); + + ForceSit(avatar, m_host.UUID); + } + + /// + /// Overload method of osForceOtherSit(string avatar) to allow a script NOT in the target prim to force + /// an avatar to sit on the target prim using normal methods as if called by the client. + /// + /// + /// + public void osForceOtherSit(string avatar, string target) + { + CheckThreatLevel(ThreatLevel.VeryHigh, "osForceOtherSit"); + + m_host.AddScriptLPS(1); + + UUID targetID = new UUID(target); + + ForceSit(avatar, targetID); + } + + public void ForceSit(string avatar, UUID targetID) + { + UUID agentID; + + if (!UUID.TryParse(avatar, out agentID)) + return; + + ScenePresence presence = World.GetScenePresence(agentID); + + SceneObjectPart part = World.GetSceneObjectPart(targetID); + + if (presence != null && + part != null && + part.SitTargetAvatar == UUID.Zero) + presence.HandleAgentRequestSit(presence.ControllingClient, + agentID, + targetID, + part.SitTargetPosition); + } + // Functions that get information from the agent itself. // // osGetAgentIP - this is used to determine the IP address of @@ -1205,12 +1280,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api sunHour += 24.0; World.RegionInfo.RegionSettings.UseEstateSun = useEstateSun; - World.RegionInfo.RegionSettings.SunPosition = sunHour + 6; // LL Region Sun Hour is 6 to 30 - World.RegionInfo.RegionSettings.FixedSun = sunFixed; + World.RegionInfo.RegionSettings.SunPosition = sunHour + 6; // LL Region Sun Hour is 6 to 30 + World.RegionInfo.RegionSettings.FixedSun = sunFixed; World.RegionInfo.RegionSettings.Save(); - World.EventManager.TriggerEstateToolsSunUpdate( - World.RegionInfo.RegionHandle, sunFixed, useEstateSun, (float)sunHour); + World.EventManager.TriggerEstateToolsSunUpdate(World.RegionInfo.RegionHandle); } /// @@ -1233,10 +1307,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World.RegionInfo.EstateSettings.UseGlobalTime = !sunFixed; World.RegionInfo.EstateSettings.SunPosition = sunHour; World.RegionInfo.EstateSettings.FixedSun = sunFixed; - World.RegionInfo.EstateSettings.Save(); + World.EstateDataService.StoreEstateSettings(World.RegionInfo.EstateSettings); - World.EventManager.TriggerEstateToolsSunUpdate( - World.RegionInfo.RegionHandle, sunFixed, World.RegionInfo.RegionSettings.UseEstateSun, (float)sunHour); + World.EventManager.TriggerEstateToolsSunUpdate(World.RegionInfo.RegionHandle); } /// @@ -1492,8 +1565,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); - ILandObject land - = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (land.LandData.OwnerID != m_host.OwnerID) return; @@ -1509,8 +1581,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); - ILandObject land - = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (land.LandData.OwnerID != m_host.OwnerID) { @@ -1560,6 +1631,47 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + public LSL_Integer osCheckODE() + { + m_host.AddScriptLPS(1); + LSL_Integer ret = 0; // false + if (m_ScriptEngine.World.PhysicsScene != null) + { + string physEngine = m_ScriptEngine.World.PhysicsScene.EngineType; + if (physEngine == "OpenDynamicsEngine") + { + ret = 1; // true + } + } + return ret; + } + + public string osGetPhysicsEngineType() + { + // High because it can be used to target attacks to known weaknesses + // This would allow a new class of griefer scripts that don't even + // require their user to know what they are doing (see script + // kiddie) + // Because it would be nice if scripts didn't blow up if the information + // about the physics engine, this function returns an empty string if + // the user does not have permission to see it. This as opposed to + // throwing an exception. + m_host.AddScriptLPS(1); + string ret = String.Empty; + if (String.IsNullOrEmpty(CheckThreatLevelTest(ThreatLevel.High, "osGetPhysicsEngineType"))) + { + if (m_ScriptEngine.World.PhysicsScene != null) + { + ret = m_ScriptEngine.World.PhysicsScene.EngineType; + // An old physics engine might have an uninitialized engine type + if (ret == null) + ret = "unknown"; + } + } + + return ret; + } + public string osGetSimulatorVersion() { // High because it can be used to target attacks to known weaknesses @@ -1732,13 +1844,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Create new asset AssetBase asset = new AssetBase(UUID.Random(), name, (sbyte)AssetType.Notecard, m_host.OwnerID.ToString()); asset.Description = description; + byte[] a; + byte[] b; + byte[] c; + + b = Util.UTF8.GetBytes(data); - int textLength = data.Length; - data - = "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length " - + textLength.ToString() + "\n" + data + "}\n"; + a = Util.UTF8.GetBytes( + "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length " + b.Length.ToString() + "\n"); - asset.Data = Util.UTF8.GetBytes(data); + c = Util.UTF8.GetBytes("}"); + + byte[] d = new byte[a.Length + b.Length + c.Length]; + Buffer.BlockCopy(a, 0, d, 0, a.Length); + Buffer.BlockCopy(b, 0, d, a.Length, b.Length); + Buffer.BlockCopy(c, 0, d, a.Length + b.Length, c.Length); + + asset.Data = d; World.AssetService.Store(asset); // Create Task Entry @@ -1753,8 +1875,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api taskItem.InvType = (int)InventoryType.Notecard; taskItem.OwnerID = m_host.OwnerID; taskItem.CreatorID = m_host.OwnerID; - taskItem.BasePermissions = (uint)PermissionMask.All; - taskItem.CurrentPermissions = (uint)PermissionMask.All; + taskItem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; + taskItem.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; taskItem.EveryonePermissions = 0; taskItem.NextPermissions = (uint)PermissionMask.All; taskItem.GroupID = m_host.GroupID; @@ -1833,8 +1955,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (a == null) return UUID.Zero; - string data = Encoding.UTF8.GetString(a.Data); - NotecardCache.Cache(assetID, data); + NotecardCache.Cache(assetID, a.Data); }; return assetID; @@ -1932,15 +2053,51 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api CheckThreatLevel(ThreatLevel.Low, "osAvatarName2Key"); m_host.AddScriptLPS(1); - UserAccount account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, firstname, lastname); - if (null == account) + IUserManagement userManager = World.RequestModuleInterface(); + if (userManager == null) { - return UUID.Zero.ToString(); + OSSLShoutError("osAvatarName2Key: UserManagement module not available"); + return string.Empty; + } + + // Check if the user is already cached + + UUID userID = userManager.GetUserIdByName(firstname, lastname); + if (userID != UUID.Zero) + return userID.ToString(); + + // Query for the user + + String realFirstName; String realLastName; String serverURI; + if (Util.ParseForeignAvatarName(firstname, lastname, out realFirstName, out realLastName, out serverURI)) + { + try + { + UserAgentServiceConnector userConnection = new UserAgentServiceConnector(serverURI, true); + + if (userConnection != null) + { + userID = userConnection.GetUUID(realFirstName, realLastName); + if (userID != UUID.Zero) + { + userManager.AddUser(userID, realFirstName, realLastName, serverURI); + return userID.ToString(); + } + } + } + catch (Exception /*e*/) + { + // m_log.Warn("[osAvatarName2Key] UserAgentServiceConnector - Unable to connect to destination grid ", e); + } } else { - return account.PrincipalID.ToString(); + UserAccount account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, firstname, lastname); + if (account != null) + return account.PrincipalID.ToString(); } + + return UUID.Zero.ToString(); } public string osKey2Name(string id) @@ -1953,19 +2110,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (UUID.TryParse(id, out key)) { UserAccount account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, key); - if (null == account) - { - return ""; - } - else - { + if (account != null) return account.Name; + + if (m_ScriptEngine.World.GridUserService != null) + { + GridUserInfo uInfo = m_ScriptEngine.World.GridUserService.GetGridUserInfo(key.ToString()); + + if (uInfo != null) + { + UUID userUUID; String gridURL; String firstName; String lastName; String tmp; + + if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out userUUID, out gridURL, out firstName, out lastName, out tmp)) + { + string grid = new Uri(gridURL).Authority; + return firstName + "." + lastName + " @" + grid; + } + } } } - else - { - return ""; - } + + return ""; } private enum InfoType @@ -2101,9 +2266,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api CheckThreatLevel(ThreatLevel.Moderate, "osGetGridHomeURI"); m_host.AddScriptLPS(1); - string HomeURI = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; + string HomeURI = Util.GetConfigVarFromSections(config, "HomeURI", + new string[] { "Startup", "Hypergrid" }, String.Empty); + if (!string.IsNullOrEmpty(HomeURI)) + return HomeURI; + + // Legacy. Remove soon! if (config.Configs["LoginService"] != null) HomeURI = config.Configs["LoginService"].GetString("SRV_HomeURI", HomeURI); @@ -2118,9 +2288,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api CheckThreatLevel(ThreatLevel.Moderate, "osGetGridGatekeeperURI"); m_host.AddScriptLPS(1); - string gatekeeperURI = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; + string gatekeeperURI = Util.GetConfigVarFromSections(config, "GatekeeperURI", + new string[] { "Startup", "Hypergrid" }, String.Empty); + + if (!string.IsNullOrEmpty(gatekeeperURI)) + return gatekeeperURI; + // Legacy. Remove soon! if (config.Configs["GridService"] != null) gatekeeperURI = config.Configs["GridService"].GetString("Gatekeeper", gatekeeperURI); @@ -2144,6 +2319,39 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return retval; } + public string osGetAvatarHomeURI(string uuid) + { + CheckThreatLevel(ThreatLevel.Low, "osGetAvatarHomeURI"); + m_host.AddScriptLPS(1); + + IUserManagement userManager = m_ScriptEngine.World.RequestModuleInterface(); + string returnValue = ""; + + if (userManager != null) + { + returnValue = userManager.GetUserServerURL(new UUID(uuid), "HomeURI"); + } + + if (returnValue == "") + { + IConfigSource config = m_ScriptEngine.ConfigSource; + returnValue = Util.GetConfigVarFromSections(config, "HomeURI", + new string[] { "Startup", "Hypergrid" }, String.Empty); + + if (!string.IsNullOrEmpty(returnValue)) + return returnValue; + + // Legacy. Remove soon! + if (config.Configs["LoginService"] != null) + returnValue = config.Configs["LoginService"].GetString("SRV_HomeURI", returnValue); + + if (String.IsNullOrEmpty(returnValue)) + returnValue = GridUserInfo(InfoType.Home); + } + + return returnValue; + } + public LSL_String osFormatString(string str, LSL_List strings) { CheckThreatLevel(ThreatLevel.VeryLow, "osFormatString"); @@ -2265,14 +2473,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // on the ILSL_Api interface. LSL_Api LSL_Api = (LSL_Api)m_LSL_Api; LSL_List retVal = new LSL_List(); - LSL_List remaining = null; + LSL_List remaining = new LSL_List(); List parts = LSL_Api.GetLinkParts(linknumber); foreach (SceneObjectPart part in parts) { remaining = LSL_Api.GetPrimParams(part, rules, ref retVal); } - while (remaining != null && remaining.Length > 2) + while (remaining.Length > 2) { linknumber = remaining.GetLSLIntegerItem(0); rules = remaining.GetSublist(1, -1); @@ -2284,6 +2492,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return retVal; } + public void osForceCreateLink(string target, int parent) + { + CheckThreatLevel(ThreatLevel.VeryLow, "osForceCreateLink"); + + m_host.AddScriptLPS(1); + + InitLSL(); + ((LSL_Api)m_LSL_Api).CreateLink(target, parent); + } + + public void osForceBreakLink(int linknum) + { + CheckThreatLevel(ThreatLevel.VeryLow, "osForceBreakLink"); + + m_host.AddScriptLPS(1); + + InitLSL(); + ((LSL_Api)m_LSL_Api).BreakLink(linknum); + } + + public void osForceBreakAllLinks() + { + CheckThreatLevel(ThreatLevel.VeryLow, "osForceBreakAllLinks"); + + m_host.AddScriptLPS(1); + + InitLSL(); + ((LSL_Api)m_LSL_Api).BreakAllLinks(); + } + public LSL_Integer osIsNpc(LSL_Key npc) { CheckThreatLevel(ThreatLevel.None, "osIsNpc"); @@ -2469,13 +2707,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ScenePresence sp = World.GetScenePresence(npcId); if (sp != null) - { - Vector3 pos = sp.AbsolutePosition; - return new LSL_Vector(pos.X, pos.Y, pos.Z); - } + return new LSL_Vector(sp.AbsolutePosition); } - return new LSL_Vector(0, 0, 0); + return Vector3.Zero; } public void osNpcMoveTo(LSL_Key npc, LSL_Vector pos) @@ -2532,21 +2767,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { UUID npcId; if (!UUID.TryParse(npc.m_string, out npcId)) - return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); + return new LSL_Rotation(Quaternion.Identity); if (!npcModule.CheckPermissions(npcId, m_host.OwnerID)) - return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); + return new LSL_Rotation(Quaternion.Identity); ScenePresence sp = World.GetScenePresence(npcId); if (sp != null) - { - Quaternion rot = sp.Rotation; - return new LSL_Rotation(rot.X, rot.Y, rot.Z, rot.W); - } + return new LSL_Rotation(sp.GetWorldRotation()); } - return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); + return Quaternion.Identity; } public void osNpcSetRot(LSL_Key npc, LSL_Rotation rotation) @@ -2824,6 +3056,51 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return SaveAppearanceToNotecard(avatarId, notecard); } + + /// + /// Get the gender as specified in avatar appearance for a given avatar key + /// + /// + /// "male" or "female" or "unknown" + public LSL_String osGetGender(LSL_Key rawAvatarId) + { + CheckThreatLevel(ThreatLevel.None, "osGetGender"); + m_host.AddScriptLPS(1); + + UUID avatarId; + if (!UUID.TryParse(rawAvatarId, out avatarId)) + return new LSL_String("unknown"); + + ScenePresence sp = World.GetScenePresence(avatarId); + + if (sp == null || sp.IsChildAgent || sp.Appearance == null || sp.Appearance.VisualParams == null) + return new LSL_String("unknown"); + + // find the index of "shape" parameter "male" + int vpShapeMaleIndex = 0; + bool indexFound = false; + VisualParam param = new VisualParam(); + foreach(var vpEntry in VisualParams.Params) + { + param = vpEntry.Value; + if (param.Name == "male" && param.Wearable == "shape") + { + indexFound = true; + break; + } + + if (param.Group == 0) + vpShapeMaleIndex++; + } + + if (!indexFound) + return new LSL_String("unknown"); + + float vpShapeMale = Utils.ByteToFloat(sp.Appearance.VisualParams[vpShapeMaleIndex], param.MinValue, param.MaxValue); + + bool isMale = vpShapeMale > 0.5f; + return new LSL_String(isMale ? "male" : "female"); + } /// /// Get current region's map texture UUID @@ -2887,6 +3164,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return ret; } + public LSL_Vector osGetRegionSize() + { + CheckThreatLevel(ThreatLevel.None, "osGetRegionSize"); + m_host.AddScriptLPS(1); + + bool isMegaregion; + IRegionCombinerModule rcMod = World.RequestModuleInterface(); + if (rcMod != null) + isMegaregion = rcMod.IsRootForMegaregion(World.RegionInfo.RegionID); + else + isMegaregion = false; + + if (isMegaregion) + { + Vector2 size = rcMod.GetSizeOfMegaregion(World.RegionInfo.RegionID); + return new LSL_Vector(size.X, size.Y, Constants.RegionHeight); + } + else + { + Scene scene = m_ScriptEngine.World; + GridRegion region = scene.GridService.GetRegionByUUID(UUID.Zero, World.RegionInfo.RegionID); + return new LSL_Vector((float)region.RegionSizeX, (float)region.RegionSizeX, Constants.RegionHeight); + } + } + public int osGetSimulatorMemory() { CheckThreatLevel(ThreatLevel.Moderate, "osGetSimulatorMemory"); @@ -2925,7 +3227,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api sp.ControllingClient.Kick(alert); // ...and close on our side - sp.Scene.IncomingCloseAgent(sp.UUID, false); + sp.Scene.CloseAgent(sp.UUID, false); } }); } @@ -2976,20 +3278,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID avatarId = new UUID(avatar); ScenePresence presence = World.GetScenePresence(avatarId); - Vector3 pos = m_host.GetWorldPosition(); - bool result = World.ScriptDanger(m_host.LocalId, new Vector3((float)pos.X, (float)pos.Y, (float)pos.Z)); - if (result) + + if (presence != null && World.ScriptDanger(m_host.LocalId, m_host.GetWorldPosition())) { - if (presence != null) - { - float health = presence.Health; - health += (float)healing; - if (health >= 100) - { - health = 100; - } - presence.setHealthWithUpdate(health); - } + float health = presence.Health; + health += (float)healing; + + if (health >= 100) + health = 100; + + presence.setHealthWithUpdate(health); } } @@ -3066,8 +3364,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (avatar != null && avatar.UUID != m_host.OwnerID) { result.Add(new LSL_String(avatar.UUID.ToString())); - OpenMetaverse.Vector3 ap = avatar.AbsolutePosition; - result.Add(new LSL_Vector(ap.X, ap.Y, ap.Z)); + result.Add(new LSL_Vector(avatar.AbsolutePosition)); result.Add(new LSL_String(avatar.Name)); } }); @@ -3263,7 +3560,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osForceAttachToOtherAvatarFromInventory(string rawAvatarId, string itemName, int attachmentPoint) { - CheckThreatLevel(ThreatLevel.Severe, "osForceAttachToOtherAvatarFromInventory"); + CheckThreatLevel(ThreatLevel.VeryHigh, "osForceAttachToOtherAvatarFromInventory"); m_host.AddScriptLPS(1); @@ -3307,14 +3604,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (sp == null) return; - InventoryItemBase newItem = World.MoveTaskInventoryItem(sp.UUID, UUID.Zero, m_host, item.ItemID); + string message; + InventoryItemBase newItem = World.MoveTaskInventoryItem(sp.UUID, UUID.Zero, m_host, item.ItemID, out message); if (newItem == null) { m_log.ErrorFormat( - "[OSSL API]: Could not create user inventory item {0} for {1}, attach point {2} in {3}", - itemName, m_host.Name, attachmentPoint, World.Name); - + "[OSSL API]: Could not create user inventory item {0} for {1}, attach point {2} in {3}: {4}", + itemName, m_host.Name, attachmentPoint, World.Name, message); + ((LSL_Api)m_LSL_Api).llSay(0, message); return; } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index dd45406..64dc2e2 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs @@ -353,7 +353,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // Position of a sensor in a child prim attached to an avatar // will be still wrong. ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); - q = avatar.Rotation * q; + + // Don't proceed if the avatar for this attachment has since been removed from the scene. + if (avatar == null) + return sensedEntities; + + q = avatar.GetWorldRotation() * q; } LSL_Types.Quaternion r = new LSL_Types.Quaternion(q); @@ -362,7 +367,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins Vector3 ZeroVector = new Vector3(0, 0, 0); - bool nameSearch = (ts.name != null && ts.name != ""); + bool nameSearch = !string.IsNullOrEmpty(ts.name); foreach (EntityBase ent in Entities) { @@ -480,7 +485,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // Position of a sensor in a child prim attached to an avatar // will be still wrong. ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); - q = avatar.Rotation * q; + + // Don't proceed if the avatar for this attachment has since been removed from the scene. + if (avatar == null) + return sensedEntities; + + q = avatar.GetWorldRotation() * q; } LSL_Types.Quaternion r = new LSL_Types.Quaternion(q); @@ -595,7 +605,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins return sensedEntities; senseEntity(sp); } - else if (ts.name != null && ts.name != "") + else if (!string.IsNullOrEmpty(ts.name)) { ScenePresence sp; // Try lookup by name will return if/when found diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs index d173db0..215c087 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; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index 98f8be7..3d58573 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -124,6 +124,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_String llGetCreator(); LSL_String llGetDate(); LSL_Float llGetEnergy(); + LSL_String llGetEnv(LSL_String name); LSL_Vector llGetForce(); LSL_Integer llGetFreeMemory(); LSL_Integer llGetFreeURLs(); @@ -149,6 +150,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Vector llGetLocalPos(); LSL_Rotation llGetLocalRot(); LSL_Float llGetMass(); + LSL_Float llGetMassMKS(); LSL_Integer llGetMemoryLimit(); void llGetNextEmail(string address, string subject); LSL_String llGetNotecardLine(string name, int line); @@ -207,7 +209,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Float llGetWallclock(); void llGiveInventory(string destination, string inventory); void llGiveInventoryList(string destination, string category, LSL_List inventory); - LSL_Integer llGiveMoney(string destination, int amount); + void llGiveMoney(string destination, int amount); + LSL_String llTransferLindenDollars(string destination, int amount); void llGodLikeRezObject(string inventory, LSL_Vector pos); LSL_Float llGround(LSL_Vector offset); LSL_Vector llGroundContour(LSL_Vector offset); @@ -337,9 +340,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void llSetCameraParams(LSL_List rules); void llSetClickAction(int action); void llSetColor(LSL_Vector color, int face); + void llSetContentType(LSL_Key id, LSL_Integer type); void llSetDamage(double damage); void llSetForce(LSL_Vector force, int local); void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local); + void llSetVelocity(LSL_Vector velocity, int local); + void llSetAngularVelocity(LSL_Vector angularVelocity, int local); void llSetHoverHeight(double height, int water, double tau); void llSetInventoryPermMask(string item, int mask, int value); void llSetLinkAlpha(int linknumber, double alpha, int face); @@ -426,6 +432,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void print(string str); void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules, string originFunc); + void llSetKeyframedMotion(LSL_List frames, LSL_List options); LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index cdd9ea8..6259b76 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs @@ -259,6 +259,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces string osGetScriptEngineName(); string osGetSimulatorVersion(); + LSL_Integer osCheckODE(); + string osGetPhysicsEngineType(); Object osParseJSONNew(string JSON); Hashtable osParseJSON(string JSON); @@ -281,6 +283,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces string osGetGridGatekeeperURI(); string osGetGridCustom(string key); + string osGetAvatarHomeURI(string uuid); + LSL_String osFormatString(string str, LSL_List strings); LSL_List osMatchString(string src, string pattern, int start); LSL_String osReplaceString(string src, string pattern, string replace, int count, int start); @@ -293,6 +297,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_List osGetLinkPrimitiveParams(int linknumber, LSL_List rules); /// + /// Identical to llCreateLink() but does not require permission from the owner. + /// + /// + /// + void osForceCreateLink(string target, int parent); + + /// + /// Identical to llBreakLink() but does not require permission from the owner. + /// + /// + void osForceBreakLink(int linknum); + + /// + /// Identical to llBreakAllLinks() but does not require permission from the owner. + /// + void osForceBreakAllLinks(); + + /// /// Check if the given key is an npc /// /// @@ -333,9 +355,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Key osOwnerSaveAppearance(string notecard); LSL_Key osAgentSaveAppearance(key agentId, string notecard); + key osGetGender(LSL_Key rawAvatarId); key osGetMapTexture(); key osGetRegionMapTexture(string regionName); LSL_List osGetRegionStats(); + vector osGetRegionSize(); int osGetSimulatorMemory(); void osKickAvatar(string FirstName,string SurName,string alert); @@ -343,6 +367,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Float osGetHealth(string avatar); void osCauseHealing(string avatar, double healing); void osCauseDamage(string avatar, double damage); + void osForceOtherSit(string avatar); + void osForceOtherSit(string avatar, string target); LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules); void osSetPrimitiveParams(LSL_Key prim, LSL_List rules); void osSetProjectionParams(bool projection, LSL_Key texture, double fov, double focus, double amb); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs index 9615315..ce17ed0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs @@ -77,6 +77,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase touch = 8, touch_end = 536870912, touch_start = 2097152, + transaction_result = 33554432, object_rez = 4194304 } @@ -235,6 +236,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_eventFlagsMap.Add("touch", scriptEvents.touch); m_eventFlagsMap.Add("touch_end", scriptEvents.touch_end); m_eventFlagsMap.Add("touch_start", scriptEvents.touch_start); + m_eventFlagsMap.Add("transaction_result", scriptEvents.transaction_result); m_eventFlagsMap.Add("object_rez", scriptEvents.object_rez); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 9bf1a64..9aecea2 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -48,6 +48,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int STATUS_DIE_AT_EDGE = 128; public const int STATUS_RETURN_AT_EDGE = 256; public const int STATUS_CAST_SHADOWS = 512; + public const int STATUS_BLOCK_GRAB_OBJECT = 1024; public const int AGENT = 1; public const int AGENT_BY_LEGACY_NAME = 1; @@ -106,6 +107,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PSYS_PART_TARGET_POS_MASK = 64; public const int PSYS_PART_TARGET_LINEAR_MASK = 128; public const int PSYS_PART_EMISSIVE_MASK = 256; + public const int PSYS_PART_RIBBON_MASK = 1024; public const int PSYS_PART_FLAGS = 0; public const int PSYS_PART_START_COLOR = 1; public const int PSYS_PART_START_ALPHA = 2; @@ -129,6 +131,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PSYS_SRC_OMEGA = 21; public const int PSYS_SRC_ANGLE_BEGIN = 22; public const int PSYS_SRC_ANGLE_END = 23; + public const int PSYS_PART_BLEND_FUNC_SOURCE = 24; + public const int PSYS_PART_BLEND_FUNC_DEST = 25; + public const int PSYS_PART_START_GLOW = 26; + public const int PSYS_PART_END_GLOW = 27; + public const int PSYS_PART_BF_ONE = 0; + public const int PSYS_PART_BF_ZERO = 1; + public const int PSYS_PART_BF_DEST_COLOR = 2; + public const int PSYS_PART_BF_SOURCE_COLOR = 3; + public const int PSYS_PART_BF_ONE_MINUS_DEST_COLOR = 4; + public const int PSYS_PART_BF_ONE_MINUS_SOURCE_COLOR = 5; + public const int PSYS_PART_BF_SOURCE_ALPHA = 7; + public const int PSYS_PART_BF_ONE_MINUS_SOURCE_ALPHA = 9; public const int PSYS_SRC_PATTERN_DROP = 1; public const int PSYS_SRC_PATTERN_EXPLODE = 2; public const int PSYS_SRC_PATTERN_ANGLE = 4; @@ -236,6 +250,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int ATTACH_HUD_BOTTOM_LEFT = 36; public const int ATTACH_HUD_BOTTOM = 37; public const int ATTACH_HUD_BOTTOM_RIGHT = 38; + public const int ATTACH_NECK = 39; + public const int ATTACH_AVATAR_CENTER = 40; #region osMessageAttachments constants @@ -355,6 +371,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int HTTP_MIMETYPE = 1; public const int HTTP_BODY_MAXLENGTH = 2; public const int HTTP_VERIFY_CERT = 3; + public const int HTTP_VERBOSE_THROTTLE = 4; + public const int HTTP_CUSTOM_HEADER = 5; + public const int HTTP_PRAGMA_NO_CACHE = 6; + + // llSetContentType + public const int CONTENT_TYPE_TEXT = 0; //text/plain + public const int CONTENT_TYPE_HTML = 1; //text/html + public const int CONTENT_TYPE_XML = 2; //application/xml + public const int CONTENT_TYPE_XHTML = 3; //application/xhtml+xml + public const int CONTENT_TYPE_ATOM = 4; //application/atom+xml + public const int CONTENT_TYPE_JSON = 5; //application/json + public const int CONTENT_TYPE_LLSD = 6; //application/llsd+xml + public const int CONTENT_TYPE_FORM = 7; //application/x-www-form-urlencoded + public const int CONTENT_TYPE_RSS = 8; //application/rss+xml public const int PRIM_MATERIAL = 2; public const int PRIM_PHYSICS = 3; @@ -381,6 +411,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_POS_LOCAL = 33; public const int PRIM_LINK_TARGET = 34; public const int PRIM_SLICE = 35; + public const int PRIM_SPECULAR = 36; + public const int PRIM_NORMAL = 37; + public const int PRIM_ALPHA_MODE = 38; public const int PRIM_TEXGEN_DEFAULT = 0; public const int PRIM_TEXGEN_PLANAR = 1; @@ -563,6 +596,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int OBJECT_PHYSICS = 21; public const int OBJECT_PHANTOM = 22; public const int OBJECT_TEMP_ON_REZ = 23; + public const int OBJECT_RENDER_WEIGHT = 24; + public const int OBJECT_HOVER_HEIGHT = 25; + public const int OBJECT_BODY_SHAPE_TYPE = 26; + public const int OBJECT_LAST_OWNER_ID = 27; // Pathfinding types public const int OPT_OTHER = -1; @@ -635,7 +672,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int TOUCH_INVALID_FACE = -1; public static readonly vector TOUCH_INVALID_TEXCOORD = new vector(-1.0, -1.0, 0.0); public static readonly vector TOUCH_INVALID_VECTOR = ZERO_VECTOR; - + // constants for llGetPrimMediaParams/llSetPrimMediaParams public const int PRIM_MEDIA_ALT_IMAGE_ENABLE = 0; public const int PRIM_MEDIA_CONTROLS = 1; @@ -652,15 +689,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_MEDIA_WHITELIST = 12; public const int PRIM_MEDIA_PERMS_INTERACT = 13; public const int PRIM_MEDIA_PERMS_CONTROL = 14; - + public const int PRIM_MEDIA_CONTROLS_STANDARD = 0; public const int PRIM_MEDIA_CONTROLS_MINI = 1; - + public const int PRIM_MEDIA_PERM_NONE = 0; public const int PRIM_MEDIA_PERM_OWNER = 1; public const int PRIM_MEDIA_PERM_GROUP = 2; public const int PRIM_MEDIA_PERM_ANYONE = 4; - + + public const int PRIM_PHYSICS_SHAPE_TYPE = 30; + public const int PRIM_PHYSICS_SHAPE_PRIM = 0; + public const int PRIM_PHYSICS_SHAPE_CONVEX = 2; + public const int PRIM_PHYSICS_SHAPE_NONE = 1; + + public const int PRIM_PHYSICS_MATERIAL = 31; + public const int DENSITY = 1; + public const int FRICTION = 2; + public const int RESTITUTION = 4; + public const int GRAVITY_MULTIPLIER = 8; + // extra constants for llSetPrimMediaParams public static readonly LSLInteger LSL_STATUS_OK = new LSLInteger(0); public static readonly LSLInteger LSL_STATUS_MALFORMED_PARAMS = new LSLInteger(1000); @@ -677,7 +725,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const string TEXTURE_PLYWOOD = "89556747-24cb-43ed-920b-47caed15465f"; public const string TEXTURE_TRANSPARENT = "8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"; public const string TEXTURE_MEDIA = "8b5fec65-8d8d-9dc5-cda8-8fdf2716e361"; - + // Constants for osGetRegionStats public const int STATS_TIME_DILATION = 0; public const int STATS_SIM_FPS = 1; @@ -730,9 +778,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public static readonly LSLInteger RC_GET_ROOT_KEY = 2; public static readonly LSLInteger RC_GET_LINK_NUM = 4; - public static readonly LSLInteger RCERR_UNKNOWN = -1; + public static readonly LSLInteger RCERR_UNKNOWN = -1; public static readonly LSLInteger RCERR_SIM_PERF_LOW = -2; - public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = 3; + public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = -3; + + public const int KFM_MODE = 1; + public const int KFM_LOOP = 1; + public const int KFM_REVERSE = 3; + public const int KFM_FORWARD = 0; + public const int KFM_PING_PONG = 2; + public const int KFM_DATA = 2; + public const int KFM_TRANSLATION = 2; + public const int KFM_ROTATION = 1; + public const int KFM_COMMAND = 0; + public const int KFM_CMD_PLAY = 0; + public const int KFM_CMD_STOP = 1; + public const int KFM_CMD_PAUSE = 2; /// /// process name parameter as regex diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index 36803a4..35aaf01 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs @@ -464,6 +464,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llGetEnergy(); } + public LSL_String llGetEnv(LSL_String name) + { + return m_LSL_Functions.llGetEnv(name); + } + public LSL_Vector llGetForce() { return m_LSL_Functions.llGetForce(); @@ -554,6 +559,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llGetLinkNumberOfSides(link); } + public void llSetKeyframedMotion(LSL_List frames, LSL_List options) + { + m_LSL_Functions.llSetKeyframedMotion(frames, options); + } + public LSL_Integer llGetListEntryType(LSL_List src, int index) { return m_LSL_Functions.llGetListEntryType(src, index); @@ -579,6 +589,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llGetMass(); } + public LSL_Float llGetMassMKS() + { + return m_LSL_Functions.llGetMassMKS(); + } + public LSL_Integer llGetMemoryLimit() { return m_LSL_Functions.llGetMemoryLimit(); @@ -869,9 +884,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llGiveInventoryList(destination, category, inventory); } - public LSL_Integer llGiveMoney(string destination, int amount) + public void llGiveMoney(string destination, int amount) { - return m_LSL_Functions.llGiveMoney(destination, amount); + m_LSL_Functions.llGiveMoney(destination, amount); + } + + public LSL_String llTransferLindenDollars(string destination, int amount) + { + return m_LSL_Functions.llTransferLindenDollars(destination, amount); } public void llGodLikeRezObject(string inventory, LSL_Vector pos) @@ -1518,6 +1538,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llSetColor(color, face); } + public void llSetContentType(LSL_Key id, LSL_Integer type) + { + m_LSL_Functions.llSetContentType(id, type); + } + public void llSetDamage(double damage) { m_LSL_Functions.llSetDamage(damage); @@ -1533,6 +1558,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llSetForceAndTorque(force, torque, local); } + public void llSetVelocity(LSL_Vector force, int local) + { + m_LSL_Functions.llSetVelocity(force, local); + } + + public void llSetAngularVelocity(LSL_Vector force, int local) + { + m_LSL_Functions.llSetAngularVelocity(force, local); + } + public void llSetHoverHeight(double height, int water, double tau) { m_LSL_Functions.llSetHoverHeight(height, water, tau); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index afa9ae0..a60f381 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs @@ -420,6 +420,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osGetScriptEngineName(); } + public LSL_Integer osCheckODE() + { + return m_OSSL_Functions.osCheckODE(); + } + + public string osGetPhysicsEngineType() + { + return m_OSSL_Functions.osGetPhysicsEngineType(); + } + public string osGetSimulatorVersion() { return m_OSSL_Functions.osGetSimulatorVersion(); @@ -500,6 +510,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osGetGridCustom(key); } + public string osGetAvatarHomeURI(string uuid) + { + return m_OSSL_Functions.osGetAvatarHomeURI(uuid); + } + public LSL_String osFormatString(string str, LSL_List strings) { return m_OSSL_Functions.osFormatString(str, strings); @@ -537,6 +552,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osGetLinkPrimitiveParams(linknumber, rules); } + public void osForceCreateLink(string target, int parent) + { + m_OSSL_Functions.osForceCreateLink(target, parent); + } + + public void osForceBreakLink(int linknum) + { + m_OSSL_Functions.osForceBreakLink(linknum); + } + + public void osForceBreakAllLinks() + { + m_OSSL_Functions.osForceBreakAllLinks(); + } + public LSL_Integer osIsNpc(LSL_Key npc) { return m_OSSL_Functions.osIsNpc(npc); @@ -708,16 +738,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase } private void Save() { + /* Remove temporarily until we have a handle to the region size if (Position.x > ((int)Constants.RegionSize - 1)) Position.x = ((int)Constants.RegionSize - 1); - if (Position.x < 0) - Position.x = 0; if (Position.y > ((int)Constants.RegionSize - 1)) Position.y = ((int)Constants.RegionSize - 1); + */ + if (Position.z > Constants.RegionHeight) + Position.z = Constants.RegionHeight; + if (Position.x < 0) + Position.x = 0; if (Position.y < 0) Position.y = 0; - if (Position.z > 768) - Position.z = 768; if (Position.z < 0) Position.z = 0; prim.OSSL.llSetPos(Position); @@ -843,6 +875,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase } } + public string osGetGender(LSL_Key rawAvatarId) + { + return m_OSSL_Functions.osGetGender(rawAvatarId); + } + public key osGetMapTexture() { return m_OSSL_Functions.osGetMapTexture(); @@ -858,6 +895,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osGetRegionStats(); } + public vector osGetRegionSize() + { + return m_OSSL_Functions.osGetRegionSize(); + } + /// /// Returns the amount of memory in use by the Simulator Daemon. /// Amount in bytes - if >= 4GB, returns 4GB. (LSL is not 64-bit aware) @@ -892,6 +934,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { m_OSSL_Functions.osCauseHealing(avatar, healing); } + + public void osForceOtherSit(string avatar) + { + m_OSSL_Functions.osForceOtherSit(avatar); + } + + public void osForceOtherSit(string avatar, string target) + { + m_OSSL_Functions.osForceOtherSit(avatar, target); + } public LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules) { 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; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] +[assembly: AssemblyVersion("0.7.6.*")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Atom.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Atom.cs deleted file mode 100644 index 27ab04e..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Atom.cs +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - public class Atom : IUnifiable - { - private static Dictionary _atomStore = new Dictionary(); - public readonly string _name; - public readonly Atom _module; - - /// - /// You should not call this constructor, but use Atom.a instead. - /// - /// - /// - private Atom(string name, Atom module) - { - _name = name; - _module = module; - } - - /// - /// Return the unique Atom object for name where module is null. You should use this to create - /// an Atom instead of calling the Atom constructor. - /// - /// - /// - public static Atom a(string name) - { - Atom atom; - if (!_atomStore.TryGetValue(name, out atom)) - { - atom = new Atom(name, null); - _atomStore[name] = atom; - } - return atom; - } - - /// - /// Return an Atom object with the name and module. If module is null or Atom.NIL, - /// this behaves like Atom.a(name) and returns the unique object where the module is null. - /// If module is not null or Atom.NIL, this may or may not be the same object as another Atom - /// with the same name and module. - /// - /// - /// - /// - public static Atom a(string name, Atom module) - { - if (module == null || module == Atom.NIL) - return a(name); - return new Atom(name, module); - } - - /// - /// If Obj is an Atom unify its _module with Module. If the Atom's _module is null, use Atom.NIL. - /// - /// - /// - /// - public static IEnumerable module(object Obj, object Module) - { - Obj = YP.getValue(Obj); - if (Obj is Atom) - { - if (((Atom)Obj)._module == null) - return YP.unify(Module, Atom.NIL); - else - return YP.unify(Module, ((Atom)Obj)._module); - } - return YP.fail(); - } - - public static readonly Atom NIL = Atom.a("[]"); - public static readonly Atom DOT = Atom.a("."); - public static readonly Atom F = Atom.a("f"); - public static readonly Atom SLASH = Atom.a("/"); - public static readonly Atom HAT = Atom.a("^"); - public static readonly Atom RULE = Atom.a(":-"); - - public IEnumerable unify(object arg) - { - arg = YP.getValue(arg); - if (arg is Atom) - return Equals(arg) ? YP.succeed() : YP.fail(); - else if (arg is Variable) - return ((Variable)arg).unify(this); - else - return YP.fail(); - } - - public void addUniqueVariables(List variableSet) - { - // Atom does not contain variables. - } - - public object makeCopy(Variable.CopyStore copyStore) - { - // Atom does not contain variables that need to be copied. - return this; - } - - public bool termEqual(object term) - { - return Equals(YP.getValue(term)); - } - - public bool ground() - { - // Atom is always ground. - return true; - } - - public override bool Equals(object obj) - { - if (obj is Atom) - { - if (_module == null && ((Atom)obj)._module == null) - // When _declaringClass is null, we always use an identical object from _atomStore. - return this == obj; - // Otherwise, ignore _declaringClass and do a normal string compare on the _name. - return _name == ((Atom)obj)._name; - } - return false; - } - - public override string ToString() - { - return _name; - } - - public override int GetHashCode() - { - // Debug: need to check _declaringClass. - return _name.GetHashCode(); - } - - public string toQuotedString() - { - if (_name.Length == 0) - return "''"; - else if (this == Atom.NIL) - return "[]"; - - StringBuilder result = new StringBuilder(_name.Length); - bool useQuotes = false; - foreach (char c in _name) - { - int cInt = (int)c; - if (c == '\'') - { - result.Append("''"); - useQuotes = true; - } - else if (c == '_' || cInt >= (int)'a' && cInt <= (int)'z' || - cInt >= (int)'A' && cInt <= (int)'Z' || cInt >= (int)'0' && cInt <= (int)'9') - result.Append(c); - else - { - // Debug: Need to handle non-printable chars. - result.Append(c); - useQuotes = true; - } - } - - if (!useQuotes && (int)_name[0] >= (int)'a' && (int)_name[0] <= (int)'z') - return result.ToString(); - else - { - // Surround in single quotes. - result.Append('\''); - return "'" + result; - } - } - - /// - /// Return true if _name is lexicographically less than atom._name. - /// - /// - /// - public bool lessThan(Atom atom) - { - return _name.CompareTo(atom._name) < 0; - } - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/BagofAnswers.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/BagofAnswers.cs deleted file mode 100644 index bbf1a5b..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/BagofAnswers.cs +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - /// - /// A BagofAnswers holds answers for bagof and setof. - /// - public class BagofAnswers - { - private object _template; - private Variable[] _freeVariables; - private Dictionary> _bagForFreeVariables; - private List _findallBagArray; - private static TermArrayEqualityComparer _termArrayEqualityComparer = - new TermArrayEqualityComparer(); - - /// - /// To get the free variables, split off any existential qualifiers from Goal such as the X in - /// "X ^ f(Y)", get the set of unbound variables in Goal that are not qualifiers, then remove - /// the unbound variables that are qualifiers as well as the unbound variables in Template. - /// - /// - /// - public BagofAnswers(object Template, object Goal) - { - _template = Template; - - // First get the set of variables that are not free variables. - List variableSet = new List(); - YP.addUniqueVariables(Template, variableSet); - object UnqualifiedGoal = YP.getValue(Goal); - while (UnqualifiedGoal is Functor2 && ((Functor2)UnqualifiedGoal)._name == Atom.HAT) - { - YP.addUniqueVariables(((Functor2)UnqualifiedGoal)._arg1, variableSet); - UnqualifiedGoal = YP.getValue(((Functor2)UnqualifiedGoal)._arg2); - } - - // Remember how many non-free variables there are so we can find the unique free variables - // that are added. - int nNonFreeVariables = variableSet.Count; - YP.addUniqueVariables(UnqualifiedGoal, variableSet); - int nFreeVariables = variableSet.Count - nNonFreeVariables; - if (nFreeVariables == 0) - { - // There were no free variables added, so we won't waste time with _bagForFreeVariables. - _freeVariables = null; - _findallBagArray = new List(); - } - else - { - // Copy the free variables. - _freeVariables = new Variable[nFreeVariables]; - for (int i = 0; i < nFreeVariables; ++i) - _freeVariables[i] = variableSet[i + nNonFreeVariables]; - - _bagForFreeVariables = new Dictionary>(_termArrayEqualityComparer); - } - } - - public void add() - { - if (_freeVariables == null) - // The goal has bound the values in _template but we don't bother with _freeVariables. - _findallBagArray.Add(YP.makeCopy(_template, new Variable.CopyStore())); - else - { - // The goal has bound the values in _template and _freeVariables. - // Find the entry for this set of _freeVariables values. - object[] freeVariableValues = new object[_freeVariables.Length]; - for (int i = 0; i < _freeVariables.Length; ++i) - freeVariableValues[i] = YP.getValue(_freeVariables[i]); - List bagArray; - if (!_bagForFreeVariables.TryGetValue(freeVariableValues, out bagArray)) - { - bagArray = new List(); - _bagForFreeVariables[freeVariableValues] = bagArray; - } - - // Now copy the template and add to the bag for the freeVariables values. - bagArray.Add(YP.makeCopy(_template, new Variable.CopyStore())); - } - } - - // disable warning on l1, don't see how we can - // code this differently - #pragma warning disable 0168, 0219 - - /// - /// For each result, unify the _freeVariables and unify bagArrayVariable with the associated bag. - /// - /// this is unified with the List of matches for template that - /// corresponds to the bindings for freeVariables. Be very careful: this does not unify with a Prolog - /// list. - /// - public IEnumerable resultArray(Variable bagArrayVariable) - { - if (_freeVariables == null) - { - // No unbound free variables, so we only filled one bag. If empty, bagof fails. - if (_findallBagArray.Count > 0) - { - foreach (bool l1 in bagArrayVariable.unify(_findallBagArray)) - yield return false; - } - } - else - { - foreach (KeyValuePair> valuesAndBag in _bagForFreeVariables) - { - foreach (bool l1 in YP.unifyArrays(_freeVariables, valuesAndBag.Key)) - { - foreach (bool l2 in bagArrayVariable.unify(valuesAndBag.Value)) - yield return false; - } - // Debug: Should we free memory of the answers already returned? - } - } - } - - /// - /// For each result, unify the _freeVariables and unify Bag with the associated bag. - /// - /// - /// - public IEnumerable result(object Bag) - { - Variable bagArrayVariable = new Variable(); - foreach (bool l1 in resultArray(bagArrayVariable)) - { - foreach (bool l2 in YP.unify(Bag, ListPair.make((List)bagArrayVariable.getValue()))) - yield return false; - } - } - - /// - /// For each result, unify the _freeVariables and unify Bag with the associated bag which is sorted - /// with duplicates removed, as in setof. - /// - /// - /// - public IEnumerable resultSet(object Bag) - { - Variable bagArrayVariable = new Variable(); - foreach (bool l1 in resultArray(bagArrayVariable)) - { - List bagArray = (List)bagArrayVariable.getValue(); - YP.sortArray(bagArray); - foreach (bool l2 in YP.unify(Bag, ListPair.makeWithoutRepeatedTerms(bagArray))) - yield return false; - } - } - - public static IEnumerable bagofArray - (object Template, object Goal, IEnumerable goalIterator, Variable bagArrayVariable) - { - BagofAnswers bagOfAnswers = new BagofAnswers(Template, Goal); - foreach (bool l1 in goalIterator) - bagOfAnswers.add(); - return bagOfAnswers.resultArray(bagArrayVariable); - } - - public static IEnumerable bagof - (object Template, object Goal, IEnumerable goalIterator, object Bag) - { - BagofAnswers bagOfAnswers = new BagofAnswers(Template, Goal); - foreach (bool l1 in goalIterator) - bagOfAnswers.add(); - return bagOfAnswers.result(Bag); - } - - public static IEnumerable setof - (object Template, object Goal, IEnumerable goalIterator, object Bag) - { - BagofAnswers bagOfAnswers = new BagofAnswers(Template, Goal); - foreach (bool l1 in goalIterator) - bagOfAnswers.add(); - return bagOfAnswers.resultSet(Bag); - } - #pragma warning restore 0168, 0219 - - /// - /// A TermArrayEqualityComparer implements IEqualityComparer to compare two object arrays using YP.termEqual. - /// - private class TermArrayEqualityComparer : IEqualityComparer - { - public bool Equals(object[] array1, object[] array2) - { - if (array1.Length != array2.Length) - return false; - for (int i = 0; i < array1.Length; ++i) - { - if (!YP.termEqual(array1[i], array2[i])) - return false; - } - return true; - } - - public int GetHashCode(object[] array) - { - int hashCode = 0; - for (int i = 0; i < array.Length; ++i) - hashCode ^= array[i].GetHashCode(); - return hashCode; - } - } - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/FindallAnswers.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/FindallAnswers.cs deleted file mode 100644 index fb9569e..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/FindallAnswers.cs +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - /// - /// A FindallAnswers holds answers for findall. - /// - public class FindallAnswers - { - private object _template; - private List _bagArray; - - public FindallAnswers(object Template) - { - _template = Template; - _bagArray = new List(); - } - - public void add() - { - _bagArray.Add(YP.makeCopy(_template, new Variable.CopyStore())); - } - - public List resultArray() - { - return _bagArray; - } - - /// - /// Unify Bag with the result. This frees the internal answers, so you can only call this once. - /// - /// - /// - public IEnumerable result(object Bag) - { - object result = ListPair.make(_bagArray); - // Try to free the memory. - _bagArray = null; - return YP.unify(Bag, result); - } - - // disable warning on l1, don't see how we can - // code this differently - #pragma warning disable 0168, 0219 - - /// - /// This is a simplified findall when the goal is a single call. - /// - /// - /// - /// - /// - public static IEnumerable findall(object Template, IEnumerable goal, object Bag) - { - FindallAnswers findallAnswers = new FindallAnswers(Template); - foreach (bool l1 in goal) - findallAnswers.add(); - return findallAnswers.result(Bag); - } - - /// - /// Like findall, except return an array of the results. - /// - /// - /// - /// - public static List findallArray(object Template, IEnumerable goal) - { - FindallAnswers findallAnswers = new FindallAnswers(Template); - foreach (bool l1 in goal) - findallAnswers.add(); - return findallAnswers.resultArray(); - } - #pragma warning restore 0168, 0219 - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor.cs deleted file mode 100644 index 4d65f5b..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor.cs +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - public class Functor : IUnifiable - { - public readonly Atom _name; - public readonly object[] _args; - - public Functor(Atom name, object[] args) - { - if (args.Length <= 3) - { - if (args.Length == 0) - throw new Exception("For arity 0 functor, just use name as an Atom"); - else if (args.Length == 1) - throw new Exception("For arity 1 functor, use Functor1"); - else if (args.Length == 2) - throw new Exception("For arity 2 functor, use Functor2"); - else if (args.Length == 3) - throw new Exception("For arity 3 functor, use Functor3"); - else - // (This shouldn't happen, but include it for completeness. - throw new Exception("Cannot create a Functor of arity " + args.Length); - } - - _name = name; - _args = args; - } - - public Functor(string name, object[] args) - : this(Atom.a(name), args) - { - } - - /// - /// Return an Atom, Functor1, Functor2, Functor3 or Functor depending on the - /// length of args. - /// Note that this is different than the Functor constructor which requires - /// the length of args to be greater than 3. - /// - /// - /// - /// - public static object make(Atom name, object[] args) - { - if (args.Length <= 0) - return name; - else if (args.Length == 1) - return new Functor1(name, args[0]); - else if (args.Length == 2) - return new Functor2(name, args[0], args[1]); - else if (args.Length == 3) - return new Functor3(name, args[0], args[1], args[2]); - else - return new Functor(name, args); - } - - /// - /// Call the main make, first converting name to an Atom. - /// - /// - /// - /// - public static object make(string name, object[] args) - { - return make(Atom.a(name), args); - } - - /// - /// If arg is another Functor, then succeed (yield once) if this and arg have the - /// same name and all functor args unify, otherwise fail (don't yield). - /// If arg is a Variable, then call its unify to unify with this. - /// Otherwise fail (don't yield). - /// - /// - /// - public IEnumerable unify(object arg) - { - arg = YP.getValue(arg); - if (arg is Functor) - { - Functor argFunctor = (Functor)arg; - if (_name.Equals(argFunctor._name)) - return YP.unifyArrays(_args, argFunctor._args); - else - return YP.fail(); - } - else if (arg is Variable) - return ((Variable)arg).unify(this); - else - return YP.fail(); - } - - public override string ToString() - { - string result = _name + "(" + YP.getValue(_args[0]); - for (int i = 1; i < _args.Length; ++i) - result += ", " + YP.getValue(_args[i]); - result += ")"; - return result; - } - - public bool termEqual(object term) - { - term = YP.getValue(term); - if (term is Functor) - { - Functor termFunctor = (Functor)term; - if (_name.Equals(termFunctor._name) && _args.Length == termFunctor._args.Length) - { - for (int i = 0; i < _args.Length; ++i) - { - if (!YP.termEqual(_args[i], termFunctor._args[i])) - return false; - } - return true; - } - } - return false; - } - - public bool lessThan(Functor functor) - { - // Do the equal check first since it is faster. - if (!_name.Equals(functor._name)) - return _name.lessThan(functor._name); - - if (_args.Length != functor._args.Length) - return _args.Length < functor._args.Length; - - for (int i = 0; i < _args.Length; ++i) - { - if (!YP.termEqual(_args[i], functor._args[i])) - return YP.termLessThan(_args[i], functor._args[i]); - } - - return false; - } - - public bool ground() - { - for (int i = 0; i < _args.Length; ++i) - { - if (!YP.ground(_args[i])) - return false; - } - return true; - } - - public void addUniqueVariables(List variableSet) - { - for (int i = 0; i < _args.Length; ++i) - YP.addUniqueVariables(_args[i], variableSet); - } - - public object makeCopy(Variable.CopyStore copyStore) - { - object[] argsCopy = new object[_args.Length]; - for (int i = 0; i < _args.Length; ++i) - argsCopy[i] = YP.makeCopy(_args[i], copyStore); - return new Functor(_name, argsCopy); - } - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor1.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor1.cs deleted file mode 100644 index 80d98b1..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor1.cs +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - public class Functor1 : IUnifiable - { - public readonly Atom _name; - public readonly object _arg1; - - public Functor1(Atom name, object arg1) - { - _name = name; - _arg1 = arg1; - } - - public Functor1(string name, object arg1) - : this(Atom.a(name), arg1) - { - } - - // disable warning on l1, don't see how we can - // code this differently - #pragma warning disable 0168, 0219 - /// - /// If arg is another Functor1, then succeed (yield once) if this and arg have the - /// same name and the functor args unify, otherwise fail (don't yield). - /// If arg is a Variable, then call its unify to unify with this. - /// Otherwise fail (don't yield). - /// - /// - /// - public IEnumerable unify(object arg) - { - arg = YP.getValue(arg); - if (arg is Functor1) - { - Functor1 argFunctor = (Functor1)arg; - if (_name.Equals(argFunctor._name)) - { - foreach (bool l1 in YP.unify(_arg1, argFunctor._arg1)) - yield return false; - } - } - else if (arg is Variable) - { - foreach (bool l1 in ((Variable)arg).unify(this)) - yield return false; - } - } - #pragma warning restore 0168, 0219 - - - public override string ToString() - { - return _name + "(" + YP.getValue(_arg1) + ")"; - } - - public bool termEqual(object term) - { - term = YP.getValue(term); - if (term is Functor1) - { - Functor1 termFunctor = (Functor1)term; - return _name.Equals(termFunctor._name) && YP.termEqual(_arg1, termFunctor._arg1); - } - return false; - } - - public bool lessThan(Functor1 functor) - { - // Do the equal check first since it is faster. - if (!_name.Equals(functor._name)) - return _name.lessThan(functor._name); - - return YP.termLessThan(_arg1, functor._arg1); - } - - public bool ground() - { - return YP.ground(_arg1); - } - - public void addUniqueVariables(List variableSet) - { - YP.addUniqueVariables(_arg1, variableSet); - } - - public object makeCopy(Variable.CopyStore copyStore) - { - return new Functor1(_name, YP.makeCopy(_arg1, copyStore)); - } - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor2.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor2.cs deleted file mode 100644 index 4c501d6..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor2.cs +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - public class Functor2 : IUnifiable - { - public readonly Atom _name; - public readonly object _arg1; - public readonly object _arg2; - - public Functor2(Atom name, object arg1, object arg2) - { - _name = name; - _arg1 = arg1; - _arg2 = arg2; - } - - public Functor2(string name, object arg1, object arg2) - : this(Atom.a(name), arg1, arg2) - { - } - - // disable warning on l1, don't see how we can - // code this differently - #pragma warning disable 0168, 0219 - /// If arg is another Functor2, then succeed (yield once) if this and arg have the - /// same name and all functor args unify, otherwise fail (don't yield). - /// If arg is a Variable, then call its unify to unify with this. - /// Otherwise fail (don't yield). - public IEnumerable unify(object arg) - { - arg = YP.getValue(arg); - if (arg is Functor2) - { - Functor2 argFunctor = (Functor2)arg; - if (_name.Equals(argFunctor._name)) - { - foreach (bool l1 in YP.unify(_arg1, argFunctor._arg1)) - { - foreach (bool l2 in YP.unify(_arg2, argFunctor._arg2)) - yield return false; - } - } - } - else if (arg is Variable) - { - foreach (bool l1 in ((Variable)arg).unify(this)) - yield return false; - } - } - #pragma warning restore 0168, 0219 - - - public override string ToString() - { - if (_name == Atom.DOT) - return listPairToString(this); - else - return _name + "(" + YP.getValue(_arg1) + ", " + YP.getValue(_arg2) + ")"; - } - - public bool termEqual(object term) - { - term = YP.getValue(term); - if (term is Functor2) - { - Functor2 termFunctor = (Functor2)term; - return _name.Equals(termFunctor._name) && YP.termEqual(_arg1, termFunctor._arg1) - && YP.termEqual(_arg2, termFunctor._arg2); - } - return false; - } - - public bool lessThan(Functor2 functor) - { - // Do the equal check first since it is faster. - if (!_name.Equals(functor._name)) - return _name.lessThan(functor._name); - - if (!YP.termEqual(_arg1, functor._arg1)) - return YP.termLessThan(_arg1, functor._arg1); - - return YP.termLessThan(_arg2, functor._arg2); - } - - public bool ground() - { - return YP.ground(_arg1) && YP.ground(_arg2); - } - - public void addUniqueVariables(List variableSet) - { - YP.addUniqueVariables(_arg1, variableSet); - YP.addUniqueVariables(_arg2, variableSet); - } - - public object makeCopy(Variable.CopyStore copyStore) - { - return new Functor2(_name, YP.makeCopy(_arg1, copyStore), - YP.makeCopy(_arg2, copyStore)); - } - - private static string listPairToString(Functor2 listPair) - { - string result = "["; - while (true) - { - object head = YP.getValue(listPair._arg1); - object tail = YP.getValue(listPair._arg2); - if (tail == (object)Atom.NIL) - { - result += head; - break; - } - else if (tail is Functor2 && ((Functor2)tail)._name == Atom.DOT) - { - result += head + ", "; - listPair = (Functor2)tail; - // Loop again. - } - else - { - // The list is not terminated with NIL. - result += head + "|" + tail; - break; - } - } - result += "]"; - return result; - } - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor3.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor3.cs deleted file mode 100644 index 94e39c4..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Functor3.cs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - public class Functor3 : IUnifiable - { - public readonly Atom _name; - public readonly object _arg1; - public readonly object _arg2; - public readonly object _arg3; - - public Functor3(Atom name, object arg1, object arg2, object arg3) - { - _name = name; - _arg1 = arg1; - _arg2 = arg2; - _arg3 = arg3; - } - - public Functor3(string name, object arg1, object arg2, object arg3) - : this(Atom.a(name), arg1, arg2, arg3) - { - } - - // disable warning on l1, don't see how we can - // code this differently - #pragma warning disable 0168, 0219 - /// If arg is another Functor3, then succeed (yield once) if this and arg have the - /// same name and all functor args unify, otherwise fail (don't yield). - /// If arg is a Variable, then call its unify to unify with this. - /// Otherwise fail (don't yield). - public IEnumerable unify(object arg) - { - arg = YP.getValue(arg); - if (arg is Functor3) - { - Functor3 argFunctor = (Functor3)arg; - if (_name.Equals(argFunctor._name)) - { - foreach (bool l1 in YP.unify(_arg1, argFunctor._arg1)) - { - foreach (bool l2 in YP.unify(_arg2, argFunctor._arg2)) - { - foreach (bool l3 in YP.unify(_arg3, argFunctor._arg3)) - yield return false; - } - } - } - } - else if (arg is Variable) - { - foreach (bool l1 in ((Variable)arg).unify(this)) - yield return false; - } - } - #pragma warning restore 0168, 0219 - - public override string ToString() - { - return _name + "(" + YP.getValue(_arg1) + ", " + YP.getValue(_arg2) + ", " + - YP.getValue(_arg3) + ")"; - } - - public bool termEqual(object term) - { - term = YP.getValue(term); - if (term is Functor3) - { - Functor3 termFunctor = (Functor3)term; - return _name.Equals(termFunctor._name) && YP.termEqual(_arg1, termFunctor._arg1) - && YP.termEqual(_arg2, termFunctor._arg2) - && YP.termEqual(_arg3, termFunctor._arg3); - } - return false; - } - - public bool lessThan(Functor3 functor) - { - // Do the equal check first since it is faster. - if (!_name.Equals(functor._name)) - return _name.lessThan(functor._name); - - if (!YP.termEqual(_arg1, functor._arg1)) - return YP.termLessThan(_arg1, functor._arg1); - - if (!YP.termEqual(_arg2, functor._arg2)) - return YP.termLessThan(_arg2, functor._arg2); - - return YP.termLessThan(_arg3, functor._arg3); - } - - public bool ground() - { - return YP.ground(_arg1) && YP.ground(_arg2) && YP.ground(_arg3); - } - - public void addUniqueVariables(List variableSet) - { - YP.addUniqueVariables(_arg1, variableSet); - YP.addUniqueVariables(_arg2, variableSet); - YP.addUniqueVariables(_arg3, variableSet); - } - - public object makeCopy(Variable.CopyStore copyStore) - { - return new Functor3(_name, YP.makeCopy(_arg1, copyStore), - YP.makeCopy(_arg2, copyStore), YP.makeCopy(_arg3, copyStore)); - } - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/IndexedAnswers.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/IndexedAnswers.cs deleted file mode 100644 index 09a9a08..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/IndexedAnswers.cs +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - /// - /// An IndexedAnswers holds answers to a query based on the values of index arguments. - /// - public class IndexedAnswers : YP.IClause - { - private int _arity; - // addAnswer adds the answer here and indexes it later. - private List _allAnswers = new List(); - // The key has the arity of answers with non-null values for each indexed arg. The value - // is a list of the matching answers. The signature is implicit in the pattern on non-null index args. - private Dictionary> _indexedAnswers = - new Dictionary>(); - // Keeps track of whether we have started adding entries to _indexedAnswers for the signature. - private Dictionary _gotAnswersForSignature = new Dictionary(); - private const int MAX_INDEX_ARGS = 31; - - public IndexedAnswers(int arity) - { - _arity = arity; - } - - /// - /// Append the answer to the list and update the indexes, if any. - /// Elements of answer must be ground, since arguments with unbound variables make this - /// into a dynamic rule which we don't index. - /// - /// - public void addAnswer(object[] answer) - { - addOrPrependAnswer(answer, false); - } - - /// - /// Prepend the answer to the list and clear the indexes so that they must be re-computed - /// on the next call to match. (Only addAnswer will maintain the indexes while adding answers.) - /// Elements of answer must be ground, since arguments with unbound variables make this - /// into a dynamic rule which we don't index. - /// - /// - public void prependAnswer(object[] answer) - { - addOrPrependAnswer(answer, true); - } - - /// - /// Do the work of addAnswer or prependAnswer. - /// - /// - private void addOrPrependAnswer(object[] answer, bool prepend) - { - if (answer.Length != _arity) - return; - - // Store a copy of the answer array. - object[] answerCopy = new object[answer.Length]; - Variable.CopyStore copyStore = new Variable.CopyStore(); - for (int i = 0; i < answer.Length; ++i) - answerCopy[i] = YP.makeCopy(answer[i], copyStore); - if (copyStore.getNUniqueVariables() > 0) - throw new InvalidOperationException - ("Elements of answer must be ground, but found " + copyStore.getNUniqueVariables() + - " unbound variables"); - - if (prepend) - { - _allAnswers.Insert(0, answerCopy); - clearIndexes(); - } - else - { - _allAnswers.Add(answerCopy); - // If match has already indexed answers for a signature, we need to add - // this to the existing indexed answers. - foreach (int signature in _gotAnswersForSignature.Keys) - indexAnswerForSignature(answerCopy, signature); - } - } - - private void indexAnswerForSignature(object[] answer, int signature) - { - // First find out which of the answer values can be used as an index. - object[] indexValues = new object[answer.Length]; - for (int i = 0; i < answer.Length; ++i) - { - // We limit the number of indexed args in a 32-bit signature. - if (i >= MAX_INDEX_ARGS) - indexValues[i] = null; - else - indexValues[i] = getIndexValue(YP.getValue(answer[i])); - } - - // We need an entry in indexArgs from indexValues for each 1 bit in signature. - HashedList indexArgs = new HashedList(indexValues.Length); - for (int i = 0; i < indexValues.Length; ++i) - { - if ((signature & (1 << i)) == 0) - indexArgs.Add(null); - else - { - if (indexValues[i] == null) - // The signature wants an index value here, but we don't have one so - // we can't add it as an answer for this signature. - return; - else - indexArgs.Add(indexValues[i]); - } - } - - // Add the answer to the answers list for indexArgs, creating the entry if needed. - List answers; - if (!_indexedAnswers.TryGetValue(indexArgs, out answers)) - { - answers = new List(); - _indexedAnswers[indexArgs] = answers; - } - answers.Add(answer); - } - - public IEnumerable match(object[] arguments) - { - if (arguments.Length != _arity) - yield break; - - // Set up indexArgs, up to arg position MAX_INDEX_ARGS. The signature has a 1 bit for - // each non-null index arg. - HashedList indexArgs = new HashedList(arguments.Length); - bool gotAllIndexArgs = true; - int signature = 0; - for (int i = 0; i < arguments.Length; ++i) - { - object indexValue = null; - if (i < MAX_INDEX_ARGS) - { - // We limit the number of args in a 32-bit signature. - indexValue = getIndexValue(YP.getValue(arguments[i])); - if (indexValue != null) - signature += (1 << i); - } - if (indexValue == null) - gotAllIndexArgs = false; - indexArgs.Add(indexValue); - } - - List answers; - if (signature == 0) - // No index args, so we have to match from _allAnswers. - answers = _allAnswers; - else - { - if (!_gotAnswersForSignature.ContainsKey(signature)) - { - // We need to create the entry in _indexedAnswers. - foreach (object[] answer in _allAnswers) - indexAnswerForSignature(answer, signature); - // Mark that we did this signature. - _gotAnswersForSignature[signature] = null; - } - if (!_indexedAnswers.TryGetValue(indexArgs, out answers)) - yield break; - } - - if (gotAllIndexArgs) - { - // All the arguments were already bound, so we don't need to do bindings. - yield return false; - yield break; - } - - // Find matches in answers. - IEnumerator[] iterators = new IEnumerator[arguments.Length]; - // Debug: If the caller asserts another answer into this same predicate during yield, the iterator - // over clauses will be corrupted. Should we take the time to copy answers? - foreach (object[] answer in answers) - { - bool gotMatch = true; - int nIterators = 0; - // Try to bind all the arguments. - for (int i = 0; i < arguments.Length; ++i) - { - if (indexArgs[i] != null) - // We already matched this argument by looking up _indexedAnswers. - continue; - - IEnumerator iterator = YP.unify(arguments[i], answer[i]).GetEnumerator(); - iterators[nIterators++] = iterator; - // MoveNext() is true if YP.unify succeeds. - if (!iterator.MoveNext()) - { - gotMatch = false; - break; - } - } - int z = 0; - try - { - if (gotMatch) - yield return false; - } - finally - { - // Manually finalize all the iterators. - for (z = 0; z < nIterators; ++z) - iterators[z].Dispose(); - } - } - } - - public IEnumerable clause(object Head, object Body) - { - Head = YP.getValue(Head); - if (Head is Variable) - throw new PrologException("instantiation_error", "Head is an unbound variable"); - object[] arguments = YP.getFunctorArgs(Head); - - // We always match Head from _allAnswers, and the Body is Atom.a("true"). - #pragma warning disable 0168, 0219 - foreach (bool l1 in YP.unify(Body, Atom.a("true"))) - { - // The caller can assert another answer into this same predicate during yield, so we have to - // make a copy of the answers. - foreach (object[] answer in _allAnswers.ToArray()) - { - foreach (bool l2 in YP.unifyArrays(arguments, answer)) - yield return false; - } - } - #pragma warning restore 0168, 0219 - } - - public IEnumerable retract(object Head, object Body) - { - Head = YP.getValue(Head); - if (Head is Variable) - throw new PrologException("instantiation_error", "Head is an unbound variable"); - object[] arguments = YP.getFunctorArgs(Head); - - // We always match Head from _allAnswers, and the Body is Atom.a("true"). - #pragma warning disable 0168, 0219 - foreach (bool l1 in YP.unify(Body, Atom.a("true"))) - { - // The caller can assert another answer into this same predicate during yield, so we have to - // make a copy of the answers. - foreach (object[] answer in _allAnswers.ToArray()) - { - foreach (bool l2 in YP.unifyArrays(arguments, answer)) - { - _allAnswers.Remove(answer); - clearIndexes(); - yield return false; - } - } - } - #pragma warning restore 0168, 0219 - } - - /// - /// After retracting or prepending an answer in _allAnswers, the indexes are invalid, so clear them. - /// - private void clearIndexes() - { - _indexedAnswers.Clear(); - _gotAnswersForSignature.Clear(); - } - - /// - /// A HashedList extends an ArrayList with methods to get a hash and to check equality - /// based on the elements of the list. - /// - public class HashedList : ArrayList - { - private bool _gotHashCode = false; - private int _hashCode; - - public HashedList() - : base() - { - } - - public HashedList(int capacity) - : base(capacity) - { - } - - public HashedList(ICollection c) - : base(c) - { - } - - // Debug: Should override all the other methods that change this. - public override int Add(object value) - { - _gotHashCode = false; - return base.Add(value); - } - - public override int GetHashCode() - { - if (!_gotHashCode) - { - int hashCode = 1; - foreach (object obj in this) - hashCode = 31 * hashCode + (obj == null ? 0 : obj.GetHashCode()); - _hashCode = hashCode; - _gotHashCode = true; - } - return _hashCode; - } - - public override bool Equals(object obj) - { - if (!(obj is ArrayList)) - return false; - - ArrayList objList = (ArrayList)obj; - if (objList.Count != Count) - return false; - - for (int i = 0; i < Count; ++i) - { - object value = objList[i]; - if (value == null) - { - if (this[i] != null) - return false; - } - else - { - if (!value.Equals(this[i])) - return false; - } - } - return true; - } - } - - /// - /// If we keep an index on value, return the value, or null if we don't index it. - /// - /// the term to examine. Assume you already called YP.getValue(value) - /// - public static object getIndexValue(object value) - { - if (value is Atom || value is string || value is Int32 || value is DateTime) - return value; - else - return null; - } - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/ListPair.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/ListPair.cs deleted file mode 100644 index daac0ba..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/ListPair.cs +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - public class ListPair : Functor2 - { - public ListPair(object head, object tail) : base(Atom.DOT, head, tail) - { - } - - public static object make(List list) - { - if (list.Count <= 0) - return Atom.NIL; - - object result = Atom.NIL; - // Start from the end. - for (int i = list.Count - 1; i >= 0; --i) - result = new ListPair(list[i], result); - return result; - } - - public static object make(object[] array) - { - if (array.Length <= 0) - return Atom.NIL; - - object result = Atom.NIL; - // Start from the end. - for (int i = array.Length - 1; i >= 0; --i) - result = new ListPair(array[i], result); - return result; - } - - /// - /// Return a ListPair version of array, where repeated elements - /// (according to YP.termEqual) are removed. - /// - /// - /// - public static object makeWithoutRepeatedTerms(object[] array) - { - if (array.Length <= 0) - return Atom.NIL; - - // Start from the end. - object previousTerm = array[array.Length - 1]; - object result = new ListPair(previousTerm, Atom.NIL); - for (int i = array.Length - 2; i >= 0; --i) - { - object term = array[i]; - if (YP.termEqual(term, previousTerm)) - continue; - result = new ListPair(term, result); - previousTerm = term; - } - return result; - } - - /// - /// Return a ListPair version of array, where repeated elements - /// (according to YP.termEqual) are removed. - /// - /// - /// - public static object makeWithoutRepeatedTerms(List array) - { - if (array.Count <= 0) - return Atom.NIL; - - // Start from the end. - object previousTerm = array[array.Count - 1]; - object result = new ListPair(previousTerm, Atom.NIL); - for (int i = array.Count - 2; i >= 0; --i) - { - object term = array[i]; - if (YP.termEqual(term, previousTerm)) - continue; - result = new ListPair(term, result); - previousTerm = term; - } - return result; - } - - public static object make(object element1) - { - return new ListPair(element1, Atom.NIL); - } - - public static object make(object element1, object element2) - { - return new ListPair(element1, new ListPair(element2, Atom.NIL)); - } - - public static object make(object element1, object element2, object element3) - { - return new ListPair(element1, - new ListPair(element2, new ListPair(element3, Atom.NIL))); - } - - /// - /// Return an array of the elements in list or null if it is not - /// a proper list. If list is Atom.NIL, return an array of zero elements. - /// If the list or one of the tails of the list is Variable, raise an instantiation_error. - /// This does not call YP.getValue on each element. - /// - /// - /// - public static object[] toArray(object list) - { - list = YP.getValue(list); - if (list.Equals(Atom.NIL)) - return new object[0]; - - List result = new List(); - object element = list; - while (true) { - if (element == Atom.NIL) - break; - if (element is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "List tail is an unbound variable"); - if (!(element is Functor2 && ((Functor2)element)._name == Atom.DOT)) - // Not a proper list. - return null; - result.Add(((Functor2)element)._arg1); - element = YP.getValue(((Functor2)element)._arg2); - } - - if (result.Count <= 0) - return null; - return result.ToArray(); - } - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Parser.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Parser.cs deleted file mode 100644 index 34010e7..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Parser.cs +++ /dev/null @@ -1,4575 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; - - // disable warning on l1, don't see how we can - // code this differently - #pragma warning disable 0168, 0219, 0162 - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - public class Parser - { - public static IEnumerable read_term2(object Term, object Options) - { - Variable Answer = new Variable(); - Variable Variables = new Variable(); - foreach (bool l1 in read_termOptions(Options, Variables)) - { - foreach (bool l2 in portable_read3(Answer, Variables, new Variable())) - { - foreach (bool l3 in remove_pos(Answer, Term)) - yield return false; - } - } - } - - public static IEnumerable read_term3(object Input, object Term, object Options) - { - Variable SaveInput = new Variable(); - Variable Answer = new Variable(); - Variable Variables = new Variable(); - foreach (bool l1 in read_termOptions(Options, Variables)) - { - foreach (bool l2 in YP.current_input(SaveInput)) - { - try - { - YP.see(Input); - foreach (bool l3 in portable_read3(Answer, Variables, new Variable())) - { - foreach (bool l4 in remove_pos(Answer, Term)) - yield return false; - } - } - finally - { - YP.see(SaveInput); - } - } - } - } - - /// - /// For read_term, check if Options has variable_names(Variables). - /// Otherwise, ignore Options. - /// - /// - /// - /// - private static IEnumerable read_termOptions(object Options, object Variables) - { - Options = YP.getValue(Options); - if (Options is Variable) - throw new PrologException(Atom.a("instantiation_error"), "Options is an unbound variable"); - // First try to match Options = [variable_names(Variables)] - foreach (bool l1 in YP.unify(Options, ListPair.make(new Functor1("variable_names", Variables)))) - { - yield return false; - yield break; - } - // Default: Ignore Options. - yield return false; - } - - public static IEnumerable read1(object Term) - { - return read_term2(Term, Atom.NIL); - } - - public static IEnumerable read2(object Input, object Term) - { - return read_term3(Input, Term, Atom.NIL); - } - - public static IEnumerable formatError(object Output, object Format, object Arguments) - { - // Debug: Simple implementation for now. - YP.write(Format); - YP.write(Arguments); - YP.nl(); - yield return false; - } - - - // Debug: Hand-modify this central predicate to do tail recursion. - public static IEnumerable read_tokens(object arg1, object arg2, object arg3) - { - bool repeat = true; - while (repeat) - { - repeat = false; - { - object C1 = arg1; - object Dict = arg2; - object Tokens = arg3; - Variable C2 = new Variable(); - if (YP.lessThanOrEqual(C1, new ListPair(32, Atom.NIL))) - { - if (YP.greaterThanOrEqual(C1, 0)) - { - foreach (bool l4 in YP.get_code(C2)) - { -#if false - foreach (bool l5 in read_tokens(C2, Dict, Tokens)) - { - yield return false; - } -#endif - arg1 = YP.getValue(C2); - arg2 = YP.getValue(Dict); - arg3 = YP.getValue(Tokens); - repeat = true; - } - } - goto cutIf1; - } - if (YP.greaterThanOrEqual(C1, new ListPair(97, Atom.NIL))) - { - if (YP.lessThanOrEqual(C1, new ListPair(122, Atom.NIL))) - { - foreach (bool l4 in read_identifier(C1, Dict, Tokens)) - { - yield return false; - } - goto cutIf2; - } - } - if (YP.greaterThanOrEqual(C1, new ListPair(65, Atom.NIL))) - { - if (YP.lessThanOrEqual(C1, new ListPair(90, Atom.NIL))) - { - foreach (bool l4 in read_variable(C1, Dict, Tokens)) - { - yield return false; - } - goto cutIf3; - } - } - if (YP.greaterThanOrEqual(C1, new ListPair(48, Atom.NIL))) - { - if (YP.lessThanOrEqual(C1, new ListPair(57, Atom.NIL))) - { - foreach (bool l4 in read_number(C1, Dict, Tokens)) - { - yield return false; - } - goto cutIf4; - } - } - if (YP.lessThan(C1, 127)) - { - foreach (bool l3 in read_special(C1, Dict, Tokens)) - { - yield return false; - } - goto cutIf5; - } - if (YP.lessThanOrEqual(C1, 160)) - { - foreach (bool l3 in YP.get_code(C2)) - { -#if false - foreach (bool l4 in read_tokens(C2, Dict, Tokens)) - { - yield return false; - } -#endif - arg1 = YP.getValue(C2); - arg2 = YP.getValue(Dict); - arg3 = YP.getValue(Tokens); - repeat = true; - } - goto cutIf6; - } - if (YP.greaterThanOrEqual(C1, 223)) - { - if (YP.notEqual(C1, 247)) - { - foreach (bool l4 in read_identifier(C1, Dict, Tokens)) - { - yield return false; - } - goto cutIf7; - } - } - if (YP.greaterThanOrEqual(C1, 192)) - { - if (YP.notEqual(C1, 215)) - { - foreach (bool l4 in read_variable(C1, Dict, Tokens)) - { - yield return false; - } - goto cutIf8; - } - } - if (YP.notEqual(C1, 170)) - { - if (YP.notEqual(C1, 186)) - { - foreach (bool l4 in read_symbol(C1, Dict, Tokens)) - { - yield return false; - } - goto cutIf9; - } - } - foreach (bool l2 in read_identifier(C1, Dict, Tokens)) - { - yield return false; - } - cutIf9: - cutIf8: - cutIf7: - cutIf6: - cutIf5: - cutIf4: - cutIf3: - cutIf2: - cutIf1: - { } - } - } - } - - // Compiler output follows. - - class YPInnerClass { } - // static Type getDeclaringClass() { return typeof(YPInnerClass).DeclaringType; } - - public static IEnumerable parseInput(object TermList) - { - { - Variable TermAndVariables = new Variable(); - FindallAnswers findallAnswers1 = new FindallAnswers(TermAndVariables); - foreach (bool l2 in parseInputHelper(TermAndVariables)) - { - findallAnswers1.add(); - } - foreach (bool l2 in findallAnswers1.result(TermList)) - { - yield return false; - } - } - } - - public static IEnumerable parseInputHelper(object arg1) - { - { - Variable Term = new Variable(); - Variable Variables = new Variable(); - Variable Answer = new Variable(); - Variable x4 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("f", Term, Variables))) - { - foreach (bool l3 in YP.repeat()) - { - foreach (bool l4 in portable_read3(Answer, Variables, x4)) - { - foreach (bool l5 in remove_pos(Answer, Term)) - { - if (YP.termEqual(Term, Atom.a("end_of_file"))) - { - yield break; - goto cutIf1; - } - yield return false; - cutIf1: - { } - } - } - } - } - } - } - - public static IEnumerable clear_errors() - { - { - yield return false; - } - } - - public static IEnumerable remove_pos(object arg1, object arg2) - { - { - Variable X = new Variable(); - foreach (bool l2 in YP.unify(arg1, X)) - { - foreach (bool l3 in YP.unify(arg2, X)) - { - if (YP.var(X)) - { - yield return true; - yield break; - } - } - } - } - { - object X = arg2; - Variable _Pos = new Variable(); - Variable _Name = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor3("$VAR", _Pos, _Name, X))) - { - if (YP.var(X)) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg2, Atom.NIL)) - { - yield return true; - yield break; - } - } - } - { - Variable H = new Variable(); - Variable T = new Variable(); - Variable NH = new Variable(); - Variable NT = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(H, T))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(NH, NT))) - { - foreach (bool l4 in remove_pos(H, NH)) - { - foreach (bool l5 in remove_pos(T, NT)) - { - yield return false; - } - } - yield break; - } - } - } - { - Variable A = new Variable(); - Variable B = new Variable(); - Variable NA = new Variable(); - Variable NB = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", A, B))) - { - foreach (bool l3 in YP.unify(arg2, new Functor2(",", NA, NB))) - { - foreach (bool l4 in remove_pos(A, NA)) - { - foreach (bool l5 in remove_pos(B, NB)) - { - yield return false; - } - } - yield break; - } - } - } - { - Variable Atom_1 = new Variable(); - Variable _F = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom_1)) - { - foreach (bool l3 in YP.unify(arg2, Atom_1)) - { - foreach (bool l4 in YP.functor(Atom_1, _F, 0)) - { - yield return false; - } - } - } - } - { - object Term = arg1; - object NewTerm = arg2; - Variable Func = new Variable(); - Variable _Pos = new Variable(); - Variable Args = new Variable(); - Variable NArgs = new Variable(); - if (YP.nonvar(Term)) - { - foreach (bool l3 in YP.univ(Term, new ListPair(Func, new ListPair(_Pos, Args)))) - { - foreach (bool l4 in remove_pos(Args, NArgs)) - { - foreach (bool l5 in YP.univ(NewTerm, new ListPair(Func, NArgs))) - { - yield return false; - } - } - } - } - } - } - - public static IEnumerable portable_read_position(object Term, object PosTerm, object Syntax) - { - { - foreach (bool l2 in portable_read(PosTerm, Syntax)) - { - foreach (bool l3 in remove_pos(PosTerm, Term)) - { - yield return false; - } - } - } - } - - public static IEnumerable portable_read(object Answer, object Syntax) - { - { - Variable Tokens = new Variable(); - Variable ParseTokens = new Variable(); - foreach (bool l2 in read_tokens1(Tokens)) - { - foreach (bool l3 in remove_comments(Tokens, ParseTokens, Syntax)) - { - foreach (bool l4 in parse2(ParseTokens, Answer)) - { - yield return false; - } - } - } - } - } - - public static IEnumerable portable_read3(object Answer, object Variables, object Syntax) - { - { - Variable Tokens = new Variable(); - Variable ParseTokens = new Variable(); - foreach (bool l2 in read_tokens2(Tokens, Variables)) - { - foreach (bool l3 in remove_comments(Tokens, ParseTokens, Syntax)) - { - foreach (bool l4 in parse2(ParseTokens, Answer)) - { - yield return false; - } - } - } - } - } - - public static IEnumerable remove_comments(object arg1, object arg2, object arg3) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg2, Atom.NIL)) - { - foreach (bool l4 in YP.unify(arg3, Atom.NIL)) - { - yield return false; - } - } - } - } - { - object Ys = arg2; - Variable S = new Variable(); - Variable E = new Variable(); - Variable Xs = new Variable(); - Variable Zs = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("comment", S, E), Xs))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("comment", S, E), Zs))) - { - foreach (bool l4 in remove_comments(Xs, Ys, Zs)) - { - yield return false; - } - yield break; - } - } - } - { - Variable Pos = new Variable(); - Variable Xs = new Variable(); - Variable Ys = new Variable(); - Variable Pos2 = new Variable(); - Variable Zs = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("/", Atom.a("["), Pos), Xs))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(Atom.a("["), Ys))) - { - foreach (bool l4 in YP.unify(arg3, new ListPair(new Functor2("list", Pos, Pos2), Zs))) - { - foreach (bool l5 in YP.unify(Pos2, YP.add(Pos, 1))) - { - foreach (bool l6 in remove_comments(Xs, Ys, Zs)) - { - yield return false; - } - } - yield break; - } - } - } - } - { - Variable Pos = new Variable(); - Variable Xs = new Variable(); - Variable Ys = new Variable(); - Variable Pos2 = new Variable(); - Variable Zs = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("/", Atom.a("]"), Pos), Xs))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(Atom.a("]"), Ys))) - { - foreach (bool l4 in YP.unify(arg3, new ListPair(new Functor2("list", Pos, Pos2), Zs))) - { - foreach (bool l5 in YP.unify(Pos2, YP.add(Pos, 1))) - { - foreach (bool l6 in remove_comments(Xs, Ys, Zs)) - { - yield return false; - } - } - yield break; - } - } - } - } - { - object Zs = arg3; - Variable Token = new Variable(); - Variable Xs = new Variable(); - Variable Ys = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Token, Xs))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(Token, Ys))) - { - foreach (bool l4 in remove_comments(Xs, Ys, Zs)) - { - yield return false; - } - } - } - } - } - - public static IEnumerable expect(object Token, object arg2, object arg3) - { - { - object Rest = arg3; - foreach (bool l2 in YP.unify(arg2, new ListPair(Token, Rest))) - { - yield return true; - yield break; - } - } - { - object S0 = arg2; - object x3 = arg3; - foreach (bool l2 in syntax_error(ListPair.make(new object[] { Token, Atom.a("or"), Atom.a("operator"), Atom.a("expected") }), S0)) - { - yield return false; - } - } - } - - public static IEnumerable parse2(object Tokens, object Answer) - { - { - Variable Term = new Variable(); - Variable LeftOver = new Variable(); - foreach (bool l2 in clear_errors()) - { - foreach (bool l3 in parse(Tokens, 1200, Term, LeftOver)) - { - foreach (bool l4 in all_read(LeftOver)) - { - foreach (bool l5 in YP.unify(Answer, Term)) - { - yield return false; - } - yield break; - } - } - foreach (bool l3 in syntax_error(Tokens)) - { - yield return false; - } - } - } - } - - public static IEnumerable all_read(object arg1) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - yield return false; - } - } - { - Variable Token = new Variable(); - Variable S = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Token, S))) - { - foreach (bool l3 in syntax_error(ListPair.make(new object[] { Atom.a("operator"), Atom.a("expected"), Atom.a("after"), Atom.a("expression") }), new ListPair(Token, S))) - { - yield return false; - } - } - } - } - - public static IEnumerable parse(object arg1, object arg2, object arg3, object arg4) - { - { - object x1 = arg2; - object x2 = arg3; - object x3 = arg4; - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in syntax_error(new ListPair(Atom.a("expression"), new ListPair(Atom.a("expected"), Atom.NIL)), Atom.NIL)) - { - yield return false; - } - } - } - { - object Precedence = arg2; - object Term = arg3; - object LeftOver = arg4; - Variable Token = new Variable(); - Variable RestTokens = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Token, RestTokens))) - { - foreach (bool l3 in parse5(Token, RestTokens, Precedence, Term, LeftOver)) - { - yield return false; - } - } - } - } - - public static IEnumerable parse5(object arg1, object arg2, object arg3, object arg4, object arg5) - { - { - object S0 = arg2; - object x2 = arg3; - object x3 = arg4; - object x4 = arg5; - foreach (bool l2 in YP.unify(arg1, Atom.a("}"))) - { - foreach (bool l3 in cannot_start(Atom.a("}"), S0)) - { - yield return false; - } - } - } - { - object S0 = arg2; - object x2 = arg3; - object x3 = arg4; - object x4 = arg5; - foreach (bool l2 in YP.unify(arg1, Atom.a("]"))) - { - foreach (bool l3 in cannot_start(Atom.a("]"), S0)) - { - yield return false; - } - } - } - { - object S0 = arg2; - object x2 = arg3; - object x3 = arg4; - object x4 = arg5; - foreach (bool l2 in YP.unify(arg1, Atom.a(")"))) - { - foreach (bool l3 in cannot_start(Atom.a(")"), S0)) - { - yield return false; - } - } - } - { - object S0 = arg2; - object x2 = arg3; - object x3 = arg4; - object x4 = arg5; - foreach (bool l2 in YP.unify(arg1, Atom.a(","))) - { - foreach (bool l3 in cannot_start(Atom.a(","), S0)) - { - yield return false; - } - } - } - { - object S0 = arg2; - object x2 = arg3; - object x3 = arg4; - object x4 = arg5; - foreach (bool l2 in YP.unify(arg1, Atom.a("|"))) - { - foreach (bool l3 in cannot_start(Atom.a("|"), S0)) - { - yield return false; - } - } - } - { - object S0 = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable Codes = new Variable(); - Variable Term = new Variable(); - Variable A = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("string", Codes))) - { - foreach (bool l3 in YP.current_prolog_flag(Atom.a("double_quotes"), Atom.a("atom"))) - { - foreach (bool l4 in YP.atom_codes(Term, Codes)) - { - foreach (bool l5 in exprtl0(S0, Term, Precedence, Answer, S)) - { - yield return false; - } - } - goto cutIf1; - } - foreach (bool l3 in YP.current_prolog_flag(Atom.a("double_quotes"), Atom.a("chars"))) - { - foreach (bool l4 in YP.atom_codes(A, Codes)) - { - foreach (bool l5 in YP.atom_chars(A, Term)) - { - foreach (bool l6 in exprtl0(S0, Term, Precedence, Answer, S)) - { - yield return false; - } - } - } - goto cutIf2; - } - foreach (bool l3 in YP.unify(Term, Codes)) - { - foreach (bool l4 in exprtl0(S0, Term, Precedence, Answer, S)) - { - yield return false; - } - } - cutIf2: - cutIf1: - { } - } - } - { - object S0 = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable Number = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("number", Number))) - { - foreach (bool l3 in exprtl0(S0, Number, Precedence, Answer, S)) - { - yield return false; - } - } - } - { - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable S1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a("["))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(Atom.a("]"), S1))) - { - foreach (bool l4 in read_atom(new Functor2("/", Atom.NIL, 0), S1, Precedence, Answer, S)) - { - yield return false; - } - yield break; - } - } - } - { - object S1 = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable Arg1 = new Variable(); - Variable S2 = new Variable(); - Variable RestArgs = new Variable(); - Variable S3 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a("["))) - { - foreach (bool l3 in parse(S1, 999, Arg1, S2)) - { - foreach (bool l4 in read_list(S2, RestArgs, S3)) - { - foreach (bool l5 in exprtl0(S3, new ListPair(Arg1, RestArgs), Precedence, Answer, S)) - { - yield return false; - } - yield break; - } - } - } - } - { - object S1 = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable Term = new Variable(); - Variable S2 = new Variable(); - Variable S3 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a("("))) - { - foreach (bool l3 in parse(S1, 1200, Term, S2)) - { - foreach (bool l4 in expect(Atom.a(")"), S2, S3)) - { - foreach (bool l5 in exprtl0(S3, Term, Precedence, Answer, S)) - { - yield return false; - } - yield break; - } - } - } - } - { - object S1 = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable Term = new Variable(); - Variable S2 = new Variable(); - Variable S3 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a(" ("))) - { - foreach (bool l3 in parse(S1, 1200, Term, S2)) - { - foreach (bool l4 in expect(Atom.a(")"), S2, S3)) - { - foreach (bool l5 in exprtl0(S3, Term, Precedence, Answer, S)) - { - yield return false; - } - yield break; - } - } - } - } - { - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable _Pos = new Variable(); - Variable S1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("/", Atom.a("{"), _Pos))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(Atom.a("}"), S1))) - { - foreach (bool l4 in read_atom(Atom.a("{}"), S1, Precedence, Answer, S)) - { - yield return false; - } - yield break; - } - } - } - { - object S1 = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable Pos = new Variable(); - Variable Term = new Variable(); - Variable S2 = new Variable(); - Variable S3 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("/", Atom.a("{"), Pos))) - { - foreach (bool l3 in parse(S1, 1200, Term, S2)) - { - foreach (bool l4 in expect(Atom.a("}"), S2, S3)) - { - foreach (bool l5 in exprtl0(S3, new Functor2("{}", Pos, Term), Precedence, Answer, S)) - { - yield return false; - } - yield break; - } - } - } - } - { - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable Variable_1 = new Variable(); - Variable Name = new Variable(); - Variable Pos = new Variable(); - Variable S1 = new Variable(); - Variable Arg1 = new Variable(); - Variable S2 = new Variable(); - Variable RestArgs = new Variable(); - Variable S3 = new Variable(); - Variable Term = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor3("var", Variable_1, Name, Pos))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(Atom.a("("), S1))) - { - foreach (bool l4 in parse(S1, 999, Arg1, S2)) - { - foreach (bool l5 in read_args(S2, RestArgs, S3)) - { - foreach (bool l6 in YP.univ(Term, new ListPair(Atom.a("call"), new ListPair(new Functor3("$VAR", Pos, Name, Variable_1), new ListPair(Arg1, RestArgs))))) - { - foreach (bool l7 in exprtl0(S3, Term, Precedence, Answer, S)) - { - yield return false; - } - } - yield break; - } - } - yield break; - } - } - } - { - object S0 = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable Variable_1 = new Variable(); - Variable Name = new Variable(); - Variable Pos = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor3("var", Variable_1, Name, Pos))) - { - foreach (bool l3 in exprtl0(S0, new Functor3("$VAR", Pos, Name, Variable_1), Precedence, Answer, S)) - { - yield return false; - } - } - } - { - object S0 = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable Atom_1 = new Variable(); - Variable P = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("atom", Atom_1, P))) - { - foreach (bool l3 in read_atom(new Functor2("/", Atom_1, P), S0, Precedence, Answer, S)) - { - yield return false; - } - } - } - } - - public static IEnumerable read_atom(object arg1, object arg2, object Precedence, object Answer, object S) - { - { - Variable _Pos = new Variable(); - Variable Number = new Variable(); - Variable S1 = new Variable(); - Variable Negative = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("/", Atom.a("-"), _Pos))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(new Functor1("number", Number), S1))) - { - foreach (bool l4 in YP.unify(Negative, YP.negate(Number))) - { - foreach (bool l5 in exprtl0(S1, Negative, Precedence, Answer, S)) - { - yield return false; - } - } - yield break; - } - } - } - { - Variable Functor_1 = new Variable(); - Variable Pos = new Variable(); - Variable S1 = new Variable(); - Variable Arg1 = new Variable(); - Variable S2 = new Variable(); - Variable RestArgs = new Variable(); - Variable S3 = new Variable(); - Variable Term = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("/", Functor_1, Pos))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(Atom.a("("), S1))) - { - foreach (bool l4 in parse(S1, 999, Arg1, S2)) - { - foreach (bool l5 in read_args(S2, RestArgs, S3)) - { - foreach (bool l6 in YP.univ(Term, new ListPair(Functor_1, new ListPair(Pos, new ListPair(Arg1, RestArgs))))) - { - foreach (bool l7 in exprtl0(S3, Term, Precedence, Answer, S)) - { - yield return false; - } - } - yield break; - } - } - yield break; - } - } - } - { - object S0 = arg2; - Variable Op = new Variable(); - Variable Pos = new Variable(); - Variable Oprec = new Variable(); - Variable Aprec = new Variable(); - Variable Flag = new Variable(); - Variable Term = new Variable(); - Variable Arg = new Variable(); - Variable S1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("/", Op, Pos))) - { - foreach (bool l3 in prefixop(Op, Oprec, Aprec)) - { - foreach (bool l4 in possible_right_operand(S0, Flag)) - { - if (YP.lessThan(Flag, 0)) - { - foreach (bool l6 in YP.univ(Term, new ListPair(Op, new ListPair(Pos, Atom.NIL)))) - { - foreach (bool l7 in exprtl0(S0, Term, Precedence, Answer, S)) - { - yield return false; - } - } - goto cutIf1; - } - if (YP.greaterThan(Oprec, Precedence)) - { - foreach (bool l6 in syntax_error(ListPair.make(new object[] { Atom.a("prefix"), Atom.a("operator"), Op, Atom.a("in"), Atom.a("context"), Atom.a("with"), Atom.a("precedence"), Precedence }), S0)) - { - yield return false; - } - goto cutIf2; - } - if (YP.greaterThan(Flag, 0)) - { - foreach (bool l6 in parse(S0, Aprec, Arg, S1)) - { - foreach (bool l7 in YP.univ(Term, ListPair.make(new object[] { Op, Pos, Arg }))) - { - foreach (bool l8 in exprtl(S1, Oprec, Term, Precedence, Answer, S)) - { - yield return false; - } - } - yield break; - } - goto cutIf3; - } - foreach (bool l5 in peepop(S0, S1)) - { - foreach (bool l6 in prefix_is_atom(S1, Oprec)) - { - foreach (bool l7 in exprtl(S1, Oprec, new Functor2("/", Op, Pos), Precedence, Answer, S)) - { - yield return false; - } - } - } - foreach (bool l5 in parse(S0, Aprec, Arg, S1)) - { - foreach (bool l6 in YP.univ(Term, ListPair.make(new object[] { Op, Pos, Arg }))) - { - foreach (bool l7 in exprtl(S1, Oprec, Term, Precedence, Answer, S)) - { - yield return false; - } - } - yield break; - } - cutIf3: - cutIf2: - cutIf1: - { } - } - yield break; - } - } - } - { - object S0 = arg2; - Variable Atom_1 = new Variable(); - Variable Pos = new Variable(); - Variable Term = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("/", Atom_1, Pos))) - { - foreach (bool l3 in YP.univ(Term, new ListPair(Atom_1, new ListPair(Pos, Atom.NIL)))) - { - foreach (bool l4 in exprtl0(S0, Term, Precedence, Answer, S)) - { - yield return false; - } - } - } - } - } - - public static IEnumerable cannot_start(object Token, object S0) - { - { - foreach (bool l2 in syntax_error(ListPair.make(new object[] { Token, Atom.a("cannot"), Atom.a("start"), Atom.a("an"), Atom.a("expression") }), S0)) - { - yield return false; - } - } - } - - public static IEnumerable read_args(object arg1, object arg2, object arg3) - { - { - object S = arg3; - Variable S1 = new Variable(); - Variable Term = new Variable(); - Variable Rest = new Variable(); - Variable S2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a(","), S1))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(Term, Rest))) - { - foreach (bool l4 in parse(S1, 999, Term, S2)) - { - foreach (bool l5 in read_args(S2, Rest, S)) - { - yield return false; - } - yield break; - } - yield break; - } - } - } - { - object S = arg3; - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a(")"), S))) - { - foreach (bool l3 in YP.unify(arg2, Atom.NIL)) - { - yield return true; - yield break; - } - } - } - { - object S = arg1; - object x2 = arg2; - object x3 = arg3; - foreach (bool l2 in syntax_error(ListPair.make(new object[] { Atom.a(", or )"), Atom.a("expected"), Atom.a("in"), Atom.a("arguments") }), S)) - { - yield return false; - } - } - } - - public static IEnumerable read_list(object arg1, object arg2, object arg3) - { - { - object x1 = arg2; - object x2 = arg3; - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in syntax_error(ListPair.make(new object[] { Atom.a(", | or ]"), Atom.a("expected"), Atom.a("in"), Atom.a("list") }), Atom.NIL)) - { - yield return false; - } - } - } - { - object Rest = arg2; - object S = arg3; - Variable Token = new Variable(); - Variable S1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Token, S1))) - { - foreach (bool l3 in read_list4(Token, S1, Rest, S)) - { - yield return false; - } - } - } - } - - public static IEnumerable read_list4(object arg1, object arg2, object arg3, object arg4) - { - { - object S1 = arg2; - object S = arg4; - Variable Term = new Variable(); - Variable Rest = new Variable(); - Variable S2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a(","))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(Term, Rest))) - { - foreach (bool l4 in parse(S1, 999, Term, S2)) - { - foreach (bool l5 in read_list(S2, Rest, S)) - { - yield return false; - } - yield break; - } - yield break; - } - } - } - { - object S1 = arg2; - object Rest = arg3; - object S = arg4; - Variable S2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a("|"))) - { - foreach (bool l3 in parse(S1, 999, Rest, S2)) - { - foreach (bool l4 in expect(Atom.a("]"), S2, S)) - { - yield return false; - } - yield break; - } - yield break; - } - } - { - Variable S1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a("]"))) - { - foreach (bool l3 in YP.unify(arg2, S1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.NIL)) - { - foreach (bool l5 in YP.unify(arg4, S1)) - { - yield return true; - yield break; - } - } - } - } - } - { - object Token = arg1; - object S1 = arg2; - object x3 = arg3; - object x4 = arg4; - foreach (bool l2 in syntax_error(ListPair.make(new object[] { Atom.a(", | or ]"), Atom.a("expected"), Atom.a("in"), Atom.a("list") }), new ListPair(Token, S1))) - { - yield return false; - } - } - } - - public static IEnumerable possible_right_operand(object arg1, object arg2) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg2, -1)) - { - yield return false; - } - } - } - { - object Flag = arg2; - Variable H = new Variable(); - Variable T = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(H, T))) - { - foreach (bool l3 in possible_right_operand3(H, Flag, T)) - { - yield return false; - } - } - } - } - - public static IEnumerable possible_right_operand3(object arg1, object arg2, object arg3) - { - { - object x4 = arg3; - Variable x1 = new Variable(); - Variable x2 = new Variable(); - Variable x3 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor3("var", x1, x2, x3))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - yield return false; - } - } - } - { - object x2 = arg3; - Variable x1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("number", x1))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - yield return false; - } - } - } - { - object x2 = arg3; - Variable x1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("string", x1))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - yield return false; - } - } - } - { - object x1 = arg3; - foreach (bool l2 in YP.unify(arg1, Atom.a(" ("))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - yield return false; - } - } - } - { - object x1 = arg3; - foreach (bool l2 in YP.unify(arg1, Atom.a("("))) - { - foreach (bool l3 in YP.unify(arg2, 0)) - { - yield return false; - } - } - } - { - object x1 = arg3; - foreach (bool l2 in YP.unify(arg1, Atom.a(")"))) - { - foreach (bool l3 in YP.unify(arg2, -1)) - { - yield return false; - } - } - } - { - Variable x1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a("["))) - { - foreach (bool l3 in YP.unify(arg2, 0)) - { - foreach (bool l4 in YP.unify(arg3, new ListPair(Atom.a("]"), x1))) - { - yield return true; - yield break; - } - } - } - } - { - object x1 = arg3; - foreach (bool l2 in YP.unify(arg1, Atom.a("["))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - yield return false; - } - } - } - { - object x1 = arg3; - foreach (bool l2 in YP.unify(arg1, Atom.a("]"))) - { - foreach (bool l3 in YP.unify(arg2, -1)) - { - yield return false; - } - } - } - { - Variable x1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a("{"))) - { - foreach (bool l3 in YP.unify(arg2, 0)) - { - foreach (bool l4 in YP.unify(arg3, new ListPair(Atom.a("}"), x1))) - { - yield return true; - yield break; - } - } - } - } - { - object x1 = arg3; - foreach (bool l2 in YP.unify(arg1, Atom.a("{"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - yield return false; - } - } - } - { - object x1 = arg3; - foreach (bool l2 in YP.unify(arg1, Atom.a("}"))) - { - foreach (bool l3 in YP.unify(arg2, -1)) - { - yield return false; - } - } - } - { - object x1 = arg3; - foreach (bool l2 in YP.unify(arg1, Atom.a(","))) - { - foreach (bool l3 in YP.unify(arg2, -1)) - { - yield return false; - } - } - } - { - object x1 = arg3; - foreach (bool l2 in YP.unify(arg1, Atom.a("|"))) - { - foreach (bool l3 in YP.unify(arg2, -1)) - { - yield return false; - } - } - } - { - object x3 = arg3; - Variable x1 = new Variable(); - Variable x2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("atom", x1, x2))) - { - foreach (bool l3 in YP.unify(arg2, 0)) - { - yield return false; - } - } - } - } - - public static IEnumerable peepop(object arg1, object arg2) - { - { - Variable F = new Variable(); - Variable Pos = new Variable(); - Variable S1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("atom", F, Pos), new ListPair(Atom.a("("), S1)))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(new Functor2("atom", F, Pos), new ListPair(Atom.a("("), S1)))) - { - yield return true; - yield break; - } - } - } - { - Variable F = new Variable(); - Variable Pos = new Variable(); - Variable S1 = new Variable(); - Variable L = new Variable(); - Variable P = new Variable(); - Variable R = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("atom", F, Pos), S1))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(new Functor(Atom.a("infixop", Atom.a("")), new object[] { new Functor2("/", F, Pos), L, P, R }), S1))) - { - foreach (bool l4 in infixop(F, L, P, R)) - { - yield return false; - } - } - } - } - { - Variable F = new Variable(); - Variable Pos = new Variable(); - Variable S1 = new Variable(); - Variable L = new Variable(); - Variable P = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("atom", F, Pos), S1))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(new Functor3(Atom.a("postfixop", Atom.a("")), new Functor2("/", F, Pos), L, P), S1))) - { - foreach (bool l4 in postfixop(F, L, P)) - { - yield return false; - } - } - } - } - { - Variable S0 = new Variable(); - foreach (bool l2 in YP.unify(arg1, S0)) - { - foreach (bool l3 in YP.unify(arg2, S0)) - { - yield return false; - } - } - } - } - - public static IEnumerable prefix_is_atom(object arg1, object arg2) - { - { - object Precedence = arg2; - Variable Token = new Variable(); - Variable x2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Token, x2))) - { - foreach (bool l3 in prefix_is_atom(Token, Precedence)) - { - yield return false; - } - } - } - { - object P = arg2; - Variable x1 = new Variable(); - Variable L = new Variable(); - Variable x3 = new Variable(); - Variable x4 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor(Atom.a("infixop", Atom.a("")), new object[] { x1, L, x3, x4 }))) - { - if (YP.greaterThanOrEqual(L, P)) - { - yield return false; - } - } - } - { - object P = arg2; - Variable x1 = new Variable(); - Variable L = new Variable(); - Variable x3 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor3(Atom.a("postfixop", Atom.a("")), x1, L, x3))) - { - if (YP.greaterThanOrEqual(L, P)) - { - yield return false; - } - } - } - { - object x1 = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.a(")"))) - { - yield return false; - } - } - { - object x1 = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.a("]"))) - { - yield return false; - } - } - { - object x1 = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.a("}"))) - { - yield return false; - } - } - { - object P = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.a("|"))) - { - if (YP.greaterThanOrEqual(1100, P)) - { - yield return false; - } - } - } - { - object P = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.a(","))) - { - if (YP.greaterThanOrEqual(1000, P)) - { - yield return false; - } - } - } - { - object x1 = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - yield return false; - } - } - } - - public static IEnumerable exprtl0(object arg1, object arg2, object arg3, object arg4, object arg5) - { - { - object x2 = arg3; - Variable Term = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg2, Term)) - { - foreach (bool l4 in YP.unify(arg4, Term)) - { - foreach (bool l5 in YP.unify(arg5, Atom.NIL)) - { - yield return false; - } - } - } - } - } - { - object Term = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable Token = new Variable(); - Variable S1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Token, S1))) - { - foreach (bool l3 in exprtl0_6(Token, Term, Precedence, Answer, S, S1)) - { - yield return false; - } - } - } - } - - public static IEnumerable exprtl0_6(object arg1, object arg2, object arg3, object arg4, object arg5, object arg6) - { - { - object x2 = arg3; - object S1 = arg6; - Variable Term = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a("}"))) - { - foreach (bool l3 in YP.unify(arg2, Term)) - { - foreach (bool l4 in YP.unify(arg4, Term)) - { - foreach (bool l5 in YP.unify(arg5, new ListPair(Atom.a("}"), S1))) - { - yield return false; - } - } - } - } - } - { - object x2 = arg3; - object S1 = arg6; - Variable Term = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a("]"))) - { - foreach (bool l3 in YP.unify(arg2, Term)) - { - foreach (bool l4 in YP.unify(arg4, Term)) - { - foreach (bool l5 in YP.unify(arg5, new ListPair(Atom.a("]"), S1))) - { - yield return false; - } - } - } - } - } - { - object x2 = arg3; - object S1 = arg6; - Variable Term = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a(")"))) - { - foreach (bool l3 in YP.unify(arg2, Term)) - { - foreach (bool l4 in YP.unify(arg4, Term)) - { - foreach (bool l5 in YP.unify(arg5, new ListPair(Atom.a(")"), S1))) - { - yield return false; - } - } - } - } - } - { - object Term = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - object S1 = arg6; - Variable Next = new Variable(); - Variable S2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a(","))) - { - if (YP.greaterThanOrEqual(Precedence, 1000)) - { - foreach (bool l4 in parse(S1, 1000, Next, S2)) - { - foreach (bool l5 in exprtl(S2, 1000, new Functor2(",", Term, Next), Precedence, Answer, S)) - { - yield return false; - } - yield break; - } - goto cutIf1; - } - foreach (bool l3 in YP.unify(Answer, Term)) - { - foreach (bool l4 in YP.unify(S, new ListPair(Atom.a(","), S1))) - { - yield return false; - } - } - cutIf1: - { } - } - } - { - object Term = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - object S1 = arg6; - Variable Next = new Variable(); - Variable S2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a("|"))) - { - if (YP.greaterThanOrEqual(Precedence, 1100)) - { - foreach (bool l4 in parse(S1, 1100, Next, S2)) - { - foreach (bool l5 in exprtl(S2, 1100, new Functor2(";", Term, Next), Precedence, Answer, S)) - { - yield return false; - } - yield break; - } - goto cutIf2; - } - foreach (bool l3 in YP.unify(Answer, Term)) - { - foreach (bool l4 in YP.unify(S, new ListPair(Atom.a("|"), S1))) - { - yield return false; - } - } - cutIf2: - { } - } - } - { - object x2 = arg2; - object x3 = arg3; - object x4 = arg4; - object x5 = arg5; - object S1 = arg6; - Variable S = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("string", S))) - { - foreach (bool l3 in cannot_follow(Atom.a("chars"), new Functor1("string", S), S1)) - { - yield return false; - } - } - } - { - object x2 = arg2; - object x3 = arg3; - object x4 = arg4; - object x5 = arg5; - object S1 = arg6; - Variable N = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("number", N))) - { - foreach (bool l3 in cannot_follow(Atom.a("number"), new Functor1("number", N), S1)) - { - yield return false; - } - } - } - { - object Term = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable S1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a("{"))) - { - foreach (bool l3 in YP.unify(arg6, new ListPair(Atom.a("}"), S1))) - { - foreach (bool l4 in exprtl0_atom(Atom.a("{}"), Term, Precedence, Answer, S, S1)) - { - yield return false; - } - yield break; - } - } - } - { - object x1 = arg2; - object x2 = arg3; - object x3 = arg4; - object x4 = arg5; - object S1 = arg6; - foreach (bool l2 in YP.unify(arg1, Atom.a("{"))) - { - foreach (bool l3 in cannot_follow(Atom.a("brace"), Atom.a("{"), S1)) - { - yield return false; - } - } - } - { - object Term = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable S1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a("["))) - { - foreach (bool l3 in YP.unify(arg6, new ListPair(Atom.a("]"), S1))) - { - foreach (bool l4 in exprtl0_atom(Atom.NIL, Term, Precedence, Answer, S, S1)) - { - yield return false; - } - yield break; - } - } - } - { - object x1 = arg2; - object x2 = arg3; - object x3 = arg4; - object x4 = arg5; - object S1 = arg6; - foreach (bool l2 in YP.unify(arg1, Atom.a("["))) - { - foreach (bool l3 in cannot_follow(Atom.a("bracket"), Atom.a("["), S1)) - { - yield return false; - } - } - } - { - object x1 = arg2; - object x2 = arg3; - object x3 = arg4; - object x4 = arg5; - object S1 = arg6; - foreach (bool l2 in YP.unify(arg1, Atom.a("("))) - { - foreach (bool l3 in cannot_follow(Atom.a("parenthesis"), Atom.a("("), S1)) - { - yield return false; - } - } - } - { - object x1 = arg2; - object x2 = arg3; - object x3 = arg4; - object x4 = arg5; - object S1 = arg6; - foreach (bool l2 in YP.unify(arg1, Atom.a(" ("))) - { - foreach (bool l3 in cannot_follow(Atom.a("parenthesis"), Atom.a("("), S1)) - { - yield return false; - } - } - } - { - object x4 = arg2; - object x5 = arg3; - object x6 = arg4; - object x7 = arg5; - object S1 = arg6; - Variable A = new Variable(); - Variable B = new Variable(); - Variable P = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor3("var", A, B, P))) - { - foreach (bool l3 in cannot_follow(Atom.a("variable"), new Functor3("var", A, B, P), S1)) - { - yield return false; - } - } - } - { - object Term = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - object S1 = arg6; - Variable F = new Variable(); - Variable P = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("atom", F, P))) - { - foreach (bool l3 in exprtl0_atom(new Functor2("/", F, P), Term, Precedence, Answer, S, S1)) - { - yield return false; - } - } - } - } - - public static IEnumerable exprtl0_atom(object arg1, object arg2, object arg3, object arg4, object arg5, object S1) - { - { - object Term = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable F = new Variable(); - Variable Pos = new Variable(); - Variable L1 = new Variable(); - Variable O1 = new Variable(); - Variable R1 = new Variable(); - Variable L2 = new Variable(); - Variable O2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("/", F, Pos))) - { - foreach (bool l3 in ambigop(F, Precedence, L1, O1, R1, L2, O2)) - { - foreach (bool l4 in prefix_is_atom(S1, Precedence)) - { - foreach (bool l5 in exprtl(new ListPair(new Functor3(Atom.a("postfixop", Atom.a("")), new Functor2("/", F, Pos), L2, O2), S1), 0, Term, Precedence, Answer, S)) - { - yield return false; - } - yield break; - } - foreach (bool l4 in exprtl(new ListPair(new Functor(Atom.a("infixop", Atom.a("")), new object[] { new Functor2("/", F, Pos), L1, O1, R1 }), S1), 0, Term, Precedence, Answer, S)) - { - yield return false; - } - foreach (bool l4 in exprtl(new ListPair(new Functor3(Atom.a("postfixop", Atom.a("")), new Functor2("/", F, Pos), L2, O2), S1), 0, Term, Precedence, Answer, S)) - { - yield return false; - } - yield break; - } - } - } - { - object Term = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable F = new Variable(); - Variable Pos = new Variable(); - Variable L1 = new Variable(); - Variable O1 = new Variable(); - Variable R1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("/", F, Pos))) - { - foreach (bool l3 in infixop(F, L1, O1, R1)) - { - foreach (bool l4 in exprtl(new ListPair(new Functor(Atom.a("infixop", Atom.a("")), new object[] { new Functor2("/", F, Pos), L1, O1, R1 }), S1), 0, Term, Precedence, Answer, S)) - { - yield return false; - } - yield break; - } - } - } - { - object Term = arg2; - object Precedence = arg3; - object Answer = arg4; - object S = arg5; - Variable F = new Variable(); - Variable Pos = new Variable(); - Variable L2 = new Variable(); - Variable O2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("/", F, Pos))) - { - foreach (bool l3 in postfixop(F, L2, O2)) - { - foreach (bool l4 in exprtl(new ListPair(new Functor3(Atom.a("postfixop", Atom.a("")), new Functor2("/", F, Pos), L2, O2), S1), 0, Term, Precedence, Answer, S)) - { - yield return false; - } - yield break; - } - } - } - { - object X = arg1; - object x2 = arg2; - object x3 = arg3; - object x4 = arg4; - object x5 = arg5; - Variable x7 = new Variable(); - foreach (bool l2 in syntax_error(ListPair.make(new object[] { new Functor2("-", Atom.a("non"), Atom.a("operator")), X, Atom.a("follows"), Atom.a("expression") }), new ListPair(new Functor2("atom", X, x7), S1))) - { - yield return false; - } - yield break; - } - } - - public static IEnumerable cannot_follow(object Type, object Token, object Tokens) - { - { - foreach (bool l2 in syntax_error(ListPair.make(new object[] { Type, Atom.a("follows"), Atom.a("expression") }), new ListPair(Token, Tokens))) - { - yield return false; - } - } - } - - public static IEnumerable exprtl(object arg1, object arg2, object arg3, object arg4, object arg5, object arg6) - { - { - object x1 = arg2; - object x3 = arg4; - Variable Term = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg3, Term)) - { - foreach (bool l4 in YP.unify(arg5, Term)) - { - foreach (bool l5 in YP.unify(arg6, Atom.NIL)) - { - yield return false; - } - } - } - } - } - { - object C = arg2; - object Term = arg3; - object Precedence = arg4; - object Answer = arg5; - object S = arg6; - Variable Token = new Variable(); - Variable Tokens = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Token, Tokens))) - { - foreach (bool l3 in exprtl_7(Token, C, Term, Precedence, Answer, S, Tokens)) - { - yield return false; - } - } - } - } - - public static IEnumerable exprtl_7(object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7) - { - { - object C = arg2; - object Term = arg3; - object Precedence = arg4; - object Answer = arg5; - object S = arg6; - object S1 = arg7; - Variable F = new Variable(); - Variable Pos = new Variable(); - Variable L = new Variable(); - Variable O = new Variable(); - Variable R = new Variable(); - Variable Other = new Variable(); - Variable S2 = new Variable(); - Variable Expr = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor(Atom.a("infixop", Atom.a("")), new object[] { new Functor2("/", F, Pos), L, O, R }))) - { - if (YP.greaterThanOrEqual(Precedence, O)) - { - if (YP.lessThanOrEqual(C, L)) - { - foreach (bool l5 in parse(S1, R, Other, S2)) - { - foreach (bool l6 in YP.univ(Expr, ListPair.make(new object[] { F, Pos, Term, Other }))) - { - foreach (bool l7 in exprtl(S2, O, Expr, Precedence, Answer, S)) - { - yield return false; - } - } - } - yield break; - } - } - } - } - { - object C = arg2; - object Term = arg3; - object Precedence = arg4; - object Answer = arg5; - object S = arg6; - object S1 = arg7; - Variable F = new Variable(); - Variable Pos = new Variable(); - Variable L = new Variable(); - Variable O = new Variable(); - Variable Expr = new Variable(); - Variable S2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor3(Atom.a("postfixop", Atom.a("")), new Functor2("/", F, Pos), L, O))) - { - if (YP.greaterThanOrEqual(Precedence, O)) - { - if (YP.lessThanOrEqual(C, L)) - { - foreach (bool l5 in YP.univ(Expr, ListPair.make(new object[] { F, Pos, Term }))) - { - foreach (bool l6 in peepop(S1, S2)) - { - foreach (bool l7 in exprtl(S2, O, Expr, Precedence, Answer, S)) - { - yield return false; - } - } - } - yield break; - } - } - } - } - { - object C = arg2; - object Term = arg3; - object Precedence = arg4; - object Answer = arg5; - object S = arg6; - object S1 = arg7; - Variable Next = new Variable(); - Variable S2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a(","))) - { - if (YP.greaterThanOrEqual(Precedence, 1000)) - { - if (YP.lessThan(C, 1000)) - { - foreach (bool l5 in parse(S1, 1000, Next, S2)) - { - foreach (bool l6 in exprtl(S2, 1000, new Functor2(",", Term, Next), Precedence, Answer, S)) - { - yield return false; - } - } - yield break; - } - } - } - } - { - object C = arg2; - object Term = arg3; - object Precedence = arg4; - object Answer = arg5; - object S = arg6; - object S1 = arg7; - Variable Next = new Variable(); - Variable S2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.a("|"))) - { - if (YP.greaterThanOrEqual(Precedence, 1100)) - { - if (YP.lessThan(C, 1100)) - { - foreach (bool l5 in parse(S1, 1100, Next, S2)) - { - foreach (bool l6 in exprtl(S2, 1100, new Functor2(";", Term, Next), Precedence, Answer, S)) - { - yield return false; - } - } - yield break; - } - } - } - } - { - object Token = arg1; - object x2 = arg2; - object x4 = arg4; - object Tokens = arg7; - Variable Term = new Variable(); - foreach (bool l2 in YP.unify(arg3, Term)) - { - foreach (bool l3 in YP.unify(arg5, Term)) - { - foreach (bool l4 in YP.unify(arg6, new ListPair(Token, Tokens))) - { - yield return false; - } - } - } - } - } - - public static IEnumerable syntax_error(object _Message, object _List) - { - { - yield break; - } - foreach (bool l1 in YP.fail()) - { - yield return false; - } - } - - public static IEnumerable syntax_error(object _List) - { - { - yield break; - } - foreach (bool l1 in YP.fail()) - { - yield return false; - } - } - - public static IEnumerable prefixop(object F, object O, object Q) - { - { - foreach (bool l2 in YP.current_op(O, Atom.a("fx"), F)) - { - foreach (bool l3 in YP.unify(Q, YP.subtract(O, 1))) - { - yield return false; - } - goto cutIf1; - } - foreach (bool l2 in YP.current_op(O, Atom.a("fy"), F)) - { - foreach (bool l3 in YP.unify(Q, O)) - { - yield return false; - } - goto cutIf2; - } - cutIf2: - cutIf1: - { } - } - } - - public static IEnumerable postfixop(object F, object P, object O) - { - { - foreach (bool l2 in YP.current_op(O, Atom.a("xf"), F)) - { - foreach (bool l3 in YP.unify(P, YP.subtract(O, 1))) - { - yield return false; - } - goto cutIf1; - } - foreach (bool l2 in YP.current_op(O, Atom.a("yf"), F)) - { - foreach (bool l3 in YP.unify(P, O)) - { - yield return false; - } - goto cutIf2; - } - cutIf2: - cutIf1: - { } - } - } - - public static IEnumerable infixop(object F, object P, object O, object Q) - { - { - foreach (bool l2 in YP.current_op(O, Atom.a("xfy"), F)) - { - foreach (bool l3 in YP.unify(P, YP.subtract(O, 1))) - { - foreach (bool l4 in YP.unify(Q, O)) - { - yield return false; - } - } - goto cutIf1; - } - foreach (bool l2 in YP.current_op(O, Atom.a("xfx"), F)) - { - foreach (bool l3 in YP.unify(P, YP.subtract(O, 1))) - { - foreach (bool l4 in YP.unify(Q, P)) - { - yield return false; - } - } - goto cutIf2; - } - foreach (bool l2 in YP.current_op(O, Atom.a("yfx"), F)) - { - foreach (bool l3 in YP.unify(Q, YP.subtract(O, 1))) - { - foreach (bool l4 in YP.unify(P, O)) - { - yield return false; - } - } - goto cutIf3; - } - cutIf3: - cutIf2: - cutIf1: - { } - } - } - - public static IEnumerable ambigop(object F, object Precedence, object L1, object O1, object R1, object L2, object O2) - { - { - foreach (bool l2 in postfixop(F, L2, O2)) - { - if (YP.lessThanOrEqual(O2, Precedence)) - { - foreach (bool l4 in infixop(F, L1, O1, R1)) - { - if (YP.lessThanOrEqual(O1, Precedence)) - { - yield return false; - } - } - } - } - } - } - - public static IEnumerable read_tokens1(object arg1) - { - { - object TokenList = arg1; - Variable C1 = new Variable(); - Variable _X = new Variable(); - Variable ListOfTokens = new Variable(); - foreach (bool l2 in YP.get_code(C1)) - { - foreach (bool l3 in read_tokens(C1, _X, ListOfTokens)) - { - foreach (bool l4 in YP.unify(TokenList, ListOfTokens)) - { - yield return false; - } - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("atom", Atom.a("end_of_file"), 0), Atom.NIL))) - { - yield return false; - } - } - } - - public static IEnumerable read_tokens2(object arg1, object arg2) - { - { - object TokenList = arg1; - object Dictionary = arg2; - Variable C1 = new Variable(); - Variable Dict = new Variable(); - Variable ListOfTokens = new Variable(); - foreach (bool l2 in YP.get_code(C1)) - { - foreach (bool l3 in read_tokens(C1, Dict, ListOfTokens)) - { - foreach (bool l4 in terminate_list(Dict)) - { - foreach (bool l5 in YP.unify(Dictionary, Dict)) - { - foreach (bool l6 in YP.unify(TokenList, ListOfTokens)) - { - yield return false; - } - } - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("atom", Atom.a("end_of_file"), 0), Atom.NIL))) - { - foreach (bool l3 in YP.unify(arg2, Atom.NIL)) - { - yield return false; - } - } - } - } - - public static IEnumerable terminate_list(object arg1) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - yield return false; - } - } - { - Variable x1 = new Variable(); - Variable Tail = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(x1, Tail))) - { - foreach (bool l3 in terminate_list(Tail)) - { - yield return false; - } - } - } - } - - public static IEnumerable read_special(object arg1, object Dict, object arg3) - { - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 95)) - { - foreach (bool l3 in read_variable(95, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 247)) - { - foreach (bool l3 in read_symbol(247, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 215)) - { - foreach (bool l3 in read_symbol(215, Dict, Tokens)) - { - yield return false; - } - } - } - { - Variable StartPos = new Variable(); - Variable EndPos = new Variable(); - Variable Tokens = new Variable(); - Variable Ch = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 37)) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("comment", StartPos, EndPos), Tokens))) - { - foreach (bool l4 in get_current_position(StartPos)) - { - foreach (bool l5 in YP.repeat()) - { - foreach (bool l6 in YP.get_code(Ch)) - { - if (YP.lessThan(Ch, new ListPair(32, Atom.NIL))) - { - if (YP.notEqual(Ch, 9)) - { - if (YP.termNotEqual(Ch, -1)) - { - foreach (bool l10 in get_current_position(EndPos)) - { - foreach (bool l11 in YP.get_code(NextCh)) - { - foreach (bool l12 in read_tokens(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - yield break; - } - } - } - } - } - } - } - } - { - object T = arg3; - Variable C2 = new Variable(); - Variable StartPos = new Variable(); - Variable EndPos = new Variable(); - Variable Tokens = new Variable(); - Variable StartPos1 = new Variable(); - Variable NextCh = new Variable(); - Variable Chars = new Variable(); - foreach (bool l2 in YP.unify(arg1, 47)) - { - foreach (bool l3 in YP.get_code(C2)) - { - if (YP.equal(C2, new ListPair(42, Atom.NIL))) - { - foreach (bool l5 in YP.unify(T, new ListPair(new Functor2("comment", StartPos, EndPos), Tokens))) - { - foreach (bool l6 in get_current_position(StartPos1)) - { - foreach (bool l7 in YP.unify(StartPos, YP.subtract(StartPos1, 1))) - { - foreach (bool l8 in read_solidus(32, NextCh)) - { - foreach (bool l9 in get_current_position(EndPos)) - { - foreach (bool l10 in read_tokens(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - } - goto cutIf1; - } - foreach (bool l4 in YP.unify(T, Tokens)) - { - foreach (bool l5 in rest_symbol(C2, Chars, NextCh)) - { - foreach (bool l6 in read_after_atom4(NextCh, Dict, Tokens, new ListPair(47, Chars))) - { - yield return false; - } - } - } - cutIf1: - { } - } - } - } - { - Variable Pos = new Variable(); - Variable Tokens = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 33)) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("atom", Atom.a("!"), Pos), Tokens))) - { - foreach (bool l4 in get_current_position(Pos)) - { - foreach (bool l5 in YP.get_code(NextCh)) - { - foreach (bool l6 in read_after_atom(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - } - { - Variable Tokens = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 40)) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(Atom.a(" ("), Tokens))) - { - foreach (bool l4 in YP.get_code(NextCh)) - { - foreach (bool l5 in read_tokens(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - { - Variable Tokens = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 41)) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(Atom.a(")"), Tokens))) - { - foreach (bool l4 in YP.get_code(NextCh)) - { - foreach (bool l5 in read_tokens(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - { - Variable Tokens = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 44)) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(Atom.a(","), Tokens))) - { - foreach (bool l4 in YP.get_code(NextCh)) - { - foreach (bool l5 in read_tokens(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - { - Variable Pos = new Variable(); - Variable Tokens = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 59)) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("atom", Atom.a(";"), Pos), Tokens))) - { - foreach (bool l4 in get_current_position(Pos)) - { - foreach (bool l5 in YP.get_code(NextCh)) - { - foreach (bool l6 in read_after_atom(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - } - { - Variable Pos = new Variable(); - Variable Tokens = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 91)) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("/", Atom.a("["), Pos), Tokens))) - { - foreach (bool l4 in get_current_position(Pos)) - { - foreach (bool l5 in YP.get_code(NextCh)) - { - foreach (bool l6 in read_tokens(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - } - { - Variable Pos = new Variable(); - Variable Tokens = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 93)) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("/", Atom.a("]"), Pos), Tokens))) - { - foreach (bool l4 in get_current_position(Pos)) - { - foreach (bool l5 in YP.get_code(NextCh)) - { - foreach (bool l6 in read_after_atom(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - } - { - Variable Pos = new Variable(); - Variable Tokens = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 123)) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("/", Atom.a("{"), Pos), Tokens))) - { - foreach (bool l4 in get_current_position(Pos)) - { - foreach (bool l5 in YP.get_code(NextCh)) - { - foreach (bool l6 in read_tokens(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - } - { - Variable Tokens = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 124)) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(Atom.a("|"), Tokens))) - { - foreach (bool l4 in YP.get_code(NextCh)) - { - foreach (bool l5 in read_tokens(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - { - Variable Tokens = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 125)) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(Atom.a("}"), Tokens))) - { - foreach (bool l4 in YP.get_code(NextCh)) - { - foreach (bool l5 in read_after_atom(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - { - object Tokens = arg3; - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 46)) - { - foreach (bool l3 in YP.get_code(NextCh)) - { - foreach (bool l4 in read_fullstop(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - { - Variable Chars = new Variable(); - Variable Tokens = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 34)) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor1("string", Chars), Tokens))) - { - foreach (bool l4 in read_string(Chars, 34, NextCh)) - { - foreach (bool l5 in read_tokens(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - { - object Tokens = arg3; - Variable Chars = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 39)) - { - foreach (bool l3 in read_string(Chars, 39, NextCh)) - { - foreach (bool l4 in read_after_atom4(NextCh, Dict, Tokens, Chars)) - { - yield return false; - } - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 35)) - { - foreach (bool l3 in read_symbol(35, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 36)) - { - foreach (bool l3 in read_symbol(36, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 38)) - { - foreach (bool l3 in read_symbol(38, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 42)) - { - foreach (bool l3 in read_symbol(42, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 43)) - { - foreach (bool l3 in read_symbol(43, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 45)) - { - foreach (bool l3 in read_symbol(45, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 58)) - { - foreach (bool l3 in read_symbol(58, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 60)) - { - foreach (bool l3 in read_symbol(60, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 61)) - { - foreach (bool l3 in read_symbol(61, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 62)) - { - foreach (bool l3 in read_symbol(62, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 63)) - { - foreach (bool l3 in read_symbol(63, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 64)) - { - foreach (bool l3 in read_symbol(64, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 92)) - { - foreach (bool l3 in read_symbol(92, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 94)) - { - foreach (bool l3 in read_symbol(94, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 96)) - { - foreach (bool l3 in read_symbol(96, Dict, Tokens)) - { - yield return false; - } - } - } - { - object Tokens = arg3; - foreach (bool l2 in YP.unify(arg1, 126)) - { - foreach (bool l3 in read_symbol(126, Dict, Tokens)) - { - yield return false; - } - } - } - } - - public static IEnumerable read_symbol(object C1, object Dict, object Tokens) - { - { - Variable C2 = new Variable(); - Variable Chars = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.get_code(C2)) - { - foreach (bool l3 in rest_symbol(C2, Chars, NextCh)) - { - foreach (bool l4 in read_after_atom4(NextCh, Dict, Tokens, new ListPair(C1, Chars))) - { - yield return false; - } - } - } - } - } - - public static IEnumerable rest_symbol(object arg1, object arg2, object arg3) - { - { - object C2 = arg1; - object LastCh = arg3; - Variable Chars = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg2, new ListPair(C2, Chars))) - { - if (YP.greaterThan(C2, 160)) - { - if (YP.lessThan(C2, 192)) - { - if (YP.notEqual(C2, 186)) - { - if (YP.notEqual(C2, 170)) - { - foreach (bool l7 in YP.get_code(NextCh)) - { - foreach (bool l8 in rest_symbol(NextCh, Chars, LastCh)) - { - yield return false; - } - } - yield break; - } - } - } - goto cutIf1; - } - foreach (bool l3 in symbol_char(C2)) - { - foreach (bool l4 in YP.get_code(NextCh)) - { - foreach (bool l5 in rest_symbol(NextCh, Chars, LastCh)) - { - yield return false; - } - } - yield break; - } - cutIf1: - { } - } - } - { - Variable C2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, C2)) - { - foreach (bool l3 in YP.unify(arg2, Atom.NIL)) - { - foreach (bool l4 in YP.unify(arg3, C2)) - { - yield return false; - } - } - } - } - } - - public static IEnumerable symbol_char(object arg1) - { - { - foreach (bool l2 in YP.unify(arg1, 35)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 36)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 38)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 42)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 43)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 45)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 46)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 47)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 58)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 60)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 61)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 62)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 63)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 64)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 92)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 94)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 96)) - { - yield return false; - } - } - { - foreach (bool l2 in YP.unify(arg1, 126)) - { - yield return false; - } - } - } - - public static IEnumerable get_current_position(object Pos) - { - { - foreach (bool l2 in YP.unify(Pos, 0)) - { - yield return false; - } - } - } - - public static IEnumerable read_after_atom4(object Ch, object Dict, object arg3, object Chars) - { - { - Variable Atom_1 = new Variable(); - Variable Pos = new Variable(); - Variable Tokens = new Variable(); - foreach (bool l2 in YP.unify(arg3, new ListPair(new Functor2("atom", Atom_1, Pos), Tokens))) - { - foreach (bool l3 in YP.unify(Pos, 0)) - { - foreach (bool l4 in YP.atom_codes(Atom_1, Chars)) - { - foreach (bool l5 in read_after_atom(Ch, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - } - - public static IEnumerable read_after_atom(object arg1, object Dict, object arg3) - { - { - Variable Tokens = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, 40)) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(Atom.a("("), Tokens))) - { - foreach (bool l4 in YP.get_code(NextCh)) - { - foreach (bool l5 in read_tokens(NextCh, Dict, Tokens)) - { - yield return false; - } - } - yield break; - } - } - } - { - object Ch = arg1; - object Tokens = arg3; - foreach (bool l2 in read_tokens(Ch, Dict, Tokens)) - { - yield return false; - } - } - } - - public static IEnumerable read_string(object Chars, object Quote, object NextCh) - { - { - Variable Ch = new Variable(); - Variable Char = new Variable(); - Variable Next = new Variable(); - foreach (bool l2 in YP.get_code(Ch)) - { - foreach (bool l3 in read_char(Ch, Quote, Char, Next)) - { - foreach (bool l4 in rest_string5(Char, Next, Chars, Quote, NextCh)) - { - yield return false; - } - } - } - } - } - - public static IEnumerable rest_string5(object arg1, object arg2, object arg3, object arg4, object arg5) - { - { - object _X = arg4; - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg1, -1)) - { - foreach (bool l3 in YP.unify(arg2, NextCh)) - { - foreach (bool l4 in YP.unify(arg3, Atom.NIL)) - { - foreach (bool l5 in YP.unify(arg5, NextCh)) - { - yield return true; - yield break; - } - } - } - } - } - { - object Char = arg1; - object Next = arg2; - object Quote = arg4; - object NextCh = arg5; - Variable Chars = new Variable(); - Variable Char2 = new Variable(); - Variable Next2 = new Variable(); - foreach (bool l2 in YP.unify(arg3, new ListPair(Char, Chars))) - { - foreach (bool l3 in read_char(Next, Quote, Char2, Next2)) - { - foreach (bool l4 in rest_string5(Char2, Next2, Chars, Quote, NextCh)) - { - yield return false; - } - } - } - } - } - - public static IEnumerable escape_char(object arg1, object arg2) - { - { - foreach (bool l2 in YP.unify(arg1, 110)) - { - foreach (bool l3 in YP.unify(arg2, 10)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 78)) - { - foreach (bool l3 in YP.unify(arg2, 10)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 116)) - { - foreach (bool l3 in YP.unify(arg2, 9)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 84)) - { - foreach (bool l3 in YP.unify(arg2, 9)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 114)) - { - foreach (bool l3 in YP.unify(arg2, 13)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 82)) - { - foreach (bool l3 in YP.unify(arg2, 13)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 118)) - { - foreach (bool l3 in YP.unify(arg2, 11)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 86)) - { - foreach (bool l3 in YP.unify(arg2, 11)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 98)) - { - foreach (bool l3 in YP.unify(arg2, 8)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 66)) - { - foreach (bool l3 in YP.unify(arg2, 8)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 102)) - { - foreach (bool l3 in YP.unify(arg2, 12)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 70)) - { - foreach (bool l3 in YP.unify(arg2, 12)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 101)) - { - foreach (bool l3 in YP.unify(arg2, 27)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 69)) - { - foreach (bool l3 in YP.unify(arg2, 27)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 100)) - { - foreach (bool l3 in YP.unify(arg2, 127)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 68)) - { - foreach (bool l3 in YP.unify(arg2, 127)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 115)) - { - foreach (bool l3 in YP.unify(arg2, 32)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 83)) - { - foreach (bool l3 in YP.unify(arg2, 32)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 122)) - { - foreach (bool l3 in YP.unify(arg2, -1)) - { - yield return false; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, 90)) - { - foreach (bool l3 in YP.unify(arg2, -1)) - { - yield return false; - } - } - } - } - - public static IEnumerable read_variable(object C1, object Dict, object arg3) - { - { - Variable Var = new Variable(); - Variable Name = new Variable(); - Variable StartPos = new Variable(); - Variable Tokens = new Variable(); - Variable Chars = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in YP.unify(arg3, new ListPair(new Functor3("var", Var, Name, StartPos), Tokens))) - { - foreach (bool l3 in get_current_position(StartPos)) - { - foreach (bool l4 in read_name(C1, Chars, NextCh)) - { - foreach (bool l5 in YP.atom_codes(Name, Chars)) - { - if (YP.termEqual(Name, Atom.a("_"))) - { - foreach (bool l7 in read_after_atom(NextCh, Dict, Tokens)) - { - yield return false; - } - goto cutIf1; - } - foreach (bool l6 in read_lookup(Dict, Name, Var)) - { - foreach (bool l7 in read_after_atom(NextCh, Dict, Tokens)) - { - yield return false; - } - } - cutIf1: - { } - } - } - } - } - } - } - - public static IEnumerable read_lookup(object arg1, object Name, object Var) - { - { - Variable N = new Variable(); - Variable V = new Variable(); - Variable L = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("=", N, V), L))) - { - foreach (bool l3 in YP.unify(N, Name)) - { - foreach (bool l4 in YP.unify(V, Var)) - { - yield return false; - } - goto cutIf1; - } - foreach (bool l3 in read_lookup(L, Name, Var)) - { - yield return false; - } - cutIf1: - { } - } - } - } - - public static IEnumerable read_solidus(object Ch, object LastCh) - { - { - Variable NextCh = new Variable(); - if (YP.equal(Ch, 42)) - { - foreach (bool l3 in YP.get_code(NextCh)) - { - if (YP.equal(NextCh, 47)) - { - foreach (bool l5 in YP.get_code(LastCh)) - { - yield return false; - } - goto cutIf2; - } - foreach (bool l4 in read_solidus(NextCh, LastCh)) - { - yield return false; - } - cutIf2: - { } - } - goto cutIf1; - } - if (YP.notEqual(Ch, -1)) - { - foreach (bool l3 in YP.get_code(NextCh)) - { - foreach (bool l4 in read_solidus(NextCh, LastCh)) - { - yield return false; - } - } - goto cutIf3; - } - foreach (bool l2 in YP.unify(LastCh, Ch)) - { - foreach (bool l3 in formatError(Atom.a("user_error"), Atom.a("~N** end of file in /*comment~n"), Atom.NIL)) - { - yield return false; - } - } - cutIf3: - cutIf1: - { } - } - } - - public static IEnumerable read_identifier(object C1, object Dict, object Tokens) - { - { - Variable Chars = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in read_name(C1, Chars, NextCh)) - { - foreach (bool l3 in read_after_atom4(NextCh, Dict, Tokens, Chars)) - { - yield return false; - } - } - } - } - - public static IEnumerable read_name(object C1, object arg2, object LastCh) - { - { - Variable Chars = new Variable(); - Variable C2 = new Variable(); - foreach (bool l2 in YP.unify(arg2, new ListPair(C1, Chars))) - { - foreach (bool l3 in YP.get_code(C2)) - { - if (YP.greaterThanOrEqual(C2, new ListPair(97, Atom.NIL))) - { - if (YP.lessThanOrEqual(C2, new ListPair(122, Atom.NIL))) - { - foreach (bool l6 in read_name(C2, Chars, LastCh)) - { - yield return false; - } - goto cutIf2; - } - if (YP.lessThan(C2, 192)) - { - if (YP.notEqual(YP.bitwiseOr(C2, 16), 186)) - { - foreach (bool l7 in YP.unify(Chars, Atom.NIL)) - { - foreach (bool l8 in YP.unify(LastCh, C2)) - { - yield return false; - } - } - goto cutIf3; - } - } - if (YP.equal(YP.bitwiseOr(C2, 32), 247)) - { - foreach (bool l6 in YP.unify(Chars, Atom.NIL)) - { - foreach (bool l7 in YP.unify(LastCh, C2)) - { - yield return false; - } - } - goto cutIf4; - } - foreach (bool l5 in read_name(C2, Chars, LastCh)) - { - yield return false; - } - cutIf4: - cutIf3: - cutIf2: - goto cutIf1; - } - if (YP.greaterThanOrEqual(C2, new ListPair(65, Atom.NIL))) - { - if (YP.greaterThan(C2, new ListPair(90, Atom.NIL))) - { - if (YP.notEqual(C2, new ListPair(95, Atom.NIL))) - { - foreach (bool l7 in YP.unify(Chars, Atom.NIL)) - { - foreach (bool l8 in YP.unify(LastCh, C2)) - { - yield return false; - } - } - goto cutIf6; - } - } - foreach (bool l5 in read_name(C2, Chars, LastCh)) - { - yield return false; - } - cutIf6: - goto cutIf5; - } - if (YP.greaterThanOrEqual(C2, new ListPair(48, Atom.NIL))) - { - if (YP.lessThanOrEqual(C2, new ListPair(57, Atom.NIL))) - { - foreach (bool l6 in read_name(C2, Chars, LastCh)) - { - yield return false; - } - goto cutIf7; - } - } - foreach (bool l4 in YP.unify(Chars, Atom.NIL)) - { - foreach (bool l5 in YP.unify(LastCh, C2)) - { - yield return false; - } - } - cutIf7: - cutIf5: - cutIf1: - { } - } - } - } - } - - public static IEnumerable read_fullstop(object Ch, object Dict, object Tokens) - { - { - Variable Number = new Variable(); - Variable Tokens1 = new Variable(); - Variable Chars = new Variable(); - Variable NextCh = new Variable(); - if (YP.lessThanOrEqual(Ch, new ListPair(57, Atom.NIL))) - { - if (YP.greaterThanOrEqual(Ch, new ListPair(48, Atom.NIL))) - { - foreach (bool l4 in YP.unify(Tokens, new ListPair(new Functor1("number", Number), Tokens1))) - { - foreach (bool l5 in read_float(Number, Dict, Tokens1, new ListPair(48, Atom.NIL), Ch)) - { - yield return false; - } - } - goto cutIf1; - } - } - if (YP.greaterThan(Ch, new ListPair(32, Atom.NIL))) - { - foreach (bool l3 in rest_symbol(Ch, Chars, NextCh)) - { - foreach (bool l4 in read_after_atom4(NextCh, Dict, Tokens, new ListPair(46, Chars))) - { - yield return false; - } - } - goto cutIf2; - } - if (YP.greaterThanOrEqual(Ch, 0)) - { - foreach (bool l3 in YP.unify(Tokens, Atom.NIL)) - { - yield return false; - } - goto cutIf3; - } - foreach (bool l2 in formatError(Atom.a("user_error"), Atom.a("~N** end of file just after full stop~n"), Atom.NIL)) - { - } - cutIf3: - cutIf2: - cutIf1: - { } - } - } - - public static IEnumerable read_float(object Number, object Dict, object Tokens, object Digits, object Digit) - { - { - Variable Chars = new Variable(); - Variable Rest = new Variable(); - Variable NextCh = new Variable(); - foreach (bool l2 in prepend(Digits, Chars, Rest)) - { - foreach (bool l3 in read_float4(Digit, Rest, NextCh, Chars)) - { - foreach (bool l4 in YP.number_codes(Number, Chars)) - { - foreach (bool l5 in read_tokens(NextCh, Dict, Tokens)) - { - yield return false; - } - } - } - } - } - } - - public static IEnumerable prepend(object arg1, object arg2, object arg3) - { - { - object X = arg3; - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(46, X))) - { - yield return false; - } - } - } - { - object Y = arg3; - Variable C = new Variable(); - Variable Cs = new Variable(); - Variable X = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(C, Cs))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(C, X))) - { - foreach (bool l4 in prepend(Cs, X, Y)) - { - yield return false; - } - } - } - } - } - - public static IEnumerable read_float4(object C1, object arg2, object NextCh, object Total) - { - { - Variable Chars = new Variable(); - Variable C2 = new Variable(); - Variable C3 = new Variable(); - Variable C4 = new Variable(); - Variable More = new Variable(); - foreach (bool l2 in YP.unify(arg2, new ListPair(C1, Chars))) - { - foreach (bool l3 in YP.get_code(C2)) - { - if (YP.greaterThanOrEqual(C2, new ListPair(48, Atom.NIL))) - { - if (YP.lessThanOrEqual(C2, new ListPair(57, Atom.NIL))) - { - foreach (bool l6 in read_float4(C2, Chars, NextCh, Total)) - { - yield return false; - } - goto cutIf1; - } - } - if (YP.equal(YP.bitwiseOr(C2, 32), new ListPair(101, Atom.NIL))) - { - foreach (bool l5 in YP.get_code(C3)) - { - if (YP.equal(C3, new ListPair(45, Atom.NIL))) - { - foreach (bool l7 in YP.get_code(C4)) - { - foreach (bool l8 in YP.unify(Chars, new ListPair(C2, new ListPair(45, More)))) - { - if (YP.greaterThanOrEqual(C4, new ListPair(48, Atom.NIL))) - { - if (YP.lessThanOrEqual(C4, new ListPair(57, Atom.NIL))) - { - foreach (bool l11 in read_exponent(C4, More, NextCh)) - { - yield return false; - } - goto cutIf4; - } - } - foreach (bool l9 in YP.unify(More, Atom.NIL)) - { - foreach (bool l10 in formatError(Atom.a("user_error"), Atom.a("~N** Missing exponent in ~s~n"), new ListPair(Total, Atom.NIL))) - { - } - } - foreach (bool l9 in YP.unify(More, new ListPair(48, Atom.NIL))) - { - foreach (bool l10 in YP.unify(NextCh, C4)) - { - yield return false; - } - } - cutIf4: - { } - } - } - goto cutIf3; - } - if (YP.equal(C3, new ListPair(43, Atom.NIL))) - { - foreach (bool l7 in YP.get_code(C4)) - { - foreach (bool l8 in YP.unify(Chars, new ListPair(C2, More))) - { - if (YP.greaterThanOrEqual(C4, new ListPair(48, Atom.NIL))) - { - if (YP.lessThanOrEqual(C4, new ListPair(57, Atom.NIL))) - { - foreach (bool l11 in read_exponent(C4, More, NextCh)) - { - yield return false; - } - goto cutIf6; - } - } - foreach (bool l9 in YP.unify(More, Atom.NIL)) - { - foreach (bool l10 in formatError(Atom.a("user_error"), Atom.a("~N** Missing exponent in ~s~n"), new ListPair(Total, Atom.NIL))) - { - } - } - foreach (bool l9 in YP.unify(More, new ListPair(48, Atom.NIL))) - { - foreach (bool l10 in YP.unify(NextCh, C4)) - { - yield return false; - } - } - cutIf6: - { } - } - } - goto cutIf5; - } - foreach (bool l6 in YP.unify(C4, C3)) - { - foreach (bool l7 in YP.unify(Chars, new ListPair(C2, More))) - { - if (YP.greaterThanOrEqual(C4, new ListPair(48, Atom.NIL))) - { - if (YP.lessThanOrEqual(C4, new ListPair(57, Atom.NIL))) - { - foreach (bool l10 in read_exponent(C4, More, NextCh)) - { - yield return false; - } - goto cutIf7; - } - } - foreach (bool l8 in YP.unify(More, Atom.NIL)) - { - foreach (bool l9 in formatError(Atom.a("user_error"), Atom.a("~N** Missing exponent in ~s~n"), new ListPair(Total, Atom.NIL))) - { - } - } - foreach (bool l8 in YP.unify(More, new ListPair(48, Atom.NIL))) - { - foreach (bool l9 in YP.unify(NextCh, C4)) - { - yield return false; - } - } - cutIf7: - { } - } - } - cutIf5: - cutIf3: - { } - } - goto cutIf2; - } - foreach (bool l4 in YP.unify(Chars, Atom.NIL)) - { - foreach (bool l5 in YP.unify(NextCh, C2)) - { - yield return false; - } - } - cutIf2: - cutIf1: - { } - } - } - } - } - - public static IEnumerable read_exponent(object C1, object arg2, object NextCh) - { - { - Variable Chars = new Variable(); - Variable C2 = new Variable(); - foreach (bool l2 in YP.unify(arg2, new ListPair(C1, Chars))) - { - foreach (bool l3 in YP.get_code(C2)) - { - if (YP.greaterThanOrEqual(C2, new ListPair(48, Atom.NIL))) - { - if (YP.lessThanOrEqual(C2, new ListPair(57, Atom.NIL))) - { - foreach (bool l6 in read_exponent(C2, Chars, NextCh)) - { - yield return false; - } - goto cutIf1; - } - } - foreach (bool l4 in YP.unify(Chars, Atom.NIL)) - { - foreach (bool l5 in YP.unify(NextCh, C2)) - { - yield return false; - } - } - cutIf1: - { } - } - } - } - } - - public static IEnumerable read_number(object C1, object Dict, object arg3) - { - { - Variable Number = new Variable(); - Variable Tokens = new Variable(); - Variable C2 = new Variable(); - Variable N = new Variable(); - Variable C = new Variable(); - Variable C3 = new Variable(); - Variable Digits = new Variable(); - foreach (bool l2 in YP.unify(arg3, new ListPair(new Functor1("number", Number), Tokens))) - { - foreach (bool l3 in read_number4(C1, C2, 0, N)) - { - if (YP.equal(C2, 39)) - { - if (YP.greaterThanOrEqual(N, 2)) - { - if (YP.lessThanOrEqual(N, 36)) - { - foreach (bool l7 in read_based(N, 0, Number, C)) - { - foreach (bool l8 in read_tokens(C, Dict, Tokens)) - { - yield return false; - } - } - goto cutIf2; - } - } - if (YP.equal(N, 0)) - { - foreach (bool l6 in YP.get_code(C3)) - { - foreach (bool l7 in read_char(C3, -1, Number, C)) - { - foreach (bool l8 in read_tokens(C, Dict, Tokens)) - { - yield return false; - } - } - } - goto cutIf3; - } - foreach (bool l5 in formatError(Atom.a("user_error"), Atom.a("~N** ~d' read as ~d '~n"), new ListPair(N, new ListPair(N, Atom.NIL)))) - { - foreach (bool l6 in YP.unify(Number, N)) - { - foreach (bool l7 in YP.unify(C, C2)) - { - foreach (bool l8 in read_tokens(C, Dict, Tokens)) - { - yield return false; - } - } - } - } - cutIf3: - cutIf2: - goto cutIf1; - } - if (YP.equal(C2, 46)) - { - foreach (bool l5 in YP.get_code(C3)) - { - if (YP.greaterThanOrEqual(C3, new ListPair(48, Atom.NIL))) - { - if (YP.lessThanOrEqual(C3, new ListPair(57, Atom.NIL))) - { - foreach (bool l8 in YP.number_codes(N, Digits)) - { - foreach (bool l9 in read_float(Number, Dict, Tokens, Digits, C3)) - { - yield return false; - } - } - goto cutIf5; - } - } - foreach (bool l6 in YP.unify(Number, N)) - { - foreach (bool l7 in read_fullstop(C3, Dict, Tokens)) - { - yield return false; - } - } - cutIf5: - { } - } - goto cutIf4; - } - foreach (bool l4 in YP.unify(Number, N)) - { - foreach (bool l5 in read_tokens(C2, Dict, Tokens)) - { - yield return false; - } - } - cutIf4: - cutIf1: - { } - } - } - } - } - - public static IEnumerable read_number4(object C0, object C, object N0, object N) - { - { - Variable N1 = new Variable(); - Variable C1 = new Variable(); - if (YP.greaterThanOrEqual(C0, new ListPair(48, Atom.NIL))) - { - if (YP.lessThanOrEqual(C0, new ListPair(57, Atom.NIL))) - { - foreach (bool l4 in YP.unify(N1, YP.add(YP.subtract(YP.multiply(N0, 10), new ListPair(48, Atom.NIL)), C0))) - { - foreach (bool l5 in YP.get_code(C1)) - { - foreach (bool l6 in read_number4(C1, C, N1, N)) - { - yield return false; - } - } - } - goto cutIf1; - } - } - if (YP.equal(C0, 95)) - { - foreach (bool l3 in YP.get_code(C1)) - { - foreach (bool l4 in read_number4(C1, C, N0, N)) - { - yield return false; - } - } - goto cutIf2; - } - foreach (bool l2 in YP.unify(C, C0)) - { - foreach (bool l3 in YP.unify(N, N0)) - { - yield return false; - } - } - cutIf2: - cutIf1: - { } - } - } - - public static IEnumerable read_based(object Base, object N0, object N, object C) - { - { - Variable C1 = new Variable(); - Variable Digit = new Variable(); - Variable N1 = new Variable(); - foreach (bool l2 in YP.get_code(C1)) - { - if (YP.greaterThanOrEqual(C1, new ListPair(48, Atom.NIL))) - { - if (YP.lessThanOrEqual(C1, new ListPair(57, Atom.NIL))) - { - foreach (bool l5 in YP.unify(Digit, YP.subtract(C1, new ListPair(48, Atom.NIL)))) - { - if (YP.lessThan(Digit, Base)) - { - foreach (bool l7 in YP.unify(N1, YP.add(YP.multiply(N0, Base), Digit))) - { - foreach (bool l8 in read_based(Base, N1, N, C)) - { - yield return false; - } - } - goto cutIf2; - } - if (YP.equal(C1, new ListPair(95, Atom.NIL))) - { - foreach (bool l7 in read_based(Base, N0, N, C)) - { - yield return false; - } - goto cutIf3; - } - foreach (bool l6 in YP.unify(N, N0)) - { - foreach (bool l7 in YP.unify(C, C1)) - { - yield return false; - } - } - cutIf3: - cutIf2: - { } - } - goto cutIf1; - } - } - if (YP.greaterThanOrEqual(C1, new ListPair(65, Atom.NIL))) - { - if (YP.lessThanOrEqual(C1, new ListPair(90, Atom.NIL))) - { - foreach (bool l5 in YP.unify(Digit, YP.subtract(C1, YP.subtract(new ListPair(65, Atom.NIL), 10)))) - { - if (YP.lessThan(Digit, Base)) - { - foreach (bool l7 in YP.unify(N1, YP.add(YP.multiply(N0, Base), Digit))) - { - foreach (bool l8 in read_based(Base, N1, N, C)) - { - yield return false; - } - } - goto cutIf5; - } - if (YP.equal(C1, new ListPair(95, Atom.NIL))) - { - foreach (bool l7 in read_based(Base, N0, N, C)) - { - yield return false; - } - goto cutIf6; - } - foreach (bool l6 in YP.unify(N, N0)) - { - foreach (bool l7 in YP.unify(C, C1)) - { - yield return false; - } - } - cutIf6: - cutIf5: - { } - } - goto cutIf4; - } - } - if (YP.greaterThanOrEqual(C1, new ListPair(97, Atom.NIL))) - { - if (YP.lessThanOrEqual(C1, new ListPair(122, Atom.NIL))) - { - foreach (bool l5 in YP.unify(Digit, YP.subtract(C1, YP.subtract(new ListPair(97, Atom.NIL), 10)))) - { - if (YP.lessThan(Digit, Base)) - { - foreach (bool l7 in YP.unify(N1, YP.add(YP.multiply(N0, Base), Digit))) - { - foreach (bool l8 in read_based(Base, N1, N, C)) - { - yield return false; - } - } - goto cutIf8; - } - if (YP.equal(C1, new ListPair(95, Atom.NIL))) - { - foreach (bool l7 in read_based(Base, N0, N, C)) - { - yield return false; - } - goto cutIf9; - } - foreach (bool l6 in YP.unify(N, N0)) - { - foreach (bool l7 in YP.unify(C, C1)) - { - yield return false; - } - } - cutIf9: - cutIf8: - { } - } - goto cutIf7; - } - } - foreach (bool l3 in YP.unify(Digit, 99)) - { - if (YP.lessThan(Digit, Base)) - { - foreach (bool l5 in YP.unify(N1, YP.add(YP.multiply(N0, Base), Digit))) - { - foreach (bool l6 in read_based(Base, N1, N, C)) - { - yield return false; - } - } - goto cutIf10; - } - if (YP.equal(C1, new ListPair(95, Atom.NIL))) - { - foreach (bool l5 in read_based(Base, N0, N, C)) - { - yield return false; - } - goto cutIf11; - } - foreach (bool l4 in YP.unify(N, N0)) - { - foreach (bool l5 in YP.unify(C, C1)) - { - yield return false; - } - } - cutIf11: - cutIf10: - { } - } - cutIf7: - cutIf4: - cutIf1: - { } - } - } - } - - public static IEnumerable read_char(object Char, object Quote, object Result, object Next) - { - { - Variable C1 = new Variable(); - Variable C2 = new Variable(); - Variable C3 = new Variable(); - Variable Ch = new Variable(); - if (YP.equal(Char, 92)) - { - foreach (bool l3 in YP.get_code(C1)) - { - if (YP.lessThan(C1, 0)) - { - foreach (bool l5 in formatError(Atom.a("user_error"), Atom.a("~N** end of file in ~cquoted~c~n"), new ListPair(Quote, new ListPair(Quote, Atom.NIL)))) - { - foreach (bool l6 in YP.unify(Result, -1)) - { - foreach (bool l7 in YP.unify(Next, C1)) - { - yield return false; - } - } - } - goto cutIf2; - } - if (YP.lessThanOrEqual(C1, new ListPair(32, Atom.NIL))) - { - foreach (bool l5 in YP.get_code(C2)) - { - foreach (bool l6 in read_char(C2, Quote, Result, Next)) - { - yield return false; - } - } - goto cutIf3; - } - if (YP.equal(YP.bitwiseOr(C1, 32), new ListPair(99, Atom.NIL))) - { - foreach (bool l5 in YP.get_code(C2)) - { - foreach (bool l6 in read_char(C2, Quote, Result, Next)) - { - yield return false; - } - } - goto cutIf4; - } - if (YP.lessThanOrEqual(C1, new ListPair(55, Atom.NIL))) - { - if (YP.greaterThanOrEqual(C1, new ListPair(48, Atom.NIL))) - { - foreach (bool l6 in YP.get_code(C2)) - { - if (YP.lessThanOrEqual(C2, new ListPair(55, Atom.NIL))) - { - if (YP.greaterThanOrEqual(C2, new ListPair(48, Atom.NIL))) - { - foreach (bool l9 in YP.get_code(C3)) - { - if (YP.lessThanOrEqual(C3, new ListPair(55, Atom.NIL))) - { - if (YP.greaterThanOrEqual(C3, new ListPair(48, Atom.NIL))) - { - foreach (bool l12 in YP.get_code(Next)) - { - foreach (bool l13 in YP.unify(Result, YP.subtract(YP.add(YP.multiply(YP.add(YP.multiply(C1, 8), C2), 8), C3), YP.multiply(73, new ListPair(48, Atom.NIL))))) - { - yield return false; - } - } - goto cutIf7; - } - } - foreach (bool l10 in YP.unify(Next, C3)) - { - foreach (bool l11 in YP.unify(Result, YP.subtract(YP.add(YP.multiply(C1, 8), C2), YP.multiply(9, new ListPair(48, Atom.NIL))))) - { - yield return false; - } - } - cutIf7: - { } - } - goto cutIf6; - } - } - foreach (bool l7 in YP.unify(Next, C2)) - { - foreach (bool l8 in YP.unify(Result, YP.subtract(C1, new ListPair(48, Atom.NIL)))) - { - yield return false; - } - } - cutIf6: - { } - } - goto cutIf5; - } - } - if (YP.equal(C1, new ListPair(94, Atom.NIL))) - { - foreach (bool l5 in YP.get_code(C2)) - { - if (YP.lessThan(C2, 0)) - { - foreach (bool l7 in formatError(Atom.a("user_error"), Atom.a("~N** end of file in ~c..~c^..~c~n"), ListPair.make(new object[] { Quote, 92, Quote }))) - { - foreach (bool l8 in YP.unify(Result, -1)) - { - foreach (bool l9 in YP.unify(Next, C2)) - { - yield return false; - } - } - } - goto cutIf9; - } - if (YP.equal(C2, new ListPair(63, Atom.NIL))) - { - foreach (bool l7 in YP.unify(Result, 127)) - { - foreach (bool l8 in YP.get_code(Next)) - { - yield return false; - } - } - goto cutIf10; - } - foreach (bool l6 in YP.unify(Result, YP.bitwiseAnd(C2, 31))) - { - foreach (bool l7 in YP.get_code(Next)) - { - yield return false; - } - } - cutIf10: - cutIf9: - { } - } - goto cutIf8; - } - foreach (bool l4 in escape_char(C1, Result)) - { - foreach (bool l5 in YP.get_code(Next)) - { - yield return false; - } - goto cutIf11; - } - foreach (bool l4 in YP.unify(Result, C1)) - { - foreach (bool l5 in YP.get_code(Next)) - { - yield return false; - } - } - cutIf11: - cutIf8: - cutIf5: - cutIf4: - cutIf3: - cutIf2: - { } - } - goto cutIf1; - } - if (YP.equal(Char, Quote)) - { - foreach (bool l3 in YP.get_code(Ch)) - { - if (YP.equal(Ch, Quote)) - { - foreach (bool l5 in YP.unify(Result, Quote)) - { - foreach (bool l6 in YP.get_code(Next)) - { - yield return false; - } - } - goto cutIf13; - } - foreach (bool l4 in YP.unify(Result, -1)) - { - foreach (bool l5 in YP.unify(Next, Ch)) - { - yield return false; - } - } - cutIf13: - { } - } - goto cutIf12; - } - if (YP.lessThan(Char, new ListPair(32, Atom.NIL))) - { - if (YP.notEqual(Char, 9)) - { - if (YP.notEqual(Char, 10)) - { - if (YP.notEqual(Char, 13)) - { - foreach (bool l6 in YP.unify(Result, -1)) - { - foreach (bool l7 in YP.unify(Next, Char)) - { - foreach (bool l8 in formatError(Atom.a("user_error"), Atom.a("~N** Strange character ~d ends ~ctoken~c~n"), ListPair.make(new object[] { Char, Quote, Quote }))) - { - yield return false; - } - } - } - goto cutIf14; - } - } - } - } - foreach (bool l2 in YP.unify(Result, Char)) - { - foreach (bool l3 in YP.get_code(Next)) - { - yield return false; - } - } - cutIf14: - cutIf12: - cutIf1: - { } - } - } - #pragma warning restore 0168, 0219, 0162 - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/PrologException.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/PrologException.cs deleted file mode 100644 index 9f5ae3d..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/PrologException.cs +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - /// - /// A PrologException is used as the exception thrown by YP.throw(Term). - /// - public class PrologException : Exception - { - public readonly object _term; - - /// - /// Create a PrologException with the given Term. The printable exception message is the full Term. - /// - /// the term of the exception - public PrologException(object Term) - : base(YP.getValue(Term).ToString()) - { - _term = YP.makeCopy(Term, new Variable.CopyStore()); - } - - /// - /// Create a PrologException where the Term is error(ErrorTerm, Message). - /// This uses YP.makeCopy to copy the ErrorTerm and Message so that they are valid after unbinding. - /// - /// the error term of the error - /// the message term of the error. If this is a string, it is converted to an - /// Atom so it can be used by Prolog code. - /// Message, converted to a string, is use as the printable exception message. - /// - public PrologException(object ErrorTerm, object Message) - : base(YP.getValue(Message).ToString()) - { - if (Message is string) - Message = Atom.a((string)Message); - _term = YP.makeCopy(new Functor2(Atom.a("error"), ErrorTerm, Message), new Variable.CopyStore()); - } - - public class TypeErrorInfo - { - public readonly Atom _Type; - public readonly object _Culprit; - public readonly object _Message; - - public TypeErrorInfo(Atom Type, object Culprit, object Message) - { - _Type = Type; - _Culprit = Culprit; - _Message = Message; - } - } - /// - /// Return the TypeErrorInfo for this exception, or null if _term does not match - /// error(type_error(Type, Culprit), Message). - /// - /// - public TypeErrorInfo getTypeErrorInfo() - { - if (!(_term is Functor2 && ((Functor2)_term)._name._name == "error")) - return null; - object errorTerm = ((Functor2)_term)._arg1; - if (!(errorTerm is Functor2 && ((Functor2)errorTerm)._name._name == "type_error")) - return null; - if (!(((Functor2)errorTerm)._arg1 is Atom)) - return null; - return new TypeErrorInfo - ((Atom)((Functor2)errorTerm)._arg1, ((Functor2)errorTerm)._arg2, ((Functor2)_term)._arg2); - } - - public class ExistenceErrorInfo - { - public readonly Atom _Type; - public readonly object _Culprit; - public readonly object _Message; - - public ExistenceErrorInfo(Atom Type, object Culprit, object Message) - { - _Type = Type; - _Culprit = Culprit; - _Message = Message; - } - - /// - /// If _Type is procedure and _Culprit is name/artity, return the name. Otherwise return null. - /// - /// - public object getProcedureName() - { - if (!(_Type._name == "procedure" && - _Culprit is Functor2 && ((Functor2)_Culprit)._name == Atom.SLASH)) - return null; - return ((Functor2)_Culprit)._arg1; - } - - /// - /// If _Type is procedure and _Culprit is name/arity and arity is an integer, return the arity. - /// Otherwise return -1. - /// - /// - public int getProcedureArity() - { - if (!(_Type._name == "procedure" && - _Culprit is Functor2 && ((Functor2)_Culprit)._name == Atom.SLASH)) - return -1; - if (!(((Functor2)_Culprit)._arg2 is int)) - return -1; - return (int)((Functor2)_Culprit)._arg2; - } - } - /// - /// Return the ExistenceErrorInfo for this exception, or null if _term does not match - /// error(existence_error(Type, Culprit), Message). If the returned ExistenceErrorInfo _Culprit is - /// procedure, you can use its getProcedureName and getProcedureArity. - /// - /// - public ExistenceErrorInfo getExistenceErrorInfo() - { - if (!(_term is Functor2 && ((Functor2)_term)._name._name == "error")) - return null; - object errorTerm = ((Functor2)_term)._arg1; - if (!(errorTerm is Functor2 && ((Functor2)errorTerm)._name._name == "existence_error")) - return null; - if (!(((Functor2)errorTerm)._arg1 is Atom)) - return null; - return new ExistenceErrorInfo - ((Atom)((Functor2)errorTerm)._arg1, ((Functor2)errorTerm)._arg2, ((Functor2)_term)._arg2); - } - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Properties/AssemblyInfo.cs deleted file mode 100644 index f6d5d41..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenSim.Region.ScriptEngine.Shared.YieldProlog")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("http://opensimulator.org")] -[assembly: AssemblyProduct("OpenSim")] -[assembly: AssemblyCopyright("OpenSimulator developers")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("8df98e6b-0425-44d6-8d91-2b3b4c56acdf")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/UndefinedPredicateException.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/UndefinedPredicateException.cs deleted file mode 100644 index 4b6112f..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/UndefinedPredicateException.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - /// - /// An UndefinedPredicateException extends PrologException to create an existence_error exception. - /// - public class UndefinedPredicateException : PrologException - { - private Atom _predicateName; - private int _arity; - - public UndefinedPredicateException(object message, Atom predicateName, int arity) - : base(new Functor2 - (Atom.a("existence_error"), Atom.a("procedure"), new Functor2(Atom.a("/"), predicateName, arity)), - message) - { - _predicateName = predicateName; - _arity = arity; - } - - public Atom PredicateName - { - get { return _predicateName; } - } - - public int Arity - { - get { return _arity; } - } - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Variable.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Variable.cs deleted file mode 100644 index ea5b7a6..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/Variable.cs +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - public interface IUnifiable - { - IEnumerable unify(object arg); - void addUniqueVariables(List variableSet); - object makeCopy(Variable.CopyStore copyStore); - bool termEqual(object term); - bool ground(); - } - - /// - /// A Variable is passed to a function so that it can be unified with - /// value or another Variable. See getValue and unify for details. - /// - public class Variable : IUnifiable - { - // Use _isBound separate from _value so that it can be bound to any value, - // including null. - private bool _isBound = false; - private object _value; - - /// - /// If this Variable is unbound, then just return this Variable. - /// Otherwise, if this has been bound to a value with unify, return the value. - /// If the bound value is another Variable, this follows the "variable chain" - /// to the end and returns the final value, or the final Variable if it is unbound. - /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html - /// - /// - public object getValue() - { - if (!_isBound) - return this; - - object result = _value; - while (result is Variable) - { - if (!((Variable)result)._isBound) - return result; - - // Keep following the Variable chain. - result = ((Variable)result)._value; - } - - return result; - } - - /// - /// If this Variable is bound, then just call YP.unify to unify this with arg. - /// (Note that if arg is an unbound Variable, then YP.unify will bind it to - /// this Variable's value.) - /// Otherwise, bind this Variable to YP.getValue(arg) and yield once. After the - /// yield, return this Variable to the unbound state. - /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html - /// - /// - /// - public IEnumerable unify(object arg) - { - if (!_isBound) - { - _value = YP.getValue(arg); - if (_value == this) - // We are unifying this unbound variable with itself, so leave it unbound. - yield return false; - else - { - _isBound = true; - try - { - yield return false; - } - finally - { - // Remove the binding. - _isBound = false; - } - } - } - else - { - // disable warning on l1, don't see how we can - // code this differently - #pragma warning disable 0168, 0219 - foreach (bool l1 in YP.unify(this, arg)) - yield return false; - #pragma warning restore 0168, 0219 - } - } - - public override string ToString() - { - object value = getValue(); - if (value == this) - return "_Variable"; - else - return getValue().ToString(); - } - - /// - /// If bound, call YP.addUniqueVariables on the value. Otherwise, if this unbound - /// variable is not already in variableSet, add it. - /// - /// - public void addUniqueVariables(List variableSet) - { - if (_isBound) - YP.addUniqueVariables(getValue(), variableSet); - else - { - if (variableSet.IndexOf(this) < 0) - variableSet.Add(this); - } - } - - /// - /// If bound, return YP.makeCopy for the value, else return copyStore.getCopy(this). - /// However, if copyStore is null, just return this. - /// - /// - /// - public object makeCopy(Variable.CopyStore copyStore) - { - if (_isBound) - return YP.makeCopy(getValue(), copyStore); - else - return copyStore == null ? this : copyStore.getCopy(this); - } - - public bool termEqual(object term) - { - if (_isBound) - return YP.termEqual(getValue(), term); - else - return this == YP.getValue(term); - } - - public bool ground() - { - if (_isBound) - // This is usually called by YP.ground which already did getValue, so this - // should never be reached, but check anyway. - return YP.ground(getValue()); - else - return false; - } - - /// - /// A CopyStore is used by makeCopy to track which Variable objects have - /// been copied. - /// - public class CopyStore - { - private List _inVariableSet = new List(); - private List _outVariableSet = new List(); - - /// - /// If inVariable has already been copied, return its copy. Otherwise, - /// return a fresh Variable associated with inVariable. - /// - /// - /// - public Variable getCopy(Variable inVariable) - { - int index = _inVariableSet.IndexOf(inVariable); - if (index >= 0) - return _outVariableSet[index]; - else - { - Variable outVariable = new Variable(); - _inVariableSet.Add(inVariable); - _outVariableSet.Add(outVariable); - return outVariable; - } - } - - /// - /// Return the number of unique variables that have been copied. - /// - /// - public int getNUniqueVariables() - { - return _inVariableSet.Count; - } - } - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs deleted file mode 100644 index f2171dd..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YP.cs +++ /dev/null @@ -1,2701 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Net.Sockets; -using System.Text; -using System.Text.RegularExpressions; -using log4net; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - /// - /// YP has static methods for general functions in Yield Prolog such as - /// and . - /// - public class YP - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static Fail _fail = new Fail(); - private static Repeat _repeat = new Repeat(); - private static Dictionary> _predicatesStore = - new Dictionary>(); - private static TextWriter _outputStream = System.Console.Out; - private static TextReader _inputStream = System.Console.In; - private static IndexedAnswers _operatorTable = null; - private static Dictionary _prologFlags = new Dictionary(); - public const int MAX_ARITY = 255; - - /// - /// An IClause is used so that dynamic predicates can call match. - /// - public interface IClause - { - IEnumerable match(object[] args); - IEnumerable clause(object Head, object Body); - } - - /// - /// If value is a Variable, then return its getValue. Otherwise, just - /// return value. You should call YP.getValue on any object that - /// may be a Variable to get the value to pass to other functions in - /// your system that are not part of Yield Prolog, such as math functions - /// or file I/O. - /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html - /// - /// - /// - public static object getValue(object value) - { - if (value is Variable) - return ((Variable)value).getValue(); - else - return value; - } - - /// - /// If arg1 or arg2 is an object with a unify method (such as Variable or - /// Functor) then just call its unify with the other argument. The object's - /// unify method will bind the values or check for equals as needed. - /// Otherwise, both arguments are "normal" (atomic) values so if they - /// are equal then succeed (yield once), else fail (don't yield). - /// For more details, see http://yieldprolog.sourceforge.net/tutorial1.html - /// - /// - /// - /// - public static IEnumerable unify(object arg1, object arg2) - { - arg1 = getValue(arg1); - arg2 = getValue(arg2); - if (arg1 is IUnifiable) - return ((IUnifiable)arg1).unify(arg2); - else if (arg2 is IUnifiable) - return ((IUnifiable)arg2).unify(arg1); - else - { - // Arguments are "normal" types. - if (arg1.Equals(arg2)) - return new Succeed(); - else - return _fail; - } - } - - /// - /// This is used for the lookup key in _factStore. - /// - public struct NameArity - { - public readonly Atom _name; - public readonly int _arity; - - public NameArity(Atom name, int arity) - { - _name = name; - _arity = arity; - } - - public override bool Equals(object obj) - { - if (obj is NameArity) - { - NameArity nameArity = (NameArity)obj; - return nameArity._name.Equals(_name) && nameArity._arity.Equals(_arity); - } - else - { - return false; - } - } - - public override int GetHashCode() - { - return _name.GetHashCode() ^ _arity.GetHashCode(); - } - } - - /// - /// Convert term to an int. - /// If term is a single-element List, use its first element - /// (to handle the char types like "a"). - /// If can't convert, throw a PrologException for type_error evaluable (because this is only - /// called from arithmetic functions). - /// - /// - /// - public static int convertInt(object term) - { - term = YP.getValue(term); - if (term is Functor2 && ((Functor2)term)._name == Atom.DOT && - YP.getValue(((Functor2)term)._arg2) == Atom.NIL) - // Assume it is a char type like "a". - term = YP.getValue(((Functor2)term)._arg1); - if (term is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Expected a number but the argument is an unbound variable"); - - try - { - return (int)term; - } - catch (InvalidCastException) - { - throw new PrologException - (new Functor2 - ("type_error", Atom.a("evaluable"), - new Functor2(Atom.SLASH, getFunctorName(term), getFunctorArgs(term).Length)), - "Term must be an integer"); - } - } - - /// - /// Convert term to a double. This may convert an int to a double, etc. - /// If term is a single-element List, use its first element - /// (to handle the char types like "a"). - /// If can't convert, throw a PrologException for type_error evaluable (because this is only - /// called from arithmetic functions). - /// - /// - /// - public static double convertDouble(object term) - { - term = YP.getValue(term); - if (term is Functor2 && ((Functor2)term)._name == Atom.DOT && - YP.getValue(((Functor2)term)._arg2) == Atom.NIL) - // Assume it is a char type like "a". - term = YP.getValue(((Functor2)term)._arg1); - if (term is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Expected a number but the argument is an unbound variable"); - - try - { - return Convert.ToDouble(term); - } - catch (InvalidCastException) - { - throw new PrologException - (new Functor2 - ("type_error", Atom.a("evaluable"), - new Functor2(Atom.SLASH, getFunctorName(term), getFunctorArgs(term).Length)), - "Term must be an integer"); - } - } - - /// - /// If term is an integer, set intTerm. - /// If term is a single-element List, use its first element - /// (to handle the char types like "a"). Return true for success, false if can't convert. - /// We use a success return value because throwing an exception is inefficient. - /// - /// - /// - public static bool getInt(object term, out int intTerm) - { - term = YP.getValue(term); - if (term is Functor2 && ((Functor2)term)._name == Atom.DOT && - YP.getValue(((Functor2)term)._arg2) == Atom.NIL) - // Assume it is a char type like "a". - term = YP.getValue(((Functor2)term)._arg1); - - if (term is int) - { - intTerm = (int)term; - return true; - } - - intTerm = 0; - return false; - } - - public static bool equal(object x, object y) - { - x = YP.getValue(x); - if (x is DateTime) - return (DateTime)x == (DateTime)YP.getValue(y); - // Assume convertDouble converts an int to a double perfectly. - return YP.convertDouble(x) == YP.convertDouble(y); - } - - public static bool notEqual(object x, object y) - { - x = YP.getValue(x); - if (x is DateTime) - return (DateTime)x != (DateTime)YP.getValue(y); - // Assume convertDouble converts an int to a double perfectly. - return YP.convertDouble(x) != YP.convertDouble(y); - } - - public static bool greaterThan(object x, object y) - { - x = YP.getValue(x); - if (x is DateTime) - return (DateTime)x > (DateTime)YP.getValue(y); - // Assume convertDouble converts an int to a double perfectly. - return YP.convertDouble(x) > YP.convertDouble(y); - } - - public static bool lessThan(object x, object y) - { - x = YP.getValue(x); - if (x is DateTime) - return (DateTime)x < (DateTime)YP.getValue(y); - // Assume convertDouble converts an int to a double perfectly. - return YP.convertDouble(x) < YP.convertDouble(y); - } - - public static bool greaterThanOrEqual(object x, object y) - { - x = YP.getValue(x); - if (x is DateTime) - return (DateTime)x >= (DateTime)YP.getValue(y); - // Assume convertDouble converts an int to a double perfectly. - return YP.convertDouble(x) >= YP.convertDouble(y); - } - - public static bool lessThanOrEqual(object x, object y) - { - x = YP.getValue(x); - if (x is DateTime) - return (DateTime)x <= (DateTime)YP.getValue(y); - // Assume convertDouble converts an int to a double perfectly. - return YP.convertDouble(x) <= YP.convertDouble(y); - } - - public static object negate(object x) - { - int intX; - if (getInt(x, out intX)) - return -intX; - return -convertDouble(x); - } - - public static object abs(object x) - { - int intX; - if (getInt(x, out intX)) - return Math.Abs(intX); - return Math.Abs(convertDouble(x)); - } - - public static object sign(object x) - { - int intX; - if (getInt(x, out intX)) - return Math.Sign(intX); - return Math.Sign(convertDouble(x)); - } - - // Use toFloat instead of float because it is a reserved keyword. - public static object toFloat(object x) - { - return convertDouble(x); - } - - /// - /// The ISO standard returns an int. - /// - /// - /// - public static object floor(object x) - { - return (int)Math.Floor(convertDouble(x)); - } - - /// - /// The ISO standard returns an int. - /// - /// - /// - public static object truncate(object x) - { - return (int)Math.Truncate(convertDouble(x)); - } - - /// - /// The ISO standard returns an int. - /// - /// - /// - public static object round(object x) - { - return (int)Math.Round(convertDouble(x)); - } - - /// - /// The ISO standard returns an int. - /// - /// - /// - public static object ceiling(object x) - { - return (int)Math.Ceiling(convertDouble(x)); - } - - public static object sin(object x) - { - return Math.Sin(YP.convertDouble(x)); - } - - public static object cos(object x) - { - return Math.Cos(YP.convertDouble(x)); - } - - public static object atan(object x) - { - return Math.Atan(YP.convertDouble(x)); - } - - public static object exp(object x) - { - return Math.Exp(YP.convertDouble(x)); - } - - public static object log(object x) - { - return Math.Log(YP.convertDouble(x)); - } - - public static object sqrt(object x) - { - return Math.Sqrt(convertDouble(x)); - } - - public static object bitwiseComplement(object x) - { - return ~YP.convertInt(x); - } - - public static object add(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return intX + intY; - return convertDouble(x) + convertDouble(y); - } - - public static object subtract(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return intX - intY; - return convertDouble(x) - convertDouble(y); - } - - public static object multiply(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return intX * intY; - return convertDouble(x) * convertDouble(y); - } - - /// - /// Return floating point, even if both arguments are integer. - /// - /// - /// - /// - public static object divide(object x, object y) - { - return convertDouble(x) / convertDouble(y); - } - - public static object intDivide(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return intX / intY; - // Still allow passing a double, but treat as an int. - return (int)convertDouble(x) / (int)convertDouble(y); - } - - public static object mod(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return intX % intY; - // Still allow passing a double, but treat as an int. - return (int)convertDouble(x) % (int)convertDouble(y); - } - - public static object pow(object x, object y) - { - return Math.Pow(YP.convertDouble(x), YP.convertDouble(y)); - } - - public static object bitwiseShiftRight(object x, object y) - { - return YP.convertInt(x) >> YP.convertInt(y); - } - - public static object bitwiseShiftLeft(object x, object y) - { - return YP.convertInt(x) << YP.convertInt(y); - } - - public static object bitwiseAnd(object x, object y) - { - return YP.convertInt(x) & YP.convertInt(y); - } - - public static object bitwiseOr(object x, object y) - { - return YP.convertInt(x) | YP.convertInt(y); - } - - public static object min(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return Math.Min(intX, intY); - return Math.Min(convertDouble(x), convertDouble(y)); - } - - public static object max(object x, object y) - { - int intX, intY; - if (getInt(x, out intX) && getInt(y, out intY)) - return Math.Max(intX, intY); - return Math.Max(convertDouble(x), convertDouble(y)); - } - - public static IEnumerable copy_term(object inTerm, object outTerm) - { - return YP.unify(outTerm, YP.makeCopy(inTerm, new Variable.CopyStore())); - } - - public static void addUniqueVariables(object term, List variableSet) - { - term = YP.getValue(term); - if (term is IUnifiable) - ((IUnifiable)term).addUniqueVariables(variableSet); - } - - public static object makeCopy(object term, Variable.CopyStore copyStore) - { - term = YP.getValue(term); - if (term is IUnifiable) - return ((IUnifiable)term).makeCopy(copyStore); - else - // term is a "normal" type. Assume it is ground. - return term; - } - - /// - /// Sort the array in place according to termLessThan. This does not remove duplicates - /// - /// - public static void sortArray(object[] array) - { - Array.Sort(array, YP.compareTerms); - } - - /// - /// Sort the array in place according to termLessThan. This does not remove duplicates - /// - /// - public static void sortArray(List array) - { - array.Sort(YP.compareTerms); - } - - /// - /// Sort List according to termLessThan, remove duplicates and unify with Sorted. - /// - /// - /// - /// - public static IEnumerable sort(object List, object Sorted) - { - object[] array = ListPair.toArray(List); - if (array == null) - return YP.fail(); - if (array.Length > 1) - sortArray(array); - return YP.unify(Sorted, ListPair.makeWithoutRepeatedTerms(array)); - } - - /// - /// Use YP.unify to unify each of the elements of the two arrays, and yield - /// once if they all unify. - /// - /// - /// - /// - public static IEnumerable unifyArrays(object[] array1, object[] array2) - { - if (array1.Length != array2.Length) - yield break; - - IEnumerator[] iterators = new IEnumerator[array1.Length]; - bool gotMatch = true; - int nIterators = 0; - // Try to bind all the arguments. - for (int i = 0; i < array1.Length; ++i) - { - IEnumerator iterator = YP.unify(array1[i], array2[i]).GetEnumerator(); - iterators[nIterators++] = iterator; - // MoveNext() is true if YP.unify succeeds. - if (!iterator.MoveNext()) - { - gotMatch = false; - break; - } - } - int z = 0; - try - { - if (gotMatch) - yield return false; - } - finally - { - // Manually finalize all the iterators. - for (z = 0; z < nIterators; ++z) - iterators[z].Dispose(); - } - } - - /// - /// Return an iterator (which you can use in a for-in loop) which does - /// zero iterations. This returns a pre-existing iterator which is - /// more efficient than letting the compiler generate a new one. - /// - /// - public static IEnumerable fail() - { - return _fail; - } - - /// - /// Return an iterator (which you can use in a for-in loop) which does - /// one iteration. This returns a pre-existing iterator which is - /// more efficient than letting the compiler generate a new one. - /// - /// - public static IEnumerable succeed() - { - return new Succeed(); - } - - /// - /// Return an iterator (which you can use in a for-in loop) which repeats - /// indefinitely. This returns a pre-existing iterator which is - /// more efficient than letting the compiler generate a new one. - /// - /// - public static IEnumerable repeat() - { - return _repeat; - } - - // disable warning on l1, don't see how we can - // code this differently - #pragma warning disable 0168, 0219 - public static IEnumerable univ(object Term, object List) - { - Term = YP.getValue(Term); - List = YP.getValue(List); - - if (nonvar(Term)) - return YP.unify(new ListPair - (getFunctorName(Term), ListPair.make(getFunctorArgs(Term))), List); - - Variable Name = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l1 in new ListPair(Name, ArgList).unify(List)) - { - object[] args = ListPair.toArray(ArgList); - if (args == null) - throw new PrologException - (new Functor2("type_error", Atom.a("list"), ArgList), - "Expected a list. Got: " + ArgList.getValue()); - if (args.Length == 0) - // Return the Name, even if it is not an Atom. - return YP.unify(Term, Name); - if (args.Length > MAX_ARITY) - throw new PrologException - (new Functor1("representation_error", Atom.a("max_arity")), - "Functor arity " + args.Length + " may not be greater than " + MAX_ARITY); - if (!atom(Name)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Name), - "Expected an atom. Got: " + Name.getValue()); - - return YP.unify(Term, Functor.make((Atom)YP.getValue(Name), args)); - } - - return YP.fail(); - } - - public static IEnumerable functor(object Term, object FunctorName, object Arity) - { - Term = YP.getValue(Term); - FunctorName = YP.getValue(FunctorName); - Arity = YP.getValue(Arity); - - if (Term is Variable) - { - if (FunctorName is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 2 FunctorName is an unbound variable"); - if (Arity is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 3 Arity is an unbound variable"); - if (!(Arity is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), Arity), "Arity is not an integer"); - if (!YP.atomic(FunctorName)) - throw new PrologException - (new Functor2("type_error", Atom.a("atomic"), FunctorName), "FunctorName is not atomic"); - - if ((int)Arity < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), Arity), - "Arity may not be less than zero"); - else if ((int)Arity == 0) - { - // Just unify Term with the atomic FunctorName. - foreach (bool l1 in YP.unify(Term, FunctorName)) - yield return false; - } - else - { - if ((int)Arity > MAX_ARITY) - throw new PrologException - (new Functor1("representation_error", Atom.a("max_arity")), - "Functor arity " + Arity + " may not be greater than " + MAX_ARITY); - if (!(FunctorName is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), FunctorName), "FunctorName is not an atom"); - // Construct a functor with unbound variables. - object[] args = new object[(int)Arity]; - for (int i = 0; i < args.Length; ++i) - args[i] = new Variable(); - foreach (bool l1 in YP.unify(Term, Functor.make((Atom)FunctorName, args))) - yield return false; - } - } - else - { - foreach (bool l1 in YP.unify(FunctorName, getFunctorName(Term))) - { - foreach (bool l2 in YP.unify(Arity, getFunctorArgs(Term).Length)) - yield return false; - } - } - } - - public static IEnumerable arg(object ArgNumber, object Term, object Value) - { - if (var(ArgNumber)) - throw new PrologException(Atom.a("instantiation_error"), "Arg 1 ArgNumber is an unbound variable"); - int argNumberInt; - if (!getInt(ArgNumber, out argNumberInt)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), ArgNumber), "Arg 1 ArgNumber must be integer"); - if (argNumberInt < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), argNumberInt), - "ArgNumber may not be less than zero"); - - if (YP.var(Term)) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 2 Term is an unbound variable"); - if (!YP.compound(Term)) - throw new PrologException - (new Functor2("type_error", Atom.a("compound"), Term), "Arg 2 Term must be compound"); - - object[] termArgs = YP.getFunctorArgs(Term); - // Silently fail if argNumberInt is out of range. - if (argNumberInt >= 1 && argNumberInt <= termArgs.Length) - { - // The first ArgNumber is at 1, not 0. - foreach (bool l1 in YP.unify(Value, termArgs[argNumberInt - 1])) - yield return false; - } - } - - public static bool termEqual(object Term1, object Term2) - { - Term1 = YP.getValue(Term1); - if (Term1 is IUnifiable) - return ((IUnifiable)Term1).termEqual(Term2); - return Term1.Equals(YP.getValue(Term2)); - } - - public static bool termNotEqual(object Term1, object Term2) - { - return !termEqual(Term1, Term2); - } - - public static bool termLessThan(object Term1, object Term2) - { - Term1 = YP.getValue(Term1); - Term2 = YP.getValue(Term2); - int term1TypeCode = getTypeCode(Term1); - int term2TypeCode = getTypeCode(Term2); - if (term1TypeCode != term2TypeCode) - return term1TypeCode < term2TypeCode; - - // The terms are the same type code. - if (term1TypeCode == -2) - { - // Variable. - // We always check for equality first because we want to be sure - // that less than returns false if the terms are equal, in - // case that the less than check really behaves like less than or equal. - if ((Variable)Term1 != (Variable)Term2) - // The hash code should be unique to a Variable object. - return Term1.GetHashCode() < Term2.GetHashCode(); - return false; - } - if (term1TypeCode == 0) - return ((Atom)Term1)._name.CompareTo(((Atom)Term2)._name) < 0; - if (term1TypeCode == 1) - return ((Functor1)Term1).lessThan((Functor1)Term2); - if (term1TypeCode == 2) - return ((Functor2)Term1).lessThan((Functor2)Term2); - if (term1TypeCode == 3) - return ((Functor3)Term1).lessThan((Functor3)Term2); - if (term1TypeCode == 4) - return ((Functor)Term1).lessThan((Functor)Term2); - - // Type code is -1 for general objects. First compare their type names. - // Note that this puts Double before Int32 as required by ISO Prolog. - string term1TypeName = Term1.GetType().ToString(); - string term2TypeName = Term2.GetType().ToString(); - if (term1TypeName != term2TypeName) - return term1TypeName.CompareTo(term2TypeName) < 0; - - // The terms are the same type name. - if (Term1 is int) - return (int)Term1 < (int)Term2; - else if (Term1 is double) - return (double)Term1 < (double)Term2; - else if (Term1 is DateTime) - return (DateTime)Term1 < (DateTime)Term2; - else if (Term1 is String) - return ((String)Term1).CompareTo((String)Term2) < 0; - // Debug: Should we try arrays, etc.? - - if (!Term1.Equals(Term2)) - // Could be equal or greater than. - return Term1.GetHashCode() < Term2.GetHashCode(); - return false; - } - - /// - /// Type code is -2 if term is a Variable, 0 if it is an Atom, - /// 1 if it is a Functor1, 2 if it is a Functor2, 3 if it is a Functor3, - /// 4 if it is Functor. - /// Otherwise, type code is -1. - /// This does not call YP.getValue(term). - /// - /// - /// - private static int getTypeCode(object term) - { - if (term is Variable) - return -2; - else if (term is Atom) - return 0; - else if (term is Functor1) - return 1; - else if (term is Functor2) - return 2; - else if (term is Functor3) - return 3; - else if (term is Functor) - return 4; - else - return -1; - } - - public static bool termLessThanOrEqual(object Term1, object Term2) - { - if (YP.termEqual(Term1, Term2)) - return true; - return YP.termLessThan(Term1, Term2); - } - - public static bool termGreaterThan(object Term1, object Term2) - { - return !YP.termLessThanOrEqual(Term1, Term2); - } - - public static bool termGreaterThanOrEqual(object Term1, object Term2) - { - // termLessThan should ensure that it returns false if terms are equal, - // so that this would return true. - return !YP.termLessThan(Term1, Term2); - } - - public static int compareTerms(object Term1, object Term2) - { - if (YP.termEqual(Term1, Term2)) - return 0; - else if (YP.termLessThan(Term1, Term2)) - return -1; - else - return 1; - } - - public static bool ground(object Term) - { - Term = YP.getValue(Term); - if (Term is IUnifiable) - return ((IUnifiable)Term).ground(); - return true; - } - - public static IEnumerable current_op - (object Priority, object Specifier, object Operator) - { - if (_operatorTable == null) - { - // Initialize. - _operatorTable = new IndexedAnswers(3); - _operatorTable.addAnswer(new object[] { 1200, Atom.a("xfx"), Atom.a(":-") }); - _operatorTable.addAnswer(new object[] { 1200, Atom.a("xfx"), Atom.a("-->") }); - _operatorTable.addAnswer(new object[] { 1200, Atom.a("fx"), Atom.a(":-") }); - _operatorTable.addAnswer(new object[] { 1200, Atom.a("fx"), Atom.a("?-") }); - _operatorTable.addAnswer(new object[] { 1100, Atom.a("xfy"), Atom.a(";") }); - _operatorTable.addAnswer(new object[] { 1050, Atom.a("xfy"), Atom.a("->") }); - _operatorTable.addAnswer(new object[] { 1000, Atom.a("xfy"), Atom.a(",") }); - _operatorTable.addAnswer(new object[] { 900, Atom.a("fy"), Atom.a("\\+") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("\\=") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("==") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("\\==") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@<") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@=<") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@>") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("@>=") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=..") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("is") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=:=") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=\\=") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("<") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a("=<") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a(">") }); - _operatorTable.addAnswer(new object[] { 700, Atom.a("xfx"), Atom.a(">=") }); - _operatorTable.addAnswer(new object[] { 600, Atom.a("xfy"), Atom.a(":") }); - _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("+") }); - _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("-") }); - _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("/\\") }); - _operatorTable.addAnswer(new object[] { 500, Atom.a("yfx"), Atom.a("\\/") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("*") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("/") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("//") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("rem") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("mod") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a("<<") }); - _operatorTable.addAnswer(new object[] { 400, Atom.a("yfx"), Atom.a(">>") }); - _operatorTable.addAnswer(new object[] { 200, Atom.a("xfx"), Atom.a("**") }); - _operatorTable.addAnswer(new object[] { 200, Atom.a("xfy"), Atom.a("^") }); - _operatorTable.addAnswer(new object[] { 200, Atom.a("fy"), Atom.a("-") }); - _operatorTable.addAnswer(new object[] { 200, Atom.a("fy"), Atom.a("\\") }); - // Debug: This is hacked in to run the Prolog test suite until we implement op/3. - _operatorTable.addAnswer(new object[] { 20, Atom.a("xfx"), Atom.a("<--") }); - } - - return _operatorTable.match(new object[] { Priority, Specifier, Operator }); - } - - public static IEnumerable atom_length(object atom, object Length) - { - atom = YP.getValue(atom); - Length = YP.getValue(Length); - if (atom is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Expected atom(Arg1) but it is an unbound variable"); - if (!(atom is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not an atom"); - if (!(Length is Variable)) - { - if (!(Length is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), Length), "Length must be var or integer"); - if ((int)Length < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), Length), - "Length must not be less than zero"); - } - return YP.unify(Length, ((Atom)atom)._name.Length); - } - - public static IEnumerable atom_concat(object Start, object End, object Whole) - { - // Debug: Should we try to preserve the _declaringClass? - Start = YP.getValue(Start); - End = YP.getValue(End); - Whole = YP.getValue(Whole); - if (Whole is Variable) - { - if (Start is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Start and arg 3 Whole are both var"); - if (End is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 2 End and arg 3 Whole are both var"); - if (!(Start is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Start), "Arg 1 Start is not an atom"); - if (!(End is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), End), "Arg 2 End is not an atom"); - - foreach (bool l1 in YP.unify(Whole, Atom.a(((Atom)Start)._name + ((Atom)End)._name))) - yield return false; - } - else - { - if (!(Whole is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Whole), "Arg 3 Whole is not an atom"); - bool gotStartLength = false; - int startLength = 0; - if (!(Start is Variable)) - { - if (!(Start is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Start), "Arg 1 Start is not var or atom"); - startLength = ((Atom)Start)._name.Length; - gotStartLength = true; - } - - bool gotEndLength = false; - int endLength = 0; - if (!(End is Variable)) - { - if (!(End is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), End), "Arg 2 End is not var or atom"); - endLength = ((Atom)End)._name.Length; - gotEndLength = true; - } - - // We are doing a search through all possible Start and End which concatenate to Whole. - string wholeString = ((Atom)Whole)._name; - for (int i = 0; i <= wholeString.Length; ++i) - { - // If we got either startLength or endLength, we know the lengths have to match so check - // the lengths instead of constructing an Atom to do it. - if (gotStartLength && startLength != i) - continue; - if (gotEndLength && endLength != wholeString.Length - i) - continue; - foreach (bool l1 in YP.unify(Start, Atom.a(wholeString.Substring(0, i)))) - { - foreach (bool l2 in YP.unify(End, Atom.a(wholeString.Substring(i, wholeString.Length - i)))) - yield return false; - } - } - } - } - - public static IEnumerable sub_atom - (object atom, object Before, object Length, object After, object Sub_atom) - { - // Debug: Should we try to preserve the _declaringClass? - atom = YP.getValue(atom); - Before = YP.getValue(Before); - Length = YP.getValue(Length); - After = YP.getValue(After); - Sub_atom = YP.getValue(Sub_atom); - if (atom is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Expected atom(Arg1) but it is an unbound variable"); - if (!(atom is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not an atom"); - if (!(Sub_atom is Variable)) - { - if (!(Sub_atom is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Sub_atom), "Sub_atom is not var or atom"); - } - - bool beforeIsInt = false; - bool lengthIsInt = false; - bool afterIsInt = false; - if (!(Before is Variable)) - { - if (!(Before is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), Before), "Before must be var or integer"); - beforeIsInt = true; - if ((int)Before < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), Before), - "Before must not be less than zero"); - } - if (!(Length is Variable)) - { - if (!(Length is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), Length), "Length must be var or integer"); - lengthIsInt = true; - if ((int)Length < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), Length), - "Length must not be less than zero"); - } - if (!(After is Variable)) - { - if (!(After is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), After), "After must be var or integer"); - afterIsInt = true; - if ((int)After < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), After), - "After must not be less than zero"); - } - - Atom atomAtom = (Atom)atom; - int atomLength = atomAtom._name.Length; - if (beforeIsInt && lengthIsInt) - { - // Special case: the caller is just trying to extract a substring, so do it quickly. - int xAfter = atomLength - (int)Before - (int)Length; - if (xAfter >= 0) - { - foreach (bool l1 in YP.unify(After, xAfter)) - { - foreach (bool l2 in YP.unify - (Sub_atom, Atom.a(atomAtom._name.Substring((int)Before, (int)Length)))) - yield return false; - } - } - } - else if (afterIsInt && lengthIsInt) - { - // Special case: the caller is just trying to extract a substring, so do it quickly. - int xBefore = atomLength - (int)After - (int)Length; - if (xBefore >= 0) - { - foreach (bool l1 in YP.unify(Before, xBefore)) - { - foreach (bool l2 in YP.unify - (Sub_atom, Atom.a(atomAtom._name.Substring(xBefore, (int)Length)))) - yield return false; - } - } - } - else - { - // We are underconstrained and doing a search, so go through all possibilities. - for (int xBefore = 0; xBefore <= atomLength; ++xBefore) - { - foreach (bool l1 in YP.unify(Before, xBefore)) - { - for (int xLength = 0; xLength <= (atomLength - xBefore); ++xLength) - { - foreach (bool l2 in YP.unify(Length, xLength)) - { - foreach (bool l3 in YP.unify(After, atomLength - (xBefore + xLength))) - { - foreach (bool l4 in YP.unify - (Sub_atom, Atom.a(atomAtom._name.Substring(xBefore, xLength)))) - yield return false; - } - } - } - } - } - } - } - - public static IEnumerable atom_chars(object atom, object List) - { - atom = YP.getValue(atom); - List = YP.getValue(List); - - if (atom is Variable) - { - if (List is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Atom and arg 2 List are both unbound variables"); - object[] codeArray = ListPair.toArray(List); - if (codeArray == null) - throw new PrologException - (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list"); - - char[] charArray = new char[codeArray.Length]; - for (int i = 0; i < codeArray.Length; ++i) - { - object listAtom = YP.getValue(codeArray[i]); - if (listAtom is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 2 List has an element which is an unbound variable"); - if (!(listAtom is Atom && ((Atom)listAtom)._name.Length == 1)) - throw new PrologException - (new Functor2("type_error", Atom.a("character"), listAtom), - "Arg 2 List has an element which is not a one character atom"); - charArray[i] = ((Atom)listAtom)._name[0]; - } - return YP.unify(atom, Atom.a(new String(charArray))); - } - else - { - if (!(atom is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not var or atom"); - - string atomString = ((Atom)atom)._name; - object charList = Atom.NIL; - // Start from the back to make the list. - for (int i = atomString.Length - 1; i >= 0; --i) - charList = new ListPair(Atom.a(atomString.Substring(i, 1)), charList); - return YP.unify(List, charList); - } - } - - public static IEnumerable atom_codes(object atom, object List) - { - atom = YP.getValue(atom); - List = YP.getValue(List); - - if (atom is Variable) - { - if (List is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Atom and arg 2 List are both unbound variables"); - object[] codeArray = ListPair.toArray(List); - if (codeArray == null) - throw new PrologException - (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list"); - - char[] charArray = new char[codeArray.Length]; - for (int i = 0; i < codeArray.Length; ++i) - { - int codeInt; - if (!getInt(codeArray[i], out codeInt) || codeInt < 0) - throw new PrologException - (new Functor1("representation_error", Atom.a("character_code")), - "Element of Arg 2 List is not a character code"); - charArray[i] = (char)codeInt; - } - return YP.unify(atom, Atom.a(new String(charArray))); - } - else - { - if (!(atom is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), atom), "Arg 1 Atom is not var or atom"); - - string atomString = ((Atom)atom)._name; - object codeList = Atom.NIL; - // Start from the back to make the list. - for (int i = atomString.Length - 1; i >= 0; --i) - codeList = new ListPair((int)atomString[i], codeList); - return YP.unify(List, codeList); - } - } - - public static IEnumerable number_chars(object Number, object List) - { - Number = YP.getValue(Number); - List = YP.getValue(List); - - if (Number is Variable) - { - if (List is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Number and arg 2 List are both unbound variables"); - object[] codeArray = ListPair.toArray(List); - if (codeArray == null) - throw new PrologException - (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list"); - - char[] charArray = new char[codeArray.Length]; - for (int i = 0; i < codeArray.Length; ++i) - { - object listAtom = YP.getValue(codeArray[i]); - if (listAtom is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 2 List has an element which is an unbound variable"); - if (!(listAtom is Atom && ((Atom)listAtom)._name.Length == 1)) - throw new PrologException - (new Functor2("type_error", Atom.a("character"), listAtom), - "Arg 2 List has an element which is not a one character atom"); - charArray[i] = ((Atom)listAtom)._name[0]; - } - return YP.unify(Number, parseNumberString(charArray)); - } - else - { - string numberString = null; - // Try converting to an int first. - int intNumber; - if (YP.getInt(Number, out intNumber)) - numberString = intNumber.ToString(); - else - { - if (!YP.number(Number)) - throw new PrologException - (new Functor2("type_error", Atom.a("number"), Number), - "Arg 1 Number is not var or number"); - // We just checked, so convertDouble shouldn't throw an exception. - numberString = YP.doubleToString(YP.convertDouble(Number)); - } - - object charList = Atom.NIL; - // Start from the back to make the list. - for (int i = numberString.Length - 1; i >= 0; --i) - charList = new ListPair(Atom.a(numberString.Substring(i, 1)), charList); - return YP.unify(List, charList); - } - } - - public static IEnumerable number_codes(object Number, object List) - { - Number = YP.getValue(Number); - List = YP.getValue(List); - - if (Number is Variable) - { - if (List is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Number and arg 2 List are both unbound variables"); - object[] codeArray = ListPair.toArray(List); - if (codeArray == null) - throw new PrologException - (new Functor2("type_error", Atom.a("list"), List), "Arg 2 List is not a list"); - - char[] charArray = new char[codeArray.Length]; - for (int i = 0; i < codeArray.Length; ++i) - { - int codeInt; - if (!getInt(codeArray[i], out codeInt) || codeInt < 0) - throw new PrologException - (new Functor1("representation_error", Atom.a("character_code")), - "Element of Arg 2 List is not a character code"); - charArray[i] = (char)codeInt; - } - return YP.unify(Number, parseNumberString(charArray)); - } - else - { - string numberString = null; - // Try converting to an int first. - int intNumber; - if (YP.getInt(Number, out intNumber)) - numberString = intNumber.ToString(); - else - { - if (!YP.number(Number)) - throw new PrologException - (new Functor2("type_error", Atom.a("number"), Number), - "Arg 1 Number is not var or number"); - // We just checked, so convertDouble shouldn't throw an exception. - numberString = YP.doubleToString(YP.convertDouble(Number)); - } - - object codeList = Atom.NIL; - // Start from the back to make the list. - for (int i = numberString.Length - 1; i >= 0; --i) - codeList = new ListPair((int)numberString[i], codeList); - return YP.unify(List, codeList); - } - } - - /// - /// Used by number_chars and number_codes. Return the number in charArray or - /// throw an exception if can't parse. - /// - /// - /// - private static object parseNumberString(char[] charArray) - { - string numberString = new String(charArray); - if (charArray.Length == 3 && numberString.StartsWith("0'")) - // This is a char code. - return (int)charArray[2]; - if (numberString.StartsWith("0x")) - { - try - { - return Int32.Parse - (numberString.Substring(2), System.Globalization.NumberStyles.AllowHexSpecifier); - } - catch (FormatException) - { - throw new PrologException - (new Functor1("syntax_error", Atom.a("number_format: " + numberString)), - "Arg 2 List is not a list for a hexadecimal number"); - } - } - // Debug: Is there a way in C# to ask if a string parses as int without throwing an exception? - try - { - // Try an int first. - return Convert.ToInt32(numberString); - } - catch (FormatException) { } - try - { - return Convert.ToDouble(numberString); - } - catch (FormatException) - { - throw new PrologException - (new Functor1("syntax_error", Atom.a("number_format: " + numberString)), - "Arg 2 List is not a list for a number"); - } - } - - public static IEnumerable char_code(object Char, object Code) - { - Char = YP.getValue(Char); - Code = YP.getValue(Code); - - int codeInt = 0; - if (!(Code is Variable)) - { - // Get codeInt now so we type check it whether or not Char is Variable. - if (!getInt(Code, out codeInt)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), Code), - "Arg 2 Code is not var or a character code"); - if (codeInt < 0) - throw new PrologException - (new Functor1("representation_error", Atom.a("character_code")), - "Arg 2 Code is not a character code"); - } - - if (Char is Variable) - { - if (Code is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Char and arg 2 Code are both unbound variables"); - - return YP.unify(Char, Atom.a(new String(new char[] {(char)codeInt}))); - } - else - { - if (!(Char is Atom) || ((Atom)Char)._name.Length != 1) - throw new PrologException - (new Functor2("type_error", Atom.a("character"), Char), - "Arg 1 Char is not var or one-character atom"); - - if (Code is Variable) - return YP.unify(Code, (int)((Atom)Char)._name[0]); - else - // Use codeInt to handle whether Code is supplied as, e.g., 97 or 0'a . - return YP.unify(codeInt, (int)((Atom)Char)._name[0]); - } - } - - /// - /// If term is an Atom or functor type, return its name. - /// Otherwise, return term. - /// - /// - /// - public static object getFunctorName(object term) - { - term = YP.getValue(term); - if (term is Functor1) - return ((Functor1)term)._name; - else if (term is Functor2) - return ((Functor2)term)._name; - else if (term is Functor3) - return ((Functor3)term)._name; - else if (term is Functor) - return ((Functor)term)._name; - else - return term; - } - - /// - /// If term is an Atom or functor type, return an array of its args. - /// Otherwise, return an empty array. - /// - /// - /// - public static object[] getFunctorArgs(object term) - { - term = YP.getValue(term); - if (term is Functor1) - { - Functor1 functor = (Functor1)term; - return new object[] { functor._arg1 }; - } - else if (term is Functor2) - { - Functor2 functor = (Functor2)term; - return new object[] { functor._arg1, functor._arg2 }; - } - else if (term is Functor3) - { - Functor3 functor = (Functor3)term; - return new object[] { functor._arg1, functor._arg2, functor._arg3 }; - } - else if (term is Functor) { - Functor functor = (Functor)term; - return functor._args; - } - else - return new object[0]; - } - - public static bool var(object Term) - { - return YP.getValue(Term) is Variable; - } - - public static bool nonvar(object Term) - { - return !YP.var(Term); - } - - public static bool atom(object Term) - { - return YP.getValue(Term) is Atom; - } - - public static bool integer(object Term) - { - // Debug: Should exhaustively check for all integer types. - return getValue(Term) is int; - } - - // Use isFloat instead of float because it is a reserved keyword. - public static bool isFloat(object Term) - { - // Debug: Should exhaustively check for all float types. - return getValue(Term) is double; - } - - public static bool number(object Term) - { - return YP.integer(Term) || YP.isFloat(Term); - } - - public static bool atomic(object Term) - { - return YP.atom(Term) || YP.number(Term); - } - - public static bool compound(object Term) - { - Term = getValue(Term); - return Term is Functor1 || Term is Functor2 || Term is Functor3 || Term is Functor; - } - - /// - /// If input is a TextReader, use it. If input is an Atom or String, create a StreamReader with the - /// input as the filename. If input is a Prolog list, then read character codes from it. - /// - /// - public static void see(object input) - { - input = YP.getValue(input); - if (input is Variable) - throw new PrologException(Atom.a("instantiation_error"), "Arg is an unbound variable"); - - if (input == null) - { - _inputStream = null; - return; - } - if (input is TextReader) - { - _inputStream = (TextReader)input; - return; - } - else if (input is Atom) - { - _inputStream = new StreamReader(((Atom)input)._name); - return; - } - else if (input is String) - { - _inputStream = new StreamReader((String)input); - return; - } - else if (input is Functor2 && ((Functor2)input)._name == Atom.DOT) - { - _inputStream = new CodeListReader(input); - return; - } - else - throw new PrologException - (new Functor2("domain_error", Atom.a("stream_or_alias"), input), - "Input stream specifier not recognized"); - } - - public static void seen() - { - if (_inputStream == null) - return; - if (_inputStream == Console.In) - return; - _inputStream.Close(); - _inputStream = Console.In; - } - - public static IEnumerable current_input(object Stream) - { - return YP.unify(Stream, _inputStream); - } - - /// - /// If output is a TextWriter, use it. If output is an Atom or a String, create a StreamWriter - /// with the input as the filename. - /// - /// - public static void tell(object output) - { - output = YP.getValue(output); - if (output is Variable) - throw new PrologException(Atom.a("instantiation_error"), "Arg is an unbound variable"); - - if (output == null) - { - _outputStream = null; - return; - } - if (output is TextWriter) - { - _outputStream = (TextWriter)output; - return; - } - else if (output is Atom) - { - _outputStream = new StreamWriter(((Atom)output)._name); - return; - } - else if (output is String) - { - _outputStream = new StreamWriter((String)output); - return; - } - else - throw new PrologException - (new Functor2("domain_error", Atom.a("stream_or_alias"), output), - "Can't open stream for " + output); - } - - public static void told() - { - if (_outputStream == null) - return; - if (_outputStream == Console.Out) - return; - _outputStream.Close(); - _outputStream = Console.Out; - } - - public static IEnumerable current_output(object Stream) - { - return YP.unify(Stream, _outputStream); - } - - public static void write(object x) - { - if (_outputStream == null) - return; - x = YP.getValue(x); - if (x is double) - _outputStream.Write(doubleToString((double)x)); - else - _outputStream.Write(x.ToString()); - } - - /// - /// Format x as a string, making sure that it won't parse as an int later. I.e., for 1.0, don't just - /// use "1" which will parse as an int. - /// - /// - /// - private static string doubleToString(double x) - { - string xString = x.ToString(); - // Debug: Is there a way in C# to ask if a string parses as int without throwing an exception? - try - { - Convert.ToInt32(xString); - // The string will parse as an int, not a double, so re-format so that it does. - // Use float if possible, else exponential if it would be too big. - return x.ToString(x >= 100000.0 ? "E1" : "f1"); - } - catch (FormatException) - { - // Assume it will parse as a double. - } - return xString; - } - - public static void put_code(object x) - { - if (_outputStream == null) - return; - if (var(x)) - throw new PrologException(Atom.a("instantiation_error"), "Arg 1 is an unbound variable"); - int xInt; - if (!getInt(x, out xInt)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), x), "Arg 1 must be integer"); - _outputStream.Write((char)xInt); - } - - public static void nl() - { - if (_outputStream == null) - return; - _outputStream.WriteLine(); - } - - public static IEnumerable get_code(object code) - { - if (_inputStream == null) - return YP.unify(code, -1); - else - return YP.unify(code, _inputStream.Read()); - } - - public static void asserta(object Term, Type declaringClass) - { - assertDynamic(Term, declaringClass, true); - } - - public static void assertz(object Term, Type declaringClass) - { - assertDynamic(Term, declaringClass, false); - } - - public static void assertDynamic(object Term, Type declaringClass, bool prepend) - { - Term = getValue(Term); - if (Term is Variable) - throw new PrologException("instantiation_error", "Term to assert is an unbound variable"); - - Variable.CopyStore copyStore = new Variable.CopyStore(); - object TermCopy = makeCopy(Term, copyStore); - object Head, Body; - if (TermCopy is Functor2 && ((Functor2)TermCopy)._name == Atom.RULE) - { - Head = YP.getValue(((Functor2)TermCopy)._arg1); - Body = YP.getValue(((Functor2)TermCopy)._arg2); - if (Head is Variable) - throw new PrologException("instantiation_error", "Head to assert is an unbound variable"); - if (Body is Variable) - throw new PrologException("instantiation_error", "Body to assert is an unbound variable"); - } - else - { - Head = TermCopy; - Body = Atom.a("true"); - } - - Atom name = getFunctorName(Head) as Atom; - if (name == null) - // name is a non-Atom, such as a number. - throw new PrologException - (new Functor2("type_error", Atom.a("callable"), Head), "Term to assert is not callable"); - object[] args = getFunctorArgs(Head); - if (isSystemPredicate(name, args.Length)) - throw new PrologException - (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"), - new Functor2(Atom.SLASH, name, args.Length)), - "Assert cannot modify static predicate " + name + "/" + args.Length); - - if (copyStore.getNUniqueVariables() == 0 && Body == Atom.a("true")) - { - // This is a fact with no unbound variables - // assertFact and prependFact use IndexedAnswers, so don't we don't need to compile. - if (prepend) - prependFact(name, args); - else - assertFact(name, args); - - return; - } - - IClause clause = YPCompiler.compileAnonymousClause(Head, Body, declaringClass); - // We expect clause to be a ClauseHeadAndBody (from Compiler.compileAnonymousFunction) - // so we can set the Head and Body. - if (clause is ClauseHeadAndBody) - ((ClauseHeadAndBody)clause).setHeadAndBody(Head, Body); - - // Add the clause to the entry in _predicatesStore. - NameArity nameArity = new NameArity(name, args.Length); - List clauses; - if (!_predicatesStore.TryGetValue(nameArity, out clauses)) - // Create an entry for the nameArity. - _predicatesStore[nameArity] = (clauses = new List()); - - if (prepend) - clauses.Insert(0, clause); - else - clauses.Add(clause); - } - - private static bool isSystemPredicate(Atom name, int arity) - { - if (arity == 2 && (name == Atom.a(",") || name == Atom.a(";") || name == Atom.DOT)) - return true; - // Use the same mapping to static predicates in YP as the compiler. - foreach (bool l1 in YPCompiler.functorCallYPFunctionName(name, arity, new Variable())) - return true; - // Debug: Do we need to check if name._module is null? - return false; - } - - /// - /// Assert values at the end of the set of facts for the predicate with the - /// name and with arity values.Length. - /// - /// must be an Atom - /// the array of arguments to the fact predicate. - /// It is an error if an value has an unbound variable. - public static void assertFact(Atom name, object[] values) - { - NameArity nameArity = new NameArity(name, values.Length); - List clauses; - IndexedAnswers indexedAnswers; - if (!_predicatesStore.TryGetValue(nameArity, out clauses)) - { - // Create an IndexedAnswers as the only clause of the predicate. - _predicatesStore[nameArity] = (clauses = new List()); - clauses.Add(indexedAnswers = new IndexedAnswers(values.Length)); - } - else - { - indexedAnswers = null; - if (clauses.Count >= 1) - indexedAnswers = clauses[clauses.Count - 1] as IndexedAnswers; - if (indexedAnswers == null) - // The latest clause is not an IndexedAnswers, so add one. - clauses.Add(indexedAnswers = new IndexedAnswers(values.Length)); - } - - indexedAnswers.addAnswer(values); - } - - /// - /// Assert values, prepending to the front of the set of facts for the predicate with the - /// name and with arity values.Length. - /// - /// must be an Atom - /// the array of arguments to the fact predicate. - /// It is an error if an value has an unbound variable. - public static void prependFact(Atom name, object[] values) - { - NameArity nameArity = new NameArity(name, values.Length); - List clauses; - IndexedAnswers indexedAnswers; - if (!_predicatesStore.TryGetValue(nameArity, out clauses)) - { - // Create an IndexedAnswers as the only clause of the predicate. - _predicatesStore[nameArity] = (clauses = new List()); - clauses.Add(indexedAnswers = new IndexedAnswers(values.Length)); - } - else - { - indexedAnswers = null; - if (clauses.Count >= 1) - indexedAnswers = clauses[0] as IndexedAnswers; - if (indexedAnswers == null) - // The first clause is not an IndexedAnswers, so prepend one. - clauses.Insert(0, indexedAnswers = new IndexedAnswers(values.Length)); - } - - indexedAnswers.prependAnswer(values); - } - - /// - /// Match all clauses of the dynamic predicate with the name and with arity - /// arguments.Length. - /// If the predicate is not defined, return the result of YP.unknownPredicate. - /// - /// must be an Atom - /// an array of arity number of arguments - /// an iterator which you can use in foreach - public static IEnumerable matchDynamic(Atom name, object[] arguments) - { - List clauses; - if (!_predicatesStore.TryGetValue(new NameArity(name, arguments.Length), out clauses)) - return unknownPredicate(name, arguments.Length, - "Undefined dynamic predicate: " + name + "/" + arguments.Length); - - if (clauses.Count == 1) - // Usually there is only one clause, so return it without needing to wrap it in an iterator. - return clauses[0].match(arguments); - else - return matchAllClauses(clauses, arguments); - } - - /// - /// Call match(arguments) for each IClause in clauses. We make this a separate - /// function so that matchDynamic itself does not need to be an iterator object. - /// - /// - /// - /// - private static IEnumerable matchAllClauses(List clauses, object[] arguments) - { - // Debug: If the caller asserts another clause into this same predicate during yield, the iterator - // over clauses will be corrupted. Should we take the time to copy clauses? - foreach (IClause clause in clauses) - { - foreach (bool lastCall in clause.match(arguments)) - { - yield return false; - if (lastCall) - // This happens after a cut in a clause. - yield break; - } - } - } - - /// - /// If _prologFlags["unknown"] is fail then return fail(), else if - /// _prologFlags["unknown"] is warning then write the message to YP.write and - /// return fail(), else throw a PrologException for existence_error. . - /// - /// - /// - /// - /// - public static IEnumerable unknownPredicate(Atom name, int arity, string message) - { - establishPrologFlags(); - - if (_prologFlags["unknown"] == Atom.a("fail")) - return fail(); - else if (_prologFlags["unknown"] == Atom.a("warning")) - { - write(message); - nl(); - return fail(); - } - else - throw new PrologException - (new Functor2 - (Atom.a("existence_error"), Atom.a("procedure"), - new Functor2(Atom.SLASH, name, arity)), message); - } - - /// - /// This is deprecated and just calls matchDynamic. This matches all clauses, - /// not just the ones defined with assertFact. - /// - /// - /// - /// - public static IEnumerable matchFact(Atom name, object[] arguments) - { - return matchDynamic(name, arguments); - } - - public static IEnumerable clause(object Head, object Body) - { - Head = getValue(Head); - Body = getValue(Body); - if (Head is Variable) - throw new PrologException("instantiation_error", "Head is an unbound variable"); - - Atom name = getFunctorName(Head) as Atom; - if (name == null) - // name is a non-Atom, such as a number. - throw new PrologException - (new Functor2("type_error", Atom.a("callable"), Head), "Head is not callable"); - object[] args = getFunctorArgs(Head); - if (isSystemPredicate(name, args.Length)) - throw new PrologException - (new Functor3("permission_error", Atom.a("access"), Atom.a("private_procedure"), - new Functor2(Atom.SLASH, name, args.Length)), - "clause cannot access private predicate " + name + "/" + args.Length); - if (!(Body is Variable) && !(YP.getFunctorName(Body) is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("callable"), Body), "Body is not callable"); - - List clauses; - if (!_predicatesStore.TryGetValue(new NameArity(name, args.Length), out clauses)) - yield break; - // The caller can assert another clause into this same predicate during yield, so we have to - // make a copy of the clauses. - foreach (IClause predicateClause in clauses.ToArray()) - { - foreach (bool l1 in predicateClause.clause(Head, Body)) - yield return false; - } - } - - public static IEnumerable retract(object Term) - { - Term = getValue(Term); - if (Term is Variable) - throw new PrologException("instantiation_error", "Term to retract is an unbound variable"); - - object Head, Body; - if (Term is Functor2 && ((Functor2)Term)._name == Atom.RULE) - { - Head = YP.getValue(((Functor2)Term)._arg1); - Body = YP.getValue(((Functor2)Term)._arg2); - } - else - { - Head = Term; - Body = Atom.a("true"); - } - if (Head is Variable) - throw new PrologException("instantiation_error", "Head is an unbound variable"); - - Atom name = getFunctorName(Head) as Atom; - if (name == null) - // name is a non-Atom, such as a number. - throw new PrologException - (new Functor2("type_error", Atom.a("callable"), Head), "Head is not callable"); - object[] args = getFunctorArgs(Head); - if (isSystemPredicate(name, args.Length)) - throw new PrologException - (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"), - new Functor2(Atom.SLASH, name, args.Length)), - "clause cannot access private predicate " + name + "/" + args.Length); - if (!(Body is Variable) && !(YP.getFunctorName(Body) is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("callable"), Body), "Body is not callable"); - - List clauses; - if (!_predicatesStore.TryGetValue(new NameArity(name, args.Length), out clauses)) - yield break; - // The caller can assert another clause into this same predicate during yield, so we have to - // make a copy of the clauses. - foreach (IClause predicateClause in clauses.ToArray()) - { - if (predicateClause is IndexedAnswers) - { - // IndexedAnswers handles its own retract. Even if it removes all of its - // answers, it is OK to leave it empty as one of the elements in clauses. - foreach (bool l1 in ((IndexedAnswers)predicateClause).retract(Head, Body)) - yield return false; - } - else - { - foreach (bool l1 in predicateClause.clause(Head, Body)) - { - clauses.Remove(predicateClause); - yield return false; - } - } - } - } - - /// - /// This is deprecated for backward compatibility. You should use retractall. - /// - /// must be an Atom - /// an array of arity number of arguments - public static void retractFact(Atom name, object[] arguments) - { - retractall(Functor.make(name, arguments)); - } - - /// - /// Retract all dynamic clauses which unify with Head. If this matches all clauses in a predicate, - /// the predicate is still defined. To completely remove the predicate, see abolish. - /// - /// - public static void retractall(object Head) - { - object name = YP.getFunctorName(Head); - object[] arguments = getFunctorArgs(Head); - if (!(name is Atom)) - return; - NameArity nameArity = new NameArity((Atom)name, arguments.Length); - List clauses; - if (!_predicatesStore.TryGetValue(nameArity, out clauses)) - // Can't find, so ignore. - return; - - foreach (object arg in arguments) - { - if (!YP.var(arg)) - throw new InvalidOperationException - ("Until matching retractall is supported, all arguments must be unbound to retract all clauses"); - } - // Clear all clauses. - _predicatesStore[nameArity] = new List(); - } - - /// - /// If NameSlashArity is var, match with all the dynamic predicates using the - /// Name/Artity form. - /// If NameSlashArity is not var, check if the Name/Arity exists as a static or - /// dynamic predicate. - /// - /// - /// if not null, used to resolve references to the default - /// module Atom.a("") - /// - public static IEnumerable current_predicate(object NameSlashArity, Type declaringClass) - { - NameSlashArity = YP.getValue(NameSlashArity); - // First check if Name and Arity are nonvar so we can do a direct lookup. - if (YP.ground(NameSlashArity)) - { - Functor2 NameArityFunctor = NameSlashArity as Functor2; - if (!(NameArityFunctor != null && NameArityFunctor._name == Atom.SLASH)) - throw new PrologException - (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity), - "Must be a name/arity predicate indicator"); - object name = YP.getValue(NameArityFunctor._arg1); - object arity = YP.getValue(NameArityFunctor._arg2); - if (name is Variable || arity is Variable) - throw new PrologException - ("instantiation_error", "Predicate indicator name or arity is an unbound variable"); - if (!(name is Atom && arity is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity), - "Must be a name/arity predicate indicator"); - if ((int)arity < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity), - "Arity may not be less than zero"); - - if (YPCompiler.isCurrentPredicate((Atom)name, (int)arity, declaringClass)) - // The predicate is defined. - yield return false; - } - else - { - foreach (NameArity key in _predicatesStore.Keys) - { - foreach (bool l1 in YP.unify - (new Functor2(Atom.SLASH, key._name, key._arity), NameSlashArity)) - yield return false; - } - } - } - - /// - /// Return true if the dynamic predicate store has an entry for the predicate - /// with name and arity. - /// - /// - /// - /// - public static bool isDynamicCurrentPredicate(Atom name, int arity) - { - return _predicatesStore.ContainsKey(new NameArity(name, arity)); - } - - public static void abolish(object NameSlashArity) - { - NameSlashArity = YP.getValue(NameSlashArity); - if (NameSlashArity is Variable) - throw new PrologException - ("instantiation_error", "Predicate indicator is an unbound variable"); - Functor2 NameArityFunctor = NameSlashArity as Functor2; - if (!(NameArityFunctor != null && NameArityFunctor._name == Atom.SLASH)) - throw new PrologException - (new Functor2("type_error", Atom.a("predicate_indicator"), NameSlashArity), - "Must be a name/arity predicate indicator"); - object name = YP.getValue(NameArityFunctor._arg1); - object arity = YP.getValue(NameArityFunctor._arg2); - if (name is Variable || arity is Variable) - throw new PrologException - ("instantiation_error", "Predicate indicator name or arity is an unbound variable"); - if (!(name is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), name), - "Predicate indicator name must be an atom"); - if (!(arity is int)) - throw new PrologException - (new Functor2("type_error", Atom.a("integer"), arity), - "Predicate indicator arity must be an integer"); - if ((int)arity < 0) - throw new PrologException - (new Functor2("domain_error", Atom.a("not_less_than_zero"), arity), - "Arity may not be less than zero"); - if ((int)arity > MAX_ARITY) - throw new PrologException - (new Functor1("representation_error", Atom.a("max_arity")), - "Arity may not be greater than " + MAX_ARITY); - - if (isSystemPredicate((Atom)name, (int)arity)) - throw new PrologException - (new Functor3("permission_error", Atom.a("modify"), Atom.a("static_procedure"), - new Functor2(Atom.SLASH, name, arity)), - "Abolish cannot modify static predicate " + name + "/" + arity); - _predicatesStore.Remove(new NameArity((Atom)name, (int)arity)); - } - - /// - /// If Goal is a simple predicate, call YP.getFunctorName(Goal) using arguments from - /// YP.getFunctorArgs(Goal). If not found, this throws a PrologException for existence_error. - /// Otherwise, compile the goal as a single clause predicate and invoke it. - /// - /// - /// if not null, used to resolve references to the default - /// module Atom.a("") - /// - public static IEnumerable getIterator(object Goal, Type declaringClass) - { - Atom name; - object[] args; - while (true) - { - Goal = YP.getValue(Goal); - if (Goal is Variable) - throw new PrologException("instantiation_error", "Goal to call is an unbound variable"); - name = YP.getFunctorName(Goal) as Atom; - if (name == null) - throw new PrologException - (new Functor2("type_error", Atom.a("callable"), Goal), "Goal to call is not callable"); - args = YP.getFunctorArgs(Goal); - if (name == Atom.HAT && args.Length == 2) - // Assume this is called from a bagof operation. Skip the leading qualifiers. - Goal = YP.getValue(((Functor2)Goal)._arg2); - else - break; - } - - IEnumerable simpleIterator = YPCompiler.getSimpleIterator(name, args, declaringClass); - if (simpleIterator != null) - // We don't need to compile since the goal is a simple predicate which we call directly. - return simpleIterator; - - // Compile the goal as a clause. - List variableSetList = new List(); - addUniqueVariables(Goal, variableSetList); - Variable[] variableSet = variableSetList.ToArray(); - - // Use Atom.F since it is ignored. - return YPCompiler.compileAnonymousClause - (Functor.make(Atom.F, variableSet), Goal, declaringClass).match(variableSet); - } - - public static void throwException(object Term) - { - throw new PrologException(Term); - } - /// - /// This must be called by any function that uses YP._prologFlags to make sure - /// the initial defaults are loaded. - /// - private static void establishPrologFlags() - { - if (_prologFlags.Count > 0) - // Already established. - return; - - // List these in the order they appear in the ISO standard. - _prologFlags["bounded"] = Atom.a("true"); - _prologFlags["max_integer"] = Int32.MaxValue; - _prologFlags["min_integer"] = Int32.MinValue; - _prologFlags["integer_rounding_function"] = Atom.a("toward_zero"); - _prologFlags["char_conversion"] = Atom.a("off"); - _prologFlags["debug"] = Atom.a("off"); - _prologFlags["max_arity"] = MAX_ARITY; - _prologFlags["unknown"] = Atom.a("error"); - _prologFlags["double_quotes"] = Atom.a("codes"); - } - - public static IEnumerable current_prolog_flag(object Key, object Value) - { - establishPrologFlags(); - - Key = YP.getValue(Key); - Value = YP.getValue(Value); - - if (Key is Variable) - { - // Bind all key values. - foreach (string key in _prologFlags.Keys) - { - foreach (bool l1 in YP.unify(Key, Atom.a(key))) - { - foreach (bool l2 in YP.unify(Value, _prologFlags[key])) - yield return false; - } - } - } - else - { - if (!(Key is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Key), "Arg 1 Key is not an atom"); - if (!_prologFlags.ContainsKey(((Atom)Key)._name)) - throw new PrologException - (new Functor2("domain_error", Atom.a("prolog_flag"), Key), - "Arg 1 Key is not a recognized flag"); - - foreach (bool l1 in YP.unify(Value, _prologFlags[((Atom)Key)._name])) - yield return false; - } - } - - public static void set_prolog_flag(object Key, object Value) - { - establishPrologFlags(); - - Key = YP.getValue(Key); - Value = YP.getValue(Value); - - if (Key is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Key is an unbound variable"); - if (Value is Variable) - throw new PrologException(Atom.a("instantiation_error"), - "Arg 1 Key is an unbound variable"); - if (!(Key is Atom)) - throw new PrologException - (new Functor2("type_error", Atom.a("atom"), Key), "Arg 1 Key is not an atom"); - - string keyName = ((Atom)Key)._name; - if (!_prologFlags.ContainsKey(keyName)) - throw new PrologException - (new Functor2("domain_error", Atom.a("prolog_flag"), Key), - "Arg 1 Key " + Key + " is not a recognized flag"); - - bool valueIsOK = false; - if (keyName == "char_conversion") - valueIsOK = (Value == _prologFlags[keyName]); - else if (keyName == "debug") - valueIsOK = (Value == _prologFlags[keyName]); - else if (keyName == "unknown") - valueIsOK = (Value == Atom.a("fail") || Value == Atom.a("warning") || - Value == Atom.a("error")); - else if (keyName == "double_quotes") - valueIsOK = (Value == Atom.a("codes") || Value == Atom.a("chars") || - Value == Atom.a("atom")); - else - throw new PrologException - (new Functor3("permission_error", Atom.a("modify"), Atom.a("flag"), Key), - "May not modify Prolog flag " + Key); - - if (!valueIsOK) - throw new PrologException - (new Functor2("domain_error", Atom.a("flag_value"), new Functor2("+", Key, Value)), - "May not set arg 1 Key " + Key + " to arg 2 Value " + Value); - - _prologFlags[keyName] = Value; - } - /// - /// script_event calls hosting script with events as a callback method. - /// - /// - /// - /// - public static IEnumerable script_event(object script_event, object script_params) - { - // string function = ((Atom)YP.getValue(script_event))._name; - object[] array = ListPair.toArray(script_params); - if (array == null) - yield return false; // return; // YP.fail(); - if (array.Length > 1) - { - //m_CmdManager.m_ScriptEngine.m_EventQueManager.AddToScriptQueue - //(localID, itemID, function, array); - // sortArray(array); - } - //return YP.unify(Sorted, ListPair.makeWithoutRepeatedTerms(array)); - yield return false; - } - - /* Non-prolog-ish functions for inline coding */ - public static string regexString(string inData, string inPattern, string presep,string postsep) - { - //string str=cycMessage; - //string strMatch = @"\. \#\$(.*)\)"; - string results = ""; - for (Match m = Regex.Match(inData,inPattern); m.Success; m=m.NextMatch()) - { - //m_log.Debug(m); - results += presep+ m + postsep; - } - return results; - } - - public static string cycComm(object msgobj) - { - string cycInputString = msgobj.ToString(); - string cycOutputString=""; - TcpClient socketForServer; - - try - { - socketForServer = new TcpClient("localHost", 3601); - } - catch - { - m_log.Error("Failed to connect to server at localhost:999"); - return ""; - } - - NetworkStream networkStream = socketForServer.GetStream(); - - System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream); - - System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream); - - try - { - // read the data from the host and display it - - { - - streamWriter.WriteLine(cycInputString); - streamWriter.Flush(); - - cycOutputString = streamReader.ReadLine(); - m_log.Debug("Cycoutput:" + cycOutputString); - //streamWriter.WriteLine("Client Message"); - //m_log.Debug("Client Message"); - streamWriter.Flush(); - } - - } - catch - { - m_log.Error("Exception reading from Server"); - return ""; - } - // tidy up - networkStream.Close(); - return cycOutputString; - - } - //public static void throwException(object Term) - //{ - // throw new PrologException(Term); - //} - /// - /// An enumerator that does zero loops. - /// - private class Fail : IEnumerator, IEnumerable - { - public bool MoveNext() - { - return false; - } - - public IEnumerator GetEnumerator() - { - return (IEnumerator)this; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public bool Current - { - get { return true; } - } - - object IEnumerator.Current - { - get { return true; } - } - - public void Dispose() - { - } - - public void Reset() - { - throw new NotImplementedException(); - } - } - - /// - /// An enumerator that does one iteration. - /// - private class Succeed : IEnumerator, IEnumerable - { - private bool _didIteration = false; - - public bool MoveNext() - { - if (!_didIteration) - { - _didIteration = true; - return true; - } - else - return false; - } - - public IEnumerator GetEnumerator() - { - return (IEnumerator)this; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public bool Current - { - get { return false; } - } - - object IEnumerator.Current - { - get { return false; } - } - - public void Dispose() - { - } - - public void Reset() - { - throw new NotImplementedException(); - } - } - - /// - /// An enumerator that repeats forever. - /// - private class Repeat : IEnumerator, IEnumerable - { - public bool MoveNext() - { - return true; - } - - public IEnumerator GetEnumerator() - { - return (IEnumerator)this; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public bool Current - { - get { return false; } - } - - object IEnumerator.Current - { - get { return false; } - } - - public void Dispose() - { - } - - public void Reset() - { - throw new NotImplementedException(); - } - } - - /// - /// An enumerator that wraps another enumerator in order to catch a PrologException. - /// - public class Catch : IEnumerator, IEnumerable - { - private IEnumerator _enumerator; - private PrologException _exception = null; - - /// - /// Call YP.getIterator(Goal, declaringClass) and save the returned iterator. - /// If getIterator throws an exception, save it the same as MoveNext(). - /// - /// - /// - public Catch(object Goal, Type declaringClass) - { - try - { - _enumerator = getIterator(Goal, declaringClass).GetEnumerator(); - } - catch (PrologException exception) - { - // MoveNext() will check this. - _exception = exception; - } - } - - /// - /// Call _enumerator.MoveNext(). If it throws a PrologException, set _exception - /// and return false. After this returns false, call unifyExceptionOrThrow. - /// - /// - public bool MoveNext() - { - if (_exception != null) - return false; - - try - { - return _enumerator.MoveNext(); - } - catch (PrologException exception) - { - _exception = exception; - return false; - } - } - - /// - /// Call this after MoveNext() returns false to check for an exception. If - /// MoveNext did not get a PrologException, don't yield. - /// Otherwise, unify the exception with Catcher and yield so the caller can - /// do the handler code. However, if can't unify with Catcher then throw the exception. - /// - /// - /// - public IEnumerable unifyExceptionOrThrow(object Catcher) - { - if (_exception != null) - { - bool didUnify = false; - foreach (bool l1 in YP.unify(_exception._term, Catcher)) - { - didUnify = true; - yield return false; - } - if (!didUnify) - throw _exception; - } - } - - public IEnumerator GetEnumerator() - { - return (IEnumerator)this; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public bool Current - { - get { return _enumerator.Current; } - } - - object IEnumerator.Current - { - get { return _enumerator.Current; } - } - - public void Dispose() - { - if (_enumerator != null) - _enumerator.Dispose(); - } - - public void Reset() - { - throw new NotImplementedException(); - } - } - #pragma warning restore 0168, 0219 - /// - /// A ClauseHeadAndBody is used in Compiler.compileAnonymousFunction as a base class - /// in order to implement YP.IClause. After creating the object, you must call setHeadAndBody. - /// - public class ClauseHeadAndBody - { - private object _Head; - private object _Body; - - public void setHeadAndBody(object Head, object Body) - { - _Head = Head; - _Body = Body; - } - - public IEnumerable clause(object Head, object Body) - { - if (_Head == null || _Body == null) - yield break; - - #pragma warning disable 0168, 0219 - foreach (bool l1 in YP.unify(Head, _Head)) - { - foreach (bool l2 in YP.unify(Body, _Body)) - yield return false; - } - #pragma warning restore 0168, 0219 - } - } - - /// - /// CodeListReader extends TextReader and overrides Read to read the next code from - /// the CodeList which is a Prolog list of integer character codes. - /// - public class CodeListReader : TextReader - { - private object _CodeList; - - public CodeListReader(object CodeList) - { - _CodeList = YP.getValue(CodeList); - } - - /// - /// If the head of _CodeList is an integer, return it and advance the list. Otherwise, - /// return -1 for end of file. - /// - /// - public override int Read() - { - Functor2 CodeListPair = _CodeList as Functor2; - int code; - if (!(CodeListPair != null && CodeListPair._name == Atom.DOT && - getInt(CodeListPair._arg1, out code))) - { - _CodeList = Atom.NIL; - return -1; - } - - // Advance. - _CodeList = YP.getValue(CodeListPair._arg2); - return code; - } - } - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YPCompiler.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YPCompiler.cs deleted file mode 100644 index c6a6748..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/YieldProlog/YPCompiler.cs +++ /dev/null @@ -1,6382 +0,0 @@ -/* - * Copyright (C) 2007-2008, Jeff Thompson - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using System.CodeDom.Compiler; -using System.Reflection; - -namespace OpenSim.Region.ScriptEngine.Shared.YieldProlog -{ - public class YPCompiler - { - private class CompilerState - { - public IndexedAnswers _pred = new IndexedAnswers(4); - public Dictionary _moduleForNameArity = new Dictionary(); - public int _gensymCounter; - public bool _useFinalCutCode; - public Variable _finalCutCode; - public bool _codeUsesYield; - public Atom _determinism; - // a list of '='(Name, Variable) - public List _variableNames; - - // Make these static functions that explicitly take the State so Prolog can call it. - - /// - /// Make a new CompilerState and bind it to State. - /// - /// - /// - public static IEnumerable make(object State) - { - return YP.unify(State, new CompilerState()); - } - - public static void assertPred(object State, object Pred, object Determinism) - { - State = YP.getValue(State); - object functorName = YP.getFunctorName(Pred); - object[] functorArgs = YP.getFunctorArgs(Pred); - // Debug: Should check if it's already asserted and is the same. - ((CompilerState)State)._pred.addAnswer - (new object[] { functorName, functorArgs.Length, Pred, YP.getValue(Determinism) }); - } - - public static void assertModuleForNameArity(object State, object Name, object Arity, object Module) - { - State = YP.getValue(State); - Name = YP.getValue(Name); - Arity = YP.getValue(Arity); - Module = YP.getValue(Module); - // If the Module Atom comes from the parser, it always has null _declaringClass. - if (Module is Atom && ((Atom)Module)._module == null && Name is Atom && Arity is int) - // Replace a previous entry if it exists. - ((CompilerState)State)._moduleForNameArity[new YP.NameArity((Atom)Name, (int)Arity)] = - (Atom)Module; - } - - public static void startFunction(object State, object Head) - { - State = YP.getValue(State); - ((CompilerState)State)._gensymCounter = 0; - ((CompilerState)State)._useFinalCutCode = false; - ((CompilerState)State)._finalCutCode = new Variable(); - ((CompilerState)State)._codeUsesYield = false; - if (CompilerState.isDetNoneOut(State, Head)) - ((CompilerState)State)._determinism = Atom.a("detNoneOut"); - else if (CompilerState.isSemidetNoneOut(State, Head)) - ((CompilerState)State)._determinism = Atom.a("semidetNoneOut"); - else - ((CompilerState)State)._determinism = Atom.a("nondet"); - } - - public static void setCodeUsesYield(object State) - { - State = YP.getValue(State); - ((CompilerState)State)._codeUsesYield = true; - } - - public static bool codeUsesYield(object State) - { - State = YP.getValue(State); - return ((CompilerState)State)._codeUsesYield; - } - - public static bool determinismEquals(object State, object Term) - { - State = YP.getValue(State); - return YP.termEqual(((CompilerState)State)._determinism, Term); - } - - /// - /// Set _variableNames to a new list of (Name = Variable) for each unique variable in rule. - /// If the variable is in variableNameSuggestions, use it, otherwise use x1, x2, etc. - /// - /// - /// - /// - public static void newVariableNames(object State, object Rule, object VariableNameSuggestions) - { - State = YP.getValue(State); - List variablesSet = new List(); - YP.addUniqueVariables(Rule, variablesSet); - - ((CompilerState)State)._variableNames = new List(); - int xCounter = 0; - foreach (Variable variable in variablesSet) - ((CompilerState)State)._variableNames.Add - (new Functor2(Atom.a("="), makeVariableName(variable, VariableNameSuggestions, ++xCounter), - variable)); - } - - private static object makeVariableName(object variable, object variableNameSuggestions, int xCounter) - { - // Debug: should require named variables to start with _ or capital. Should - // check for duplicates and clashes with keywords. - for (object element = YP.getValue(variableNameSuggestions); - element is Functor2 && ((Functor2)element)._name == Atom.DOT; - element = YP.getValue(((Functor2)element)._arg2)) - { - object suggestionPair = YP.getValue(((Functor2)element)._arg1); - if (sameVariable(variable, ((Functor2)suggestionPair)._arg2)) - { - Atom suggestion = (Atom)YP.getValue(((Functor2)suggestionPair)._arg1); - if (suggestion.Equals(Atom.a("Atom"))) - suggestion = Atom.a("Atom_1"); - if (suggestion.Equals(Atom.a("Variable"))) - suggestion = Atom.a("Variable_1"); - if (suggestion.Equals(Atom.a("Functor"))) - suggestion = Atom.a("Functor_1"); - return suggestion; - } - } - - return Atom.a("x" + xCounter); - } - - /// - /// Unify Result with the name assigned by CompilerState.newVariableNames in State._variableNames - /// for variable. - /// - /// a Variable - /// - /// the assigned Name - public static IEnumerable getVariableName(object State, object variable, object Result) - { - State = YP.getValue(State); - foreach (object variableInfo in ((CompilerState)State)._variableNames) - { - if (variableInfo is Functor2 && ((Functor2)variableInfo)._name.Equals(Atom.a("="))) - { - if (sameVariable(variable, ((Functor2)variableInfo)._arg2)) - return YP.unify(Result, ((Functor2)variableInfo)._arg1); - } - } - - // We set up names for all unique variables, so this should never happen. - throw new PrologException(Atom.a("Can't find entry in _variableNames")); - } - - public static IEnumerable variableNamesList(object State, object VariableNamesList) - { - State = YP.getValue(State); - return YP.unify(VariableNamesList, ListPair.make(((CompilerState)State)._variableNames)); - } - - public static IEnumerable gensym(object State, object Base, object Symbol) - { - State = YP.getValue(State); - return YP.unify(Symbol, Atom.a(Base.ToString() + ++((CompilerState)State)._gensymCounter)); - } - - // disable warning on l1, don't see how we can - // code this differently - #pragma warning disable 0168, 0164, 0162, 0219 - public static bool isDetNoneOut(object State, object Term) - { - State = YP.getValue(State); - object functorName = YP.getFunctorName(Term); - object[] functorArgs = YP.getFunctorArgs(Term); - - Variable pred = new Variable(); - foreach (bool l1 in ((CompilerState)State)._pred.match - (new object[] { functorName, functorArgs.Length, pred, Atom.a("det") })) - { - if (CompilerState.isNoneOut(YP.getFunctorArgs(pred.getValue()))) - { - return true; - } - } - - return false; - } - - public static bool isSemidetNoneOut(object State, object Term) - { - State = YP.getValue(State); - object functorName = YP.getFunctorName(Term); - object[] functorArgs = YP.getFunctorArgs(Term); - - Variable pred = new Variable(); - foreach (bool l1 in ((CompilerState)State)._pred.match - (new object[] { functorName, functorArgs.Length, pred, Atom.a("semidet") })) - { - if (CompilerState.isNoneOut(YP.getFunctorArgs(pred.getValue()))) - { - return true; - } - } - - return false; - } - #pragma warning restore 0168, 0164, 0162, 0219 - - /// - /// Return false if any of args is out, otherwise true. - /// args is an array of ::(Type,Mode) where Mode is in or out. - /// - /// - /// - private static bool isNoneOut(object[] args) - { - foreach (object arg in args) - { - if (arg is Functor2 && ((Functor2)arg)._name == Atom.a("::") && - ((Functor2)arg)._arg2 == Atom.a("out")) - return false; - } - return true; - } - - public static bool nameArityHasModule(object State, object Name, object Arity, object Module) - { - State = YP.getValue(State); - Name = YP.getValue(Name); - Arity = YP.getValue(Arity); - Module = YP.getValue(Module); - if (Name is Atom && Arity is int) - { - Atom FoundModule; - if (!((CompilerState)State)._moduleForNameArity.TryGetValue - (new YP.NameArity((Atom)Name, (int)Arity), out FoundModule)) - return false; - return FoundModule == Module; - } - return false; - } - } - - // disable warning on l1, don't see how we can - // code this differently - #pragma warning disable 0168, 0219,0164,0162 - - /// - /// Use makeFunctionPseudoCode, convertFunctionCSharp and compileAnonymousFunction - /// to return an anonymous YP.IClause for the Head and Body of a rule clause. - /// - /// a prolog term such as new Functor2("test1", X, Y). - /// Note that the name of the head is ignored. - /// - /// a prolog term such as - /// new Functor2(",", new Functor1(Atom.a("test2", Atom.a("")), X), - /// new Functor2("=", Y, X)). - /// This may not be null. (For a head-only clause, set the Body to Atom.a("true"). - /// - /// if not null, the code is compiled as a subclass of this class - /// to resolve references to the default module Atom.a("") - /// a new YP.IClause object on which you can call match(object[] args) where - /// args length is the arity of the Head - public static YP.IClause compileAnonymousClause(object Head, object Body, Type declaringClass) - { - object[] args = YP.getFunctorArgs(Head); - // compileAnonymousFunction wants "function". - object Rule = new Functor2(Atom.RULE, Functor.make("function", args), Body); - object RuleList = ListPair.make(new Functor2(Atom.F, Rule, Atom.NIL)); - - StringWriter functionCode = new StringWriter(); - Variable SaveOutputStream = new Variable(); - foreach (bool l1 in YP.current_output(SaveOutputStream)) - { - try - { - YP.tell(functionCode); - Variable PseudoCode = new Variable(); - foreach (bool l2 in makeFunctionPseudoCode(RuleList, PseudoCode)) - { - if (YP.termEqual(PseudoCode, Atom.a("getDeclaringClass"))) - // Ignore getDeclaringClass since we have access to the one passed in. - continue; - - convertFunctionCSharp(PseudoCode); - } - YP.told(); - } - finally - { - // Restore after calling tell. - YP.tell(SaveOutputStream.getValue()); - } - } - return YPCompiler.compileAnonymousFunction - (functionCode.ToString(), args.Length, declaringClass); - } - - /// - /// Use CodeDomProvider to compile the functionCode and return a YP.ClauseHeadAndBody - /// which implements YP.IClause. - /// The function name must be "function" and have nArgs arguments. - /// - /// the code for the iterator, such as - /// "public static IEnumerable function() { yield return false; }" - /// - /// the number of args in the function - /// if not null, then use the functionCode inside a class which - /// inherits from contextClass, so that references in functionCode to methods in declaringClass don't - /// have to be qualified - /// a new YP.IClause object on which you can call match(object[] args) where - /// args length is nArgs - public static YP.IClause compileAnonymousFunction(string functionCode, int nArgs, Type declaringClass) - { - CompilerParameters parameters = new CompilerParameters(); - // This gets the location of the System assembly. - parameters.ReferencedAssemblies.Add(typeof(System.Int32).Assembly.Location); - // This gets the location of this assembly which also has YieldProlog.YP, etc. - parameters.ReferencedAssemblies.Add(typeof(YPCompiler).Assembly.Location); - if (declaringClass != null) - parameters.ReferencedAssemblies.Add(declaringClass.Assembly.Location); - parameters.GenerateInMemory = true; - - StringBuilder sourceCode = new StringBuilder(); - sourceCode.Append(@" -using System; -using System.Collections.Generic; -using OpenSim.Region.ScriptEngine.Shared.YieldProlog; - -namespace Temporary { - public class Temporary : YP.ClauseHeadAndBody, YP.IClause {"); - if (declaringClass == null) - // We don't extend a class with getDeclaringClass, so define it. - sourceCode.Append(@" - public class Inner { - public static System.Type getDeclaringClass() { return null; } -"); - else - sourceCode.Append(@" - public class Inner : " + declaringClass.FullName + @" { -"); - sourceCode.Append(functionCode); - // Basically, match applies the args to function. - sourceCode.Append(@" - } - public IEnumerable match(object[] args) { - return Inner.function("); - if (nArgs >= 1) - sourceCode.Append("args[0]"); - for (int i = 1; i < nArgs; ++i) - sourceCode.Append(", args[" + i + "]"); - sourceCode.Append(@"); - } - } -} -"); - - CompilerResults results = CodeDomProvider.CreateProvider - ("CSharp").CompileAssemblyFromSource(parameters, sourceCode.ToString()); - if (results.Errors.Count > 0) - throw new Exception("Error evaluating code: " + results.Errors[0]); - - // Return a new Temporary.Temporary object. - return (YP.IClause)results.CompiledAssembly.GetType - ("Temporary.Temporary").GetConstructor(Type.EmptyTypes).Invoke(null); - } - - /// - /// If the functor with name and args can be called directly as determined by - /// functorCallFunctionName, then call it and return its iterator. If the predicate is - /// dynamic and undefined, or if static and the method cannot be found, return - /// the result of YP.unknownPredicate. - /// This returns null if the functor has a special form than needs to be compiled - /// (including ,/2 and ;/2). - /// - /// - /// - /// used to resolve references to the default - /// module Atom.a(""). If a declaringClass is needed to resolve the reference but it is - /// null, this throws a PrologException for existence_error - /// - public static IEnumerable getSimpleIterator(Atom name, object[] args, Type declaringClass) - { - CompilerState state = new CompilerState(); - Variable FunctionName = new Variable(); - foreach (bool l1 in functorCallFunctionName(state, name, args.Length, FunctionName)) - { - Atom functionNameAtom = ((Atom)FunctionName.getValue()); - if (functionNameAtom == Atom.NIL) - // name is for a dynamic predicate. - return YP.matchDynamic(name, args); - - string methodName = functionNameAtom._name; - // Set the default for the method to call. - Type methodClass = declaringClass; - - bool checkMode = false; - if (methodName.StartsWith("YP.")) - { - // Assume we only check mode in calls to standard Prolog predicates in YP. - checkMode = true; - - // Use the method in class YP. - methodName = methodName.Substring(3); - methodClass = typeof(YP); - } - if (methodName.Contains(".")) - // We don't support calling inner classes, etc. - return null; - - if (methodClass == null) - return YP.unknownPredicate - (name, args.Length, - "Cannot find predicate function for: " + name + "/" + args.Length + - " because declaringClass is null. Set declaringClass to the class containing " + - methodName); - try - { - if (checkMode) - { - assertYPPred(state); - object functor = Functor.make(name, args); - if (CompilerState.isDetNoneOut(state, functor)) - { - methodClass.InvokeMember - (methodName, BindingFlags.InvokeMethod, null, null, args); - return YP.succeed(); - } - if (CompilerState.isSemidetNoneOut(state, functor)) - { - if ((bool)methodClass.InvokeMember - (methodName, BindingFlags.InvokeMethod, null, null, args)) - return YP.succeed(); - else - return YP.fail(); - } - - } - return (IEnumerable)methodClass.InvokeMember - (methodName, BindingFlags.InvokeMethod, null, null, args); - } - catch (TargetInvocationException exception) - { - throw exception.InnerException; - } - catch (MissingMethodException) - { - return YP.unknownPredicate - (name, args.Length, - "Cannot find predicate function " + methodName + " for " + name + "/" + args.Length + - " in " + methodClass.FullName); - } - } - - return null; - } - - /// - /// Return true if there is a dynamic or static predicate with name and arity. - /// This returns false for built-in predicates. - /// - /// - /// - /// used to resolve references to the default - /// module Atom.a(""). If a declaringClass is needed to resolve the reference but it is - /// null, return false - /// - public static bool isCurrentPredicate(Atom name, int arity, Type declaringClass) - { - CompilerState state = new CompilerState(); - Variable FunctionName = new Variable(); - foreach (bool l1 in functorCallFunctionName(state, name, arity, FunctionName)) - { - Atom functionNameAtom = ((Atom)FunctionName.getValue()); - if (functionNameAtom == Atom.NIL) - // name is for a dynamic predicate. - return YP.isDynamicCurrentPredicate(name, arity); - - string methodName = functionNameAtom._name; - - if (methodName.StartsWith("YP.")) - // current_predicate/1 should fail for built-ins. - return false; - if (methodName.Contains(".")) - // We don't support calling inner classes, etc. - return false; - if (declaringClass == null) - return false; - - foreach (MemberInfo member in declaringClass.GetMember(methodName)) - { - MethodInfo method = member as MethodInfo; - if (method == null) - continue; - if ((method.Attributes | MethodAttributes.Static) == 0) - // Not a static method. - continue; - if (method.GetParameters().Length == arity) - return true; - } - } - - return false; - } - - // Compiler output follows. - - public class YPInnerClass { } - public static System.Type getDeclaringClass() { return typeof(YPInnerClass).DeclaringType; } - - public static void repeatWrite(object arg1, object N) - { - { - object _Value = arg1; - if (YP.termEqual(N, 0)) - { - return; - } - } - { - object Value = arg1; - Variable NextN = new Variable(); - YP.write(Value); - foreach (bool l2 in YP.unify(NextN, YP.subtract(N, 1))) - { - repeatWrite(Value, NextN); - return; - } - } - } - - public static bool sameVariable(object Variable1, object Variable2) - { - { - if (YP.var(Variable1)) - { - if (YP.var(Variable2)) - { - if (YP.termEqual(Variable1, Variable2)) - { - return true; - } - } - } - } - return false; - } - - public static IEnumerable makeFunctionPseudoCode(object RuleList, object FunctionCode) - { - { - Variable State = new Variable(); - foreach (bool l2 in CompilerState.make(State)) - { - assertYPPred(State); - processCompilerDirectives(RuleList, State); - foreach (bool l3 in YP.unify(FunctionCode, Atom.a("getDeclaringClass"))) - { - yield return false; - } - foreach (bool l3 in makeFunctionPseudoCode3(RuleList, State, FunctionCode)) - { - yield return false; - } - } - } - } - - public static void assertYPPred(object State) - { - { - CompilerState.assertPred(State, Atom.a("nl"), Atom.a("det")); - CompilerState.assertPred(State, new Functor1("write", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("det")); - CompilerState.assertPred(State, new Functor1("put_code", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("det")); - CompilerState.assertPred(State, new Functor1("see", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("det")); - CompilerState.assertPred(State, Atom.a("seen"), Atom.a("det")); - CompilerState.assertPred(State, new Functor1("tell", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("det")); - CompilerState.assertPred(State, Atom.a("told"), Atom.a("det")); - CompilerState.assertPred(State, new Functor1("throw", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("det")); - CompilerState.assertPred(State, new Functor1("abolish", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("det")); - CompilerState.assertPred(State, new Functor1("retractall", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("det")); - CompilerState.assertPred(State, new Functor2("set_prolog_flag", new Functor2("::", Atom.a("univ"), Atom.a("in")), new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("det")); - CompilerState.assertPred(State, new Functor1("var", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - CompilerState.assertPred(State, new Functor1("nonvar", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - CompilerState.assertPred(State, new Functor1("atom", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - CompilerState.assertPred(State, new Functor1("integer", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - CompilerState.assertPred(State, new Functor1("float", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - CompilerState.assertPred(State, new Functor1("number", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - CompilerState.assertPred(State, new Functor1("atomic", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - CompilerState.assertPred(State, new Functor1("compound", new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - CompilerState.assertPred(State, new Functor2("==", new Functor2("::", Atom.a("univ"), Atom.a("in")), new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - CompilerState.assertPred(State, new Functor2("\\==", new Functor2("::", Atom.a("univ"), Atom.a("in")), new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - CompilerState.assertPred(State, new Functor2("@<", new Functor2("::", Atom.a("univ"), Atom.a("in")), new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - CompilerState.assertPred(State, new Functor2("@=<", new Functor2("::", Atom.a("univ"), Atom.a("in")), new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - CompilerState.assertPred(State, new Functor2("@>", new Functor2("::", Atom.a("univ"), Atom.a("in")), new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - CompilerState.assertPred(State, new Functor2("@>=", new Functor2("::", Atom.a("univ"), Atom.a("in")), new Functor2("::", Atom.a("univ"), Atom.a("in"))), Atom.a("semidet")); - return; - } - } - - public static void processCompilerDirectives(object arg1, object arg2) - { - { - object _State = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - return; - } - } - { - object State = arg2; - Variable Pred = new Variable(); - Variable Determinism = new Variable(); - Variable x3 = new Variable(); - Variable RestRules = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("f", new Functor1(":-", new Functor1("pred", new Functor2("is", Pred, Determinism))), x3), RestRules))) - { - CompilerState.assertPred(State, Pred, Determinism); - processCompilerDirectives(RestRules, State); - return; - } - } - { - object State = arg2; - Variable Module = new Variable(); - Variable PredicateList = new Variable(); - Variable x3 = new Variable(); - Variable RestRules = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("f", new Functor1(":-", new Functor2("import", Module, PredicateList)), x3), RestRules))) - { - foreach (bool l3 in importPredicateList(State, Module, PredicateList)) - { - processCompilerDirectives(RestRules, State); - return; - } - } - } - { - object State = arg2; - Variable x1 = new Variable(); - Variable x2 = new Variable(); - Variable RestRules = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("f", new Functor1(":-", x1), x2), RestRules))) - { - processCompilerDirectives(RestRules, State); - return; - } - } - { - object State = arg2; - Variable Head = new Variable(); - Variable _Body = new Variable(); - Variable x3 = new Variable(); - Variable RestRules = new Variable(); - Variable Name = new Variable(); - Variable Arity = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("f", new Functor2(":-", Head, _Body), x3), RestRules))) - { - foreach (bool l3 in YP.functor(Head, Name, Arity)) - { - CompilerState.assertModuleForNameArity(State, Name, Arity, Atom.a("")); - processCompilerDirectives(RestRules, State); - return; - } - } - } - { - object State = arg2; - Variable Fact = new Variable(); - Variable x2 = new Variable(); - Variable RestRules = new Variable(); - Variable Name = new Variable(); - Variable Arity = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("f", Fact, x2), RestRules))) - { - foreach (bool l3 in YP.functor(Fact, Name, Arity)) - { - CompilerState.assertModuleForNameArity(State, Name, Arity, Atom.a("")); - processCompilerDirectives(RestRules, State); - return; - } - } - } - { - object State = arg2; - Variable x1 = new Variable(); - Variable RestRules = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(x1, RestRules))) - { - processCompilerDirectives(RestRules, State); - return; - } - } - } - - public static IEnumerable importPredicateList(object arg1, object arg2, object arg3) - { - { - object _State = arg1; - object _Module = arg2; - foreach (bool l2 in YP.unify(arg3, Atom.NIL)) - { - yield return true; - yield break; - } - } - { - object State = arg1; - object Module = arg2; - Variable Name = new Variable(); - Variable Arity = new Variable(); - Variable Rest = new Variable(); - foreach (bool l2 in YP.unify(arg3, new ListPair(new Functor2("/", Name, Arity), Rest))) - { - CompilerState.assertModuleForNameArity(State, Name, Arity, Module); - foreach (bool l3 in importPredicateList(State, Module, Rest)) - { - yield return true; - yield break; - } - } - } - { - object State = arg1; - object Module = arg2; - Variable x3 = new Variable(); - Variable Rest = new Variable(); - foreach (bool l2 in YP.unify(arg3, new ListPair(x3, Rest))) - { - foreach (bool l3 in importPredicateList(State, Module, Rest)) - { - yield return true; - yield break; - } - } - } - } - - public static IEnumerable makeFunctionPseudoCode3(object RuleList, object State, object FunctionCode) - { - { - Variable SamePredicateRuleList = new Variable(); - Variable RestRules = new Variable(); - foreach (bool l2 in samePredicateRuleList(RuleList, SamePredicateRuleList, RestRules)) - { - if (YP.termNotEqual(SamePredicateRuleList, Atom.NIL)) - { - foreach (bool l4 in compileSamePredicateFunction(SamePredicateRuleList, State, FunctionCode)) - { - yield return false; - } - foreach (bool l4 in makeFunctionPseudoCode3(RestRules, State, FunctionCode)) - { - yield return false; - } - } - } - } - } - - public static IEnumerable compileSamePredicateFunction(object SamePredicateRuleList, object State, object FunctionCode) - { - { - Variable FirstRule = new Variable(); - Variable x5 = new Variable(); - Variable x6 = new Variable(); - Variable x7 = new Variable(); - Variable Head = new Variable(); - Variable x9 = new Variable(); - Variable ArgAssignments = new Variable(); - Variable Calls = new Variable(); - Variable Rule = new Variable(); - Variable VariableNameSuggestions = new Variable(); - Variable ClauseBag = new Variable(); - Variable Name = new Variable(); - Variable ArgsList = new Variable(); - Variable FunctionArgNames = new Variable(); - Variable MergedArgName = new Variable(); - Variable ArgName = new Variable(); - Variable MergedArgNames = new Variable(); - Variable FunctionArgs = new Variable(); - Variable BodyCode = new Variable(); - Variable ReturnType = new Variable(); - Variable BodyWithReturn = new Variable(); - foreach (bool l2 in YP.unify(new ListPair(new Functor2("f", FirstRule, x5), x6), SamePredicateRuleList)) - { - foreach (bool l3 in YP.unify(FirstRule, new Functor1(":-", x7))) - { - goto cutIf1; - } - foreach (bool l3 in YP.unify(new Functor2(":-", Head, x9), FirstRule)) - { - CompilerState.startFunction(State, Head); - FindallAnswers findallAnswers3 = new FindallAnswers(new Functor2("f", ArgAssignments, Calls)); - foreach (bool l4 in member(new Functor2("f", Rule, VariableNameSuggestions), SamePredicateRuleList)) - { - foreach (bool l5 in compileBodyWithHeadBindings(Rule, VariableNameSuggestions, State, ArgAssignments, Calls)) - { - findallAnswers3.add(); - } - } - foreach (bool l4 in findallAnswers3.result(ClauseBag)) - { - foreach (bool l5 in YP.univ(Head, new ListPair(Name, ArgsList))) - { - foreach (bool l6 in getFunctionArgNames(ArgsList, 1, FunctionArgNames)) - { - FindallAnswers findallAnswers4 = new FindallAnswers(MergedArgName); - foreach (bool l7 in member(ArgName, FunctionArgNames)) - { - foreach (bool l8 in argAssignedAll(ArgName, ClauseBag, MergedArgName)) - { - findallAnswers4.add(); - goto cutIf5; - } - foreach (bool l8 in YP.unify(MergedArgName, ArgName)) - { - findallAnswers4.add(); - } - cutIf5: - { } - } - foreach (bool l7 in findallAnswers4.result(MergedArgNames)) - { - foreach (bool l8 in maplist_arg(MergedArgNames, FunctionArgs)) - { - foreach (bool l9 in maplist_compileClause(ClauseBag, MergedArgNames, BodyCode)) - { - if (CompilerState.determinismEquals(State, Atom.a("detNoneOut"))) - { - foreach (bool l11 in YP.unify(ReturnType, Atom.a("void"))) - { - if (CompilerState.determinismEquals(State, Atom.a("semidetNoneOut"))) - { - foreach (bool l13 in append(BodyCode, new ListPair(Atom.a("returnfalse"), Atom.NIL), BodyWithReturn)) - { - foreach (bool l14 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf7; - } - if (CompilerState.determinismEquals(State, Atom.a("detNoneOut"))) - { - foreach (bool l13 in YP.unify(BodyWithReturn, BodyCode)) - { - foreach (bool l14 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf8; - } - if (CompilerState.codeUsesYield(State)) - { - foreach (bool l13 in YP.unify(BodyWithReturn, BodyCode)) - { - foreach (bool l14 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf9; - } - foreach (bool l12 in append(BodyCode, new ListPair(new Functor2("foreach", new Functor2("call", Atom.a("YP.fail"), Atom.NIL), new ListPair(Atom.a("yieldfalse"), Atom.NIL)), Atom.NIL), BodyWithReturn)) - { - foreach (bool l13 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - cutIf9: - cutIf8: - cutIf7: - { } - } - goto cutIf6; - } - if (CompilerState.determinismEquals(State, Atom.a("semidetNoneOut"))) - { - foreach (bool l11 in YP.unify(ReturnType, Atom.a("bool"))) - { - if (CompilerState.determinismEquals(State, Atom.a("semidetNoneOut"))) - { - foreach (bool l13 in append(BodyCode, new ListPair(Atom.a("returnfalse"), Atom.NIL), BodyWithReturn)) - { - foreach (bool l14 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf11; - } - if (CompilerState.determinismEquals(State, Atom.a("detNoneOut"))) - { - foreach (bool l13 in YP.unify(BodyWithReturn, BodyCode)) - { - foreach (bool l14 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf12; - } - if (CompilerState.codeUsesYield(State)) - { - foreach (bool l13 in YP.unify(BodyWithReturn, BodyCode)) - { - foreach (bool l14 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf13; - } - foreach (bool l12 in append(BodyCode, new ListPair(new Functor2("foreach", new Functor2("call", Atom.a("YP.fail"), Atom.NIL), new ListPair(Atom.a("yieldfalse"), Atom.NIL)), Atom.NIL), BodyWithReturn)) - { - foreach (bool l13 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - cutIf13: - cutIf12: - cutIf11: - { } - } - goto cutIf10; - } - foreach (bool l10 in YP.unify(ReturnType, Atom.a("IEnumerable"))) - { - if (CompilerState.determinismEquals(State, Atom.a("semidetNoneOut"))) - { - foreach (bool l12 in append(BodyCode, new ListPair(Atom.a("returnfalse"), Atom.NIL), BodyWithReturn)) - { - foreach (bool l13 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf14; - } - if (CompilerState.determinismEquals(State, Atom.a("detNoneOut"))) - { - foreach (bool l12 in YP.unify(BodyWithReturn, BodyCode)) - { - foreach (bool l13 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf15; - } - if (CompilerState.codeUsesYield(State)) - { - foreach (bool l12 in YP.unify(BodyWithReturn, BodyCode)) - { - foreach (bool l13 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf16; - } - foreach (bool l11 in append(BodyCode, new ListPair(new Functor2("foreach", new Functor2("call", Atom.a("YP.fail"), Atom.NIL), new ListPair(Atom.a("yieldfalse"), Atom.NIL)), Atom.NIL), BodyWithReturn)) - { - foreach (bool l12 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - cutIf16: - cutIf15: - cutIf14: - { } - } - cutIf10: - cutIf6: - { } - } - } - } - } - } - } - goto cutIf2; - } - foreach (bool l3 in YP.unify(Head, FirstRule)) - { - CompilerState.startFunction(State, Head); - FindallAnswers findallAnswers17 = new FindallAnswers(new Functor2("f", ArgAssignments, Calls)); - foreach (bool l4 in member(new Functor2("f", Rule, VariableNameSuggestions), SamePredicateRuleList)) - { - foreach (bool l5 in compileBodyWithHeadBindings(Rule, VariableNameSuggestions, State, ArgAssignments, Calls)) - { - findallAnswers17.add(); - } - } - foreach (bool l4 in findallAnswers17.result(ClauseBag)) - { - foreach (bool l5 in YP.univ(Head, new ListPair(Name, ArgsList))) - { - foreach (bool l6 in getFunctionArgNames(ArgsList, 1, FunctionArgNames)) - { - FindallAnswers findallAnswers18 = new FindallAnswers(MergedArgName); - foreach (bool l7 in member(ArgName, FunctionArgNames)) - { - foreach (bool l8 in argAssignedAll(ArgName, ClauseBag, MergedArgName)) - { - findallAnswers18.add(); - goto cutIf19; - } - foreach (bool l8 in YP.unify(MergedArgName, ArgName)) - { - findallAnswers18.add(); - } - cutIf19: - { } - } - foreach (bool l7 in findallAnswers18.result(MergedArgNames)) - { - foreach (bool l8 in maplist_arg(MergedArgNames, FunctionArgs)) - { - foreach (bool l9 in maplist_compileClause(ClauseBag, MergedArgNames, BodyCode)) - { - if (CompilerState.determinismEquals(State, Atom.a("detNoneOut"))) - { - foreach (bool l11 in YP.unify(ReturnType, Atom.a("void"))) - { - if (CompilerState.determinismEquals(State, Atom.a("semidetNoneOut"))) - { - foreach (bool l13 in append(BodyCode, new ListPair(Atom.a("returnfalse"), Atom.NIL), BodyWithReturn)) - { - foreach (bool l14 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf21; - } - if (CompilerState.determinismEquals(State, Atom.a("detNoneOut"))) - { - foreach (bool l13 in YP.unify(BodyWithReturn, BodyCode)) - { - foreach (bool l14 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf22; - } - if (CompilerState.codeUsesYield(State)) - { - foreach (bool l13 in YP.unify(BodyWithReturn, BodyCode)) - { - foreach (bool l14 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf23; - } - foreach (bool l12 in append(BodyCode, new ListPair(new Functor2("foreach", new Functor2("call", Atom.a("YP.fail"), Atom.NIL), new ListPair(Atom.a("yieldfalse"), Atom.NIL)), Atom.NIL), BodyWithReturn)) - { - foreach (bool l13 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - cutIf23: - cutIf22: - cutIf21: - { } - } - goto cutIf20; - } - if (CompilerState.determinismEquals(State, Atom.a("semidetNoneOut"))) - { - foreach (bool l11 in YP.unify(ReturnType, Atom.a("bool"))) - { - if (CompilerState.determinismEquals(State, Atom.a("semidetNoneOut"))) - { - foreach (bool l13 in append(BodyCode, new ListPair(Atom.a("returnfalse"), Atom.NIL), BodyWithReturn)) - { - foreach (bool l14 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf25; - } - if (CompilerState.determinismEquals(State, Atom.a("detNoneOut"))) - { - foreach (bool l13 in YP.unify(BodyWithReturn, BodyCode)) - { - foreach (bool l14 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf26; - } - if (CompilerState.codeUsesYield(State)) - { - foreach (bool l13 in YP.unify(BodyWithReturn, BodyCode)) - { - foreach (bool l14 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf27; - } - foreach (bool l12 in append(BodyCode, new ListPair(new Functor2("foreach", new Functor2("call", Atom.a("YP.fail"), Atom.NIL), new ListPair(Atom.a("yieldfalse"), Atom.NIL)), Atom.NIL), BodyWithReturn)) - { - foreach (bool l13 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - cutIf27: - cutIf26: - cutIf25: - { } - } - goto cutIf24; - } - foreach (bool l10 in YP.unify(ReturnType, Atom.a("IEnumerable"))) - { - if (CompilerState.determinismEquals(State, Atom.a("semidetNoneOut"))) - { - foreach (bool l12 in append(BodyCode, new ListPair(Atom.a("returnfalse"), Atom.NIL), BodyWithReturn)) - { - foreach (bool l13 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf28; - } - if (CompilerState.determinismEquals(State, Atom.a("detNoneOut"))) - { - foreach (bool l12 in YP.unify(BodyWithReturn, BodyCode)) - { - foreach (bool l13 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf29; - } - if (CompilerState.codeUsesYield(State)) - { - foreach (bool l12 in YP.unify(BodyWithReturn, BodyCode)) - { - foreach (bool l13 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - goto cutIf30; - } - foreach (bool l11 in append(BodyCode, new ListPair(new Functor2("foreach", new Functor2("call", Atom.a("YP.fail"), Atom.NIL), new ListPair(Atom.a("yieldfalse"), Atom.NIL)), Atom.NIL), BodyWithReturn)) - { - foreach (bool l12 in YP.unify(FunctionCode, new Functor("function", new object[] { ReturnType, Name, FunctionArgs, BodyWithReturn }))) - { - yield return false; - } - } - cutIf30: - cutIf29: - cutIf28: - { } - } - cutIf24: - cutIf20: - { } - } - } - } - } - } - } - } - cutIf2: - cutIf1: - { } - } - } - } - - public static IEnumerable samePredicateRuleList(object arg1, object arg2, object arg3) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg2, Atom.NIL)) - { - foreach (bool l4 in YP.unify(arg3, Atom.NIL)) - { - yield return true; - yield break; - } - } - } - } - { - Variable First = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(First, Atom.NIL))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(First, Atom.NIL))) - { - foreach (bool l4 in YP.unify(arg3, Atom.NIL)) - { - yield return true; - yield break; - } - } - } - } - { - object SamePredicateRuleList = arg2; - object RestRules = arg3; - Variable First = new Variable(); - Variable Rest = new Variable(); - Variable FirstRule = new Variable(); - Variable x6 = new Variable(); - Variable SecondRule = new Variable(); - Variable x8 = new Variable(); - Variable x9 = new Variable(); - Variable FirstHead = new Variable(); - Variable x11 = new Variable(); - Variable SecondHead = new Variable(); - Variable x13 = new Variable(); - Variable Name = new Variable(); - Variable Arity = new Variable(); - Variable RestSamePredicates = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(First, Rest))) - { - foreach (bool l3 in YP.unify(new Functor2("f", FirstRule, x6), First)) - { - foreach (bool l4 in YP.unify(new ListPair(new Functor2("f", SecondRule, x8), x9), Rest)) - { - foreach (bool l5 in YP.unify(new Functor2(":-", FirstHead, x11), FirstRule)) - { - foreach (bool l6 in YP.unify(new Functor2(":-", SecondHead, x13), SecondRule)) - { - foreach (bool l7 in YP.functor(FirstHead, Name, Arity)) - { - foreach (bool l8 in YP.functor(SecondHead, Name, Arity)) - { - foreach (bool l9 in samePredicateRuleList(Rest, RestSamePredicates, RestRules)) - { - foreach (bool l10 in YP.unify(SamePredicateRuleList, new ListPair(First, RestSamePredicates))) - { - yield return true; - yield break; - } - } - goto cutIf3; - } - foreach (bool l8 in YP.unify(SamePredicateRuleList, new ListPair(First, Atom.NIL))) - { - foreach (bool l9 in YP.unify(RestRules, Rest)) - { - yield return true; - yield break; - } - } - cutIf3: - { } - } - goto cutIf2; - } - foreach (bool l6 in YP.unify(SecondHead, SecondRule)) - { - foreach (bool l7 in YP.functor(FirstHead, Name, Arity)) - { - foreach (bool l8 in YP.functor(SecondHead, Name, Arity)) - { - foreach (bool l9 in samePredicateRuleList(Rest, RestSamePredicates, RestRules)) - { - foreach (bool l10 in YP.unify(SamePredicateRuleList, new ListPair(First, RestSamePredicates))) - { - yield return true; - yield break; - } - } - goto cutIf4; - } - foreach (bool l8 in YP.unify(SamePredicateRuleList, new ListPair(First, Atom.NIL))) - { - foreach (bool l9 in YP.unify(RestRules, Rest)) - { - yield return true; - yield break; - } - } - cutIf4: - { } - } - } - cutIf2: - goto cutIf1; - } - foreach (bool l5 in YP.unify(FirstHead, FirstRule)) - { - foreach (bool l6 in YP.unify(new Functor2(":-", SecondHead, x13), SecondRule)) - { - foreach (bool l7 in YP.functor(FirstHead, Name, Arity)) - { - foreach (bool l8 in YP.functor(SecondHead, Name, Arity)) - { - foreach (bool l9 in samePredicateRuleList(Rest, RestSamePredicates, RestRules)) - { - foreach (bool l10 in YP.unify(SamePredicateRuleList, new ListPair(First, RestSamePredicates))) - { - yield return true; - yield break; - } - } - goto cutIf6; - } - foreach (bool l8 in YP.unify(SamePredicateRuleList, new ListPair(First, Atom.NIL))) - { - foreach (bool l9 in YP.unify(RestRules, Rest)) - { - yield return true; - yield break; - } - } - cutIf6: - { } - } - goto cutIf5; - } - foreach (bool l6 in YP.unify(SecondHead, SecondRule)) - { - foreach (bool l7 in YP.functor(FirstHead, Name, Arity)) - { - foreach (bool l8 in YP.functor(SecondHead, Name, Arity)) - { - foreach (bool l9 in samePredicateRuleList(Rest, RestSamePredicates, RestRules)) - { - foreach (bool l10 in YP.unify(SamePredicateRuleList, new ListPair(First, RestSamePredicates))) - { - yield return true; - yield break; - } - } - goto cutIf7; - } - foreach (bool l8 in YP.unify(SamePredicateRuleList, new ListPair(First, Atom.NIL))) - { - foreach (bool l9 in YP.unify(RestRules, Rest)) - { - yield return true; - yield break; - } - } - cutIf7: - { } - } - } - cutIf5: - { } - } - cutIf1: - { } - } - } - } - } - } - - public static IEnumerable maplist_compileClause(object arg1, object arg2, object arg3) - { - { - object _MergedArgNames = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg3, Atom.NIL)) - { - yield return true; - yield break; - } - } - } - { - object MergedArgNames = arg2; - Variable ArgAssignments = new Variable(); - Variable Calls = new Variable(); - Variable Rest = new Variable(); - Variable ClauseCode = new Variable(); - Variable RestResults = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("f", ArgAssignments, Calls), Rest))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor1("blockScope", ClauseCode), RestResults))) - { - foreach (bool l4 in prependArgAssignments(ArgAssignments, Calls, MergedArgNames, ClauseCode)) - { - foreach (bool l5 in maplist_compileClause(Rest, MergedArgNames, RestResults)) - { - yield return true; - yield break; - } - } - } - } - } - } - - public static IEnumerable prependArgAssignments(object arg1, object arg2, object arg3, object arg4) - { - { - object _MergedArgNames = arg3; - Variable In = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg2, In)) - { - foreach (bool l4 in YP.unify(arg4, In)) - { - yield return true; - yield break; - } - } - } - } - { - object In = arg2; - object MergedArgNames = arg3; - object ClauseCode = arg4; - Variable VariableName = new Variable(); - Variable ArgName = new Variable(); - Variable RestArgAssignments = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("f", VariableName, ArgName), RestArgAssignments))) - { - foreach (bool l3 in member(VariableName, MergedArgNames)) - { - foreach (bool l4 in prependArgAssignments(RestArgAssignments, In, MergedArgNames, ClauseCode)) - { - yield return true; - yield break; - } - goto cutIf1; - } - foreach (bool l3 in prependArgAssignments(RestArgAssignments, new ListPair(new Functor3("declare", Atom.a("object"), VariableName, new Functor1("var", ArgName)), In), MergedArgNames, ClauseCode)) - { - yield return true; - yield break; - } - cutIf1: - { } - } - } - } - - public static IEnumerable argAssignedAll(object arg1, object arg2, object VariableName) - { - { - object _ArgName = arg1; - foreach (bool l2 in YP.unify(arg2, Atom.NIL)) - { - if (YP.nonvar(VariableName)) - { - yield return true; - yield break; - } - } - } - { - object ArgName = arg1; - Variable ArgAssignments = new Variable(); - Variable _Calls = new Variable(); - Variable RestClauseBag = new Variable(); - foreach (bool l2 in YP.unify(arg2, new ListPair(new Functor2("f", ArgAssignments, _Calls), RestClauseBag))) - { - foreach (bool l3 in member(new Functor2("f", VariableName, ArgName), ArgAssignments)) - { - foreach (bool l4 in argAssignedAll(ArgName, RestClauseBag, VariableName)) - { - yield return false; - } - } - } - } - } - - public static IEnumerable maplist_arg(object arg1, object arg2) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg2, Atom.NIL)) - { - yield return true; - yield break; - } - } - } - { - Variable First = new Variable(); - Variable Rest = new Variable(); - Variable RestResults = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(First, Rest))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(new Functor1("arg", First), RestResults))) - { - foreach (bool l4 in maplist_arg(Rest, RestResults)) - { - yield return true; - yield break; - } - } - } - } - } - - public static IEnumerable getFunctionArgNames(object arg1, object arg2, object arg3) - { - { - object _StartArgNumber = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg3, Atom.NIL)) - { - yield return true; - yield break; - } - } - } - { - object StartArgNumber = arg2; - Variable x1 = new Variable(); - Variable Rest = new Variable(); - Variable ArgName = new Variable(); - Variable RestFunctionArgs = new Variable(); - Variable NumberCodes = new Variable(); - Variable NumberAtom = new Variable(); - Variable NextArgNumber = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(x1, Rest))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(ArgName, RestFunctionArgs))) - { - foreach (bool l4 in YP.number_codes(StartArgNumber, NumberCodes)) - { - foreach (bool l5 in YP.atom_codes(NumberAtom, NumberCodes)) - { - foreach (bool l6 in YP.atom_concat(Atom.a("arg"), NumberAtom, ArgName)) - { - foreach (bool l7 in YP.unify(NextArgNumber, YP.add(StartArgNumber, 1))) - { - foreach (bool l8 in getFunctionArgNames(Rest, NextArgNumber, RestFunctionArgs)) - { - yield return true; - yield break; - } - } - } - } - } - } - } - } - } - - public static IEnumerable compileBodyWithHeadBindings(object Rule, object VariableNameSuggestions, object State, object ArgAssignments, object Calls) - { - { - Variable Head = new Variable(); - Variable Body = new Variable(); - Variable x8 = new Variable(); - Variable HeadArgs = new Variable(); - Variable CompiledHeadArgs = new Variable(); - Variable BodyCode = new Variable(); - Variable VariableNamesList = new Variable(); - Variable ArgUnifications = new Variable(); - foreach (bool l2 in YP.unify(new Functor2(":-", Head, Body), Rule)) - { - CompilerState.newVariableNames(State, Rule, VariableNameSuggestions); - foreach (bool l3 in YP.univ(Head, new ListPair(x8, HeadArgs))) - { - foreach (bool l4 in maplist_compileTerm(HeadArgs, State, CompiledHeadArgs)) - { - foreach (bool l5 in compileRuleBody(Body, State, BodyCode)) - { - foreach (bool l6 in CompilerState.variableNamesList(State, VariableNamesList)) - { - foreach (bool l7 in compileArgUnifications(HeadArgs, CompiledHeadArgs, 1, HeadArgs, BodyCode, ArgUnifications)) - { - foreach (bool l8 in compileDeclarations(VariableNamesList, HeadArgs, Atom.NIL, ArgAssignments, ArgUnifications, Calls)) - { - yield return true; - yield break; - } - } - } - } - } - } - } - } - { - foreach (bool l2 in compileBodyWithHeadBindings(new Functor2(":-", Rule, Atom.a("true")), VariableNameSuggestions, State, ArgAssignments, Calls)) - { - yield return true; - yield break; - } - } - } - - public static IEnumerable compileArgUnifications(object arg1, object arg2, object arg3, object arg4, object arg5, object arg6) - { - { - object x1 = arg2; - object x2 = arg3; - object x3 = arg4; - Variable BodyCode = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg5, BodyCode)) - { - foreach (bool l4 in YP.unify(arg6, BodyCode)) - { - yield return true; - yield break; - } - } - } - } - { - object Index = arg3; - object AllHeadArgs = arg4; - object BodyCode = arg5; - object ArgUnifications = arg6; - Variable HeadArg = new Variable(); - Variable RestHeadArgs = new Variable(); - Variable x3 = new Variable(); - Variable RestCompiledHeadArgs = new Variable(); - Variable _ArgIndex1 = new Variable(); - Variable NextIndex = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(HeadArg, RestHeadArgs))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(x3, RestCompiledHeadArgs))) - { - foreach (bool l4 in getVariableArgIndex1(HeadArg, AllHeadArgs, _ArgIndex1)) - { - foreach (bool l5 in YP.unify(NextIndex, YP.add(Index, 1))) - { - foreach (bool l6 in compileArgUnifications(RestHeadArgs, RestCompiledHeadArgs, NextIndex, AllHeadArgs, BodyCode, ArgUnifications)) - { - yield return true; - yield break; - } - } - } - } - } - } - { - object Index = arg3; - object AllHeadArgs = arg4; - object BodyCode = arg5; - Variable _HeadArg = new Variable(); - Variable RestHeadArgs = new Variable(); - Variable CompiledHeadArg = new Variable(); - Variable RestCompiledHeadArgs = new Variable(); - Variable ArgName = new Variable(); - Variable RestArgUnifications = new Variable(); - Variable NumberCodes = new Variable(); - Variable NumberAtom = new Variable(); - Variable NextIndex = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(_HeadArg, RestHeadArgs))) - { - foreach (bool l3 in YP.unify(arg2, new ListPair(CompiledHeadArg, RestCompiledHeadArgs))) - { - foreach (bool l4 in YP.unify(arg6, new ListPair(new Functor2("foreach", new Functor2("call", Atom.a("YP.unify"), new ListPair(new Functor1("var", ArgName), new ListPair(CompiledHeadArg, Atom.NIL))), RestArgUnifications), Atom.NIL))) - { - foreach (bool l5 in YP.number_codes(Index, NumberCodes)) - { - foreach (bool l6 in YP.atom_codes(NumberAtom, NumberCodes)) - { - foreach (bool l7 in YP.atom_concat(Atom.a("arg"), NumberAtom, ArgName)) - { - foreach (bool l8 in YP.unify(NextIndex, YP.add(Index, 1))) - { - foreach (bool l9 in compileArgUnifications(RestHeadArgs, RestCompiledHeadArgs, NextIndex, AllHeadArgs, BodyCode, RestArgUnifications)) - { - yield return true; - yield break; - } - } - } - } - } - } - } - } - } - } - - public static IEnumerable compileDeclarations(object arg1, object arg2, object arg3, object arg4, object arg5, object arg6) - { - { - object _HeadArgs = arg2; - Variable ArgAssignmentsIn = new Variable(); - Variable DeclarationsIn = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg3, ArgAssignmentsIn)) - { - foreach (bool l4 in YP.unify(arg4, ArgAssignmentsIn)) - { - foreach (bool l5 in YP.unify(arg5, DeclarationsIn)) - { - foreach (bool l6 in YP.unify(arg6, DeclarationsIn)) - { - yield return true; - yield break; - } - } - } - } - } - } - { - object HeadArgs = arg2; - object ArgAssignmentsIn = arg3; - object ArgAssignmentsOut = arg4; - object DeclarationsIn = arg5; - object DeclarationsOut = arg6; - Variable VariableName = new Variable(); - Variable Var = new Variable(); - Variable RestVariableNames = new Variable(); - Variable ArgIndex1 = new Variable(); - Variable NumberCodes = new Variable(); - Variable NumberAtom = new Variable(); - Variable ArgName = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("=", VariableName, Var), RestVariableNames))) - { - foreach (bool l3 in getVariableArgIndex1(Var, HeadArgs, ArgIndex1)) - { - foreach (bool l4 in YP.number_codes(ArgIndex1, NumberCodes)) - { - foreach (bool l5 in YP.atom_codes(NumberAtom, NumberCodes)) - { - foreach (bool l6 in YP.atom_concat(Atom.a("arg"), NumberAtom, ArgName)) - { - foreach (bool l7 in compileDeclarations(RestVariableNames, HeadArgs, new ListPair(new Functor2("f", VariableName, ArgName), ArgAssignmentsIn), ArgAssignmentsOut, DeclarationsIn, DeclarationsOut)) - { - yield return true; - yield break; - } - } - } - } - } - } - } - { - object HeadArgs = arg2; - object ArgAssignmentsIn = arg3; - object ArgAssignmentsOut = arg4; - object DeclarationsIn = arg5; - Variable VariableName = new Variable(); - Variable _Var = new Variable(); - Variable RestVariableNames = new Variable(); - Variable DeclarationsOut = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("=", VariableName, _Var), RestVariableNames))) - { - foreach (bool l3 in YP.unify(arg6, new ListPair(new Functor3("declare", Atom.a("Variable"), VariableName, new Functor2("new", Atom.a("Variable"), Atom.NIL)), DeclarationsOut))) - { - foreach (bool l4 in compileDeclarations(RestVariableNames, HeadArgs, ArgAssignmentsIn, ArgAssignmentsOut, DeclarationsIn, DeclarationsOut)) - { - yield return true; - yield break; - } - } - } - } - } - - public static IEnumerable getVariableArgIndex1(object Var, object arg2, object arg3) - { - { - Variable FirstHeadArgs = new Variable(); - Variable RestHeadArgs = new Variable(); - Variable x4 = new Variable(); - foreach (bool l2 in YP.unify(arg2, new ListPair(FirstHeadArgs, RestHeadArgs))) - { - foreach (bool l3 in YP.unify(arg3, 1)) - { - if (sameVariable(Var, FirstHeadArgs)) - { - foreach (bool l5 in getVariableArgIndex1(Var, RestHeadArgs, x4)) - { - goto cutIf1; - } - yield return false; - cutIf1: - yield break; - } - } - } - } - { - object Index = arg3; - Variable x2 = new Variable(); - Variable RestHeadArgs = new Variable(); - Variable RestIndex = new Variable(); - foreach (bool l2 in YP.unify(arg2, new ListPair(x2, RestHeadArgs))) - { - foreach (bool l3 in getVariableArgIndex1(Var, RestHeadArgs, RestIndex)) - { - foreach (bool l4 in YP.unify(Index, YP.add(1, RestIndex))) - { - yield return true; - yield break; - } - } - } - } - } - - public static IEnumerable compileRuleBody(object arg1, object arg2, object arg3) - { - { - object A = arg1; - object State = arg2; - object PseudoCode = arg3; - if (YP.var(A)) - { - foreach (bool l3 in compileRuleBody(new Functor2(",", new Functor1("call", A), Atom.a("true")), State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - Variable B = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", A, B))) - { - if (YP.var(A)) - { - foreach (bool l4 in compileRuleBody(new Functor2(",", new Functor1("call", A), B), State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - Variable B = new Variable(); - Variable ACode = new Variable(); - Variable BCode = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", A, B))) - { - foreach (bool l3 in compileFunctorCall(A, State, ACode)) - { - if (CompilerState.isDetNoneOut(State, A)) - { - foreach (bool l5 in compileRuleBody(B, State, BCode)) - { - foreach (bool l6 in YP.unify(PseudoCode, new ListPair(ACode, BCode))) - { - yield return true; - yield break; - } - } - } - if (CompilerState.isSemidetNoneOut(State, A)) - { - foreach (bool l5 in compileRuleBody(B, State, BCode)) - { - foreach (bool l6 in YP.unify(PseudoCode, new ListPair(new Functor2("if", ACode, BCode), Atom.NIL))) - { - yield return true; - yield break; - } - } - } - foreach (bool l4 in compileRuleBody(B, State, BCode)) - { - foreach (bool l5 in YP.unify(PseudoCode, new ListPair(new Functor2("foreach", ACode, BCode), Atom.NIL))) - { - yield return true; - yield break; - } - } - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - Variable T = new Variable(); - Variable B = new Variable(); - Variable C = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor2(";", new Functor2("->", A, T), B), C))) - { - foreach (bool l3 in compileRuleBody(new Functor2(";", new Functor2("->", A, new Functor2(",", T, C)), new Functor2(",", B, C)), State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - Variable B = new Variable(); - Variable C = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor2(";", A, B), C))) - { - foreach (bool l3 in compileRuleBody(new Functor2(";", new Functor2(",", A, C), new Functor2(",", B, C)), State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - Variable A = new Variable(); - Variable B = new Variable(); - Variable ACode = new Variable(); - Variable BCode = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor1("\\+", A), B))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("if", new Functor1("not", ACode), BCode), Atom.NIL))) - { - if (CompilerState.isSemidetNoneOut(State, A)) - { - foreach (bool l5 in compileFunctorCall(A, State, ACode)) - { - foreach (bool l6 in compileRuleBody(B, State, BCode)) - { - yield return true; - yield break; - } - } - } - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - Variable B = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor1("\\+", A), B))) - { - foreach (bool l3 in compileRuleBody(new Functor2(",", new Functor2(";", new Functor2("->", A, Atom.a("fail")), Atom.a("true")), B), State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - Variable B = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor1("once", A), B))) - { - foreach (bool l3 in compileRuleBody(new Functor2(",", new Functor2(";", new Functor2("->", A, Atom.a("true")), Atom.a("fail")), B), State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - Variable T = new Variable(); - Variable B = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor2("->", A, T), B))) - { - foreach (bool l3 in compileRuleBody(new Functor2(",", new Functor2(";", new Functor2("->", A, T), Atom.a("fail")), B), State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - Variable B = new Variable(); - Variable C = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor2("\\=", A, B), C))) - { - foreach (bool l3 in compileRuleBody(new Functor2(",", new Functor1("\\+", new Functor2("=", A, B)), C), State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - Variable ACode = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", Atom.a("!"), A))) - { - foreach (bool l3 in compileRuleBody(A, State, ACode)) - { - foreach (bool l4 in append(ACode, new ListPair(Atom.a("yieldbreak"), Atom.NIL), PseudoCode)) - { - yield return true; - yield break; - } - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable Name = new Variable(); - Variable A = new Variable(); - Variable ACode = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor1("$CUTIF", Name), A))) - { - foreach (bool l3 in compileRuleBody(A, State, ACode)) - { - foreach (bool l4 in append(ACode, new ListPair(new Functor1("breakBlock", Name), Atom.NIL), PseudoCode)) - { - yield return true; - yield break; - } - } - } - } - { - object _State = arg2; - Variable x1 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", Atom.a("fail"), x1))) - { - foreach (bool l3 in YP.unify(arg3, Atom.NIL)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", Atom.a("true"), A))) - { - foreach (bool l3 in compileRuleBody(A, State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - Variable A = new Variable(); - Variable Term = new Variable(); - Variable B = new Variable(); - Variable ACode = new Variable(); - Variable TermCode = new Variable(); - Variable BCode = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor2("is", A, Term), B))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("foreach", new Functor2("call", Atom.a("YP.unify"), new ListPair(ACode, new ListPair(TermCode, Atom.NIL))), BCode), Atom.NIL))) - { - foreach (bool l4 in compileTerm(A, State, ACode)) - { - foreach (bool l5 in compileExpression(Term, State, TermCode)) - { - foreach (bool l6 in compileRuleBody(B, State, BCode)) - { - yield return true; - yield break; - } - } - } - } - } - } - { - object State = arg2; - Variable ACode = new Variable(); - Variable B = new Variable(); - Variable BCode = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor1("$DET_NONE_OUT", ACode), B))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(ACode, BCode))) - { - foreach (bool l4 in compileRuleBody(B, State, BCode)) - { - yield return true; - yield break; - } - } - } - } - { - object State = arg2; - Variable A = new Variable(); - Variable B = new Variable(); - Variable FunctionName = new Variable(); - Variable X1Code = new Variable(); - Variable X2Code = new Variable(); - Variable BCode = new Variable(); - Variable Name = new Variable(); - Variable X1 = new Variable(); - Variable X2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", A, B))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("if", new Functor2("call", FunctionName, new ListPair(X1Code, new ListPair(X2Code, Atom.NIL))), BCode), Atom.NIL))) - { - foreach (bool l4 in YP.univ(A, ListPair.make(new object[] { Name, X1, X2 }))) - { - foreach (bool l5 in binaryExpressionConditional(Name, FunctionName)) - { - foreach (bool l6 in compileExpression(X1, State, X1Code)) - { - foreach (bool l7 in compileExpression(X2, State, X2Code)) - { - foreach (bool l8 in compileRuleBody(B, State, BCode)) - { - yield return true; - yield break; - } - } - } - } - } - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable Template = new Variable(); - Variable Goal = new Variable(); - Variable Bag = new Variable(); - Variable B = new Variable(); - Variable TemplateCode = new Variable(); - Variable FindallAnswers = new Variable(); - Variable GoalAndAddCode = new Variable(); - Variable BagCode = new Variable(); - Variable BCode = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor3("findall", Template, Goal, Bag), B))) - { - foreach (bool l3 in compileTerm(Template, State, TemplateCode)) - { - foreach (bool l4 in CompilerState.gensym(State, Atom.a("findallAnswers"), FindallAnswers)) - { - foreach (bool l5 in compileRuleBody(new Functor2(",", Goal, new Functor2(",", new Functor1("$DET_NONE_OUT", new Functor3("callMember", new Functor1("var", FindallAnswers), Atom.a("add"), Atom.NIL)), Atom.a("fail"))), State, GoalAndAddCode)) - { - foreach (bool l6 in compileTerm(Bag, State, BagCode)) - { - foreach (bool l7 in compileRuleBody(B, State, BCode)) - { - foreach (bool l8 in append(new ListPair(new Functor3("declare", Atom.a("FindallAnswers"), FindallAnswers, new Functor2("new", Atom.a("FindallAnswers"), new ListPair(TemplateCode, Atom.NIL))), GoalAndAddCode), new ListPair(new Functor2("foreach", new Functor3("callMember", new Functor1("var", FindallAnswers), Atom.a("result"), new ListPair(BagCode, Atom.NIL)), BCode), Atom.NIL), PseudoCode)) - { - yield return true; - yield break; - } - } - } - } - } - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable Template = new Variable(); - Variable Goal = new Variable(); - Variable Bag = new Variable(); - Variable B = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor3("bagof", Template, Goal, Bag), B))) - { - foreach (bool l3 in compileBagof(Atom.a("result"), Template, Goal, Bag, B, State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable Template = new Variable(); - Variable Goal = new Variable(); - Variable Bag = new Variable(); - Variable B = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor3("setof", Template, Goal, Bag), B))) - { - foreach (bool l3 in compileBagof(Atom.a("resultSet"), Template, Goal, Bag, B, State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - Variable A = new Variable(); - Variable B = new Variable(); - Variable ATermCode = new Variable(); - Variable BCode = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor1("call", A), B))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("foreach", new Functor2("call", Atom.a("YP.getIterator"), new ListPair(ATermCode, new ListPair(new Functor2("call", Atom.a("getDeclaringClass"), Atom.NIL), Atom.NIL))), BCode), Atom.NIL))) - { - foreach (bool l4 in compileTerm(A, State, ATermCode)) - { - foreach (bool l5 in compileRuleBody(B, State, BCode)) - { - yield return true; - yield break; - } - } - } - } - } - { - object State = arg2; - Variable A = new Variable(); - Variable B = new Variable(); - Variable ATermCode = new Variable(); - Variable BCode = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor1("current_predicate", A), B))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("foreach", new Functor2("call", Atom.a("YP.current_predicate"), new ListPair(ATermCode, new ListPair(new Functor2("call", Atom.a("getDeclaringClass"), Atom.NIL), Atom.NIL))), BCode), Atom.NIL))) - { - foreach (bool l4 in compileTerm(A, State, ATermCode)) - { - foreach (bool l5 in compileRuleBody(B, State, BCode)) - { - yield return true; - yield break; - } - } - } - } - } - { - object State = arg2; - Variable A = new Variable(); - Variable B = new Variable(); - Variable ATermCode = new Variable(); - Variable BCode = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor1("asserta", A), B))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("call", Atom.a("YP.asserta"), new ListPair(ATermCode, new ListPair(new Functor2("call", Atom.a("getDeclaringClass"), Atom.NIL), Atom.NIL))), BCode))) - { - foreach (bool l4 in compileTerm(A, State, ATermCode)) - { - foreach (bool l5 in compileRuleBody(B, State, BCode)) - { - yield return true; - yield break; - } - } - } - } - } - { - object State = arg2; - Variable A = new Variable(); - Variable B = new Variable(); - Variable ATermCode = new Variable(); - Variable BCode = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor1("assertz", A), B))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("call", Atom.a("YP.assertz"), new ListPair(ATermCode, new ListPair(new Functor2("call", Atom.a("getDeclaringClass"), Atom.NIL), Atom.NIL))), BCode))) - { - foreach (bool l4 in compileTerm(A, State, ATermCode)) - { - foreach (bool l5 in compileRuleBody(B, State, BCode)) - { - yield return true; - yield break; - } - } - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - Variable B = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor1("assert", A), B))) - { - foreach (bool l3 in compileRuleBody(new Functor2(",", new Functor1("assertz", A), B), State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - Variable Goal = new Variable(); - Variable Catcher = new Variable(); - Variable Handler = new Variable(); - Variable B = new Variable(); - Variable CatchGoal = new Variable(); - Variable GoalTermCode = new Variable(); - Variable BCode = new Variable(); - Variable CatcherTermCode = new Variable(); - Variable HandlerAndBCode = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor3("catch", Goal, Catcher, Handler), B))) - { - foreach (bool l3 in YP.unify(arg3, ListPair.make(new object[] { new Functor3("declare", Atom.a("YP.Catch"), CatchGoal, new Functor2("new", Atom.a("YP.Catch"), new ListPair(GoalTermCode, new ListPair(new Functor2("call", Atom.a("getDeclaringClass"), Atom.NIL), Atom.NIL)))), new Functor2("foreach", new Functor1("var", CatchGoal), BCode), new Functor2("foreach", new Functor3("callMember", new Functor1("var", CatchGoal), Atom.a("unifyExceptionOrThrow"), new ListPair(CatcherTermCode, Atom.NIL)), HandlerAndBCode) }))) - { - foreach (bool l4 in CompilerState.gensym(State, Atom.a("catchGoal"), CatchGoal)) - { - foreach (bool l5 in compileTerm(Goal, State, GoalTermCode)) - { - foreach (bool l6 in compileTerm(Catcher, State, CatcherTermCode)) - { - foreach (bool l7 in compileRuleBody(B, State, BCode)) - { - foreach (bool l8 in compileRuleBody(new Functor2(",", Handler, B), State, HandlerAndBCode)) - { - yield return true; - yield break; - } - } - } - } - } - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - Variable B = new Variable(); - Variable C = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(",", new Functor2(",", A, B), C))) - { - foreach (bool l3 in compileRuleBody(new Functor2(",", A, new Functor2(",", B, C)), State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - Variable B = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(";", A, B))) - { - if (YP.var(A)) - { - foreach (bool l4 in compileRuleBody(new Functor2(";", new Functor1("call", A), B), State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - } - { - object State = arg2; - Variable A = new Variable(); - Variable T = new Variable(); - Variable B = new Variable(); - Variable CutIfLabel = new Variable(); - Variable Code = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(";", new Functor2("->", A, T), B))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor2("breakableBlock", CutIfLabel, Code), Atom.NIL))) - { - foreach (bool l4 in CompilerState.gensym(State, Atom.a("cutIf"), CutIfLabel)) - { - foreach (bool l5 in compileRuleBody(new Functor2(";", new Functor2(",", A, new Functor2(",", new Functor1("$CUTIF", CutIfLabel), T)), B), State, Code)) - { - yield return true; - yield break; - } - } - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable _B = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(";", Atom.a("!"), _B))) - { - foreach (bool l3 in compileRuleBody(Atom.a("!"), State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - object PseudoCode = arg3; - Variable A = new Variable(); - Variable B = new Variable(); - Variable ACode = new Variable(); - Variable BCode = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2(";", A, B))) - { - foreach (bool l3 in compileRuleBody(A, State, ACode)) - { - foreach (bool l4 in compileRuleBody(B, State, BCode)) - { - foreach (bool l5 in append(ACode, BCode, PseudoCode)) - { - yield return true; - yield break; - } - } - } - } - } - { - object State = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.a("!"))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(Atom.a("return"), Atom.NIL))) - { - if (CompilerState.determinismEquals(State, Atom.a("detNoneOut"))) - { - yield return true; - yield break; - } - } - } - } - { - object State = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.a("!"))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(Atom.a("returntrue"), Atom.NIL))) - { - if (CompilerState.determinismEquals(State, Atom.a("semidetNoneOut"))) - { - yield return true; - yield break; - } - } - } - } - { - object State = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.a("!"))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(Atom.a("yieldtrue"), new ListPair(Atom.a("yieldbreak"), Atom.NIL)))) - { - CompilerState.setCodeUsesYield(State); - yield return true; - yield break; - } - } - } - { - object _State = arg2; - Variable Name = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("$CUTIF", Name))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(new Functor1("breakBlock", Name), Atom.NIL))) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.a("true"))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(Atom.a("return"), Atom.NIL))) - { - if (CompilerState.determinismEquals(State, Atom.a("detNoneOut"))) - { - yield return true; - yield break; - } - } - } - } - { - object State = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.a("true"))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(Atom.a("returntrue"), Atom.NIL))) - { - if (CompilerState.determinismEquals(State, Atom.a("semidetNoneOut"))) - { - yield return true; - yield break; - } - } - } - } - { - object State = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.a("true"))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(Atom.a("yieldfalse"), Atom.NIL))) - { - CompilerState.setCodeUsesYield(State); - yield return true; - yield break; - } - } - } - { - object A = arg1; - object State = arg2; - object PseudoCode = arg3; - foreach (bool l2 in compileRuleBody(new Functor2(",", A, Atom.a("true")), State, PseudoCode)) - { - yield return true; - yield break; - } - } - } - - public static IEnumerable compileBagof(object ResultMethod, object Template, object Goal, object Bag, object B, object State, object PseudoCode) - { - { - Variable TemplateCode = new Variable(); - Variable GoalTermCode = new Variable(); - Variable UnqualifiedGoal = new Variable(); - Variable BagofAnswers = new Variable(); - Variable GoalAndAddCode = new Variable(); - Variable BagCode = new Variable(); - Variable BCode = new Variable(); - foreach (bool l2 in compileTerm(Template, State, TemplateCode)) - { - foreach (bool l3 in compileTerm(Goal, State, GoalTermCode)) - { - foreach (bool l4 in unqualifiedGoal(Goal, UnqualifiedGoal)) - { - foreach (bool l5 in CompilerState.gensym(State, Atom.a("bagofAnswers"), BagofAnswers)) - { - foreach (bool l6 in compileRuleBody(new Functor2(",", UnqualifiedGoal, new Functor2(",", new Functor1("$DET_NONE_OUT", new Functor3("callMember", new Functor1("var", BagofAnswers), Atom.a("add"), Atom.NIL)), Atom.a("fail"))), State, GoalAndAddCode)) - { - foreach (bool l7 in compileTerm(Bag, State, BagCode)) - { - foreach (bool l8 in compileRuleBody(B, State, BCode)) - { - foreach (bool l9 in append(new ListPair(new Functor3("declare", Atom.a("BagofAnswers"), BagofAnswers, new Functor2("new", Atom.a("BagofAnswers"), new ListPair(TemplateCode, new ListPair(GoalTermCode, Atom.NIL)))), GoalAndAddCode), new ListPair(new Functor2("foreach", new Functor3("callMember", new Functor1("var", BagofAnswers), ResultMethod, new ListPair(BagCode, Atom.NIL)), BCode), Atom.NIL), PseudoCode)) - { - yield return true; - yield break; - } - } - } - } - } - } - } - } - } - } - - public static IEnumerable unqualifiedGoal(object arg1, object arg2) - { - { - object Goal = arg1; - foreach (bool l2 in YP.unify(arg2, new Functor1("call", Goal))) - { - if (YP.var(Goal)) - { - yield return true; - yield break; - } - } - } - { - object UnqualifiedGoal = arg2; - Variable x1 = new Variable(); - Variable Goal = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("^", x1, Goal))) - { - foreach (bool l3 in unqualifiedGoal(Goal, UnqualifiedGoal)) - { - yield return true; - yield break; - } - } - } - { - Variable UnqualifiedGoal = new Variable(); - foreach (bool l2 in YP.unify(arg1, UnqualifiedGoal)) - { - foreach (bool l3 in YP.unify(arg2, UnqualifiedGoal)) - { - yield return true; - yield break; - } - } - } - } - - public static IEnumerable binaryExpressionConditional(object arg1, object arg2) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.a("=:="))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.equal"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("=\\="))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.notEqual"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a(">"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.greaterThan"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("<"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.lessThan"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a(">="))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.greaterThanOrEqual"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("=<"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.lessThanOrEqual"))) - { - yield return true; - yield break; - } - } - } - } - - public static IEnumerable compileFunctorCall(object Functor_1, object State, object PseudoCode) - { - { - Variable FunctorName = new Variable(); - Variable FunctorArgs = new Variable(); - Variable x6 = new Variable(); - Variable Arity = new Variable(); - Variable FunctionName = new Variable(); - Variable CompiledArgs = new Variable(); - foreach (bool l2 in YP.univ(Functor_1, new ListPair(FunctorName, FunctorArgs))) - { - foreach (bool l3 in YP.functor(Functor_1, x6, Arity)) - { - foreach (bool l4 in functorCallFunctionName(State, FunctorName, Arity, FunctionName)) - { - foreach (bool l5 in maplist_compileTerm(FunctorArgs, State, CompiledArgs)) - { - if (YP.termEqual(FunctionName, Atom.NIL)) - { - foreach (bool l7 in YP.unify(PseudoCode, new Functor2("call", Atom.a("YP.matchDynamic"), new ListPair(new Functor2("call", Atom.a("Atom.a"), new ListPair(new Functor1("object", FunctorName), Atom.NIL)), new ListPair(new Functor1("objectArray", CompiledArgs), Atom.NIL))))) - { - yield return true; - yield break; - } - goto cutIf1; - } - foreach (bool l6 in YP.unify(PseudoCode, new Functor3("functorCall", FunctionName, FunctorArgs, CompiledArgs))) - { - yield return true; - yield break; - } - cutIf1: - { } - } - } - } - } - } - } - - public static IEnumerable functorCallFunctionName(object arg1, object arg2, object arg3, object arg4) - { - { - object _State = arg1; - object Name = arg2; - object Arity = arg3; - object x4 = arg4; - if (functorCallIsSpecialForm(Name, Arity)) - { - yield break; - } - } - { - object x1 = arg1; - object Name = arg2; - object Arity = arg3; - object FunctionName = arg4; - foreach (bool l2 in functorCallYPFunctionName(Name, Arity, FunctionName)) - { - yield return true; - yield break; - } - } - { - object State = arg1; - object Arity = arg3; - Variable Name = new Variable(); - foreach (bool l2 in YP.unify(arg2, Name)) - { - foreach (bool l3 in YP.unify(arg4, Name)) - { - if (CompilerState.nameArityHasModule(State, Name, Arity, Atom.a(""))) - { - yield return true; - yield break; - } - } - } - } - { - object _State = arg1; - object _Arity = arg3; - Variable Name = new Variable(); - foreach (bool l2 in YP.unify(arg2, Name)) - { - foreach (bool l3 in YP.unify(arg4, Name)) - { - foreach (bool l4 in Atom.module(Name, Atom.a(""))) - { - yield return true; - yield break; - } - } - } - } - { - object _State = arg1; - object Name = arg2; - object _Arity = arg3; - foreach (bool l2 in YP.unify(arg4, Atom.NIL)) - { - foreach (bool l3 in Atom.module(Name, Atom.NIL)) - { - yield return true; - yield break; - } - } - } - { - object _State = arg1; - object Name = arg2; - object Arity = arg3; - object x4 = arg4; - Variable Module = new Variable(); - Variable Message = new Variable(); - foreach (bool l2 in Atom.module(Name, Module)) - { - foreach (bool l3 in YP.atom_concat(Atom.a("Not supporting calls to external module: "), Module, Message)) - { - YP.throwException(new Functor2("error", new Functor2("type_error", Atom.a("callable"), new Functor2("/", Name, Arity)), Message)); - yield return true; - yield break; - } - } - } - { - object _State = arg1; - object Name = arg2; - object _Arity = arg3; - object x4 = arg4; - YP.throwException(new Functor2("error", new Functor2("type_error", Atom.a("callable"), Name), Atom.a("Term is not callable"))); - yield return true; - yield break; - } - } - - public static bool functorCallIsSpecialForm(object Name, object Arity) - { - { - Variable x3 = new Variable(); - if (YP.termEqual(Arity, 0)) - { - if (YP.termEqual(Name, Atom.a("!"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("fail"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("true"))) - { - return true; - } - } - if (YP.termEqual(Arity, 1)) - { - if (YP.termEqual(Name, Atom.a("\\+"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("once"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("$CUTIF"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("$DET_NONE_OUT"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("call"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("current_predicate"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("asserta"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("assertz"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("assert"))) - { - return true; - } - } - if (YP.termEqual(Arity, 2)) - { - if (YP.termEqual(Name, Atom.a(";"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a(","))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("->"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("\\="))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("is"))) - { - return true; - } - foreach (bool l3 in binaryExpressionConditional(Name, x3)) - { - return true; - } - } - if (YP.termEqual(Arity, 3)) - { - if (YP.termEqual(Name, Atom.a("findall"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("bagof"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("setof"))) - { - return true; - } - if (YP.termEqual(Name, Atom.a("catch"))) - { - return true; - } - } - } - return false; - } - - public static IEnumerable functorCallYPFunctionName(object arg1, object arg2, object arg3) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.a("="))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.unify"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("=.."))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.univ"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("var"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.var"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("nonvar"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.nonvar"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("arg"))) - { - foreach (bool l3 in YP.unify(arg2, 3)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.arg"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("functor"))) - { - foreach (bool l3 in YP.unify(arg2, 3)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.functor"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("repeat"))) - { - foreach (bool l3 in YP.unify(arg2, 0)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.repeat"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("get_code"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.get_code"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("current_op"))) - { - foreach (bool l3 in YP.unify(arg2, 3)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.current_op"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("atom_length"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.atom_length"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("atom_concat"))) - { - foreach (bool l3 in YP.unify(arg2, 3)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.atom_concat"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("sub_atom"))) - { - foreach (bool l3 in YP.unify(arg2, 5)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.sub_atom"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("atom_chars"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.atom_chars"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("atom_codes"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.atom_codes"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("char_code"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.char_code"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("number_chars"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.number_chars"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("number_codes"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.number_codes"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("copy_term"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.copy_term"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("sort"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.sort"))) - { - yield return true; - yield break; - } - } - } - } - { - // Manually included : script_event for callback to LSL/C# - - //object x1 = arg1; - foreach (bool l2 in YP.unify(arg1, Atom.a(@"script_event"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a(@"YP.script_event"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("nl"))) - { - foreach (bool l3 in YP.unify(arg2, 0)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.nl"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("write"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.write"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("put_code"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.put_code"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("see"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.see"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("seen"))) - { - foreach (bool l3 in YP.unify(arg2, 0)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.seen"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("tell"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.tell"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("told"))) - { - foreach (bool l3 in YP.unify(arg2, 0)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.told"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("clause"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.clause"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("retract"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.retract"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("abolish"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.abolish"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("retractall"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.retractall"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("atom"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.atom"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("integer"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.integer"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("float"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.isFloat"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("number"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.number"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("atomic"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.atomic"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("compound"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.compound"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("=="))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.termEqual"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("\\=="))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.termNotEqual"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("@<"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.termLessThan"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("@=<"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.termLessThanOrEqual"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("@>"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.termGreaterThan"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("@>="))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.termGreaterThanOrEqual"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("throw"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.throwException"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("current_prolog_flag"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.current_prolog_flag"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("set_prolog_flag"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.set_prolog_flag"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("current_input"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.current_input"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("current_output"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("YP.current_output"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("read_term"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("Parser.read_term2"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("read_term"))) - { - foreach (bool l3 in YP.unify(arg2, 3)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("Parser.read_term3"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("read"))) - { - foreach (bool l3 in YP.unify(arg2, 1)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("Parser.read1"))) - { - yield return true; - yield break; - } - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("read"))) - { - foreach (bool l3 in YP.unify(arg2, 2)) - { - foreach (bool l4 in YP.unify(arg3, Atom.a("Parser.read2"))) - { - yield return true; - yield break; - } - } - } - } - } - - public static IEnumerable compileTerm(object arg1, object arg2, object arg3) - { - { - object Term = arg1; - object State = arg2; - Variable VariableName = new Variable(); - foreach (bool l2 in YP.unify(arg3, new Functor1("var", VariableName))) - { - if (YP.var(Term)) - { - foreach (bool l4 in CompilerState.getVariableName(State, Term, VariableName)) - { - yield return true; - yield break; - } - } - } - } - { - object _State = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg3, new Functor1("var", Atom.a("Atom.NIL")))) - { - yield return true; - yield break; - } - } - } - { - object Term = arg1; - object State = arg2; - object Code = arg3; - Variable ModuleCode = new Variable(); - if (YP.atom(Term)) - { - foreach (bool l3 in compileAtomModule(Term, 0, State, ModuleCode)) - { - foreach (bool l4 in YP.unify(Code, new Functor2("call", Atom.a("Atom.a"), new ListPair(new Functor1("object", Term), new ListPair(ModuleCode, Atom.NIL))))) - { - yield return true; - yield break; - } - goto cutIf1; - } - foreach (bool l3 in YP.unify(Code, new Functor2("call", Atom.a("Atom.a"), new ListPair(new Functor1("object", Term), Atom.NIL)))) - { - yield return true; - yield break; - } - cutIf1: - { } - } - } - { - object State = arg2; - Variable First = new Variable(); - Variable Rest = new Variable(); - Variable CompiledList = new Variable(); - Variable x5 = new Variable(); - Variable Rest2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(First, Rest))) - { - foreach (bool l3 in YP.unify(arg3, new Functor2("call", Atom.a("ListPair.make"), new ListPair(new Functor1("objectArray", CompiledList), Atom.NIL)))) - { - if (YP.nonvar(Rest)) - { - foreach (bool l5 in YP.unify(Rest, new ListPair(x5, Rest2))) - { - if (YP.termNotEqual(Rest2, Atom.NIL)) - { - foreach (bool l7 in maplist_compileTerm(new ListPair(First, Rest), State, CompiledList)) - { - yield return true; - yield break; - } - } - } - } - } - } - } - { - object State = arg2; - Variable First = new Variable(); - Variable Rest = new Variable(); - Variable Arg1 = new Variable(); - Variable Arg2 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(First, Rest))) - { - foreach (bool l3 in YP.unify(arg3, new Functor2("new", Atom.a("ListPair"), new ListPair(Arg1, new ListPair(Arg2, Atom.NIL))))) - { - foreach (bool l4 in compileTerm(First, State, Arg1)) - { - foreach (bool l5 in compileTerm(Rest, State, Arg2)) - { - yield return true; - yield break; - } - } - } - } - } - { - object Term = arg1; - object State = arg2; - object Result = arg3; - Variable Name = new Variable(); - Variable TermArgs = new Variable(); - Variable x6 = new Variable(); - Variable Arity = new Variable(); - Variable ModuleCode = new Variable(); - Variable NameCode = new Variable(); - Variable X1 = new Variable(); - Variable Arg1 = new Variable(); - Variable X2 = new Variable(); - Variable Arg2 = new Variable(); - Variable X3 = new Variable(); - Variable Arg3 = new Variable(); - Variable Args = new Variable(); - foreach (bool l2 in YP.univ(Term, new ListPair(Name, TermArgs))) - { - if (YP.termEqual(TermArgs, Atom.NIL)) - { - foreach (bool l4 in YP.unify(Result, new Functor1("object", Name))) - { - yield return true; - yield break; - } - goto cutIf2; - } - foreach (bool l3 in YP.functor(Term, x6, Arity)) - { - foreach (bool l4 in compileAtomModule(Name, Arity, State, ModuleCode)) - { - foreach (bool l5 in YP.unify(NameCode, new Functor2("call", Atom.a("Atom.a"), new ListPair(new Functor1("object", Name), new ListPair(ModuleCode, Atom.NIL))))) - { - foreach (bool l6 in YP.unify(TermArgs, new ListPair(X1, Atom.NIL))) - { - foreach (bool l7 in compileTerm(X1, State, Arg1)) - { - foreach (bool l8 in YP.unify(Result, new Functor2("new", Atom.a("Functor1"), new ListPair(NameCode, new ListPair(Arg1, Atom.NIL))))) - { - yield return true; - yield break; - } - } - goto cutIf4; - } - foreach (bool l6 in YP.unify(TermArgs, new ListPair(X1, new ListPair(X2, Atom.NIL)))) - { - foreach (bool l7 in compileTerm(X1, State, Arg1)) - { - foreach (bool l8 in compileTerm(X2, State, Arg2)) - { - foreach (bool l9 in YP.unify(Result, new Functor2("new", Atom.a("Functor2"), ListPair.make(new object[] { NameCode, Arg1, Arg2 })))) - { - yield return true; - yield break; - } - } - } - goto cutIf5; - } - foreach (bool l6 in YP.unify(TermArgs, ListPair.make(new object[] { X1, X2, X3 }))) - { - foreach (bool l7 in compileTerm(X1, State, Arg1)) - { - foreach (bool l8 in compileTerm(X2, State, Arg2)) - { - foreach (bool l9 in compileTerm(X3, State, Arg3)) - { - foreach (bool l10 in YP.unify(Result, new Functor2("new", Atom.a("Functor3"), ListPair.make(new object[] { NameCode, Arg1, Arg2, Arg3 })))) - { - yield return true; - yield break; - } - } - } - } - } - foreach (bool l6 in maplist_compileTerm(TermArgs, State, Args)) - { - foreach (bool l7 in YP.unify(Result, new Functor2("new", Atom.a("Functor"), new ListPair(NameCode, new ListPair(new Functor1("objectArray", Args), Atom.NIL))))) - { - yield return true; - yield break; - } - } - cutIf5: - cutIf4: - { } - } - goto cutIf3; - } - foreach (bool l4 in YP.unify(NameCode, new Functor1("object", Name))) - { - foreach (bool l5 in YP.unify(TermArgs, new ListPair(X1, Atom.NIL))) - { - foreach (bool l6 in compileTerm(X1, State, Arg1)) - { - foreach (bool l7 in YP.unify(Result, new Functor2("new", Atom.a("Functor1"), new ListPair(NameCode, new ListPair(Arg1, Atom.NIL))))) - { - yield return true; - yield break; - } - } - goto cutIf6; - } - foreach (bool l5 in YP.unify(TermArgs, new ListPair(X1, new ListPair(X2, Atom.NIL)))) - { - foreach (bool l6 in compileTerm(X1, State, Arg1)) - { - foreach (bool l7 in compileTerm(X2, State, Arg2)) - { - foreach (bool l8 in YP.unify(Result, new Functor2("new", Atom.a("Functor2"), ListPair.make(new object[] { NameCode, Arg1, Arg2 })))) - { - yield return true; - yield break; - } - } - } - goto cutIf7; - } - foreach (bool l5 in YP.unify(TermArgs, ListPair.make(new object[] { X1, X2, X3 }))) - { - foreach (bool l6 in compileTerm(X1, State, Arg1)) - { - foreach (bool l7 in compileTerm(X2, State, Arg2)) - { - foreach (bool l8 in compileTerm(X3, State, Arg3)) - { - foreach (bool l9 in YP.unify(Result, new Functor2("new", Atom.a("Functor3"), ListPair.make(new object[] { NameCode, Arg1, Arg2, Arg3 })))) - { - yield return true; - yield break; - } - } - } - } - } - foreach (bool l5 in maplist_compileTerm(TermArgs, State, Args)) - { - foreach (bool l6 in YP.unify(Result, new Functor2("new", Atom.a("Functor"), new ListPair(NameCode, new ListPair(new Functor1("objectArray", Args), Atom.NIL))))) - { - yield return true; - yield break; - } - } - cutIf7: - cutIf6: - { } - } - cutIf3: - { } - } - cutIf2: - { } - } - } - } - - public static IEnumerable compileAtomModule(object Name, object arg2, object arg3, object ModuleCode) - { - { - object Arity = arg2; - object State = arg3; - if (CompilerState.nameArityHasModule(State, Name, Arity, Atom.a(""))) - { - foreach (bool l3 in YP.unify(ModuleCode, new Functor2("call", Atom.a("Atom.a"), new ListPair(new Functor1("object", Atom.a("")), Atom.NIL)))) - { - yield return true; - yield break; - } - } - } - { - object _Arity = arg2; - object _State = arg3; - Variable Module = new Variable(); - foreach (bool l2 in Atom.module(Name, Module)) - { - if (YP.termNotEqual(Module, Atom.NIL)) - { - foreach (bool l4 in YP.unify(ModuleCode, new Functor2("call", Atom.a("Atom.a"), new ListPair(new Functor1("object", Module), Atom.NIL)))) - { - yield return true; - yield break; - } - } - } - } - } - - public static IEnumerable maplist_compileTerm(object arg1, object arg2, object arg3) - { - { - object _State = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg3, Atom.NIL)) - { - yield return true; - yield break; - } - } - } - { - object State = arg2; - Variable First = new Variable(); - Variable Rest = new Variable(); - Variable FirstResult = new Variable(); - Variable RestResults = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(First, Rest))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(FirstResult, RestResults))) - { - if (YP.nonvar(Rest)) - { - foreach (bool l5 in compileTerm(First, State, FirstResult)) - { - foreach (bool l6 in maplist_compileTerm(Rest, State, RestResults)) - { - yield return true; - yield break; - } - } - } - } - } - } - } - - public static IEnumerable compileExpression(object Term, object State, object Result) - { - { - Variable Name = new Variable(); - Variable TermArgs = new Variable(); - Variable X1 = new Variable(); - Variable FunctionName = new Variable(); - Variable Arg1 = new Variable(); - Variable x9 = new Variable(); - Variable X2 = new Variable(); - Variable Arg2 = new Variable(); - Variable x12 = new Variable(); - Variable Arity = new Variable(); - if (YP.nonvar(Term)) - { - foreach (bool l3 in YP.univ(Term, new ListPair(Name, TermArgs))) - { - if (YP.atom(Name)) - { - foreach (bool l5 in YP.unify(TermArgs, new ListPair(X1, Atom.NIL))) - { - foreach (bool l6 in unaryFunction(Name, FunctionName)) - { - foreach (bool l7 in compileExpression(X1, State, Arg1)) - { - foreach (bool l8 in YP.unify(Result, new Functor2("call", FunctionName, new ListPair(Arg1, Atom.NIL)))) - { - yield return true; - yield break; - } - } - goto cutIf1; - } - } - foreach (bool l5 in YP.unify(Term, new ListPair(x9, Atom.NIL))) - { - foreach (bool l6 in compileTerm(Term, State, Result)) - { - yield return true; - yield break; - } - goto cutIf2; - } - foreach (bool l5 in YP.unify(TermArgs, new ListPair(X1, new ListPair(X2, Atom.NIL)))) - { - foreach (bool l6 in binaryFunction(Name, FunctionName)) - { - foreach (bool l7 in compileExpression(X1, State, Arg1)) - { - foreach (bool l8 in compileExpression(X2, State, Arg2)) - { - foreach (bool l9 in YP.unify(Result, new Functor2("call", FunctionName, new ListPair(Arg1, new ListPair(Arg2, Atom.NIL))))) - { - yield return true; - yield break; - } - } - } - goto cutIf3; - } - } - foreach (bool l5 in YP.functor(Term, x12, Arity)) - { - YP.throwException(new Functor2("error", new Functor2("type_error", Atom.a("evaluable"), new Functor2("/", Name, Arity)), Atom.a("Not an expression function"))); - yield return false; - } - cutIf3: - cutIf2: - cutIf1: - { } - } - } - } - } - { - foreach (bool l2 in compileTerm(Term, State, Result)) - { - yield return true; - yield break; - } - } - } - - public static IEnumerable unaryFunction(object arg1, object arg2) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.a("-"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.negate"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("abs"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.abs"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("sign"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.sign"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("float"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.toFloat"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("floor"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.floor"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("truncate"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.truncate"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("round"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.round"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("ceiling"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.ceiling"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("sin"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.sin"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("cos"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.cos"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("atan"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.atan"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("exp"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.exp"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("log"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.log"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("sqrt"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.sqrt"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("\\"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.bitwiseComplement"))) - { - yield return true; - yield break; - } - } - } - } - - public static IEnumerable binaryFunction(object arg1, object arg2) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.a("+"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.add"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("-"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.subtract"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("*"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.multiply"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("/"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.divide"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("//"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.intDivide"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("mod"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.mod"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("**"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.pow"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a(">>"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.bitwiseShiftRight"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("<<"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.bitwiseShiftLeft"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("/\\"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.bitwiseAnd"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("\\/"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.bitwiseOr"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("min"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.min"))) - { - yield return true; - yield break; - } - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("max"))) - { - foreach (bool l3 in YP.unify(arg2, Atom.a("YP.max"))) - { - yield return true; - yield break; - } - } - } - } - - public static void convertFunctionCSharp(object arg1) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.a("getDeclaringClass"))) - { - YP.write(Atom.a("public class YPInnerClass {}")); - YP.nl(); - YP.write(Atom.a("public static System.Type getDeclaringClass() { return typeof(YPInnerClass).DeclaringType; }")); - YP.nl(); - YP.nl(); - return; - } - } - { - Variable ReturnType = new Variable(); - Variable Name = new Variable(); - Variable ArgList = new Variable(); - Variable Body = new Variable(); - Variable Level = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor("function", new object[] { ReturnType, Name, ArgList, Body }))) - { - YP.write(Atom.a("public static ")); - YP.write(ReturnType); - YP.write(Atom.a(" ")); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListCSharp(ArgList); - YP.write(Atom.a(") {")); - YP.nl(); - foreach (bool l3 in YP.unify(Level, 1)) - { - convertStatementListCSharp(Body, Level); - YP.write(Atom.a("}")); - YP.nl(); - YP.nl(); - return; - } - } - } - } - - public static IEnumerable convertStatementListCSharp(object arg1, object x1, object x2) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - yield return true; - yield break; - } - } - } - - public static void convertStatementListCSharp(object arg1, object Level) - { - { - Variable Name = new Variable(); - Variable Body = new Variable(); - Variable RestStatements = new Variable(); - Variable NewStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("breakableBlock", Name, Body), RestStatements))) - { - foreach (bool l3 in append(Body, new ListPair(new Functor1("label", Name), RestStatements), NewStatements)) - { - convertStatementListCSharp(NewStatements, Level); - return; - } - } - } - { - Variable Type = new Variable(); - Variable Name = new Variable(); - Variable Expression = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor3("declare", Type, Name, Expression), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Type); - YP.write(Atom.a(" ")); - YP.write(Name); - YP.write(Atom.a(" = ")); - convertExpressionCSharp(Expression); - YP.write(Atom.a(";")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - { - Variable Name = new Variable(); - Variable Expression = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("assign", Name, Expression), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Name); - YP.write(Atom.a(" = ")); - convertExpressionCSharp(Expression); - YP.write(Atom.a(";")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - { - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("yieldtrue"), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Atom.a("yield return true;")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - { - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("yieldfalse"), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Atom.a("yield return false;")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - { - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("yieldbreak"), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Atom.a("yield break;")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - { - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("return"), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Atom.a("return;")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - { - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("returntrue"), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Atom.a("return true;")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - { - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("returnfalse"), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Atom.a("return false;")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - { - Variable Name = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor1("label", Name), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Name); - YP.write(Atom.a(":")); - YP.nl(); - if (YP.termEqual(RestStatements, Atom.NIL)) - { - convertIndentationCSharp(Level); - YP.write(Atom.a("{}")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - goto cutIf1; - } - convertStatementListCSharp(RestStatements, Level); - return; - cutIf1: - { } - } - } - { - Variable Name = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor1("breakBlock", Name), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Atom.a("goto ")); - YP.write(Name); - YP.write(Atom.a(";")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - { - Variable Name = new Variable(); - Variable ArgList = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("call", Name, ArgList), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListCSharp(ArgList); - YP.write(Atom.a(");")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - { - Variable Name = new Variable(); - Variable _FunctorArgs = new Variable(); - Variable ArgList = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor3("functorCall", Name, _FunctorArgs, ArgList), RestStatements))) - { - convertStatementListCSharp(new ListPair(new Functor2("call", Name, ArgList), RestStatements), Level); - return; - } - } - { - Variable Obj = new Variable(); - Variable Name = new Variable(); - Variable ArgList = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor3("callMember", new Functor1("var", Obj), Name, ArgList), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Obj); - YP.write(Atom.a(".")); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListCSharp(ArgList); - YP.write(Atom.a(");")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - { - Variable Body = new Variable(); - Variable RestStatements = new Variable(); - Variable NextLevel = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor1("blockScope", Body), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Atom.a("{")); - YP.nl(); - foreach (bool l3 in YP.unify(NextLevel, YP.add(Level, 1))) - { - convertStatementListCSharp(Body, NextLevel); - convertIndentationCSharp(Level); - YP.write(Atom.a("}")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - } - { - Variable Expression = new Variable(); - Variable Body = new Variable(); - Variable RestStatements = new Variable(); - Variable NextLevel = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("if", Expression, Body), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Atom.a("if (")); - convertExpressionCSharp(Expression); - YP.write(Atom.a(") {")); - YP.nl(); - foreach (bool l3 in YP.unify(NextLevel, YP.add(Level, 1))) - { - convertStatementListCSharp(Body, NextLevel); - convertIndentationCSharp(Level); - YP.write(Atom.a("}")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - } - { - Variable Expression = new Variable(); - Variable Body = new Variable(); - Variable RestStatements = new Variable(); - Variable NextLevel = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("foreach", Expression, Body), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Atom.a("foreach (bool l")); - YP.write(Level); - YP.write(Atom.a(" in ")); - convertExpressionCSharp(Expression); - YP.write(Atom.a(") {")); - YP.nl(); - foreach (bool l3 in YP.unify(NextLevel, YP.add(Level, 1))) - { - convertStatementListCSharp(Body, NextLevel); - convertIndentationCSharp(Level); - YP.write(Atom.a("}")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - } - { - Variable Expression = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor1("throw", Expression), RestStatements))) - { - convertIndentationCSharp(Level); - YP.write(Atom.a("throw ")); - convertExpressionCSharp(Expression); - YP.write(Atom.a(";")); - YP.nl(); - convertStatementListCSharp(RestStatements, Level); - return; - } - } - } - - public static void convertIndentationCSharp(object Level) - { - { - Variable N = new Variable(); - foreach (bool l2 in YP.unify(N, YP.multiply(Level, 2))) - { - repeatWrite(Atom.a(" "), N); - return; - } - } - } - - public static void convertArgListCSharp(object arg1) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - return; - } - } - { - Variable Head = new Variable(); - Variable Tail = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Head, Tail))) - { - convertExpressionCSharp(Head); - if (YP.termNotEqual(Tail, Atom.NIL)) - { - YP.write(Atom.a(", ")); - convertArgListCSharp(Tail); - return; - goto cutIf1; - } - convertArgListCSharp(Tail); - return; - cutIf1: - { } - } - } - } - - public static void convertExpressionCSharp(object arg1) - { - { - Variable X = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("arg", X))) - { - YP.write(Atom.a("object ")); - YP.write(X); - return; - } - } - { - Variable Name = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("call", Name, ArgList))) - { - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListCSharp(ArgList); - YP.write(Atom.a(")")); - return; - } - } - { - Variable Name = new Variable(); - Variable _FunctorArgs = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor3("functorCall", Name, _FunctorArgs, ArgList))) - { - convertExpressionCSharp(new Functor2("call", Name, ArgList)); - return; - } - } - { - Variable Obj = new Variable(); - Variable Name = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor3("callMember", new Functor1("var", Obj), Name, ArgList))) - { - YP.write(Obj); - YP.write(Atom.a(".")); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListCSharp(ArgList); - YP.write(Atom.a(")")); - return; - } - } - { - Variable Name = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("new", Name, ArgList))) - { - YP.write(Atom.a("new ")); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListCSharp(ArgList); - YP.write(Atom.a(")")); - return; - } - } - { - Variable Name = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("var", Name))) - { - YP.write(Name); - return; - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("null"))) - { - YP.write(Atom.a("null")); - return; - } - } - { - Variable X = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("not", X))) - { - YP.write(Atom.a("!(")); - convertExpressionCSharp(X); - YP.write(Atom.a(")")); - return; - } - } - { - Variable X = new Variable(); - Variable Y = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("and", X, Y))) - { - YP.write(Atom.a("(")); - convertExpressionCSharp(X); - YP.write(Atom.a(") && (")); - convertExpressionCSharp(Y); - YP.write(Atom.a(")")); - return; - } - } - { - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("objectArray", ArgList))) - { - YP.write(Atom.a("new object[] {")); - convertArgListCSharp(ArgList); - YP.write(Atom.a("}")); - return; - } - } - { - Variable X = new Variable(); - Variable Codes = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("object", X))) - { - if (YP.atom(X)) - { - YP.write(Atom.a("\"")); - foreach (bool l4 in YP.atom_codes(X, Codes)) - { - convertStringCodesCSharp(Codes); - YP.write(Atom.a("\"")); - return; - } - } - } - } - { - Variable X = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("object", X))) - { - YP.write(X); - return; - } - } - } - - public static void convertStringCodesCSharp(object arg1) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - return; - } - } - { - Variable Code = new Variable(); - Variable RestCodes = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Code, RestCodes))) - { - foreach (bool l3 in putCStringCode(Code)) - { - convertStringCodesCSharp(RestCodes); - return; - } - } - } - } - - public static void convertFunctionJavascript(object arg1) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.a("getDeclaringClass"))) - { - YP.write(Atom.a("function getDeclaringClass() { return null; }")); - YP.nl(); - YP.nl(); - return; - } - } - { - Variable x1 = new Variable(); - Variable Name = new Variable(); - Variable ArgList = new Variable(); - Variable Body = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor("function", new object[] { x1, Name, ArgList, Body }))) - { - YP.write(Atom.a("function ")); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListJavascript(ArgList); - YP.write(Atom.a(") {")); - YP.nl(); - convertStatementListJavascript(Body, 1); - YP.write(Atom.a("}")); - YP.nl(); - YP.nl(); - return; - } - } - } - - public static void convertStatementListJavascript(object arg1, object arg2) - { - { - object x1 = arg2; - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - return; - } - } - { - object Level = arg2; - Variable Name = new Variable(); - Variable Body = new Variable(); - Variable RestStatements = new Variable(); - Variable NextLevel = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("breakableBlock", Name, Body), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Name); - YP.write(Atom.a(":")); - YP.nl(); - convertIndentationJavascript(Level); - YP.write(Atom.a("{")); - YP.nl(); - foreach (bool l3 in YP.unify(NextLevel, YP.add(Level, 1))) - { - convertStatementListJavascript(Body, NextLevel); - convertIndentationJavascript(Level); - YP.write(Atom.a("}")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - } - { - object Level = arg2; - Variable _Type = new Variable(); - Variable Name = new Variable(); - Variable Expression = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor3("declare", _Type, Name, Expression), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Atom.a("var ")); - YP.write(Name); - YP.write(Atom.a(" = ")); - convertExpressionJavascript(Expression); - YP.write(Atom.a(";")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - { - object Level = arg2; - Variable Name = new Variable(); - Variable Expression = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("assign", Name, Expression), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Name); - YP.write(Atom.a(" = ")); - convertExpressionJavascript(Expression); - YP.write(Atom.a(";")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - { - object Level = arg2; - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("yieldtrue"), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Atom.a("yield true;")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - { - object Level = arg2; - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("yieldfalse"), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Atom.a("yield false;")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - { - object Level = arg2; - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("yieldbreak"), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Atom.a("return;")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - { - object Level = arg2; - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("return"), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Atom.a("return;")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - { - object Level = arg2; - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("returntrue"), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Atom.a("return true;")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - { - object Level = arg2; - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("returnfalse"), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Atom.a("return false;")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - { - object Level = arg2; - Variable Name = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor1("breakBlock", Name), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Atom.a("break ")); - YP.write(Name); - YP.write(Atom.a(";")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - { - object Level = arg2; - Variable Name = new Variable(); - Variable ArgList = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("call", Name, ArgList), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListJavascript(ArgList); - YP.write(Atom.a(");")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - { - object Level = arg2; - Variable Name = new Variable(); - Variable _FunctorArgs = new Variable(); - Variable ArgList = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor3("functorCall", Name, _FunctorArgs, ArgList), RestStatements))) - { - convertStatementListJavascript(new ListPair(new Functor2("call", Name, ArgList), RestStatements), Level); - return; - } - } - { - object Level = arg2; - Variable Obj = new Variable(); - Variable Name = new Variable(); - Variable ArgList = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor3("callMember", new Functor1("var", Obj), Name, ArgList), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Obj); - YP.write(Atom.a(".")); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListJavascript(ArgList); - YP.write(Atom.a(");")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - { - object Level = arg2; - Variable Body = new Variable(); - Variable RestStatements = new Variable(); - Variable NextLevel = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor1("blockScope", Body), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Atom.a("{")); - YP.nl(); - foreach (bool l3 in YP.unify(NextLevel, YP.add(Level, 1))) - { - convertStatementListJavascript(Body, NextLevel); - convertIndentationJavascript(Level); - YP.write(Atom.a("}")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - } - { - object Level = arg2; - Variable Expression = new Variable(); - Variable Body = new Variable(); - Variable RestStatements = new Variable(); - Variable NextLevel = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("if", Expression, Body), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Atom.a("if (")); - convertExpressionJavascript(Expression); - YP.write(Atom.a(") {")); - YP.nl(); - foreach (bool l3 in YP.unify(NextLevel, YP.add(Level, 1))) - { - convertStatementListJavascript(Body, NextLevel); - convertIndentationJavascript(Level); - YP.write(Atom.a("}")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - } - { - object Level = arg2; - Variable Expression = new Variable(); - Variable Body = new Variable(); - Variable RestStatements = new Variable(); - Variable NextLevel = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("foreach", Expression, Body), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Atom.a("for each (var l")); - YP.write(Level); - YP.write(Atom.a(" in ")); - convertExpressionJavascript(Expression); - YP.write(Atom.a(") {")); - YP.nl(); - foreach (bool l3 in YP.unify(NextLevel, YP.add(Level, 1))) - { - convertStatementListJavascript(Body, NextLevel); - convertIndentationJavascript(Level); - YP.write(Atom.a("}")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - } - { - object Level = arg2; - Variable Expression = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor1("throw", Expression), RestStatements))) - { - convertIndentationJavascript(Level); - YP.write(Atom.a("throw ")); - convertExpressionJavascript(Expression); - YP.write(Atom.a(";")); - YP.nl(); - convertStatementListJavascript(RestStatements, Level); - return; - } - } - } - - public static void convertIndentationJavascript(object Level) - { - { - Variable N = new Variable(); - foreach (bool l2 in YP.unify(N, YP.multiply(Level, 2))) - { - repeatWrite(Atom.a(" "), N); - return; - } - } - } - - public static void convertArgListJavascript(object arg1) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - return; - } - } - { - Variable Head = new Variable(); - Variable Tail = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Head, Tail))) - { - convertExpressionJavascript(Head); - if (YP.termNotEqual(Tail, Atom.NIL)) - { - YP.write(Atom.a(", ")); - convertArgListJavascript(Tail); - return; - goto cutIf1; - } - convertArgListJavascript(Tail); - return; - cutIf1: - { } - } - } - } - - public static void convertExpressionJavascript(object arg1) - { - { - Variable X = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("arg", X))) - { - YP.write(X); - return; - } - } - { - Variable Name = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("call", Name, ArgList))) - { - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListJavascript(ArgList); - YP.write(Atom.a(")")); - return; - } - } - { - Variable Name = new Variable(); - Variable _FunctorArgs = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor3("functorCall", Name, _FunctorArgs, ArgList))) - { - convertExpressionJavascript(new Functor2("call", Name, ArgList)); - return; - } - } - { - Variable Obj = new Variable(); - Variable Name = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor3("callMember", new Functor1("var", Obj), Name, ArgList))) - { - YP.write(Obj); - YP.write(Atom.a(".")); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListJavascript(ArgList); - YP.write(Atom.a(")")); - return; - } - } - { - Variable Name = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("new", Name, ArgList))) - { - YP.write(Atom.a("new ")); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListJavascript(ArgList); - YP.write(Atom.a(")")); - return; - } - } - { - Variable Name = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("var", Name))) - { - YP.write(Name); - return; - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("null"))) - { - YP.write(Atom.a("null")); - return; - } - } - { - Variable X = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("not", X))) - { - YP.write(Atom.a("!(")); - convertExpressionJavascript(X); - YP.write(Atom.a(")")); - return; - } - } - { - Variable X = new Variable(); - Variable Y = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("and", X, Y))) - { - YP.write(Atom.a("(")); - convertExpressionJavascript(X); - YP.write(Atom.a(") && (")); - convertExpressionJavascript(Y); - YP.write(Atom.a(")")); - return; - } - } - { - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("objectArray", ArgList))) - { - YP.write(Atom.a("[")); - convertArgListJavascript(ArgList); - YP.write(Atom.a("]")); - return; - } - } - { - Variable X = new Variable(); - Variable Codes = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("object", X))) - { - if (YP.atom(X)) - { - YP.write(Atom.a("\"")); - foreach (bool l4 in YP.atom_codes(X, Codes)) - { - convertStringCodesJavascript(Codes); - YP.write(Atom.a("\"")); - return; - } - } - } - } - { - Variable X = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("object", X))) - { - YP.write(X); - return; - } - } - } - - public static void convertStringCodesJavascript(object arg1) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - return; - } - } - { - Variable Code = new Variable(); - Variable RestCodes = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Code, RestCodes))) - { - foreach (bool l3 in putCStringCode(Code)) - { - convertStringCodesJavascript(RestCodes); - return; - } - } - } - } - - public static void convertFunctionPython(object arg1) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.a("getDeclaringClass"))) - { - YP.write(Atom.a("def getDeclaringClass():")); - YP.nl(); - YP.write(Atom.a(" return None")); - YP.nl(); - YP.nl(); - return; - } - } - { - Variable x1 = new Variable(); - Variable Name = new Variable(); - Variable ArgList = new Variable(); - Variable Body = new Variable(); - Variable Level = new Variable(); - Variable HasBreakableBlock = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor("function", new object[] { x1, Name, ArgList, Body }))) - { - YP.write(Atom.a("def ")); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListPython(ArgList); - YP.write(Atom.a("):")); - YP.nl(); - foreach (bool l3 in YP.unify(Level, 1)) - { - if (hasBreakableBlockPython(Body)) - { - foreach (bool l5 in YP.unify(HasBreakableBlock, 1)) - { - if (YP.termEqual(HasBreakableBlock, 1)) - { - convertIndentationPython(Level); - YP.write(Atom.a("doBreak = False")); - YP.nl(); - foreach (bool l7 in convertStatementListPython(Body, Level, HasBreakableBlock)) - { - YP.nl(); - return; - } - goto cutIf2; - } - foreach (bool l6 in convertStatementListPython(Body, Level, HasBreakableBlock)) - { - YP.nl(); - return; - } - cutIf2: - { } - } - goto cutIf1; - } - foreach (bool l4 in YP.unify(HasBreakableBlock, 0)) - { - if (YP.termEqual(HasBreakableBlock, 1)) - { - convertIndentationPython(Level); - YP.write(Atom.a("doBreak = False")); - YP.nl(); - foreach (bool l6 in convertStatementListPython(Body, Level, HasBreakableBlock)) - { - YP.nl(); - return; - } - goto cutIf3; - } - foreach (bool l5 in convertStatementListPython(Body, Level, HasBreakableBlock)) - { - YP.nl(); - return; - } - cutIf3: - { } - } - cutIf1: - { } - } - } - } - } - - public static bool hasBreakableBlockPython(object arg1) - { - { - Variable _Name = new Variable(); - Variable _Body = new Variable(); - Variable _RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("breakableBlock", _Name, _Body), _RestStatements))) - { - return true; - } - } - { - Variable Body = new Variable(); - Variable _RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor1("blockScope", Body), _RestStatements))) - { - if (hasBreakableBlockPython(Body)) - { - return true; - } - } - } - { - Variable _Expression = new Variable(); - Variable Body = new Variable(); - Variable _RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("if", _Expression, Body), _RestStatements))) - { - if (hasBreakableBlockPython(Body)) - { - return true; - } - } - } - { - Variable _Expression = new Variable(); - Variable Body = new Variable(); - Variable _RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("foreach", _Expression, Body), _RestStatements))) - { - if (hasBreakableBlockPython(Body)) - { - return true; - } - } - } - { - Variable x1 = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(x1, RestStatements))) - { - if (hasBreakableBlockPython(RestStatements)) - { - return true; - } - } - } - return false; - } - - public static IEnumerable convertStatementListPython(object arg1, object arg2, object arg3) - { - { - object x1 = arg2; - object x2 = arg3; - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - yield return true; - yield break; - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable Name = new Variable(); - Variable Body = new Variable(); - Variable RestStatements = new Variable(); - Variable NextLevel = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("breakableBlock", Name, Body), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Name); - YP.write(Atom.a(" = False")); - YP.nl(); - convertIndentationPython(Level); - YP.write(Atom.a("for _ in [1]:")); - YP.nl(); - foreach (bool l3 in YP.unify(NextLevel, YP.add(Level, 1))) - { - foreach (bool l4 in convertStatementListPython(Body, NextLevel, HasBreakableBlock)) - { - convertIndentationPython(Level); - YP.write(Atom.a("if ")); - YP.write(Name); - YP.write(Atom.a(":")); - YP.nl(); - convertIndentationPython(NextLevel); - YP.write(Atom.a("doBreak = False")); - YP.nl(); - convertIndentationPython(Level); - YP.write(Atom.a("if doBreak:")); - YP.nl(); - convertIndentationPython(NextLevel); - YP.write(Atom.a("break")); - YP.nl(); - foreach (bool l5 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable _Type = new Variable(); - Variable Name = new Variable(); - Variable Expression = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor3("declare", _Type, Name, Expression), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Name); - YP.write(Atom.a(" = ")); - convertExpressionPython(Expression); - YP.nl(); - foreach (bool l3 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable Name = new Variable(); - Variable Expression = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("assign", Name, Expression), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Name); - YP.write(Atom.a(" = ")); - convertExpressionPython(Expression); - YP.nl(); - foreach (bool l3 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("yieldtrue"), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Atom.a("yield True")); - YP.nl(); - foreach (bool l3 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("yieldfalse"), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Atom.a("yield False")); - YP.nl(); - foreach (bool l3 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("yieldbreak"), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Atom.a("return")); - YP.nl(); - foreach (bool l3 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("return"), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Atom.a("return")); - YP.nl(); - foreach (bool l3 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("returntrue"), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Atom.a("return True")); - YP.nl(); - foreach (bool l3 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Atom.a("returnfalse"), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Atom.a("return False")); - YP.nl(); - foreach (bool l3 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable Name = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor1("breakBlock", Name), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Name); - YP.write(Atom.a(" = True")); - YP.nl(); - convertIndentationPython(Level); - YP.write(Atom.a("doBreak = True")); - YP.nl(); - convertIndentationPython(Level); - YP.write(Atom.a("break")); - YP.nl(); - foreach (bool l3 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable Name = new Variable(); - Variable ArgList = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("call", Name, ArgList), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListPython(ArgList); - YP.write(Atom.a(")")); - YP.nl(); - foreach (bool l3 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable Name = new Variable(); - Variable _FunctorArgs = new Variable(); - Variable ArgList = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor3("functorCall", Name, _FunctorArgs, ArgList), RestStatements))) - { - foreach (bool l3 in convertStatementListPython(new ListPair(new Functor2("call", Name, ArgList), RestStatements), Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable Obj = new Variable(); - Variable Name = new Variable(); - Variable ArgList = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor3("callMember", new Functor1("var", Obj), Name, ArgList), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Obj); - YP.write(Atom.a(".")); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListPython(ArgList); - YP.write(Atom.a(")")); - YP.nl(); - foreach (bool l3 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable Body = new Variable(); - Variable RestStatements = new Variable(); - Variable NextLevel = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor1("blockScope", Body), RestStatements))) - { - if (YP.termEqual(HasBreakableBlock, 1)) - { - convertIndentationPython(Level); - YP.write(Atom.a("for _ in [1]:")); - YP.nl(); - foreach (bool l4 in YP.unify(NextLevel, YP.add(Level, 1))) - { - foreach (bool l5 in convertStatementListPython(Body, NextLevel, HasBreakableBlock)) - { - if (YP.termEqual(HasBreakableBlock, 1)) - { - if (YP.greaterThan(Level, 1)) - { - convertIndentationPython(Level); - YP.write(Atom.a("if doBreak:")); - YP.nl(); - convertIndentationPython(NextLevel); - YP.write(Atom.a("break")); - YP.nl(); - foreach (bool l8 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - goto cutIf3; - } - foreach (bool l7 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - cutIf3: - goto cutIf2; - } - foreach (bool l6 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - cutIf2: - { } - } - } - goto cutIf1; - } - foreach (bool l3 in YP.unify(NextLevel, Level)) - { - foreach (bool l4 in convertStatementListPython(Body, NextLevel, HasBreakableBlock)) - { - if (YP.termEqual(HasBreakableBlock, 1)) - { - if (YP.greaterThan(Level, 1)) - { - convertIndentationPython(Level); - YP.write(Atom.a("if doBreak:")); - YP.nl(); - convertIndentationPython(NextLevel); - YP.write(Atom.a("break")); - YP.nl(); - foreach (bool l7 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - goto cutIf5; - } - foreach (bool l6 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - cutIf5: - goto cutIf4; - } - foreach (bool l5 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - cutIf4: - { } - } - } - cutIf1: - { } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable Expression = new Variable(); - Variable Body = new Variable(); - Variable RestStatements = new Variable(); - Variable NextLevel = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("if", Expression, Body), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Atom.a("if ")); - convertExpressionPython(Expression); - YP.write(Atom.a(":")); - YP.nl(); - foreach (bool l3 in YP.unify(NextLevel, YP.add(Level, 1))) - { - foreach (bool l4 in convertStatementListPython(Body, NextLevel, HasBreakableBlock)) - { - foreach (bool l5 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable Expression = new Variable(); - Variable Body = new Variable(); - Variable RestStatements = new Variable(); - Variable NextLevel = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor2("foreach", Expression, Body), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Atom.a("for l")); - YP.write(Level); - YP.write(Atom.a(" in ")); - convertExpressionPython(Expression); - YP.write(Atom.a(":")); - YP.nl(); - foreach (bool l3 in YP.unify(NextLevel, YP.add(Level, 1))) - { - foreach (bool l4 in convertStatementListPython(Body, NextLevel, HasBreakableBlock)) - { - if (YP.termEqual(HasBreakableBlock, 1)) - { - convertIndentationPython(Level); - YP.write(Atom.a("if doBreak:")); - YP.nl(); - convertIndentationPython(NextLevel); - YP.write(Atom.a("break")); - YP.nl(); - foreach (bool l6 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - goto cutIf6; - } - foreach (bool l5 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - cutIf6: - { } - } - } - } - } - { - object Level = arg2; - object HasBreakableBlock = arg3; - Variable Expression = new Variable(); - Variable RestStatements = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(new Functor1("throw", Expression), RestStatements))) - { - convertIndentationPython(Level); - YP.write(Atom.a("raise ")); - convertExpressionPython(Expression); - YP.nl(); - foreach (bool l3 in convertStatementListPython(RestStatements, Level, HasBreakableBlock)) - { - yield return true; - yield break; - } - } - } - } - - public static void convertIndentationPython(object Level) - { - { - Variable N = new Variable(); - foreach (bool l2 in YP.unify(N, YP.multiply(Level, 2))) - { - repeatWrite(Atom.a(" "), N); - return; - } - } - } - - public static void convertArgListPython(object arg1) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - return; - } - } - { - Variable Head = new Variable(); - Variable Tail = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Head, Tail))) - { - convertExpressionPython(Head); - if (YP.termNotEqual(Tail, Atom.NIL)) - { - YP.write(Atom.a(", ")); - convertArgListPython(Tail); - return; - goto cutIf1; - } - convertArgListPython(Tail); - return; - cutIf1: - { } - } - } - } - - public static void convertExpressionPython(object arg1) - { - { - Variable X = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("arg", X))) - { - YP.write(X); - return; - } - } - { - Variable Name = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("call", Name, ArgList))) - { - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListPython(ArgList); - YP.write(Atom.a(")")); - return; - } - } - { - Variable Name = new Variable(); - Variable _FunctorArgs = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor3("functorCall", Name, _FunctorArgs, ArgList))) - { - convertExpressionPython(new Functor2("call", Name, ArgList)); - return; - } - } - { - Variable Obj = new Variable(); - Variable Name = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor3("callMember", new Functor1("var", Obj), Name, ArgList))) - { - YP.write(Obj); - YP.write(Atom.a(".")); - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListPython(ArgList); - YP.write(Atom.a(")")); - return; - } - } - { - Variable Name = new Variable(); - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("new", Name, ArgList))) - { - YP.write(Name); - YP.write(Atom.a("(")); - convertArgListPython(ArgList); - YP.write(Atom.a(")")); - return; - } - } - { - Variable Name = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("var", Name))) - { - YP.write(Name); - return; - } - } - { - foreach (bool l2 in YP.unify(arg1, Atom.a("null"))) - { - YP.write(Atom.a("None")); - return; - } - } - { - Variable X = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("not", X))) - { - YP.write(Atom.a("not (")); - convertExpressionPython(X); - YP.write(Atom.a(")")); - return; - } - } - { - Variable X = new Variable(); - Variable Y = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor2("and", X, Y))) - { - YP.write(Atom.a("(")); - convertExpressionPython(X); - YP.write(Atom.a(") and (")); - convertExpressionPython(Y); - YP.write(Atom.a(")")); - return; - } - } - { - Variable ArgList = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("objectArray", ArgList))) - { - YP.write(Atom.a("[")); - convertArgListPython(ArgList); - YP.write(Atom.a("]")); - return; - } - } - { - Variable X = new Variable(); - Variable Codes = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("object", X))) - { - if (YP.atom(X)) - { - YP.write(Atom.a("\"")); - foreach (bool l4 in YP.atom_codes(X, Codes)) - { - convertStringCodesPython(Codes); - YP.write(Atom.a("\"")); - return; - } - } - } - } - { - Variable X = new Variable(); - foreach (bool l2 in YP.unify(arg1, new Functor1("object", X))) - { - YP.write(X); - return; - } - } - } - - public static void convertStringCodesPython(object arg1) - { - { - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - return; - } - } - { - Variable Code = new Variable(); - Variable RestCodes = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(Code, RestCodes))) - { - if (YP.termEqual(Code, 34)) - { - YP.put_code(92); - YP.put_code(Code); - convertStringCodesPython(RestCodes); - return; - goto cutIf1; - } - if (YP.termEqual(Code, 92)) - { - YP.put_code(92); - YP.put_code(Code); - convertStringCodesPython(RestCodes); - return; - goto cutIf1; - } - YP.put_code(Code); - convertStringCodesPython(RestCodes); - return; - cutIf1: - { } - } - } - } - - public static IEnumerable putCStringCode(object Code) - { - { - Variable HexDigit = new Variable(); - Variable HexChar = new Variable(); - if (YP.lessThanOrEqual(Code, 31)) - { - if (YP.lessThanOrEqual(Code, 15)) - { - YP.write(Atom.a("\\u000")); - foreach (bool l4 in YP.unify(HexDigit, Code)) - { - if (YP.lessThanOrEqual(HexDigit, 9)) - { - foreach (bool l6 in YP.unify(HexChar, YP.add(HexDigit, 48))) - { - YP.put_code(HexChar); - yield return true; - yield break; - } - goto cutIf2; - } - foreach (bool l5 in YP.unify(HexChar, YP.add(HexDigit, 55))) - { - YP.put_code(HexChar); - yield return true; - yield break; - } - cutIf2: - { } - } - goto cutIf1; - } - YP.write(Atom.a("\\u001")); - foreach (bool l3 in YP.unify(HexDigit, YP.subtract(Code, 16))) - { - if (YP.lessThanOrEqual(HexDigit, 9)) - { - foreach (bool l5 in YP.unify(HexChar, YP.add(HexDigit, 48))) - { - YP.put_code(HexChar); - yield return true; - yield break; - } - goto cutIf3; - } - foreach (bool l4 in YP.unify(HexChar, YP.add(HexDigit, 55))) - { - YP.put_code(HexChar); - yield return true; - yield break; - } - cutIf3: - { } - } - cutIf1: - { } - } - } - { - if (YP.termEqual(Code, 34)) - { - YP.put_code(92); - YP.put_code(34); - yield return true; - yield break; - } - } - { - if (YP.termEqual(Code, 92)) - { - YP.put_code(92); - YP.put_code(92); - yield return true; - yield break; - } - } - { - YP.put_code(Code); - yield return true; - yield break; - } - } - - public static IEnumerable member(object X, object arg2) - { - { - Variable x2 = new Variable(); - foreach (bool l2 in YP.unify(arg2, new ListPair(X, x2))) - { - yield return false; - } - } - { - Variable x2 = new Variable(); - Variable Rest = new Variable(); - foreach (bool l2 in YP.unify(arg2, new ListPair(x2, Rest))) - { - foreach (bool l3 in member(X, Rest)) - { - yield return false; - } - } - } - } - - public static IEnumerable append(object arg1, object arg2, object arg3) - { - { - Variable List = new Variable(); - foreach (bool l2 in YP.unify(arg1, Atom.NIL)) - { - foreach (bool l3 in YP.unify(arg2, List)) - { - foreach (bool l4 in YP.unify(arg3, List)) - { - yield return false; - } - } - } - } - { - object List2 = arg2; - Variable X = new Variable(); - Variable List1 = new Variable(); - Variable List12 = new Variable(); - foreach (bool l2 in YP.unify(arg1, new ListPair(X, List1))) - { - foreach (bool l3 in YP.unify(arg3, new ListPair(X, List12))) - { - foreach (bool l4 in append(List1, List2, List12)) - { - yield return false; - } - } - } - } - } - #pragma warning restore 0168, 0219, 0164,0162 - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs index 97dd0f6..4e0c273 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; using System.Reflection; using log4net; using Tools; - using OpenSim.Region.Framework.Interfaces; namespace OpenSim.Region.ScriptEngine.Shared.CodeTools @@ -49,6 +48,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools private List m_warnings = new List(); private IScriptModuleComms m_comms = null; + private bool m_insertCoopTerminationChecks; + private static string m_coopTerminationCheck = "opensim_reserved_CheckForCoopTermination();"; + + /// + /// Keep a record of the previous node when we do the parsing. + /// + /// + /// We do this here because the parser generated by CSTools does not retain a reference to its parent node. + /// The previous node is required so we can correctly insert co-op termination checks when required. + /// +// private SYMBOL m_previousNode; + /// /// Creates an 'empty' CSCodeGenerator instance. /// @@ -58,9 +69,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools ResetCounters(); } - public CSCodeGenerator(IScriptModuleComms comms) + public CSCodeGenerator(IScriptModuleComms comms, bool insertCoopTerminationChecks) { m_comms = comms; + m_insertCoopTerminationChecks = insertCoopTerminationChecks; ResetCounters(); } @@ -150,12 +162,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools m_braceCount++; // line number - m_CSharpLine += 3; + m_CSharpLine += 9; // here's the payload retstr += GenerateLine(); foreach (SYMBOL s in m_astRoot.kids) - retstr += GenerateNode(s); + retstr += GenerateNode(m_astRoot, s); // close braces! m_braceCount--; @@ -165,7 +177,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // Removes all carriage return characters which may be generated in Windows platform. Is there // cleaner way of doing this? - retstr=retstr.Replace("\r", ""); + retstr = retstr.Replace("\r", ""); return retstr; } @@ -191,9 +203,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// Recursively called to generate each type of node. Will generate this /// node, then all it's children. /// + /// The parent node. /// The current node to generate code for. /// String containing C# code for SYMBOL s. - private string GenerateNode(SYMBOL s) + private string GenerateNode(SYMBOL previousSymbol, SYMBOL s) { string retstr = String.Empty; @@ -207,11 +220,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools else if (s is State) retstr += GenerateState((State) s); else if (s is CompoundStatement) - retstr += GenerateCompoundStatement((CompoundStatement) s); + retstr += GenerateCompoundStatement(previousSymbol, (CompoundStatement) s); else if (s is Declaration) retstr += GenerateDeclaration((Declaration) s); else if (s is Statement) - retstr += GenerateStatement((Statement) s); + retstr += GenerateStatement(previousSymbol, (Statement) s); else if (s is ReturnStatement) retstr += GenerateReturnStatement((ReturnStatement) s); else if (s is JumpLabel) @@ -261,7 +274,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools else { foreach (SYMBOL kid in s.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(s, kid); } return retstr; @@ -295,7 +308,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += GenerateLine(")"); foreach (SYMBOL kid in remainingKids) - retstr += GenerateNode(kid); + retstr += GenerateNode(gf, kid); return retstr; } @@ -312,7 +325,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools foreach (SYMBOL s in gv.kids) { retstr += Indent(); - retstr += GenerateNode(s); + retstr += GenerateNode(gv, s); retstr += GenerateLine(";"); } @@ -365,7 +378,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += GenerateLine(")"); foreach (SYMBOL kid in remainingKids) - retstr += GenerateNode(kid); + retstr += GenerateNode(se, kid); return retstr; } @@ -404,7 +417,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools foreach (SYMBOL s in al.kids) { - retstr += GenerateNode(s); + retstr += GenerateNode(al, s); if (0 < comma--) retstr += Generate(", "); } @@ -417,7 +430,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// /// The CompoundStatement node. /// String containing C# code for CompoundStatement cs. - private string GenerateCompoundStatement(CompoundStatement cs) + private string GenerateCompoundStatement(SYMBOL previousSymbol, CompoundStatement cs) { string retstr = String.Empty; @@ -425,8 +438,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += GenerateIndentedLine("{"); m_braceCount++; + if (m_insertCoopTerminationChecks) + { + // We have to check in event functions as well because the user can manually call these. + if (previousSymbol is GlobalFunctionDefinition + || previousSymbol is WhileStatement + || previousSymbol is DoWhileStatement + || previousSymbol is ForLoop + || previousSymbol is StateEvent) + retstr += GenerateIndentedLine(m_coopTerminationCheck); + } + foreach (SYMBOL kid in cs.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(cs, kid); // closing brace m_braceCount--; @@ -450,10 +474,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// /// The Statement node. /// String containing C# code for Statement s. - private string GenerateStatement(Statement s) + private string GenerateStatement(SYMBOL previousSymbol, Statement s) { string retstr = String.Empty; bool printSemicolon = true; + bool transformToBlock = false; + + if (m_insertCoopTerminationChecks) + { + // A non-braced single line do while structure cannot contain multiple statements. + // So to insert the termination check we change this to a braced control structure instead. + if (previousSymbol is WhileStatement + || previousSymbol is DoWhileStatement + || previousSymbol is ForLoop) + { + transformToBlock = true; + + // FIXME: This will be wrongly indented because the previous for/while/dowhile will have already indented. + retstr += GenerateIndentedLine("{"); + + retstr += GenerateIndentedLine(m_coopTerminationCheck); + } + } retstr += Indent(); @@ -466,12 +508,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // (MONO) error. if (!(s.kids.Top is IdentExpression && 1 == s.kids.Count)) foreach (SYMBOL kid in s.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(s, kid); } if (printSemicolon) retstr += GenerateLine(";"); + if (transformToBlock) + { + // FIXME: This will be wrongly indented because the for/while/dowhile is currently handling the unindent + retstr += GenerateIndentedLine("}"); + } + return retstr; } @@ -487,10 +535,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools List identifiers = new List(); checkForMultipleAssignments(identifiers, a); - retstr += GenerateNode((SYMBOL) a.kids.Pop()); + retstr += GenerateNode(a, (SYMBOL) a.kids.Pop()); retstr += Generate(String.Format(" {0} ", a.AssignmentType), a); foreach (SYMBOL kid in a.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(a, kid); return retstr; } @@ -563,7 +611,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += Generate("return ", rs); foreach (SYMBOL kid in rs.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(rs, kid); return retstr; } @@ -575,7 +623,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// String containing C# code for JumpLabel jl. private string GenerateJumpLabel(JumpLabel jl) { - return Generate(String.Format("{0}:", CheckName(jl.LabelName)), jl) + " NoOp();\n"; + string labelStatement; + + if (m_insertCoopTerminationChecks) + labelStatement = m_coopTerminationCheck; + else + labelStatement = "NoOp();"; + + return GenerateLine(String.Format("{0}: {1}", CheckName(jl.LabelName), labelStatement), jl); } /// @@ -598,14 +653,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += GenerateIndented("if (", ifs); - retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); + retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop()); retstr += GenerateLine(")"); // CompoundStatement handles indentation itself but we need to do it // otherwise. bool indentHere = ifs.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); + retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop()); if (indentHere) m_braceCount--; if (0 < ifs.kids.Count) // do it again for an else @@ -614,7 +669,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools indentHere = ifs.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) ifs.kids.Pop()); + retstr += GenerateNode(ifs, (SYMBOL) ifs.kids.Pop()); if (indentHere) m_braceCount--; } @@ -641,14 +696,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += GenerateIndented("while (", ws); - retstr += GenerateNode((SYMBOL) ws.kids.Pop()); + retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop()); retstr += GenerateLine(")"); // CompoundStatement handles indentation itself but we need to do it // otherwise. bool indentHere = ws.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) ws.kids.Pop()); + retstr += GenerateNode(ws, (SYMBOL) ws.kids.Pop()); if (indentHere) m_braceCount--; return retstr; @@ -669,11 +724,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // otherwise. bool indentHere = dws.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) dws.kids.Pop()); + retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop()); if (indentHere) m_braceCount--; retstr += GenerateIndented("while (", dws); - retstr += GenerateNode((SYMBOL) dws.kids.Pop()); + retstr += GenerateNode(dws, (SYMBOL) dws.kids.Pop()); retstr += GenerateLine(");"); return retstr; @@ -702,7 +757,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += Generate("; "); // for (x = 0; x < 10; x++) // ^^^^^^ - retstr += GenerateNode((SYMBOL) fl.kids.Pop()); + retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop()); retstr += Generate("; "); // for (x = 0; x < 10; x++) // ^^^ @@ -713,7 +768,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // otherwise. bool indentHere = fl.kids.Top is Statement; if (indentHere) m_braceCount++; - retstr += GenerateNode((SYMBOL) fl.kids.Pop()); + retstr += GenerateNode(fl, (SYMBOL) fl.kids.Pop()); if (indentHere) m_braceCount--; return retstr; @@ -758,7 +813,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools while (s is ParenthesisExpression) s = (SYMBOL)s.kids.Pop(); - retstr += GenerateNode(s); + retstr += GenerateNode(fls, s); if (0 < comma--) retstr += Generate(", "); } @@ -779,20 +834,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools { // special case handling for logical and/or, see Mantis 3174 retstr += "((bool)("; - retstr += GenerateNode((SYMBOL)be.kids.Pop()); + retstr += GenerateNode(be, (SYMBOL)be.kids.Pop()); retstr += "))"; retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol.Substring(0,1)), be); retstr += "((bool)("; foreach (SYMBOL kid in be.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(be, kid); retstr += "))"; } else { - retstr += GenerateNode((SYMBOL)be.kids.Pop()); + retstr += GenerateNode(be, (SYMBOL)be.kids.Pop()); retstr += Generate(String.Format(" {0} ", be.ExpressionSymbol), be); foreach (SYMBOL kid in be.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(be, kid); } return retstr; @@ -808,7 +863,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += Generate(ue.UnarySymbol, ue); - retstr += GenerateNode((SYMBOL) ue.kids.Pop()); + retstr += GenerateNode(ue, (SYMBOL) ue.kids.Pop()); return retstr; } @@ -824,7 +879,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += Generate("("); foreach (SYMBOL kid in pe.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(pe, kid); retstr += Generate(")"); return retstr; @@ -861,7 +916,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // we wrap all typecasted statements in parentheses retstr += Generate(String.Format("({0}) (", te.TypecastType), te); - retstr += GenerateNode((SYMBOL) te.kids.Pop()); + retstr += GenerateNode(te, (SYMBOL) te.kids.Pop()); retstr += Generate(")"); return retstr; @@ -882,7 +937,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools { string retval = null; if (value is int) - retval = ((int)value).ToString(); + retval = String.Format("new LSL_Types.LSLInteger({0})",((int)value).ToString()); else if (value is float) retval = String.Format("new LSL_Types.LSLFloat({0})",((float)value).ToString()); else if (value is string) @@ -931,7 +986,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools } foreach (SYMBOL kid in fc.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(fc, kid); retstr += Generate(")"); @@ -980,11 +1035,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += Generate(String.Format("new {0}(", vc.Type), vc); - retstr += GenerateNode((SYMBOL) vc.kids.Pop()); + retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) vc.kids.Pop()); + retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) vc.kids.Pop()); + retstr += GenerateNode(vc, (SYMBOL) vc.kids.Pop()); retstr += Generate(")"); return retstr; @@ -1000,13 +1055,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools string retstr = String.Empty; retstr += Generate(String.Format("new {0}(", rc.Type), rc); - retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); retstr += Generate(", "); - retstr += GenerateNode((SYMBOL) rc.kids.Pop()); + retstr += GenerateNode(rc, (SYMBOL) rc.kids.Pop()); retstr += Generate(")"); return retstr; @@ -1024,7 +1079,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools retstr += Generate(String.Format("new {0}(", lc.Type), lc); foreach (SYMBOL kid in lc.kids) - retstr += GenerateNode(kid); + retstr += GenerateNode(lc, kid); retstr += Generate(")"); diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index 03be2ab..af324bf 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs @@ -58,9 +58,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools { lsl = 0, cs = 1, - vb = 2, - js = 3, - yp = 4 + vb = 2 } /// @@ -72,6 +70,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools private bool CompileWithDebugInformation; private Dictionary AllowedCompilers = new Dictionary(StringComparer.CurrentCultureIgnoreCase); private Dictionary LanguageMapping = new Dictionary(StringComparer.CurrentCultureIgnoreCase); + private bool m_insertCoopTerminationCalls; private string FilePrefix; private string ScriptEnginesPath = null; @@ -84,9 +83,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools private static CSharpCodeProvider CScodeProvider = new CSharpCodeProvider(); private static VBCodeProvider VBcodeProvider = new VBCodeProvider(); -// private static JScriptCodeProvider JScodeProvider = new JScriptCodeProvider(); - private static CSharpCodeProvider YPcodeProvider = new CSharpCodeProvider(); // YP is translated into CSharp - private static YP2CSConverter YP_Converter = new YP2CSConverter(); // private static int instanceID = new Random().Next(0, int.MaxValue); // Unique number to use on our compiled files private static UInt64 scriptCompileCounter = 0; // And a counter @@ -95,20 +91,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools private Dictionary, KeyValuePair>> m_lineMaps = new Dictionary, KeyValuePair>>(); + public bool in_startup = true; + public Compiler(IScriptEngine scriptEngine) { - m_scriptEngine = scriptEngine;; + m_scriptEngine = scriptEngine; ScriptEnginesPath = scriptEngine.ScriptEnginePath; ReadConfig(); } - public bool in_startup = true; public void ReadConfig() { // Get some config WriteScriptSourceToDebugFile = m_scriptEngine.Config.GetBoolean("WriteScriptSourceToDebugFile", false); CompileWithDebugInformation = m_scriptEngine.Config.GetBoolean("CompileWithDebugInformation", true); bool DeleteScriptsOnStartup = m_scriptEngine.Config.GetBoolean("DeleteScriptsOnStartup", true); + m_insertCoopTerminationCalls = m_scriptEngine.Config.GetString("ScriptStopStrategy", "abort") == "co-op"; // Get file prefix from scriptengine name and make it file system safe: FilePrefix = "CommonCompiler"; @@ -120,7 +118,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools if (in_startup) { in_startup = false; - CreateScriptsDirectory(); + CheckOrCreateScriptsDirectory(); // First time we start? Delete old files if (DeleteScriptsOnStartup) @@ -131,8 +129,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools LanguageMapping.Add(enumCompileType.cs.ToString(), enumCompileType.cs); LanguageMapping.Add(enumCompileType.vb.ToString(), enumCompileType.vb); LanguageMapping.Add(enumCompileType.lsl.ToString(), enumCompileType.lsl); - LanguageMapping.Add(enumCompileType.js.ToString(), enumCompileType.js); - LanguageMapping.Add(enumCompileType.yp.ToString(), enumCompileType.yp); // Allowed compilers string allowComp = m_scriptEngine.Config.GetString("AllowedCompilers", "lsl"); @@ -189,13 +185,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools } // We now have an allow-list, a mapping list, and a default language - } /// - /// Create the directory where compiled scripts are stored. + /// Create the directory where compiled scripts are stored if it does not already exist. /// - private void CreateScriptsDirectory() + private void CheckOrCreateScriptsDirectory() { if (!Directory.Exists(ScriptEnginesPath)) { @@ -285,15 +280,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools return GetCompilerOutput(assetID.ToString()); } - /// - /// Converts script from LSL to CS and calls CompileFromCSText - /// - /// LSL script - /// Filename to .dll assembly - public void PerformScriptCompile(string Script, string asset, UUID ownerUUID, + public void PerformScriptCompile( + string source, string asset, UUID ownerUUID, out string assembly, out Dictionary, KeyValuePair> linemap) { -// m_log.DebugFormat("[Compiler]: Compiling script\n{0}", Script); + PerformScriptCompile(source, asset, ownerUUID, false, out assembly, out linemap); + } + + public void PerformScriptCompile( + string source, string asset, UUID ownerUUID, bool alwaysRecompile, + out string assembly, out Dictionary, KeyValuePair> linemap) + { +// m_log.DebugFormat("[Compiler]: Checking script for asset {0} in {1}\n{2}", asset, m_scriptEngine.World.Name, source); IScriptModuleComms comms = m_scriptEngine.World.RequestModuleInterface(); @@ -302,33 +300,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools assembly = GetCompilerOutput(asset); - if (!Directory.Exists(ScriptEnginesPath)) - { - try - { - Directory.CreateDirectory(ScriptEnginesPath); - } - catch (Exception) - { - } - } +// m_log.DebugFormat("[Compiler]: Retrieved assembly {0} for asset {1} in {2}", assembly, asset, m_scriptEngine.World.Name); - if (!Directory.Exists(Path.Combine(ScriptEnginesPath, - m_scriptEngine.World.RegionInfo.RegionID.ToString()))) - { - try - { - Directory.CreateDirectory(ScriptEnginesPath); - } - catch (Exception) - { - } - } + CheckOrCreateScriptsDirectory(); - // Don't recompile if we already have it + // Don't recompile if we're not forced to and we already have it // Performing 3 file exists tests for every script can still be slow - if (File.Exists(assembly) && File.Exists(assembly + ".text") && File.Exists(assembly + ".map")) + if (!alwaysRecompile && File.Exists(assembly) && File.Exists(assembly + ".text") && File.Exists(assembly + ".map")) { +// m_log.DebugFormat("[Compiler]: Found existing assembly {0} for asset {1} in {2}", assembly, asset, m_scriptEngine.World.Name); + // If we have already read this linemap file, then it will be in our dictionary. // Don't build another copy of the dictionary (saves memory) and certainly // don't keep reading the same file from disk multiple times. @@ -338,31 +319,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools return; } - if (Script == String.Empty) - { +// m_log.DebugFormat("[Compiler]: Compiling assembly {0} for asset {1} in {2}", assembly, asset, m_scriptEngine.World.Name); + + if (source == String.Empty) throw new Exception("Cannot find script assembly and no script text present"); - } enumCompileType language = DefaultCompileLanguage; - if (Script.StartsWith("//c#", true, CultureInfo.InvariantCulture)) + if (source.StartsWith("//c#", true, CultureInfo.InvariantCulture)) language = enumCompileType.cs; - if (Script.StartsWith("//vb", true, CultureInfo.InvariantCulture)) + if (source.StartsWith("//vb", true, CultureInfo.InvariantCulture)) { language = enumCompileType.vb; // We need to remove //vb, it won't compile with that - Script = Script.Substring(4, Script.Length - 4); + source = source.Substring(4, source.Length - 4); } - if (Script.StartsWith("//lsl", true, CultureInfo.InvariantCulture)) + if (source.StartsWith("//lsl", true, CultureInfo.InvariantCulture)) language = enumCompileType.lsl; - if (Script.StartsWith("//js", true, CultureInfo.InvariantCulture)) - language = enumCompileType.js; - - if (Script.StartsWith("//yp", true, CultureInfo.InvariantCulture)) - language = enumCompileType.yp; - // m_log.DebugFormat("[Compiler]: Compile language is {0}", language); if (!AllowedCompilers.ContainsKey(language.ToString())) @@ -381,13 +356,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools throw new Exception(errtext); } - string compileScript = Script; + string compileScript = source; if (language == enumCompileType.lsl) { // Its LSL, convert it to C# - LSL_Converter = (ICodeConverter)new CSCodeGenerator(comms); - compileScript = LSL_Converter.Convert(Script); + LSL_Converter = (ICodeConverter)new CSCodeGenerator(comms, m_insertCoopTerminationCalls); + compileScript = LSL_Converter.Convert(source); // copy converter warnings into our warnings. foreach (string warning in LSL_Converter.GetWarnings()) @@ -401,26 +376,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools WriteMapFile(assembly + ".map", linemap); } - if (language == enumCompileType.yp) - { - // Its YP, convert it to C# - compileScript = YP_Converter.Convert(Script); - } - switch (language) { case enumCompileType.cs: case enumCompileType.lsl: - compileScript = CreateCSCompilerScript(compileScript); + compileScript = CreateCSCompilerScript( + compileScript, + m_scriptEngine.ScriptClassName, + m_scriptEngine.ScriptBaseClassName, + m_scriptEngine.ScriptBaseClassParameters); break; case enumCompileType.vb: - compileScript = CreateVBCompilerScript(compileScript); - break; -// case enumCompileType.js: -// compileScript = CreateJSCompilerScript(compileScript); -// break; - case enumCompileType.yp: - compileScript = CreateYPCompilerScript(compileScript); + compileScript = CreateVBCompilerScript( + compileScript, m_scriptEngine.ScriptClassName, m_scriptEngine.ScriptBaseClassName); break; } @@ -451,43 +419,44 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // return compileScript; // } - private static string CreateCSCompilerScript(string compileScript) + public static string CreateCSCompilerScript( + string compileScript, string className, string baseClassName, ParameterInfo[] constructorParameters) { - compileScript = String.Empty + - "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + - String.Empty + "namespace SecondLife { " + - String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + - @"public Script() { } " + - compileScript + - "} }\r\n"; - return compileScript; - } + compileScript = string.Format( +@"using OpenSim.Region.ScriptEngine.Shared; +using System.Collections.Generic; + +namespace SecondLife +{{ + public class {0} : {1} + {{ + public {0}({2}) : base({3}) {{}} +{4} + }} +}}", + className, + baseClassName, + constructorParameters != null + ? string.Join(", ", Array.ConvertAll(constructorParameters, pi => pi.ToString())) + : "", + constructorParameters != null + ? string.Join(", ", Array.ConvertAll(constructorParameters, pi => pi.Name)) + : "", + compileScript); - private static string CreateYPCompilerScript(string compileScript) - { - compileScript = String.Empty + - "using OpenSim.Region.ScriptEngine.Shared.YieldProlog; " + - "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + - String.Empty + "namespace SecondLife { " + - String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + - //@"public Script() { } " + - @"static OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP YP=null; " + - @"public Script() { YP= new OpenSim.Region.ScriptEngine.Shared.YieldProlog.YP(); } " + - - compileScript + - "} }\r\n"; return compileScript; } - private static string CreateVBCompilerScript(string compileScript) + public static string CreateVBCompilerScript(string compileScript, string className, string baseClassName) { compileScript = String.Empty + "Imports OpenSim.Region.ScriptEngine.Shared: Imports System.Collections.Generic: " + String.Empty + "NameSpace SecondLife:" + - String.Empty + "Public Class Script: Inherits OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass: " + + String.Empty + "Public Class " + className + ": Inherits " + baseClassName + "\r\nPublic Sub New()\r\nEnd Sub: " + compileScript + ":End Class :End Namespace\r\n"; + return compileScript; } @@ -506,7 +475,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools scriptCompileCounter++; try { - File.Delete(assembly); + if (File.Exists(assembly)) + { + File.SetAttributes(assembly, FileAttributes.Normal); + File.Delete(assembly); + } } catch (Exception e) // NOTLEGIT - Should be just FileIOException { @@ -549,11 +522,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenMetaverseTypes.dll")); - if (lang == enumCompileType.yp) - { - parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, - "OpenSim.Region.ScriptEngine.Shared.YieldProlog.dll")); - } + if (m_scriptEngine.ScriptReferencedAssemblies != null) + Array.ForEach( + m_scriptEngine.ScriptReferencedAssemblies, + a => parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, a))); parameters.GenerateExecutable = false; parameters.OutputAssembly = assembly; @@ -579,6 +551,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools results = CScodeProvider.CompileAssemblyFromSource( parameters, Script); } + // Deal with an occasional segv in the compiler. // Rarely, if ever, occurs twice in succession. // Line # == 0 and no file name are indications that @@ -586,7 +559,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // error log. if (results.Errors.Count > 0) { - if (!retried && (results.Errors[0].FileName == null || results.Errors[0].FileName == String.Empty) && + if (!retried && string.IsNullOrEmpty(results.Errors[0].FileName) && results.Errors[0].Line == 0) { // System.Console.WriteLine("retrying failed compilation"); @@ -603,41 +576,42 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools } } while (!complete); break; -// case enumCompileType.js: -// results = JScodeProvider.CompileAssemblyFromSource( -// parameters, Script); -// break; - case enumCompileType.yp: - results = YPcodeProvider.CompileAssemblyFromSource( - parameters, Script); - break; default: throw new Exception("Compiler is not able to recongnize " + "language type \"" + lang.ToString() + "\""); } - // Check result - // Go through errors +// foreach (Type type in results.CompiledAssembly.GetTypes()) +// { +// foreach (MethodInfo method in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) +// { +// m_log.DebugFormat("[COMPILER]: {0}.{1}", type.FullName, method.Name); +// } +// } // // WARNINGS AND ERRORS // bool hadErrors = false; string errtext = String.Empty; - if (results.Errors.Count > 0) { foreach (CompilerError CompErr in results.Errors) { string severity = CompErr.IsWarning ? "Warning" : "Error"; - KeyValuePair lslPos; + KeyValuePair errorPos; // Show 5 errors max, but check entire list for errors if (severity == "Error") { - lslPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]); + // C# scripts will not have a linemap since theres no line translation involved. + if (!m_lineMaps.ContainsKey(assembly)) + errorPos = new KeyValuePair(CompErr.Line, CompErr.Column); + else + errorPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]); + string text = CompErr.ErrorText; // Use LSL type names @@ -647,7 +621,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // The Second Life viewer's script editor begins // countingn lines and columns at 0, so we subtract 1. errtext += String.Format("({0},{1}): {4} {2}: {3}\n", - lslPos.Key - 1, lslPos.Value - 1, + errorPos.Key - 1, errorPos.Value - 1, CompErr.ErrorNumber, text, severity); hadErrors = true; } @@ -699,9 +673,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools try { - FileStream fs = File.Open(assembly, FileMode.Open, FileAccess.Read); - fs.Read(data, 0, data.Length); - fs.Close(); + using (FileStream fs = File.Open(assembly, FileMode.Open, FileAccess.Read)) + fs.Read(data, 0, data.Length); } catch (Exception) { @@ -716,19 +689,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools Byte[] buf = Encoding.ASCII.GetBytes(filetext); - FileStream sfs = File.Create(assembly + ".text"); - sfs.Write(buf, 0, buf.Length); - sfs.Close(); + using (FileStream sfs = File.Create(assembly + ".text")) + sfs.Write(buf, 0, buf.Length); return assembly; } - private class kvpSorter : IComparer> + private class kvpSorter : IComparer, KeyValuePair>> { - public int Compare(KeyValuePair a, - KeyValuePair b) + public int Compare(KeyValuePair, KeyValuePair> a, + KeyValuePair, KeyValuePair> b) { - return a.Key.CompareTo(b.Key); + int kc = a.Key.Key.CompareTo(b.Key.Key); + return (kc != 0) ? kc : a.Key.Value.CompareTo(b.Key.Value); } } @@ -745,30 +718,46 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools out ret)) return ret; - List> sorted = - new List>(positionMap.Keys); + var sorted = new List, KeyValuePair>>(positionMap); sorted.Sort(new kvpSorter()); int l = 1; int c = 1; + int pl = 1; - foreach (KeyValuePair cspos in sorted) + foreach (KeyValuePair, KeyValuePair> posmap in sorted) { - if (cspos.Key >= line) + //m_log.DebugFormat("[Compiler]: Scanning line map {0},{1} --> {2},{3}", posmap.Key.Key, posmap.Key.Value, posmap.Value.Key, posmap.Value.Value); + int nl = posmap.Value.Key + line - posmap.Key.Key; // New, translated LSL line and column. + int nc = posmap.Value.Value + col - posmap.Key.Value; + // Keep going until we find the first point passed line,col. + if (posmap.Key.Key > line) { - if (cspos.Key > line) - return new KeyValuePair(l, c); - if (cspos.Value > col) - return new KeyValuePair(l, c); - c = cspos.Value; - if (c == 0) - c++; + //m_log.DebugFormat("[Compiler]: Line is larger than requested {0},{1}, returning {2},{3}", line, col, l, c); + if (pl < line) + { + //m_log.DebugFormat("[Compiler]: Previous line ({0}) is less than requested line ({1}), setting column to 1.", pl, line); + c = 1; + } + break; } - else + if (posmap.Key.Key == line && posmap.Key.Value > col) { - l = cspos.Key; + // Never move l,c backwards. + if (nl > l || (nl == l && nc > c)) + { + //m_log.DebugFormat("[Compiler]: Using offset relative to this: {0} + {1} - {2}, {3} + {4} - {5} = {6}, {7}", + // posmap.Value.Key, line, posmap.Key.Key, posmap.Value.Value, col, posmap.Key.Value, nl, nc); + l = nl; + c = nc; + } + //m_log.DebugFormat("[Compiler]: Column is larger than requested {0},{1}, returning {2},{3}", line, col, l, c); + break; } + pl = posmap.Key.Key; + l = posmap.Value.Key; + c = posmap.Value.Value; } return new KeyValuePair(l, c); } @@ -794,7 +783,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools return message; } - private static void WriteMapFile(string filename, Dictionary, KeyValuePair> linemap) { string mapstring = String.Empty; @@ -806,40 +794,42 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools } Byte[] mapbytes = Encoding.ASCII.GetBytes(mapstring); - FileStream mfs = File.Create(filename); - mfs.Write(mapbytes, 0, mapbytes.Length); - mfs.Close(); - } + using (FileStream mfs = File.Create(filename)) + mfs.Write(mapbytes, 0, mapbytes.Length); + } private static Dictionary, KeyValuePair> ReadMapFile(string filename) { Dictionary, KeyValuePair> linemap; try { - StreamReader r = File.OpenText(filename); - linemap = new Dictionary, KeyValuePair>(); - - string line; - while ((line = r.ReadLine()) != null) + using (StreamReader r = File.OpenText(filename)) { - String[] parts = line.Split(new Char[] { ',' }); - int kk = System.Convert.ToInt32(parts[0]); - int kv = System.Convert.ToInt32(parts[1]); - int vk = System.Convert.ToInt32(parts[2]); - int vv = System.Convert.ToInt32(parts[3]); + linemap = new Dictionary, KeyValuePair>(); - KeyValuePair k = new KeyValuePair(kk, kv); - KeyValuePair v = new KeyValuePair(vk, vv); + string line; + while ((line = r.ReadLine()) != null) + { + String[] parts = line.Split(new Char[] { ',' }); + int kk = System.Convert.ToInt32(parts[0]); + int kv = System.Convert.ToInt32(parts[1]); + int vk = System.Convert.ToInt32(parts[2]); + int vv = System.Convert.ToInt32(parts[3]); + + KeyValuePair k = new KeyValuePair(kk, kv); + KeyValuePair v = new KeyValuePair(vk, vv); - linemap[k] = v; + linemap[k] = v; + } } } catch { linemap = new Dictionary, KeyValuePair>(); } + return linemap; } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/LSL2CSCodeTransformer.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/LSL2CSCodeTransformer.cs index e77b3d2..0fb3574 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/LSL2CSCodeTransformer.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/LSL2CSCodeTransformer.cs @@ -27,12 +27,16 @@ using System; using System.Collections.Generic; +using System.Reflection; +using log4net; using Tools; namespace OpenSim.Region.ScriptEngine.Shared.CodeTools { public class LSL2CSCodeTransformer { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private SYMBOL m_astRoot = null; private static Dictionary m_datatypeLSL2OpenSim = null; @@ -78,6 +82,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools /// The current node to transform. private void TransformNode(SYMBOL s) { +// m_log.DebugFormat("[LSL2CSCODETRANSFORMER]: Tranforming node {0}", s); + // make sure to put type lower in the inheritance hierarchy first // ie: since IdentConstant and StringConstant inherit from Constant, // put IdentConstant and StringConstant before Constant @@ -103,10 +109,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // We need to check for that here. if (null != s.kids[i]) { +// m_log.Debug("[LSL2CSCODETRANSFORMER]: Moving down level"); + if (!(s is Assignment || s is ArgumentDeclarationList) && s.kids[i] is Declaration) AddImplicitInitialization(s, i); TransformNode((SYMBOL) s.kids[i]); + +// m_log.Debug("[LSL2CSCODETRANSFORMER]: Moving up level"); } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs index c65caa8..0aece99 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; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs index 77e087c..b92f3a3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CSCodeGeneratorTest.cs @@ -762,6 +762,7 @@ default public void TestIfStatement() { TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); string input = @"// let's test if statements diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs index 05a8756..b476e32 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs @@ -25,12 +25,14 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System; using System.IO; using System.CodeDom.Compiler; using System.Collections.Generic; using Microsoft.CSharp; using NUnit.Framework; using OpenSim.Region.ScriptEngine.Shared.CodeTools; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Tests.Common; namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests @@ -46,7 +48,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests private string m_testDir; private CSharpCodeProvider m_CSCodeProvider; private CompilerParameters m_compilerParameters; - private CompilerResults m_compilerResults; + // private CompilerResults m_compilerResults; + private ResolveEventHandler m_resolveEventHandler; /// /// Creates a temporary directory where build artifacts are stored. @@ -61,14 +64,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests // Create the temporary directory for housing build artifacts. Directory.CreateDirectory(m_testDir); } + } + + [SetUp] + public override void SetUp() + { + base.SetUp(); // Create a CSCodeProvider and CompilerParameters. m_CSCodeProvider = new CSharpCodeProvider(); m_compilerParameters = new CompilerParameters(); - string rootPath = Path.Combine(Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory), "bin"); + string rootPath = System.AppDomain.CurrentDomain.BaseDirectory; + + m_resolveEventHandler = new ResolveEventHandler(AssemblyResolver.OnAssemblyResolve); + + System.AppDomain.CurrentDomain.AssemblyResolve += m_resolveEventHandler; + m_compilerParameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.dll")); m_compilerParameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.Api.Runtime.dll")); + m_compilerParameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenMetaverseTypes.dll")); m_compilerParameters.GenerateExecutable = false; } @@ -76,9 +91,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests /// Removes the temporary build directory and any build artifacts /// inside it. /// - [TestFixtureTearDown] + [TearDown] public void CleanUp() { + System.AppDomain.CurrentDomain.AssemblyResolve -= m_resolveEventHandler; + if (Directory.Exists(m_testDir)) { // Blow away the temporary directory with artifacts. @@ -86,52 +103,100 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests } } + private CompilerResults CompileScript( + string input, out Dictionary, KeyValuePair> positionMap) + { + m_compilerParameters.OutputAssembly = Path.Combine(m_testDir, Path.GetRandomFileName() + ".dll"); + + CSCodeGenerator cg = new CSCodeGenerator(); + string output = cg.Convert(input); + + output = Compiler.CreateCSCompilerScript(output, "script1", typeof(ScriptBaseClass).FullName, null); + // System.Console.WriteLine(output); + + positionMap = cg.PositionMap; + + CompilerResults compilerResults = m_CSCodeProvider.CompileAssemblyFromSource(m_compilerParameters, output); + + // foreach (KeyValuePair key in positionMap.Keys) + // { + // KeyValuePair val = positionMap[key]; + // + // System.Console.WriteLine("{0},{1} => {2},{3}", key.Key, key.Value, val.Key, val.Value); + // } + // + // foreach (CompilerError compErr in m_compilerResults.Errors) + // { + // System.Console.WriteLine("Error: {0},{1} => {2}", compErr.Line, compErr.Column, compErr); + // } + + return compilerResults; + } + + /// + /// Test that line number errors are resolved as expected when preceding code contains a jump. + /// + [Test] + public void TestJumpAndSyntaxError() + { + TestHelpers.InMethod(); + + Dictionary, KeyValuePair> positionMap; + + CompilerResults compilerResults = CompileScript( +@"default +{ + state_entry() + { + jump l; + @l; + i = 1; + } +}", out positionMap); + + Assert.AreEqual( + new KeyValuePair(7, 9), + positionMap[new KeyValuePair(compilerResults.Errors[0].Line, compilerResults.Errors[0].Column)]); + } + /// /// Test the C# compiler error message can be mapped to the correct /// line/column in the LSL source when an undeclared variable is used. /// - //[Test] + [Test] public void TestUseUndeclaredVariable() { TestHelpers.InMethod(); - m_compilerParameters.OutputAssembly = Path.Combine(m_testDir, Path.GetRandomFileName() + ".dll"); + Dictionary, KeyValuePair> positionMap; - string input = @"default + CompilerResults compilerResults = CompileScript( +@"default { state_entry() { integer y = x + 3; } -}"; +}", out positionMap); - CSCodeGenerator cg = new CSCodeGenerator(); - string output = "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\n" + - "namespace SecondLife { " + - "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass {\n" + - "public Script() { } " + - cg.Convert(input) + - "} }\n"; - Dictionary, KeyValuePair> positionMap = cg.PositionMap; - - m_compilerResults = m_CSCodeProvider.CompileAssemblyFromSource(m_compilerParameters, output); - - Assert.AreEqual(new KeyValuePair(5, 21), - positionMap[new KeyValuePair(m_compilerResults.Errors[0].Line, m_compilerResults.Errors[0].Column)]); + Assert.AreEqual( + new KeyValuePair(5, 21), + positionMap[new KeyValuePair(compilerResults.Errors[0].Line, compilerResults.Errors[0].Column)]); } /// /// Test that a string can be cast to string and another string /// concatenated. /// - //[Test] + [Test] public void TestCastAndConcatString() { TestHelpers.InMethod(); - m_compilerParameters.OutputAssembly = Path.Combine(m_testDir, Path.GetRandomFileName() + ".dll"); + Dictionary, KeyValuePair> positionMap; - string input = @"string s = "" a string""; + CompilerResults compilerResults = CompileScript( +@"string s = "" a string""; default { @@ -141,18 +206,9 @@ default string tmp = (string) gAvatarKey + s; llSay(0, tmp); } -}"; +}", out positionMap); - CSCodeGenerator cg = new CSCodeGenerator(); - string output = "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\n" + - "namespace SecondLife { " + - "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass {\n" + - "public Script() { } " + - cg.Convert(input) + - "} }\n"; - m_compilerResults = m_CSCodeProvider.CompileAssemblyFromSource(m_compilerParameters, output); - - Assert.AreEqual(0, m_compilerResults.Errors.Count); + Assert.AreEqual(0, compilerResults.Errors.Count); } } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/LSL_EventTests.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/LSL_EventTests.cs new file mode 100644 index 0000000..67ce10a --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/LSL_EventTests.cs @@ -0,0 +1,359 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using NUnit.Framework; +using OpenSim.Region.ScriptEngine.Shared.CodeTools; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + public class LSL_EventTests : OpenSimTestCase + { + CSCodeGenerator m_cg = new CSCodeGenerator(); + + [Test] + public void TestBadEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestCompile("default { bad() {} }", true); + } + + [Test] + public void TestAttachEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestKeyArgEvent("attach"); + } + + [Test] + public void TestObjectRezEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestKeyArgEvent("object_rez"); + } + + [Test] + public void TestMovingEndEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestVoidArgEvent("moving_end"); + } + + [Test] + public void TestMovingStartEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestVoidArgEvent("moving_start"); + } + + [Test] + public void TestNoSensorEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestVoidArgEvent("no_sensor"); + } + + [Test] + public void TestNotAtRotTargetEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestVoidArgEvent("not_at_rot_target"); + } + + [Test] + public void TestNotAtTargetEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestVoidArgEvent("not_at_target"); + } + + [Test] + public void TestStateEntryEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestVoidArgEvent("state_entry"); + } + + [Test] + public void TestStateExitEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestVoidArgEvent("state_exit"); + } + + [Test] + public void TestTimerEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestVoidArgEvent("timer"); + } + + private void TestVoidArgEvent(string eventName) + { + TestCompile("default { " + eventName + "() {} }", false); + TestCompile("default { " + eventName + "(integer n) {} }", true); + } + + [Test] + public void TestChangedEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestIntArgEvent("changed"); + } + + [Test] + public void TestCollisionEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestIntArgEvent("collision"); + } + + [Test] + public void TestCollisionStartEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestIntArgEvent("collision_start"); + } + + [Test] + public void TestCollisionEndEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestIntArgEvent("collision_end"); + } + + [Test] + public void TestOnRezEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestIntArgEvent("on_rez"); + } + + [Test] + public void TestRunTimePermissionsEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestIntArgEvent("run_time_permissions"); + } + + [Test] + public void TestSensorEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestIntArgEvent("sensor"); + } + + [Test] + public void TestTouchEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestIntArgEvent("touch"); + } + + [Test] + public void TestTouchStartEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestIntArgEvent("touch_start"); + } + + [Test] + public void TestTouchEndEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestIntArgEvent("touch_end"); + } + + [Test] + public void TestLandCollisionEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestVectorArgEvent("land_collision"); + } + + [Test] + public void TestLandCollisionStartEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestVectorArgEvent("land_collision_start"); + } + + [Test] + public void TestLandCollisionEndEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestVectorArgEvent("land_collision_end"); + } + + [Test] + public void TestAtRotTargetEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestIntRotRotArgEvent("at_rot_target"); + } + + [Test] + public void TestAtTargetEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestIntVecVecArgEvent("at_target"); + } + + [Test] + public void TestControlEvent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestKeyIntIntArgEvent("control"); + } + + private void TestIntArgEvent(string eventName) + { + TestCompile("default { " + eventName + "(integer n) {} }", false); + TestCompile("default { " + eventName + "{{}} }", true); + TestCompile("default { " + eventName + "(string s) {{}} }", true); + TestCompile("default { " + eventName + "(integer n, integer o) {{}} }", true); + } + + private void TestKeyArgEvent(string eventName) + { + TestCompile("default { " + eventName + "(key k) {} }", false); + TestCompile("default { " + eventName + "{{}} }", true); + TestCompile("default { " + eventName + "(string s) {{}} }", true); + TestCompile("default { " + eventName + "(key k, key l) {{}} }", true); + } + + private void TestVectorArgEvent(string eventName) + { + TestCompile("default { " + eventName + "(vector v) {} }", false); + TestCompile("default { " + eventName + "{{}} }", true); + TestCompile("default { " + eventName + "(string s) {{}} }", true); + TestCompile("default { " + eventName + "(vector v, vector w) {{}} }", true); + } + + private void TestIntRotRotArgEvent(string eventName) + { + TestCompile("default { " + eventName + "(integer n, rotation r, rotation s) {} }", false); + TestCompile("default { " + eventName + "{{}} }", true); + TestCompile("default { " + eventName + "(string s) {{}} }", true); + TestCompile("default { " + eventName + "(integer n, rotation r, rotation s, rotation t) {{}} }", true); + } + + private void TestIntVecVecArgEvent(string eventName) + { + TestCompile("default { " + eventName + "(integer n, vector v, vector w) {} }", false); + TestCompile("default { " + eventName + "{{}} }", true); + TestCompile("default { " + eventName + "(string s) {{}} }", true); + TestCompile("default { " + eventName + "(integer n, vector v, vector w, vector x) {{}} }", true); + } + + private void TestKeyIntIntArgEvent(string eventName) + { + TestCompile("default { " + eventName + "(key k, integer n, integer o) {} }", false); + TestCompile("default { " + eventName + "{{}} }", true); + TestCompile("default { " + eventName + "(string s) {{}} }", true); + TestCompile("default { " + eventName + "(key k, integer n, integer o, integer p) {{}} }", true); + } + + private void TestCompile(string script, bool expectException) + { + bool gotException = false; + Exception ge = null; + + try + { + m_cg.Convert(script); + } + catch (Exception e) + { + gotException = true; + ge = e; + } + + Assert.That( + gotException, + Is.EqualTo(expectException), + "Failed on {0}, exception {1}", script, ge != null ? ge.ToString() : "n/a"); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/YP2CSConverter.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/YP2CSConverter.cs deleted file mode 100644 index 7ea3cfc..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/YP2CSConverter.cs +++ /dev/null @@ -1,117 +0,0 @@ -/* -* Copyright (c) Contributors, http://opensimulator.org/ -* See CONTRIBUTORS.TXT for a full list of copyright holders. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the OpenSimulator Project nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -*/ - -using System; -using System.IO; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; -using OpenSim.Region.ScriptEngine.Shared.YieldProlog; - -namespace OpenSim.Region.ScriptEngine.Shared.CodeTools -{ - public class YP2CSConverter - { - public YP2CSConverter() - { - } - - public string Convert(string Script) - { - string CS_code = GenCode(Script); - return CS_code; - } - - static string GenCode(string myCode) - { - Variable TermList = new Variable(); - Variable FunctionCode = new Variable(); - - string CS_code = ""; - - int cs_pointer = myCode.IndexOf("\n//cs"); - if (cs_pointer > 0) - { - CS_code = myCode.Substring(cs_pointer); // CS code comes after - myCode = myCode.Substring(0, cs_pointer); - } - myCode.Replace("//yp", "%YPCode"); - - StringWriter myCS_SW = new StringWriter(); - StringReader myCode_SR = new StringReader(" yp_nop_header_nop. \n "+myCode + "\n"); - - YP.see(myCode_SR); - YP.tell(myCS_SW); - - //m_log.Debug("Mycode\n ===================================\n" + myCode+"\n"); - -// disable warning: don't see how we can code this differently short -// of rewriting the whole thing -#pragma warning disable 0168, 0219 - foreach (bool l1 in Parser.parseInput(TermList)) - { - foreach (bool l2 in YPCompiler.makeFunctionPseudoCode(TermList, FunctionCode)) - { - // ListPair VFC = new ListPair(FunctionCode, new Variable()); - //m_log.Debug("-------------------------") - //m_log.Debug(FunctionCode.ToString()) - //m_log.Debug("-------------------------") - YPCompiler.convertFunctionCSharp(FunctionCode); - //YPCompiler.convertStringCodesCSharp(VFC); - } - } -#pragma warning restore 0168, 0219 - YP.seen(); - myCS_SW.Close(); - YP.told(); - StringBuilder bu = myCS_SW.GetStringBuilder(); - string finalcode = "//YPEncoded\n" + bu.ToString(); - // FIX script events (we're in the same script) - // 'YP.script_event(Atom.a(@"sayit"),' ==> 'sayit(' - finalcode = Regex.Replace(finalcode, - @"YP.script_event\(Atom.a\(\@\""(.*?)""\)\,", - @"this.$1(", - RegexOptions.Compiled | RegexOptions.Singleline); - finalcode = Regex.Replace(finalcode, - @"YP.script_event\(Atom.a\(\""(.*?)""\)\,", - @"this.$1(", - RegexOptions.Compiled | RegexOptions.Singleline); - finalcode = Regex.Replace(finalcode, - @" static ", - @" ", - RegexOptions.Compiled | RegexOptions.Singleline); - - finalcode = CS_code+"\n\r"+ finalcode; - finalcode = Regex.Replace(finalcode, - @"PrologCallback", - @"public IEnumerable ", - RegexOptions.Compiled | RegexOptions.Singleline); - return finalcode; - } - } -} diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/lsl.lexer.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/lsl.lexer.cs index cad27b7..f87f446 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/lsl.lexer.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/lsl.lexer.cs @@ -357,21 +357,25 @@ public override int yynum { get { return 90; }} public class HTTP_REQUEST_EVENT : TOKEN{ public override string yyname { get { return "HTTP_REQUEST_EVENT";}} public override int yynum { get { return 91; }} public HTTP_REQUEST_EVENT(Lexer yyl):base(yyl) {}} -//%IDENT+92 -public class IDENT : TOKEN{ public override string yyname { get { return "IDENT";}} +//%TRANSACTION_RESULT_EVENT+92 +public class TRANSACTION_RESULT_EVENT : TOKEN{ public override string yyname { get { return "TRANSACTION_RESULT_EVENT";}} public override int yynum { get { return 92; }} + public TRANSACTION_RESULT_EVENT(Lexer yyl):base(yyl) {}} +//%IDENT+93 +public class IDENT : TOKEN{ public override string yyname { get { return "IDENT";}} +public override int yynum { get { return 93; }} public IDENT(Lexer yyl):base(yyl) {}} -//%INTEGER_CONSTANT+93 +//%INTEGER_CONSTANT+94 public class INTEGER_CONSTANT : TOKEN{ public override string yyname { get { return "INTEGER_CONSTANT";}} -public override int yynum { get { return 93; }} +public override int yynum { get { return 94; }} public INTEGER_CONSTANT(Lexer yyl):base(yyl) {}} -//%HEX_INTEGER_CONSTANT+94 +//%HEX_INTEGER_CONSTANT+95 public class HEX_INTEGER_CONSTANT : TOKEN{ public override string yyname { get { return "HEX_INTEGER_CONSTANT";}} -public override int yynum { get { return 94; }} +public override int yynum { get { return 95; }} public HEX_INTEGER_CONSTANT(Lexer yyl):base(yyl) {}} -//%FLOAT_CONSTANT+95 +//%FLOAT_CONSTANT+96 public class FLOAT_CONSTANT : TOKEN{ public override string yyname { get { return "FLOAT_CONSTANT";}} -public override int yynum { get { return 95; }} +public override int yynum { get { return 96; }} public FLOAT_CONSTANT(Lexer yyl):base(yyl) {}} //%|LSLTokens public class yyLSLTokens : YyLexer { @@ -476,9 +480,9 @@ public class yyLSLTokens : YyLexer { 2,1,3,56,0, 2,1,3,57,0, 2,1,7,9,122, -9,1,9,3,96, -33,123,5,1,3, -96,33,2,1,7, +9,1,9,3,238, +22,123,5,1,3, +238,22,2,1,7, 10,124,9,1,10, 3,178,0,125,5, 1,3,178,0,2, @@ -502,8 +506,8 @@ public class yyLSLTokens : YyLexer { 9,0,2,1,3, 10,0,2,1,7, 15,134,9,1,15, -3,15,7,135,5, -1,3,15,7,2, +3,0,6,135,5, +1,3,0,6,2, 1,7,17,136,9, 1,17,3,0,224, 137,5,1,3,0, @@ -573,18 +577,18 @@ public class yyLSLTokens : YyLexer { 79,0,77,0,77, 0,69,0,78,0, 84,0,160,12,1, -1073,161,5,119,3, +1095,161,5,119,3, 1,0,162,12,1, -1074,163,5,0,164, -11,1,1041,0,165, +1096,163,5,0,164, +11,1,1063,0,165, 4,0,1,-1,3, 9,0,162,3,10, -0,166,12,1,1275, +0,166,12,1,1297, 167,5,0,168,11, -1,1045,0,165,1, +1,1067,0,165,1, -1,3,13,0,162, 3,0,3,162,3, -96,33,162,3,32, +0,6,162,3,32, 0,162,3,33,0, 162,3,34,0,162, 3,35,0,162,3, @@ -593,12 +597,12 @@ public class yyLSLTokens : YyLexer { 162,3,40,0,162, 3,41,0,162,3, 42,0,169,12,1, -1414,170,5,1,3, +1436,170,5,1,3, 47,0,171,12,1, -1518,172,5,0,173, -11,1,1027,0,165, +1540,172,5,0,173, +11,1,1049,0,165, 1,-1,174,11,1, -1041,0,165,1,-1, +1063,0,165,1,-1, 3,43,0,162,3, 44,0,162,3,45, 0,162,3,46,0, @@ -641,15 +645,15 @@ public class yyLSLTokens : YyLexer { 162,3,93,0,162, 3,94,0,162,3, 95,0,162,3,96, -0,162,3,97,0, +0,162,3,238,22, 162,3,98,0,162, 3,99,0,162,3, 100,0,162,3,101, -0,162,3,102,0, +0,162,3,97,0, 162,3,103,0,162, 3,104,0,162,3, 105,0,162,3,106, -0,162,3,107,0, +0,162,3,102,0, 162,3,108,0,162, 3,109,0,162,3, 110,0,162,3,111, @@ -665,11 +669,11 @@ public class yyLSLTokens : YyLexer { 162,3,123,0,162, 3,124,0,162,3, 125,0,162,3,96, -6,162,3,126,0, -162,3,58,15,162, -3,59,15,162,3, -136,4,162,3,160, -0,162,3,15,7, +6,162,3,107,0, +162,3,126,0,162, +3,58,15,162,3, +59,15,162,3,136, +4,162,3,160,0, 162,3,170,0,162, 3,171,0,162,3, 172,0,162,3,173, @@ -687,17 +691,17 @@ public class yyLSLTokens : YyLexer { 78,0,73,0,84, 0,73,0,65,0, 76,0,176,12,1, -1674,177,5,91,3, +1696,177,5,91,3, 9,0,178,12,1, -40509,179,5,0,180, -11,1,1050,0,165, +42571,179,5,0,180, +11,1,1072,0,165, 1,-1,3,10,0, 178,3,13,0,178, 3,32,0,178,3, 33,0,181,12,1, -43542,182,5,1,3, +45604,182,5,1,3, 61,0,183,12,1, -43657,184,5,0,185, +45719,184,5,0,185, 11,1,142,0,186, 4,36,69,0,88, 0,67,0,76,0, @@ -714,13 +718,13 @@ public class yyLSLTokens : YyLexer { 65,0,84,0,73, 0,79,0,78,0, 1,-1,3,34,0, -189,12,1,43783,190, +189,12,1,45845,190, 5,0,191,11,1, -941,0,165,1,-1, +963,0,165,1,-1, 3,37,0,192,12, -1,41733,193,5,1, +1,43795,193,5,1, 3,61,0,194,12, -1,41848,195,5,0, +1,43910,195,5,0, 196,11,1,40,0, 197,4,28,80,0, 69,0,82,0,67, @@ -734,9 +738,9 @@ public class yyLSLTokens : YyLexer { 82,0,67,0,69, 0,78,0,84,0, 1,-1,3,38,0, -200,12,1,41974,201, +200,12,1,44036,201, 5,1,3,38,0, -202,12,1,42074,203, +202,12,1,44136,203, 5,0,204,11,1, 185,0,205,4,14, 65,0,77,0,80, @@ -746,7 +750,7 @@ public class yyLSLTokens : YyLexer { 0,207,4,6,65, 0,77,0,80,0, 1,-1,3,40,0, -208,12,1,41246,209, +208,12,1,43308,209, 5,0,210,11,1, 71,0,211,4,20, 76,0,69,0,70, @@ -754,7 +758,7 @@ public class yyLSLTokens : YyLexer { 80,0,65,0,82, 0,69,0,78,0, 1,-1,3,41,0, -212,12,1,41610,213, +212,12,1,43672,213, 5,0,214,11,1, 76,0,215,4,22, 82,0,73,0,71, @@ -763,9 +767,9 @@ public class yyLSLTokens : YyLexer { 0,82,0,69,0, 78,0,1,-1,3, 42,0,216,12,1, -42215,217,5,1,3, +44277,217,5,1,3, 61,0,218,12,1, -42330,219,5,0,220, +44392,219,5,0,220, 11,1,28,0,221, 4,22,83,0,84, 0,65,0,82,0, @@ -777,9 +781,9 @@ public class yyLSLTokens : YyLexer { 0,84,0,65,0, 82,0,1,-1,3, 43,0,224,12,1, -45231,225,5,2,3, +47293,225,5,2,3, 61,0,226,12,1, -45346,227,5,0,228, +47408,227,5,0,228, 11,1,16,0,229, 4,22,80,0,76, 0,85,0,83,0, @@ -787,7 +791,7 @@ public class yyLSLTokens : YyLexer { 0,85,0,65,0, 76,0,83,0,1, -1,3,43,0,230, -12,1,45468,231,5, +12,1,47530,231,5, 0,232,11,1,2, 0,233,4,18,73, 0,78,0,67,0, @@ -798,15 +802,15 @@ public class yyLSLTokens : YyLexer { 4,8,80,0,76, 0,85,0,83,0, 1,-1,3,44,0, -236,12,1,42456,237, +236,12,1,44518,237, 5,0,238,11,1, 61,0,239,4,10, 67,0,79,0,77, 0,77,0,65,0, 1,-1,3,45,0, -240,12,1,40641,241, +240,12,1,42703,241, 5,2,3,45,0, -242,12,1,40728,243, +242,12,1,42790,243, 5,0,244,11,1, 10,0,245,4,18, 68,0,69,0,67, @@ -814,7 +818,7 @@ public class yyLSLTokens : YyLexer { 77,0,69,0,78, 0,84,0,1,-1, 3,61,0,246,12, -1,40876,247,5,0, +1,42938,247,5,0, 248,11,1,22,0, 249,4,24,77,0, 73,0,78,0,85, @@ -827,9 +831,9 @@ public class yyLSLTokens : YyLexer { 0,78,0,85,0, 83,0,1,-1,3, 46,0,252,12,1, -42577,253,5,14,3, +44639,253,5,14,3, 48,0,254,12,1, -40243,255,5,14,3, +42305,255,5,14,3, 48,0,254,3,49, 0,254,3,50,0, 254,3,51,0,254, @@ -839,11 +843,11 @@ public class yyLSLTokens : YyLexer { 254,3,56,0,254, 3,57,0,254,3, 101,0,256,12,1, -39706,257,5,12,3, +41768,257,5,12,3, 43,0,258,12,1, -40033,259,5,10,3, +42095,259,5,10,3, 48,0,260,12,1, -39768,261,5,12,3, +41830,261,5,12,3, 48,0,260,3,49, 0,260,3,50,0, 260,3,51,0,260, @@ -853,8 +857,8 @@ public class yyLSLTokens : YyLexer { 260,3,56,0,260, 3,57,0,260,3, 102,0,262,12,1, -39774,263,5,0,264, -11,1,882,0,265, +41836,263,5,0,264, +11,1,904,0,265, 4,28,70,0,76, 0,79,0,65,0, 84,0,95,0,67, @@ -862,7 +866,7 @@ public class yyLSLTokens : YyLexer { 83,0,84,0,65, 0,78,0,84,0, 1,-1,3,70,0, -262,266,11,1,882, +262,266,11,1,904, 0,265,1,-1,3, 49,0,260,3,50, 0,260,3,51,0, @@ -884,7 +888,7 @@ public class yyLSLTokens : YyLexer { 1,-1,3,102,0, 262,3,69,0,256, 3,70,0,262,267, -11,1,882,0,265, +11,1,904,0,265, 1,-1,3,49,0, 254,3,50,0,254, 3,51,0,254,3, @@ -901,15 +905,15 @@ public class yyLSLTokens : YyLexer { 0,82,0,73,0, 79,0,68,0,1, -1,3,47,0,270, -12,1,42698,271,5, +12,1,44760,271,5, 3,3,47,0,272, -12,1,42922,273,5, +12,1,44984,273,5, 118,3,1,0,274, -12,1,42923,275,5, +12,1,44985,275,5, 118,3,1,0,274, 3,9,0,274,3, -96,33,274,3,13, -0,274,3,0,3, +13,0,274,3,0, +3,274,3,0,6, 274,3,32,0,274, 3,33,0,274,3, 34,0,274,3,35, @@ -960,16 +964,16 @@ public class yyLSLTokens : YyLexer { 0,274,3,93,0, 274,3,94,0,274, 3,95,0,274,3, -96,0,274,3,97, -0,274,3,98,0, +96,0,274,3,238, +22,274,3,98,0, 274,3,99,0,274, 3,100,0,274,3, -101,0,274,3,102, +101,0,274,3,97, 0,274,3,103,0, 274,3,104,0,274, 3,105,0,274,3, -106,0,274,3,107, -0,274,3,15,7, +106,0,274,3,102, +0,274,3,108,0, 274,3,109,0,274, 3,110,0,274,3, 111,0,274,3,112, @@ -981,10 +985,10 @@ public class yyLSLTokens : YyLexer { 274,3,119,0,274, 3,120,0,274,3, 121,0,274,3,122, -0,274,3,108,0, +0,274,3,123,0, 274,3,124,0,274, 3,125,0,274,3, -96,6,274,3,123, +96,6,274,3,107, 0,274,3,126,0, 274,3,58,15,274, 3,59,15,274,3, @@ -1001,11 +1005,11 @@ public class yyLSLTokens : YyLexer { 274,3,0,224,274, 3,40,32,274,3, 63,32,274,276,11, -1,1054,0,165,1, +1,1076,0,165,1, -1,3,9,0,274, -3,96,33,274,3, -13,0,274,3,0, -3,274,3,32,0, +3,13,0,274,3, +0,3,274,3,0, +6,274,3,32,0, 274,3,33,0,274, 3,34,0,274,3, 35,0,274,3,36, @@ -1056,16 +1060,16 @@ public class yyLSLTokens : YyLexer { 0,274,3,94,0, 274,3,95,0,274, 3,96,0,274,3, -97,0,274,3,98, +238,22,274,3,98, 0,274,3,99,0, 274,3,100,0,274, 3,101,0,274,3, -102,0,274,3,103, +97,0,274,3,103, 0,274,3,104,0, 274,3,105,0,274, 3,106,0,274,3, -107,0,274,3,15, -7,274,3,109,0, +102,0,274,3,108, +0,274,3,109,0, 274,3,110,0,274, 3,111,0,274,3, 112,0,274,3,113, @@ -1076,11 +1080,11 @@ public class yyLSLTokens : YyLexer { 0,274,3,119,0, 274,3,120,0,274, 3,121,0,274,3, -122,0,274,3,108, +122,0,274,3,123, 0,274,3,124,0, 274,3,125,0,274, 3,96,6,274,3, -123,0,274,3,126, +107,0,274,3,126, 0,274,3,58,15, 274,3,59,15,274, 3,136,4,274,3, @@ -1096,9 +1100,9 @@ public class yyLSLTokens : YyLexer { 1,274,3,0,224, 274,3,40,32,274, 3,63,32,274,277, -11,1,1054,0,165, +11,1,1076,0,165, 1,-1,3,61,0, -278,12,1,43173,279, +278,12,1,45235,279, 5,0,280,11,1, 34,0,281,4,24, 83,0,76,0,65, @@ -1107,19 +1111,19 @@ public class yyLSLTokens : YyLexer { 0,85,0,65,0, 76,0,83,0,1, -1,3,42,0,282, -12,1,42799,283,5, -0,284,11,1,1015, +12,1,44861,283,5, +0,284,11,1,1037, 0,165,1,-1,285, 11,1,96,0,286, 4,10,83,0,76, 0,65,0,83,0, 72,0,1,-1,3, 48,0,287,12,1, -39296,288,5,13,3, +41358,288,5,13,3, 120,0,289,12,1, -39320,290,5,22,3, +41382,290,5,22,3, 102,0,291,12,1, -39321,292,5,22,3, +41383,292,5,22,3, 102,0,291,3,48, 0,291,3,49,0, 291,3,50,0,291, @@ -1138,7 +1142,7 @@ public class yyLSLTokens : YyLexer { 3,68,0,291,3, 69,0,291,3,70, 0,291,293,11,1, -863,0,294,4,40, +885,0,294,4,40, 72,0,69,0,88, 0,95,0,73,0, 78,0,84,0,69, @@ -1166,9 +1170,9 @@ public class yyLSLTokens : YyLexer { 0,291,3,70,0, 291,0,165,1,-1, 3,48,0,295,12, -1,39598,296,5,11, +1,41660,296,5,11, 3,46,0,297,12, -1,39701,298,5,14, +1,41763,298,5,14, 3,48,0,254,3, 49,0,254,3,50, 0,254,3,51,0, @@ -1180,7 +1184,7 @@ public class yyLSLTokens : YyLexer { 3,101,0,256,3, 102,0,262,3,69, 0,256,3,70,0, -262,299,11,1,882, +262,299,11,1,904, 0,265,1,-1,3, 48,0,295,3,49, 0,295,3,50,0, @@ -1190,7 +1194,7 @@ public class yyLSLTokens : YyLexer { 0,295,3,55,0, 295,3,56,0,295, 3,57,0,295,300, -11,1,857,0,301, +11,1,879,0,301, 4,32,73,0,78, 0,84,0,69,0, 71,0,69,0,82, @@ -1207,7 +1211,7 @@ public class yyLSLTokens : YyLexer { 56,0,295,3,54, 0,295,3,46,0, 297,3,57,0,295, -302,11,1,857,0, +302,11,1,879,0, 301,1,-1,3,49, 0,295,3,50,0, 295,3,51,0,295, @@ -1217,16 +1221,16 @@ public class yyLSLTokens : YyLexer { 295,3,56,0,295, 3,57,0,295,3, 59,0,303,12,1, -43300,304,5,0,305, +45362,304,5,0,305, 11,1,46,0,306, 4,18,83,0,69, 0,77,0,73,0, 67,0,79,0,76, 0,79,0,78,0, 1,-1,3,60,0, -307,12,1,44268,308, +307,12,1,46330,308, 5,2,3,60,0, -309,12,1,44382,310, +309,12,1,46444,310, 5,0,311,11,1, 197,0,312,4,20, 76,0,69,0,70, @@ -1234,7 +1238,7 @@ public class yyLSLTokens : YyLexer { 83,0,72,0,73, 0,70,0,84,0, 1,-1,3,61,0, -313,12,1,44503,314, +313,12,1,46565,314, 5,0,315,11,1, 148,0,316,4,22, 76,0,69,0,83, @@ -1249,9 +1253,9 @@ public class yyLSLTokens : YyLexer { 0,71,0,76,0, 69,0,1,-1,3, 61,0,319,12,1, -44629,320,5,1,3, +46691,320,5,1,3, 61,0,321,12,1, -44744,322,5,0,323, +46806,322,5,0,323, 11,1,136,0,324, 4,26,69,0,81, 0,85,0,65,0, @@ -1264,9 +1268,9 @@ public class yyLSLTokens : YyLexer { 81,0,85,0,65, 0,76,0,83,0, 1,-1,3,62,0, -327,12,1,44870,328, +327,12,1,46932,328, 5,2,3,61,0, -329,12,1,44985,330, +329,12,1,47047,330, 5,0,331,11,1, 154,0,332,4,28, 71,0,82,0,69, @@ -1276,7 +1280,7 @@ public class yyLSLTokens : YyLexer { 85,0,65,0,76, 0,83,0,1,-1, 3,62,0,333,12, -1,45106,334,5,0, +1,47168,334,5,0, 335,11,1,203,0, 336,4,22,82,0, 73,0,71,0,72, @@ -1291,13 +1295,13 @@ public class yyLSLTokens : YyLexer { 0,71,0,76,0, 69,0,1,-1,3, 64,0,339,12,1, -43421,340,5,0,341, +45483,340,5,0,341, 11,1,106,0,342, 4,4,65,0,84, 0,1,-1,3,65, -0,343,12,1,1675, +0,343,12,1,1697, 344,5,63,3,109, -0,345,12,1,1676, +0,345,12,1,1698, 346,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -1349,7 +1353,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -347,11,1,845,0, +347,11,1,867,0, 348,4,10,73,0, 68,0,69,0,78, 0,84,0,1,-1, @@ -1403,7 +1407,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,349,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,66,0,343, 3,67,0,343,3, 68,0,343,3,69, @@ -1425,7 +1429,7 @@ public class yyLSLTokens : YyLexer { 88,0,343,3,89, 0,343,3,90,0, 343,3,91,0,350, -12,1,41124,351,5, +12,1,43186,351,5, 0,352,11,1,126, 0,353,4,24,76, 0,69,0,70,0, @@ -1434,7 +1438,7 @@ public class yyLSLTokens : YyLexer { 67,0,75,0,69, 0,84,0,1,-1, 3,93,0,354,12, -1,41489,355,5,0, +1,43551,355,5,0, 356,11,1,131,0, 357,4,26,82,0, 73,0,71,0,72, @@ -1443,21 +1447,21 @@ public class yyLSLTokens : YyLexer { 0,67,0,75,0, 69,0,84,0,1, -1,3,94,0,358, -12,1,45593,359,5, +12,1,47655,359,5, 0,360,11,1,170, 0,361,4,10,67, 0,65,0,82,0, 69,0,84,0,1, -1,3,95,0,343, 3,97,0,362,12, -1,20677,363,5,63, +1,22739,363,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,345,3, 115,0,345,3,116, -0,364,12,1,20712, +0,364,12,1,22774, 365,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -1465,7 +1469,7 @@ public class yyLSLTokens : YyLexer { 113,0,345,3,114, 0,345,3,115,0, 345,3,116,0,366, -12,1,20747,367,5, +12,1,22809,367,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -1508,7 +1512,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,90,0, 345,3,95,0,345, 3,97,0,368,12, -1,20790,369,5,63, +1,22852,369,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -1552,7 +1556,7 @@ public class yyLSLTokens : YyLexer { 3,95,0,345,3, 97,0,345,3,98, 0,345,3,99,0, -370,12,1,20835,371, +370,12,1,22897,371, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -1601,7 +1605,7 @@ public class yyLSLTokens : YyLexer { 345,3,102,0,345, 3,103,0,345,3, 104,0,372,12,1, -20885,373,5,63,3, +22947,373,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -1662,7 +1666,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,376,11,1,845, +345,376,11,1,867, 0,348,1,-1,3, 100,0,345,3,101, 0,345,3,102,0, @@ -1671,7 +1675,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -377,11,1,845,0, +377,11,1,867,0, 348,1,-1,3,98, 0,345,3,99,0, 345,3,100,0,345, @@ -1682,7 +1686,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,378,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,117,0,345,3, 118,0,345,3,119, 0,345,3,120,0, @@ -1717,17 +1721,17 @@ public class yyLSLTokens : YyLexer { 345,3,88,0,345, 3,89,0,345,3, 90,0,345,3,95, -0,379,12,1,21278, +0,379,12,1,23340, 380,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, -0,381,12,1,21311, +0,381,12,1,23373, 382,5,63,3,109, 0,345,3,110,0, 345,3,111,0,383, -12,1,21341,384,5, +12,1,23403,384,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -1735,7 +1739,7 @@ public class yyLSLTokens : YyLexer { 345,3,114,0,345, 3,115,0,345,3, 116,0,385,12,1, -21376,386,5,63,3, +23438,386,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -1777,14 +1781,14 @@ public class yyLSLTokens : YyLexer { 345,3,89,0,345, 3,90,0,345,3, 95,0,387,12,1, -21462,388,5,63,3, +23524,388,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, 0,345,3,116,0, -389,12,1,21497,390, +389,12,1,23559,390, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -1827,13 +1831,13 @@ public class yyLSLTokens : YyLexer { 89,0,345,3,90, 0,345,3,95,0, 345,3,97,0,391, -12,1,21540,392,5, +12,1,23602,392,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, 0,345,3,113,0, 345,3,114,0,393, -12,1,21573,394,5, +12,1,23635,394,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -1881,7 +1885,7 @@ public class yyLSLTokens : YyLexer { 345,3,101,0,345, 3,102,0,345,3, 103,0,395,12,1, -21622,396,5,63,3, +23684,396,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -1927,14 +1931,14 @@ public class yyLSLTokens : YyLexer { 345,3,99,0,345, 3,100,0,345,3, 101,0,397,12,1, -21669,398,5,63,3, +23731,398,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, 0,345,3,116,0, -399,12,1,21704,400, +399,12,1,23766,400, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -2040,19 +2044,19 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,403,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,102,0,345,3, 103,0,345,3,104, 0,345,3,105,0, 345,3,106,0,345, 3,107,0,345,3, 108,0,345,404,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,104,0,345, 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,405,11,1,845, +345,405,11,1,867, 0,348,1,-1,3, 115,0,345,3,116, 0,345,3,117,0, @@ -2100,7 +2104,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,406,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,98,0,345,3, 99,0,345,3,100, 0,345,3,101,0, @@ -2110,7 +2114,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,407, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,117,0, 345,3,118,0,345, 3,119,0,345,3, @@ -2156,7 +2160,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,408,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,97,0,345,3, 98,0,345,3,99, 0,345,3,100,0, @@ -2167,7 +2171,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,409,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,117,0,345, 3,118,0,345,3, 119,0,345,3,120, @@ -2212,7 +2216,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,410,11,1,845, +345,410,11,1,867, 0,348,1,-1,3, 112,0,345,3,113, 0,345,3,114,0, @@ -2262,10 +2266,10 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,411, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,115,0, 345,3,116,0,412, -12,1,22513,413,5, +12,1,24575,413,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -2308,13 +2312,13 @@ public class yyLSLTokens : YyLexer { 0,345,3,90,0, 345,3,95,0,345, 3,97,0,414,12, -1,22556,415,5,63, +1,24618,415,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,416,12, -1,22589,417,5,63, +1,24651,417,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -2361,7 +2365,7 @@ public class yyLSLTokens : YyLexer { 345,3,100,0,345, 3,101,0,345,3, 102,0,345,3,103, -0,418,12,1,22638, +0,418,12,1,24700, 419,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -2407,7 +2411,7 @@ public class yyLSLTokens : YyLexer { 345,3,98,0,345, 3,99,0,345,3, 100,0,345,3,101, -0,420,12,1,22685, +0,420,12,1,24747, 421,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -2415,7 +2419,7 @@ public class yyLSLTokens : YyLexer { 113,0,345,3,114, 0,345,3,115,0, 345,3,116,0,422, -12,1,22720,423,5, +12,1,24782,423,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -2519,20 +2523,20 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,426,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,102,0,345, 3,103,0,345,3, 104,0,345,3,105, 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,427, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,104,0, 345,3,105,0,345, 3,106,0,345,3, 107,0,345,3,108, 0,345,428,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,115,0,345,3, 116,0,345,3,117, 0,345,3,118,0, @@ -2579,7 +2583,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,429,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,98,0,345, 3,99,0,345,3, 100,0,345,3,101, @@ -2589,7 +2593,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -430,11,1,845,0, +430,11,1,867,0, 348,1,-1,3,117, 0,345,3,118,0, 345,3,119,0,345, @@ -2635,7 +2639,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,431,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,97,0,345, 3,98,0,345,3, 99,0,345,3,100, @@ -2646,7 +2650,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,432, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,117,0, 345,3,118,0,345, 3,119,0,345,3, @@ -2692,16 +2696,16 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,433,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,98,0,343,3, 99,0,434,12,1, -23439,435,5,63,3, +25501,435,5,63,3, 109,0,345,3,110, 0,345,3,111,0, -436,12,1,23469,437, +436,12,1,25531,437, 5,63,3,109,0, 345,3,110,0,438, -12,1,23498,439,5, +12,1,25560,439,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -2709,16 +2713,16 @@ public class yyLSLTokens : YyLexer { 345,3,114,0,345, 3,115,0,345,3, 116,0,440,12,1, -23533,441,5,63,3, +25595,441,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,442,12,1, -23566,443,5,63,3, +25628,443,5,63,3, 109,0,345,3,110, 0,345,3,111,0, -444,12,1,23596,445, +444,12,1,25658,445, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -2770,7 +2774,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,446,12, -1,23650,447,5,63, +1,25712,447,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -2829,7 +2833,7 @@ public class yyLSLTokens : YyLexer { 0,69,0,86,0, 69,0,78,0,84, 0,1,-1,450,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, @@ -2878,7 +2882,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,451,11,1,845, +345,451,11,1,867, 0,348,1,-1,3, 115,0,345,3,116, 0,345,3,117,0, @@ -2926,7 +2930,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,452,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,117,0,345,3, 118,0,345,3,119, 0,345,3,120,0, @@ -2971,7 +2975,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -453,11,1,845,0, +453,11,1,867,0, 348,1,-1,3,111, 0,345,3,112,0, 345,3,113,0,345, @@ -3021,7 +3025,7 @@ public class yyLSLTokens : YyLexer { 345,3,105,0,345, 3,106,0,345,3, 107,0,345,3,108, -0,454,12,1,24123, +0,454,12,1,26185, 455,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -3073,7 +3077,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,456, -12,1,24177,457,5, +12,1,26239,457,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -3122,14 +3126,14 @@ public class yyLSLTokens : YyLexer { 3,102,0,345,3, 103,0,345,3,104, 0,345,3,105,0, -458,12,1,24228,459, +458,12,1,26290,459, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, 345,3,115,0,460, -12,1,24262,461,5, +12,1,26324,461,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -3178,14 +3182,14 @@ public class yyLSLTokens : YyLexer { 3,102,0,345,3, 103,0,345,3,104, 0,345,3,105,0, -462,12,1,24313,463, +462,12,1,26375,463, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,464,12, -1,24343,465,5,63, +1,26405,465,5,63, 3,109,0,345,3, 110,0,466,12,1, -24372,467,5,63,3, +26434,467,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -3227,13 +3231,13 @@ public class yyLSLTokens : YyLexer { 345,3,89,0,345, 3,90,0,345,3, 95,0,468,12,1, -24458,469,5,63,3, +26520,469,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, -0,470,12,1,24492, +0,470,12,1,26554, 471,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -3241,7 +3245,7 @@ public class yyLSLTokens : YyLexer { 113,0,345,3,114, 0,345,3,115,0, 345,3,116,0,472, -12,1,24527,473,5, +12,1,26589,473,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -3284,20 +3288,20 @@ public class yyLSLTokens : YyLexer { 0,345,3,90,0, 345,3,95,0,345, 3,97,0,474,12, -1,24570,475,5,63, +1,26632,475,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,476,12, -1,24603,477,5,63, +1,26665,477,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,345,3, 115,0,345,3,116, -0,478,12,1,24638, +0,478,12,1,26700, 479,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -3404,7 +3408,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,482,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,115,0,345,3, 116,0,345,3,117, 0,345,3,118,0, @@ -3451,7 +3455,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,483,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,98,0,345, 3,99,0,345,3, 100,0,345,3,101, @@ -3461,7 +3465,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -484,11,1,845,0, +484,11,1,867,0, 348,1,-1,3,117, 0,345,3,118,0, 345,3,119,0,345, @@ -3507,7 +3511,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,485,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,116,0,345, 3,117,0,345,3, 118,0,345,3,119, @@ -3547,10 +3551,10 @@ public class yyLSLTokens : YyLexer { 345,3,98,0,345, 3,99,0,345,3, 100,0,345,3,101, -0,486,12,1,25105, +0,486,12,1,27167, 487,5,63,3,109, 0,345,3,110,0, -488,12,1,25134,489, +488,12,1,27196,489, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -3595,7 +3599,7 @@ public class yyLSLTokens : YyLexer { 345,3,97,0,345, 3,98,0,345,3, 99,0,345,3,100, -0,490,12,1,25180, +0,490,12,1,27242, 491,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -3663,7 +3667,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -494,11,1,845,0, +494,11,1,867,0, 348,1,-1,3,111, 0,345,3,112,0, 345,3,113,0,345, @@ -3714,14 +3718,14 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,495,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,102,0,345,3, 103,0,345,3,104, 0,345,3,105,0, 345,3,106,0,345, 3,107,0,345,3, 108,0,345,496,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,97,0,345, 3,98,0,345,3, 99,0,345,3,100, @@ -3789,7 +3793,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,499,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, @@ -3838,11 +3842,11 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,500,11,1,845, +345,500,11,1,867, 0,348,1,-1,3, 106,0,345,3,107, 0,345,3,108,0, -345,501,11,1,845, +345,501,11,1,867, 0,348,1,-1,3, 116,0,345,3,117, 0,345,3,118,0, @@ -3889,14 +3893,14 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,502,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,106,0,345, 3,107,0,345,3, 108,0,345,503,11, -1,845,0,348,1, --1,504,11,1,845, +1,867,0,348,1, +-1,504,11,1,867, 0,348,1,-1,505, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,112,0, 345,3,113,0,345, 3,114,0,345,3, @@ -3942,7 +3946,7 @@ public class yyLSLTokens : YyLexer { 3,101,0,345,3, 102,0,345,3,103, 0,345,3,104,0, -506,12,1,26129,507, +506,12,1,28191,507, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -3985,10 +3989,10 @@ public class yyLSLTokens : YyLexer { 89,0,345,3,90, 0,345,3,95,0, 345,3,97,0,508, -12,1,26172,509,5, +12,1,28234,509,5, 63,3,109,0,345, 3,110,0,510,12, -1,26201,511,5,63, +1,28263,511,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -4035,7 +4039,7 @@ public class yyLSLTokens : YyLexer { 345,3,100,0,345, 3,101,0,345,3, 102,0,345,3,103, -0,512,12,1,26250, +0,512,12,1,28312, 513,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -4081,7 +4085,7 @@ public class yyLSLTokens : YyLexer { 345,3,98,0,345, 3,99,0,345,3, 100,0,345,3,101, -0,514,12,1,26297, +0,514,12,1,28359, 515,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -4127,7 +4131,7 @@ public class yyLSLTokens : YyLexer { 345,3,98,0,345, 3,99,0,345,3, 100,0,516,12,1, -26343,517,5,63,3, +28405,517,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -4192,20 +4196,20 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,520, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,102,0, 345,3,103,0,345, 3,104,0,345,3, 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -521,11,1,845,0, +521,11,1,867,0, 348,1,-1,3,104, 0,345,3,105,0, 345,3,106,0,345, 3,107,0,345,3, 108,0,345,522,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, @@ -4255,7 +4259,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -523,11,1,845,0, +523,11,1,867,0, 348,1,-1,3,98, 0,345,3,99,0, 345,3,100,0,345, @@ -4266,17 +4270,17 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,524,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,525,11,1,845, +345,525,11,1,867, 0,348,1,-1,3, 100,0,526,12,1, -26920,527,5,63,3, +28982,527,5,63,3, 109,0,345,3,110, 0,345,3,111,0, -528,12,1,26950,529, +528,12,1,29012,529, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -4370,14 +4374,14 @@ public class yyLSLTokens : YyLexer { 0,345,3,90,0, 345,3,95,0,345, 3,97,0,532,12, -1,27083,533,5,63, +1,29145,533,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,345,3, 115,0,345,3,116, -0,534,12,1,27118, +0,534,12,1,29180, 535,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -4420,14 +4424,14 @@ public class yyLSLTokens : YyLexer { 3,89,0,345,3, 90,0,345,3,95, 0,345,3,97,0, -536,12,1,27161,537, +536,12,1,29223,537, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, 345,3,115,0,538, -12,1,27195,539,5, +12,1,29257,539,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -4473,13 +4477,13 @@ public class yyLSLTokens : YyLexer { 98,0,345,3,99, 0,345,3,100,0, 345,3,101,0,540, -12,1,27242,541,5, +12,1,29304,541,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, 0,345,3,113,0, 345,3,114,0,542, -12,1,27275,543,5, +12,1,29337,543,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -4488,7 +4492,7 @@ public class yyLSLTokens : YyLexer { 3,115,0,345,3, 116,0,345,3,117, 0,345,3,118,0, -544,12,1,27312,545, +544,12,1,29374,545, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -4534,13 +4538,13 @@ public class yyLSLTokens : YyLexer { 3,98,0,345,3, 99,0,345,3,100, 0,345,3,101,0, -546,12,1,27359,547, +546,12,1,29421,547, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, -548,12,1,27392,549, +548,12,1,29454,549, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -4646,14 +4650,14 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,552, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,102,0, 345,3,103,0,345, 3,104,0,345,3, 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -553,11,1,845,0, +553,11,1,867,0, 348,1,-1,3,119, 0,345,3,120,0, 345,3,121,0,345, @@ -4697,7 +4701,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -554,11,1,845,0, +554,11,1,867,0, 348,1,-1,3,115, 0,345,3,116,0, 345,3,117,0,345, @@ -4744,7 +4748,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,555,11,1,845, +345,555,11,1,867, 0,348,1,-1,3, 102,0,345,3,103, 0,345,3,104,0, @@ -4752,7 +4756,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,556,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,116,0,345,3, 117,0,345,3,118, 0,345,3,119,0, @@ -4798,7 +4802,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,557, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,98,0, 345,3,99,0,345, 3,100,0,345,3, @@ -4808,7 +4812,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,558,11,1,845, +345,558,11,1,867, 0,348,1,-1,3, 117,0,345,3,118, 0,345,3,119,0, @@ -4854,12 +4858,12 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,559, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,98,0, 345,3,99,0,345, 3,100,0,345,3, 101,0,560,12,1, -28167,561,5,63,3, +30229,561,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -4905,7 +4909,7 @@ public class yyLSLTokens : YyLexer { 345,3,99,0,345, 3,100,0,345,3, 101,0,345,3,102, -0,562,12,1,28215, +0,562,12,1,30277, 563,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -4948,7 +4952,7 @@ public class yyLSLTokens : YyLexer { 3,89,0,345,3, 90,0,345,3,95, 0,345,3,97,0, -564,12,1,28258,565, +564,12,1,30320,565, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -4957,7 +4961,7 @@ public class yyLSLTokens : YyLexer { 345,3,115,0,345, 3,116,0,345,3, 117,0,566,12,1, -28294,567,5,63,3, +30356,567,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -5008,7 +5012,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -568,12,1,28348,569, +568,12,1,30410,569, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -5016,7 +5020,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,114,0, 345,3,115,0,345, 3,116,0,570,12, -1,28383,571,5,63, +1,30445,571,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -5119,8 +5123,8 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,574,11, -1,845,0,348,1, --1,575,11,1,845, +1,867,0,348,1, +-1,575,11,1,867, 0,348,1,-1,3, 118,0,345,3,119, 0,345,3,120,0, @@ -5165,7 +5169,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -576,11,1,845,0, +576,11,1,867,0, 348,1,-1,3,98, 0,345,3,99,0, 345,3,100,0,345, @@ -5176,24 +5180,24 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,577,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,103,0,345,3, 104,0,345,3,105, 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,578, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,102,0, 345,3,103,0,345, 3,104,0,345,3, 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -579,11,1,845,0, +579,11,1,867,0, 348,1,-1,3,101, -0,580,12,1,28961, +0,580,12,1,31023, 581,5,63,3,109, -0,582,12,1,28989, +0,582,12,1,31051, 583,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -5236,7 +5240,7 @@ public class yyLSLTokens : YyLexer { 3,89,0,345,3, 90,0,345,3,95, 0,345,3,97,0, -584,12,1,29032,585, +584,12,1,31094,585, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -5285,7 +5289,7 @@ public class yyLSLTokens : YyLexer { 345,3,102,0,345, 3,103,0,345,3, 104,0,345,3,105, -0,586,12,1,29083, +0,586,12,1,31145, 587,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -5337,7 +5341,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,588, -12,1,29137,589,5, +12,1,31199,589,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -5395,11 +5399,11 @@ public class yyLSLTokens : YyLexer { 0,95,0,69,0, 86,0,69,0,78, 0,84,0,1,-1, -592,11,1,845,0, +592,11,1,867,0, 348,1,-1,3,106, 0,345,3,107,0, 345,3,108,0,345, -593,11,1,845,0, +593,11,1,867,0, 348,1,-1,3,98, 0,345,3,99,0, 345,3,100,0,345, @@ -5410,7 +5414,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,594,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,110,0,345,3, 111,0,345,3,112, 0,345,3,113,0, @@ -5461,13 +5465,13 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,595,12,1, -29495,596,5,63,3, +31557,596,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, -0,597,12,1,29529, +0,597,12,1,31591, 598,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -5513,7 +5517,7 @@ public class yyLSLTokens : YyLexer { 345,3,98,0,345, 3,99,0,345,3, 100,0,345,3,101, -0,599,12,1,29576, +0,599,12,1,31638, 600,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -5574,7 +5578,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,603,11,1,845, +345,603,11,1,867, 0,348,1,-1,3, 116,0,345,3,117, 0,345,3,118,0, @@ -5621,20 +5625,20 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,604,11, -1,845,0,348,1, --1,605,11,1,845, +1,867,0,348,1, +-1,605,11,1,867, 0,348,1,-1,3, 102,0,606,12,1, -29922,607,5,63,3, +31984,607,5,63,3, 109,0,345,3,110, 0,345,3,111,0, -608,12,1,29952,609, +608,12,1,32014,609, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, -610,12,1,29985,611, +610,12,1,32047,611, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -5735,7 +5739,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,614,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, @@ -5784,11 +5788,11 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -615,12,1,30216,616, +615,12,1,32278,616, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,617,12, -1,30246,618,5,63, +1,32308,618,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -5831,14 +5835,14 @@ public class yyLSLTokens : YyLexer { 345,3,90,0,345, 3,95,0,345,3, 97,0,619,12,1, -30289,620,5,63,3, +32351,620,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, 0,345,3,116,0, -621,12,1,30324,622, +621,12,1,32386,622, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -5940,7 +5944,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,625, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,98,0, 345,3,99,0,345, 3,100,0,345,3, @@ -5950,7 +5954,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,626,11,1,845, +345,626,11,1,867, 0,348,1,-1,3, 112,0,345,3,113, 0,345,3,114,0, @@ -6000,19 +6004,19 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,627, -11,1,845,0,348, +11,1,867,0,348, 1,-1,628,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,103,0,343,3, 104,0,629,12,1, -30764,630,5,63,3, +32826,630,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, 0,345,3,116,0, -631,12,1,30799,632, +631,12,1,32861,632, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -6020,11 +6024,11 @@ public class yyLSLTokens : YyLexer { 0,345,3,114,0, 345,3,115,0,345, 3,116,0,633,12, -1,30834,634,5,63, +1,32896,634,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, -635,12,1,30865,636, +635,12,1,32927,636, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -6066,13 +6070,13 @@ public class yyLSLTokens : YyLexer { 3,88,0,345,3, 89,0,345,3,90, 0,345,3,95,0, -637,12,1,30951,638, +637,12,1,33013,638, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, -639,12,1,30984,640, +639,12,1,33046,640, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -6118,12 +6122,12 @@ public class yyLSLTokens : YyLexer { 3,98,0,345,3, 99,0,345,3,100, 0,345,3,101,0, -641,12,1,31031,642, +641,12,1,33093,642, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, 112,0,345,3,113, -0,643,12,1,31063, +0,643,12,1,33125, 644,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -6132,7 +6136,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,115,0, 345,3,116,0,345, 3,117,0,645,12, -1,31099,646,5,63, +1,33161,646,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -6178,21 +6182,21 @@ public class yyLSLTokens : YyLexer { 0,345,3,99,0, 345,3,100,0,345, 3,101,0,647,12, -1,31146,648,5,63, +1,33208,648,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,345,3, 115,0,649,12,1, -31180,650,5,63,3, +33242,650,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, 0,345,3,116,0, -651,12,1,31215,652, +651,12,1,33277,652, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -6297,7 +6301,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -655,11,1,845,0, +655,11,1,867,0, 348,1,-1,3,116, 0,345,3,117,0, 345,3,118,0,345, @@ -6344,14 +6348,14 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,656,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,102,0,345,3, 103,0,345,3,104, 0,345,3,105,0, 345,3,106,0,345, 3,107,0,345,3, 108,0,345,657,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,118,0,345, 3,119,0,345,3, 120,0,345,3,121, @@ -6396,27 +6400,27 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,658,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,114,0,345,3, 115,0,659,12,1, -31665,660,5,63,3, +33727,660,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,661, -12,1,31696,662,5, +12,1,33758,662,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,663,12,1, -31726,664,5,63,3, +33788,664,5,63,3, 109,0,345,3,110, -0,665,12,1,31755, +0,665,12,1,33817, 666,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, 0,345,3,115,0, -667,12,1,31789,668, +667,12,1,33851,668, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -6462,7 +6466,7 @@ public class yyLSLTokens : YyLexer { 3,98,0,345,3, 99,0,345,3,100, 0,345,3,101,0, -669,12,1,31836,670, +669,12,1,33898,670, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -6529,7 +6533,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -673,11,1,845,0, +673,11,1,867,0, 348,1,-1,3,116, 0,345,3,117,0, 345,3,118,0,345, @@ -6576,7 +6580,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,674,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, @@ -6626,7 +6630,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,675, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,112,0, 345,3,113,0,345, 3,114,0,345,3, @@ -6676,7 +6680,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,676,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,113,0,345,3, 114,0,345,3,115, 0,345,3,116,0, @@ -6724,7 +6728,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,677,11,1,845, +345,677,11,1,867, 0,348,1,-1,3, 116,0,345,3,117, 0,345,3,118,0, @@ -6771,14 +6775,14 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,678,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,102,0,345, 3,103,0,345,3, 104,0,345,3,105, 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,679, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,115,0, 345,3,116,0,345, 3,117,0,345,3, @@ -6825,7 +6829,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -680,11,1,845,0, +680,11,1,867,0, 348,1,-1,3,97, 0,345,3,98,0, 345,3,99,0,345, @@ -6836,7 +6840,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,681,11,1,845, +345,681,11,1,867, 0,348,1,-1,3, 113,0,345,3,114, 0,345,3,115,0, @@ -6885,7 +6889,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -682,11,1,845,0, +682,11,1,867,0, 348,1,-1,3,117, 0,345,3,118,0, 345,3,119,0,345, @@ -6931,7 +6935,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,683,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,117,0,345, 3,118,0,345,3, 119,0,345,3,120, @@ -6976,12 +6980,12 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,684,11,1,845, +345,684,11,1,867, 0,348,1,-1,3, 105,0,685,12,1, -32925,686,5,63,3, +34987,686,5,63,3, 109,0,345,3,110, -0,687,12,1,32954, +0,687,12,1,35016, 688,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -6989,7 +6993,7 @@ public class yyLSLTokens : YyLexer { 113,0,345,3,114, 0,345,3,115,0, 345,3,116,0,689, -12,1,32989,690,5, +12,1,35051,690,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -7035,7 +7039,7 @@ public class yyLSLTokens : YyLexer { 98,0,345,3,99, 0,345,3,100,0, 345,3,101,0,691, -12,1,33036,692,5, +12,1,35098,692,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -7083,7 +7087,7 @@ public class yyLSLTokens : YyLexer { 345,3,101,0,345, 3,102,0,345,3, 103,0,693,12,1, -33085,694,5,63,3, +35147,694,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -7129,13 +7133,13 @@ public class yyLSLTokens : YyLexer { 345,3,99,0,345, 3,100,0,345,3, 101,0,695,12,1, -33132,696,5,63,3, +35194,696,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,697,12,1, -33165,698,5,63,3, +35227,698,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -7239,27 +7243,27 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,701,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,102,0,345, 3,103,0,345,3, 104,0,345,3,105, 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,702, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,104,0, 345,3,105,0,345, 3,106,0,345,3, 107,0,345,3,108, 0,345,703,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,102,0,345,3, 103,0,345,3,104, 0,345,3,105,0, 345,3,106,0,345, 3,107,0,345,3, 108,0,345,704,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,117,0,345, 3,118,0,345,3, 119,0,345,3,120, @@ -7304,7 +7308,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,705,11,1,845, +345,705,11,1,867, 0,348,1,-1,3, 111,0,345,3,112, 0,345,3,113,0, @@ -7350,7 +7354,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,100,0, 345,3,101,0,345, 3,102,0,706,12, -1,33693,707,5,63, +1,35755,707,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -7409,9 +7413,9 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -710,11,1,845,0, +710,11,1,867,0, 348,1,-1,3,106, -0,711,12,1,33886, +0,711,12,1,35948, 712,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -7420,13 +7424,13 @@ public class yyLSLTokens : YyLexer { 0,345,3,115,0, 345,3,116,0,345, 3,117,0,713,12, -1,33922,714,5,63, +1,35984,714,5,63, 3,109,0,715,12, -1,33950,716,5,63, +1,36012,716,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, -717,12,1,33981,718, +717,12,1,36043,718, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -7529,7 +7533,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,721,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,110,0,345, 3,111,0,345,3, 112,0,345,3,113, @@ -7580,7 +7584,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,722, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,118,0, 345,3,119,0,345, 3,120,0,345,3, @@ -7625,9 +7629,9 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,723,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,107,0,724, -12,1,34367,725,5, +12,1,36429,725,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -7673,7 +7677,7 @@ public class yyLSLTokens : YyLexer { 98,0,345,3,99, 0,345,3,100,0, 345,3,101,0,726, -12,1,34414,727,5, +12,1,36476,727,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -7685,7 +7689,7 @@ public class yyLSLTokens : YyLexer { 345,3,119,0,345, 3,120,0,345,3, 121,0,728,12,1, -34454,729,5,63,3, +36516,729,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -7782,16 +7786,16 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,732,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,102,0,345,3, 103,0,345,3,104, 0,345,3,105,0, 345,3,106,0,345, 3,107,0,345,3, 108,0,345,733,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,108,0,734, -12,1,34728,735,5, +12,1,36790,735,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -7834,10 +7838,10 @@ public class yyLSLTokens : YyLexer { 0,345,3,90,0, 345,3,95,0,345, 3,97,0,736,12, -1,34771,737,5,63, +1,36833,737,5,63, 3,109,0,345,3, 110,0,738,12,1, -34800,739,5,63,3, +36862,739,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -7882,7 +7886,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,98,0, 345,3,99,0,345, 3,100,0,740,12, -1,34846,741,5,63, +1,36908,741,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -7924,7 +7928,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,89,0, 345,3,90,0,345, 3,95,0,742,12, -1,34932,743,5,63, +1,36994,743,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -7968,11 +7972,11 @@ public class yyLSLTokens : YyLexer { 3,95,0,345,3, 97,0,345,3,98, 0,345,3,99,0, -744,12,1,34977,745, +744,12,1,37039,745, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,746,12, -1,35007,747,5,63, +1,37069,747,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -8023,7 +8027,7 @@ public class yyLSLTokens : YyLexer { 345,3,105,0,345, 3,106,0,345,3, 107,0,345,3,108, -0,748,12,1,35061, +0,748,12,1,37123, 749,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -8075,7 +8079,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,750, -12,1,35115,751,5, +12,1,37177,751,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -8124,14 +8128,14 @@ public class yyLSLTokens : YyLexer { 3,102,0,345,3, 103,0,345,3,104, 0,345,3,105,0, -752,12,1,35166,753, +752,12,1,37228,753, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, 345,3,115,0,754, -12,1,35200,755,5, +12,1,37262,755,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -8180,14 +8184,14 @@ public class yyLSLTokens : YyLexer { 3,102,0,345,3, 103,0,345,3,104, 0,345,3,105,0, -756,12,1,35251,757, +756,12,1,37313,757, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,758,12, -1,35281,759,5,63, +1,37343,759,5,63, 3,109,0,345,3, 110,0,760,12,1, -35310,761,5,63,3, +37372,761,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -8229,13 +8233,13 @@ public class yyLSLTokens : YyLexer { 345,3,89,0,345, 3,90,0,345,3, 95,0,762,12,1, -35396,763,5,63,3, +37458,763,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, -0,764,12,1,35430, +0,764,12,1,37492, 765,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -8243,7 +8247,7 @@ public class yyLSLTokens : YyLexer { 113,0,345,3,114, 0,345,3,115,0, 345,3,116,0,766, -12,1,35465,767,5, +12,1,37527,767,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -8286,20 +8290,20 @@ public class yyLSLTokens : YyLexer { 0,345,3,90,0, 345,3,95,0,345, 3,97,0,768,12, -1,35508,769,5,63, +1,37570,769,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,770,12, -1,35541,771,5,63, +1,37603,771,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,345,3, 115,0,345,3,116, -0,772,12,1,35576, +0,772,12,1,37638, 773,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -8408,7 +8412,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,776,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,115,0,345,3, 116,0,345,3,117, 0,345,3,118,0, @@ -8455,7 +8459,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,777,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,98,0,345, 3,99,0,345,3, 100,0,345,3,101, @@ -8465,7 +8469,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -778,11,1,845,0, +778,11,1,867,0, 348,1,-1,3,117, 0,345,3,118,0, 345,3,119,0,345, @@ -8511,7 +8515,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,779,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,116,0,345, 3,117,0,345,3, 118,0,345,3,119, @@ -8551,10 +8555,10 @@ public class yyLSLTokens : YyLexer { 345,3,98,0,345, 3,99,0,345,3, 100,0,345,3,101, -0,780,12,1,36043, +0,780,12,1,38105, 781,5,63,3,109, 0,345,3,110,0, -782,12,1,36072,783, +782,12,1,38134,783, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -8599,7 +8603,7 @@ public class yyLSLTokens : YyLexer { 345,3,97,0,345, 3,98,0,345,3, 99,0,345,3,100, -0,784,12,1,36118, +0,784,12,1,38180, 785,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -8669,7 +8673,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -788,11,1,845,0, +788,11,1,867,0, 348,1,-1,3,111, 0,345,3,112,0, 345,3,113,0,345, @@ -8720,14 +8724,14 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,789,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,102,0,345,3, 103,0,345,3,104, 0,345,3,105,0, 345,3,106,0,345, 3,107,0,345,3, 108,0,345,790,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,97,0,345, 3,98,0,345,3, 99,0,345,3,100, @@ -8797,7 +8801,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,793,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, @@ -8846,11 +8850,11 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,794,11,1,845, +345,794,11,1,867, 0,348,1,-1,3, 106,0,345,3,107, 0,345,3,108,0, -345,795,11,1,845, +345,795,11,1,867, 0,348,1,-1,3, 116,0,345,3,117, 0,345,3,118,0, @@ -8897,14 +8901,14 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,796,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,106,0,345, 3,107,0,345,3, 108,0,345,797,11, -1,845,0,348,1, --1,798,11,1,845, +1,867,0,348,1, +-1,798,11,1,867, 0,348,1,-1,799, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,112,0, 345,3,113,0,345, 3,114,0,345,3, @@ -8954,7 +8958,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,800,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,100,0,345,3, 101,0,345,3,102, 0,345,3,103,0, @@ -8962,7 +8966,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,801,11,1,845, +345,801,11,1,867, 0,348,1,-1,3, 97,0,345,3,98, 0,345,3,99,0, @@ -8974,7 +8978,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,802,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,101,0,345,3, 102,0,345,3,103, 0,345,3,104,0, @@ -8982,7 +8986,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,803,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, @@ -9032,7 +9036,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,804, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,98,0, 345,3,99,0,345, 3,100,0,345,3, @@ -9040,10 +9044,10 @@ public class yyLSLTokens : YyLexer { 0,345,3,103,0, 345,3,104,0,345, 3,105,0,805,12, -1,37419,806,5,63, +1,39481,806,5,63, 3,109,0,345,3, 110,0,807,12,1, -37448,808,5,63,3, +39510,808,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -9093,7 +9097,7 @@ public class yyLSLTokens : YyLexer { 345,3,104,0,345, 3,105,0,345,3, 106,0,345,3,107, -0,809,12,1,37501, +0,809,12,1,39563, 810,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -9135,9 +9139,9 @@ public class yyLSLTokens : YyLexer { 345,3,88,0,345, 3,89,0,345,3, 90,0,345,3,95, -0,811,12,1,37587, +0,811,12,1,39649, 812,5,63,3,109, -0,813,12,1,37615, +0,813,12,1,39677, 814,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -9183,21 +9187,21 @@ public class yyLSLTokens : YyLexer { 345,3,98,0,345, 3,99,0,345,3, 100,0,345,3,101, -0,815,12,1,37662, +0,815,12,1,39724, 816,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, 0,345,3,115,0, -817,12,1,37696,818, +817,12,1,39758,818, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, 345,3,115,0,819, -12,1,37730,820,5, +12,1,39792,820,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -9240,7 +9244,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,90,0, 345,3,95,0,345, 3,97,0,821,12, -1,37773,822,5,63, +1,39835,822,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -9287,7 +9291,7 @@ public class yyLSLTokens : YyLexer { 345,3,100,0,345, 3,101,0,345,3, 102,0,345,3,103, -0,823,12,1,37822, +0,823,12,1,39884, 824,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -9333,7 +9337,7 @@ public class yyLSLTokens : YyLexer { 345,3,98,0,345, 3,99,0,345,3, 100,0,345,3,101, -0,825,12,1,37869, +0,825,12,1,39931, 826,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -9400,13 +9404,13 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,829, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,104,0, 345,3,105,0,345, 3,106,0,345,3, 107,0,345,3,108, 0,345,830,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,98,0,345,3, 99,0,345,3,100, 0,345,3,101,0, @@ -9416,7 +9420,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,831, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,116,0, 345,3,117,0,345, 3,118,0,345,3, @@ -9462,7 +9466,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,832,11,1,845, +345,832,11,1,867, 0,348,1,-1,3, 116,0,345,3,117, 0,345,3,118,0, @@ -9509,14 +9513,14 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,833,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,102,0,345, 3,103,0,345,3, 104,0,345,3,105, 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,834, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,110,0, 345,3,111,0,345, 3,112,0,345,3, @@ -9567,7 +9571,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -835,11,1,845,0, +835,11,1,867,0, 348,1,-1,3,97, 0,345,3,98,0, 345,3,99,0,345, @@ -9578,15 +9582,15 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,836,11,1,845, +345,836,11,1,867, 0,348,1,-1,3, 108,0,345,837,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, 0,345,3,115,0, -838,12,1,38653,839, +838,12,1,40715,839, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -9594,7 +9598,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,114,0, 345,3,115,0,345, 3,116,0,840,12, -1,38688,841,5,63, +1,40750,841,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -9640,10 +9644,10 @@ public class yyLSLTokens : YyLexer { 0,345,3,99,0, 345,3,100,0,345, 3,101,0,842,12, -1,38735,843,5,63, +1,40797,843,5,63, 3,109,0,345,3, 110,0,844,12,1, -38764,845,5,63,3, +40826,845,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -9750,7 +9754,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,848, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,102,0, 345,3,103,0,345, 3,104,0,345,3, @@ -9807,7 +9811,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,851,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,116,0,345, 3,117,0,345,3, 118,0,345,3,119, @@ -9853,20 +9857,20 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -852,11,1,845,0, +852,11,1,867,0, 348,1,-1,3,106, 0,345,3,107,0, 345,3,108,0,345, -853,11,1,845,0, +853,11,1,867,0, 348,1,-1,3,109, -0,854,12,1,1942, +0,854,12,1,1964, 855,5,63,3,109, 0,345,3,110,0, 345,3,111,0,856, -12,1,1972,857,5, +12,1,1994,857,5, 63,3,109,0,345, 3,110,0,858,12, -1,2001,859,5,63, +1,2023,859,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -9912,7 +9916,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,99,0, 345,3,100,0,345, 3,101,0,860,12, -1,2048,861,5,63, +1,2070,861,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -9923,7 +9927,7 @@ public class yyLSLTokens : YyLexer { 345,3,118,0,345, 3,119,0,345,3, 120,0,345,3,121, -0,862,12,1,2088, +0,862,12,1,2110, 863,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -10022,14 +10026,14 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,866,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,102,0,345,3, 103,0,345,3,104, 0,345,3,105,0, 345,3,106,0,345, 3,107,0,345,3, 108,0,345,867,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, @@ -10037,7 +10041,7 @@ public class yyLSLTokens : YyLexer { 345,3,116,0,345, 3,117,0,345,3, 118,0,868,12,1, -2369,869,5,63,3, +2391,869,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -10086,10 +10090,10 @@ public class yyLSLTokens : YyLexer { 0,345,3,103,0, 345,3,104,0,345, 3,105,0,870,12, -1,2420,871,5,63, +1,2442,871,5,63, 3,109,0,345,3, 110,0,872,12,1, -2449,873,5,63,3, +2471,873,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -10136,7 +10140,7 @@ public class yyLSLTokens : YyLexer { 3,100,0,345,3, 101,0,345,3,102, 0,345,3,103,0, -874,12,1,2498,875, +874,12,1,2520,875, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -10178,14 +10182,14 @@ public class yyLSLTokens : YyLexer { 3,88,0,345,3, 89,0,345,3,90, 0,345,3,95,0, -876,12,1,2584,877, +876,12,1,2606,877, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, 345,3,115,0,878, -12,1,2618,879,5, +12,1,2640,879,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -10193,7 +10197,7 @@ public class yyLSLTokens : YyLexer { 345,3,114,0,345, 3,115,0,345,3, 116,0,880,12,1, -2653,881,5,63,3, +2675,881,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -10235,13 +10239,13 @@ public class yyLSLTokens : YyLexer { 345,3,89,0,345, 3,90,0,345,3, 95,0,345,3,97, -0,882,12,1,2696, +0,882,12,1,2718, 883,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, -0,884,12,1,2729, +0,884,12,1,2751, 885,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -10249,7 +10253,7 @@ public class yyLSLTokens : YyLexer { 113,0,345,3,114, 0,345,3,115,0, 345,3,116,0,886, -12,1,2764,887,5, +12,1,2786,887,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -10354,7 +10358,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,890, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,115,0, 345,3,116,0,345, 3,117,0,345,3, @@ -10401,7 +10405,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -891,11,1,845,0, +891,11,1,867,0, 348,1,-1,3,98, 0,345,3,99,0, 345,3,100,0,345, @@ -10412,7 +10416,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,892,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,117,0,345,3, 118,0,345,3,119, 0,345,3,120,0, @@ -10457,7 +10461,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -893,11,1,845,0, +893,11,1,867,0, 348,1,-1,3,116, 0,345,3,117,0, 345,3,118,0,345, @@ -10498,10 +10502,10 @@ public class yyLSLTokens : YyLexer { 0,345,3,99,0, 345,3,100,0,345, 3,101,0,894,12, -1,3231,895,5,63, +1,3253,895,5,63, 3,109,0,345,3, 110,0,896,12,1, -3260,897,5,63,3, +3282,897,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -10546,7 +10550,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,98,0, 345,3,99,0,345, 3,100,0,898,12, -1,3306,899,5,63, +1,3328,899,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -10612,7 +10616,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,902,11,1,845, +345,902,11,1,867, 0,348,1,-1,3, 111,0,345,3,112, 0,345,3,113,0, @@ -10663,14 +10667,14 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,903,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,102,0,345, 3,103,0,345,3, 104,0,345,3,105, 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,904, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,97,0, 345,3,98,0,345, 3,99,0,345,3, @@ -10681,13 +10685,13 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -905,11,1,845,0, +905,11,1,867,0, 348,1,-1,3,104, 0,345,3,105,0, 345,3,106,0,345, 3,107,0,345,3, 108,0,345,906,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, @@ -10737,11 +10741,11 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -907,11,1,845,0, +907,11,1,867,0, 348,1,-1,3,106, 0,345,3,107,0, 345,3,108,0,345, -908,11,1,845,0, +908,11,1,867,0, 348,1,-1,3,119, 0,345,3,120,0, 345,3,121,0,345, @@ -10785,7 +10789,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -909,11,1,845,0, +909,11,1,867,0, 348,1,-1,3,112, 0,345,3,113,0, 345,3,114,0,345, @@ -10835,20 +10839,20 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,910,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,110,0,911, -12,1,4103,912,5, +12,1,4125,912,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,913,12,1, -4133,914,5,63,3, +4155,914,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, 0,345,3,116,0, -915,12,1,4168,916, +915,12,1,4190,916, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -10890,7 +10894,7 @@ public class yyLSLTokens : YyLexer { 3,88,0,345,3, 89,0,345,3,90, 0,345,3,95,0, -917,12,1,4254,918, +917,12,1,4276,918, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -10933,7 +10937,7 @@ public class yyLSLTokens : YyLexer { 89,0,345,3,90, 0,345,3,95,0, 345,3,97,0,919, -12,1,4297,920,5, +12,1,4319,920,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -10941,7 +10945,7 @@ public class yyLSLTokens : YyLexer { 345,3,114,0,345, 3,115,0,345,3, 116,0,921,12,1, -4332,922,5,63,3, +4354,922,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -10983,16 +10987,16 @@ public class yyLSLTokens : YyLexer { 345,3,89,0,345, 3,90,0,345,3, 95,0,923,12,1, -4418,924,5,63,3, +4440,924,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,925,12,1, -4451,926,5,63,3, +4473,926,5,63,3, 109,0,345,3,110, 0,345,3,111,0, -927,12,1,4481,928, +927,12,1,4503,928, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -11000,7 +11004,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,114,0, 345,3,115,0,345, 3,116,0,929,12, -1,4516,930,5,63, +1,4538,930,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -11042,14 +11046,14 @@ public class yyLSLTokens : YyLexer { 0,345,3,89,0, 345,3,90,0,345, 3,95,0,931,12, -1,4602,932,5,63, +1,4624,932,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,345,3, 115,0,345,3,116, -0,933,12,1,4637, +0,933,12,1,4659, 934,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -11092,13 +11096,13 @@ public class yyLSLTokens : YyLexer { 3,89,0,345,3, 90,0,345,3,95, 0,345,3,97,0, -935,12,1,4680,936, +935,12,1,4702,936, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, -937,12,1,4713,938, +937,12,1,4735,938, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -11146,7 +11150,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,101,0, 345,3,102,0,345, 3,103,0,939,12, -1,4762,940,5,63, +1,4784,940,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -11192,14 +11196,14 @@ public class yyLSLTokens : YyLexer { 0,345,3,99,0, 345,3,100,0,345, 3,101,0,941,12, -1,4809,942,5,63, +1,4831,942,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,345,3, 115,0,345,3,116, -0,943,12,1,4844, +0,943,12,1,4866, 944,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -11306,7 +11310,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,947,11,1,845, +345,947,11,1,867, 0,348,1,-1,3, 102,0,345,3,103, 0,345,3,104,0, @@ -11314,12 +11318,12 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,948,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,104,0,345,3, 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -949,11,1,845,0, +949,11,1,867,0, 348,1,-1,3,115, 0,345,3,116,0, 345,3,117,0,345, @@ -11366,7 +11370,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,950,11,1,845, +345,950,11,1,867, 0,348,1,-1,3, 98,0,345,3,99, 0,345,3,100,0, @@ -11377,7 +11381,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,951,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,117,0,345, 3,118,0,345,3, 119,0,345,3,120, @@ -11422,7 +11426,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,952,11,1,845, +345,952,11,1,867, 0,348,1,-1,3, 97,0,345,3,98, 0,345,3,99,0, @@ -11434,7 +11438,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,953,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,117,0,345,3, 118,0,345,3,119, 0,345,3,120,0, @@ -11479,7 +11483,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -954,11,1,845,0, +954,11,1,867,0, 348,1,-1,3,112, 0,345,3,113,0, 345,3,114,0,345, @@ -11529,10 +11533,10 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,955,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,115,0,345, 3,116,0,956,12, -1,5653,957,5,63, +1,5675,957,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -11575,13 +11579,13 @@ public class yyLSLTokens : YyLexer { 345,3,90,0,345, 3,95,0,345,3, 97,0,958,12,1, -5696,959,5,63,3, +5718,959,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,960,12,1, -5729,961,5,63,3, +5751,961,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -11628,7 +11632,7 @@ public class yyLSLTokens : YyLexer { 3,100,0,345,3, 101,0,345,3,102, 0,345,3,103,0, -962,12,1,5778,963, +962,12,1,5800,963, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -11674,7 +11678,7 @@ public class yyLSLTokens : YyLexer { 3,98,0,345,3, 99,0,345,3,100, 0,345,3,101,0, -964,12,1,5825,965, +964,12,1,5847,965, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -11682,7 +11686,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,114,0, 345,3,115,0,345, 3,116,0,966,12, -1,5860,967,5,63, +1,5882,967,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -11787,20 +11791,20 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -970,11,1,845,0, +970,11,1,867,0, 348,1,-1,3,102, 0,345,3,103,0, 345,3,104,0,345, 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,971,11,1,845, +345,971,11,1,867, 0,348,1,-1,3, 104,0,345,3,105, 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,972, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,115,0, 345,3,116,0,345, 3,117,0,345,3, @@ -11847,7 +11851,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -973,11,1,845,0, +973,11,1,867,0, 348,1,-1,3,98, 0,345,3,99,0, 345,3,100,0,345, @@ -11858,7 +11862,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,974,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,117,0,345,3, 118,0,345,3,119, 0,345,3,120,0, @@ -11903,7 +11907,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -975,11,1,845,0, +975,11,1,867,0, 348,1,-1,3,97, 0,345,3,98,0, 345,3,99,0,345, @@ -11914,7 +11918,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,976,11,1,845, +345,976,11,1,867, 0,348,1,-1,3, 117,0,345,3,118, 0,345,3,119,0, @@ -11960,7 +11964,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,977, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,98,0, 345,3,99,0,345, 3,100,0,345,3, @@ -11970,7 +11974,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,978,11,1,845, +345,978,11,1,867, 0,348,1,-1,3, 97,0,345,3,98, 0,345,3,99,0, @@ -11982,7 +11986,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,979,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,117,0,345,3, 118,0,345,3,119, 0,345,3,120,0, @@ -12017,14 +12021,14 @@ public class yyLSLTokens : YyLexer { 345,3,88,0,345, 3,89,0,345,3, 90,0,345,3,95, -0,980,12,1,6739, +0,980,12,1,6761, 981,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, 0,345,3,115,0, -982,12,1,6773,983, +982,12,1,6795,983, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -12070,26 +12074,26 @@ public class yyLSLTokens : YyLexer { 3,98,0,345,3, 99,0,345,3,100, 0,345,3,101,0, -984,12,1,6820,985, +984,12,1,6842,985, 5,63,3,109,0, 345,3,110,0,986, -12,1,6849,987,5, +12,1,6871,987,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, 0,345,3,113,0, 345,3,114,0,345, 3,115,0,988,12, -1,6883,989,5,63, +1,6905,989,5,63, 3,109,0,345,3, 110,0,345,3,111, -0,990,12,1,6913, +0,990,12,1,6935, 991,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, -0,992,12,1,6946, +0,992,12,1,6968, 993,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -12195,7 +12199,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,996,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, @@ -12244,7 +12248,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,997,11,1,845, +345,997,11,1,867, 0,348,1,-1,3, 116,0,345,3,117, 0,345,3,118,0, @@ -12291,7 +12295,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,998,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, @@ -12341,14 +12345,14 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -999,11,1,845,0, +999,11,1,867,0, 348,1,-1,3,102, 0,345,3,103,0, 345,3,104,0,345, 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1000,11,1,845, +345,1000,11,1,867, 0,348,1,-1,3, 116,0,345,3,117, 0,345,3,118,0, @@ -12395,7 +12399,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1001,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,97,0,345, 3,98,0,345,3, 99,0,345,3,100, @@ -12406,7 +12410,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,1002, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,112,0, 345,3,113,0,345, 3,114,0,345,3, @@ -12456,12 +12460,12 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1003,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,111,0,1004,12, -1,7704,1005,5,63, +1,7726,1005,5,63, 3,109,0,345,3, 110,0,1006,12,1, -7733,1007,5,63,3, +7755,1007,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -12503,13 +12507,13 @@ public class yyLSLTokens : YyLexer { 345,3,89,0,345, 3,90,0,345,3, 95,0,1008,12,1, -7819,1009,5,63,3, +7841,1009,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,1010,12,1, -7852,1011,5,63,3, +7874,1011,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -12555,7 +12559,7 @@ public class yyLSLTokens : YyLexer { 345,3,99,0,345, 3,100,0,345,3, 101,0,1012,12,1, -7899,1013,5,63,3, +7921,1013,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -12567,7 +12571,7 @@ public class yyLSLTokens : YyLexer { 119,0,345,3,120, 0,345,3,121,0, 345,3,122,0,1014, -12,1,7940,1015,5, +12,1,7962,1015,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -12665,14 +12669,14 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1018,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,102,0,345, 3,103,0,345,3, 104,0,345,3,105, 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,1019, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,115,0, 345,3,116,0,345, 3,117,0,345,3, @@ -12719,7 +12723,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1020,11,1,845,0, +1020,11,1,867,0, 348,1,-1,3,97, 0,345,3,98,0, 345,3,99,0,345, @@ -12730,7 +12734,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1021,11,1,845, +345,1021,11,1,867, 0,348,1,-1,3, 111,0,345,3,112, 0,345,3,113,0, @@ -12773,7 +12777,7 @@ public class yyLSLTokens : YyLexer { 345,3,95,0,345, 3,97,0,345,3, 98,0,1022,12,1, -8348,1023,5,63,3, +8370,1023,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -12823,7 +12827,7 @@ public class yyLSLTokens : YyLexer { 345,3,104,0,345, 3,105,0,345,3, 106,0,1024,12,1, -8400,1025,5,63,3, +8422,1025,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -12869,7 +12873,7 @@ public class yyLSLTokens : YyLexer { 345,3,99,0,345, 3,100,0,345,3, 101,0,1026,12,1, -8447,1027,5,63,3, +8469,1027,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -12913,7 +12917,7 @@ public class yyLSLTokens : YyLexer { 95,0,345,3,97, 0,345,3,98,0, 345,3,99,0,1028, -12,1,8492,1029,5, +12,1,8514,1029,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -12921,7 +12925,7 @@ public class yyLSLTokens : YyLexer { 345,3,114,0,345, 3,115,0,345,3, 116,0,1030,12,1, -8527,1031,5,63,3, +8549,1031,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -12963,13 +12967,13 @@ public class yyLSLTokens : YyLexer { 345,3,89,0,345, 3,90,0,345,3, 95,0,1032,12,1, -8613,1033,5,63,3, +8635,1033,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,1034,12,1, -8646,1035,5,63,3, +8668,1035,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -13015,7 +13019,7 @@ public class yyLSLTokens : YyLexer { 345,3,99,0,345, 3,100,0,345,3, 101,0,1036,12,1, -8693,1037,5,63,3, +8715,1037,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -13027,7 +13031,7 @@ public class yyLSLTokens : YyLexer { 119,0,345,3,120, 0,345,3,121,0, 345,3,122,0,1038, -12,1,8734,1039,5, +12,1,8756,1039,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -13126,7 +13130,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1042,11,1,845, +345,1042,11,1,867, 0,348,1,-1,3, 102,0,345,3,103, 0,345,3,104,0, @@ -13134,7 +13138,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1043,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,115,0,345,3, 116,0,345,3,117, 0,345,3,118,0, @@ -13181,7 +13185,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1044,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,97,0,345, 3,98,0,345,3, 99,0,345,3,100, @@ -13192,7 +13196,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,1045, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,117,0, 345,3,118,0,345, 3,119,0,345,3, @@ -13238,7 +13242,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1046,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,100,0,345,3, 101,0,345,3,102, 0,345,3,103,0, @@ -13246,7 +13250,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1047,11,1,845, +345,1047,11,1,867, 0,348,1,-1,3, 102,0,345,3,103, 0,345,3,104,0, @@ -13254,10 +13258,10 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1048,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,107,0,345,3, 108,0,345,1049,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,99,0,345, 3,100,0,345,3, 101,0,345,3,102, @@ -13266,22 +13270,22 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1050,11,1,845, +345,1050,11,1,867, 0,348,1,-1,3, 112,0,343,3,113, 0,343,3,114,0, -1051,12,1,9507,1052, +1051,12,1,9529,1052, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,1053,12, -1,9537,1054,5,63, +1,9559,1054,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,345,3, 115,0,345,3,116, -0,1055,12,1,9572, +0,1055,12,1,9594, 1056,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -13324,7 +13328,7 @@ public class yyLSLTokens : YyLexer { 3,89,0,345,3, 90,0,345,3,95, 0,345,3,97,0, -1057,12,1,9615,1058, +1057,12,1,9637,1058, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -13332,7 +13336,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,114,0, 345,3,115,0,345, 3,116,0,1059,12, -1,9650,1060,5,63, +1,9672,1060,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -13381,13 +13385,13 @@ public class yyLSLTokens : YyLexer { 102,0,345,3,103, 0,345,3,104,0, 345,3,105,0,1061, -12,1,9701,1062,5, +12,1,9723,1062,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,1063,12,1, -9731,1064,5,63,3, +9753,1064,5,63,3, 109,0,345,3,110, -0,1065,12,1,9760, +0,1065,12,1,9782, 1066,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -13495,7 +13499,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1069,11,1,845,0, +1069,11,1,867,0, 348,1,-1,3,112, 0,345,3,113,0, 345,3,114,0,345, @@ -13545,11 +13549,11 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1070,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,106,0,345, 3,107,0,345,3, 108,0,345,1071,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,117,0,345, 3,118,0,345,3, 119,0,345,3,120, @@ -13594,7 +13598,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1072,11,1,845, +345,1072,11,1,867, 0,348,1,-1,3, 98,0,345,3,99, 0,345,3,100,0, @@ -13605,7 +13609,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1073,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,117,0,345, 3,118,0,345,3, 119,0,345,3,120, @@ -13650,16 +13654,16 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1074,11,1,845, +345,1074,11,1,867, 0,348,1,-1,3, 112,0,345,3,113, 0,345,3,114,0, 345,3,115,0,345, 3,116,0,345,3, 117,0,1075,12,1, -10383,1076,5,63,3, +10405,1076,5,63,3, 109,0,345,3,110, -0,1077,12,1,10412, +0,1077,12,1,10434, 1078,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -13701,7 +13705,7 @@ public class yyLSLTokens : YyLexer { 345,3,88,0,345, 3,89,0,345,3, 90,0,345,3,95, -0,1079,12,1,10498, +0,1079,12,1,10520, 1080,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -13709,7 +13713,7 @@ public class yyLSLTokens : YyLexer { 113,0,345,3,114, 0,345,3,115,0, 345,3,116,0,1081, -12,1,10533,1082,5, +12,1,10555,1082,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -13758,9 +13762,9 @@ public class yyLSLTokens : YyLexer { 3,102,0,345,3, 103,0,345,3,104, 0,345,3,105,0, -1083,12,1,10584,1084, +1083,12,1,10606,1084, 5,63,3,109,0, -1085,12,1,10612,1086, +1085,12,1,10634,1086, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -13806,7 +13810,7 @@ public class yyLSLTokens : YyLexer { 3,98,0,345,3, 99,0,345,3,100, 0,345,3,101,0, -1087,12,1,10659,1088, +1087,12,1,10681,1088, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -13848,12 +13852,12 @@ public class yyLSLTokens : YyLexer { 3,88,0,345,3, 89,0,345,3,90, 0,345,3,95,0, -1089,12,1,10745,1090, +1089,12,1,10767,1090, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, 112,0,1091,12,1, -10776,1092,5,63,3, +10798,1092,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -13899,15 +13903,15 @@ public class yyLSLTokens : YyLexer { 345,3,99,0,345, 3,100,0,345,3, 101,0,1093,12,1, -10823,1094,5,63,3, +10845,1094,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,1095,12,1, -10856,1096,5,63,3, +10878,1096,5,63,3, 109,0,1097,12,1, -10884,1098,5,63,3, +10906,1098,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -13956,20 +13960,20 @@ public class yyLSLTokens : YyLexer { 0,345,3,103,0, 345,3,104,0,345, 3,105,0,1099,12, -1,10935,1100,5,63, +1,10957,1100,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,345,3, 115,0,1101,12,1, -10969,1102,5,63,3, +10991,1102,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, -0,1103,12,1,11003, +0,1103,12,1,11025, 1104,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -14019,20 +14023,20 @@ public class yyLSLTokens : YyLexer { 345,3,103,0,345, 3,104,0,345,3, 105,0,1105,12,1, -11054,1106,5,63,3, +11076,1106,5,63,3, 109,0,345,3,110, 0,345,3,111,0, -1107,12,1,11084,1108, +1107,12,1,11106,1108, 5,63,3,109,0, 345,3,110,0,1109, -12,1,11113,1110,5, +12,1,11135,1110,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, 0,345,3,113,0, 345,3,114,0,345, 3,115,0,1111,12, -1,11147,1112,5,63, +1,11169,1112,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -14141,7 +14145,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1115,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, @@ -14191,7 +14195,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1116,11,1,845,0, +1116,11,1,867,0, 348,1,-1,3,112, 0,345,3,113,0, 345,3,114,0,345, @@ -14241,11 +14245,11 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1117,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,106,0,345, 3,107,0,345,3, 108,0,345,1118,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,116,0,345, 3,117,0,345,3, 118,0,345,3,119, @@ -14291,7 +14295,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1119,11,1,845,0, +1119,11,1,867,0, 348,1,-1,3,116, 0,345,3,117,0, 345,3,118,0,345, @@ -14338,11 +14342,11 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1120,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,106,0,345,3, 107,0,345,3,108, 0,345,1121,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,110,0,345,3, 111,0,345,3,112, 0,345,3,113,0, @@ -14393,7 +14397,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1122,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,115,0,345, 3,116,0,345,3, 117,0,345,3,118, @@ -14440,14 +14444,14 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,1123, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,102,0, 345,3,103,0,345, 3,104,0,345,3, 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1124,11,1,845,0, +1124,11,1,867,0, 348,1,-1,3,113, 0,345,3,114,0, 345,3,115,0,345, @@ -14496,7 +14500,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,1125, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,97,0, 345,3,98,0,345, 3,99,0,345,3, @@ -14507,14 +14511,14 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1126,11,1,845,0, +1126,11,1,867,0, 348,1,-1,3,102, 0,345,3,103,0, 345,3,104,0,345, 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1127,11,1,845, +345,1127,11,1,867, 0,348,1,-1,3, 110,0,345,3,111, 0,345,3,112,0, @@ -14566,11 +14570,11 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1128,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,106,0,345,3, 107,0,345,3,108, 0,345,1129,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,117,0,345,3, 118,0,345,3,119, 0,345,3,120,0, @@ -14615,7 +14619,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1130,11,1,845,0, +1130,11,1,867,0, 348,1,-1,3,97, 0,345,3,98,0, 345,3,99,0,345, @@ -14626,7 +14630,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1131,11,1,845, +345,1131,11,1,867, 0,348,1,-1,3, 111,0,345,3,112, 0,345,3,113,0, @@ -14677,7 +14681,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1132,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,118,0,345, 3,119,0,345,3, 120,0,345,3,121, @@ -14716,12 +14720,12 @@ public class yyLSLTokens : YyLexer { 0,345,3,99,0, 345,3,100,0,345, 3,101,0,1133,12, -1,12674,1134,5,63, +1,12696,1134,5,63, 3,109,0,1135,12, -1,12702,1136,5,63, +1,12724,1136,5,63, 3,109,0,345,3, 110,0,345,3,111, -0,1137,12,1,12732, +0,1137,12,1,12754, 1138,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -14729,7 +14733,7 @@ public class yyLSLTokens : YyLexer { 113,0,345,3,114, 0,345,3,115,0, 345,3,116,0,1139, -12,1,12767,1140,5, +12,1,12789,1140,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -14775,7 +14779,7 @@ public class yyLSLTokens : YyLexer { 98,0,345,3,99, 0,345,3,100,0, 345,3,101,0,1141, -12,1,12814,1142,5, +12,1,12836,1142,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -14817,7 +14821,7 @@ public class yyLSLTokens : YyLexer { 88,0,345,3,89, 0,345,3,90,0, 345,3,95,0,1143, -12,1,12900,1144,5, +12,1,12922,1144,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -14862,7 +14866,7 @@ public class yyLSLTokens : YyLexer { 3,97,0,345,3, 98,0,345,3,99, 0,345,3,100,0, -1145,12,1,12946,1146, +1145,12,1,12968,1146, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -14905,7 +14909,7 @@ public class yyLSLTokens : YyLexer { 89,0,345,3,90, 0,345,3,95,0, 345,3,97,0,1147, -12,1,12989,1148,5, +12,1,13011,1148,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -14913,7 +14917,7 @@ public class yyLSLTokens : YyLexer { 345,3,114,0,345, 3,115,0,345,3, 116,0,1149,12,1, -13024,1150,5,63,3, +13046,1150,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -14955,7 +14959,7 @@ public class yyLSLTokens : YyLexer { 345,3,89,0,345, 3,90,0,345,3, 95,0,345,3,97, -0,1151,12,1,13067, +0,1151,12,1,13089, 1152,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -15025,7 +15029,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1155,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,117,0,345, 3,118,0,345,3, 119,0,345,3,120, @@ -15070,7 +15074,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1156,11,1,845, +345,1156,11,1,867, 0,348,1,-1,3, 98,0,345,3,99, 0,345,3,100,0, @@ -15081,7 +15085,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1157,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,101,0,345, 3,102,0,345,3, 103,0,345,3,104, @@ -15089,7 +15093,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1158,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,97,0,345, 3,98,0,345,3, 99,0,345,3,100, @@ -15100,14 +15104,14 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,1159, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,102,0, 345,3,103,0,345, 3,104,0,345,3, 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1160,11,1,845,0, +1160,11,1,867,0, 348,1,-1,3,117, 0,345,3,118,0, 345,3,119,0,345, @@ -15153,7 +15157,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1161,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, @@ -15202,14 +15206,14 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1162,11,1,845, +345,1162,11,1,867, 0,348,1,-1,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,345,3, 115,0,345,3,116, -0,1163,12,1,13789, +0,1163,12,1,13811, 1164,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -15218,16 +15222,16 @@ public class yyLSLTokens : YyLexer { 0,345,3,115,0, 345,3,116,0,345, 3,117,0,1165,12, -1,13825,1166,5,63, +1,13847,1166,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, 345,3,113,0,345, 3,114,0,1167,12, -1,13858,1168,5,63, +1,13880,1168,5,63, 3,109,0,345,3, 110,0,1169,12,1, -13887,1170,5,63,3, +13909,1170,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -15332,7 +15336,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1173,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,115,0,345,3, 116,0,345,3,117, 0,345,3,118,0, @@ -15379,7 +15383,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1174,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,118,0,345, 3,119,0,345,3, 120,0,345,3,121, @@ -15424,7 +15428,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1175,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,117,0,345,3, 118,0,345,3,119, 0,345,3,120,0, @@ -15469,30 +15473,30 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1176,11,1,845,0, +1176,11,1,867,0, 348,1,-1,3,102, 0,345,3,103,0, 345,3,104,0,345, 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1177,11,1,845, +345,1177,11,1,867, 0,348,1,-1,3, 115,0,1178,12,1, -14428,1179,5,63,3, +14450,1179,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, 0,345,3,116,0, -1180,12,1,14463,1181, +1180,12,1,14485,1181, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, -1182,12,1,14496,1183, +1182,12,1,14518,1183, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -15541,10 +15545,10 @@ public class yyLSLTokens : YyLexer { 345,3,102,0,345, 3,103,0,345,3, 104,0,345,3,105, -0,1184,12,1,14547, +0,1184,12,1,14569, 1185,5,63,3,109, 0,345,3,110,0, -1186,12,1,14576,1187, +1186,12,1,14598,1187, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -15592,7 +15596,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,101,0, 345,3,102,0,345, 3,103,0,1188,12, -1,14625,1189,5,63, +1,14647,1189,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -15654,7 +15658,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,1192, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,111,0, 345,3,112,0,345, 3,113,0,345,3, @@ -15704,11 +15708,11 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1193,11,1,845, +345,1193,11,1,867, 0,348,1,-1,3, 106,0,345,3,107, 0,345,3,108,0, -345,1194,11,1,845, +345,1194,11,1,867, 0,348,1,-1,3, 115,0,345,3,116, 0,345,3,117,0, @@ -15747,14 +15751,14 @@ public class yyLSLTokens : YyLexer { 345,3,90,0,345, 3,95,0,345,3, 97,0,1195,12,1, -14986,1196,5,63,3, +15008,1196,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,345,3,115, 0,345,3,116,0, -1197,12,1,15021,1198, +1197,12,1,15043,1198, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -15800,7 +15804,7 @@ public class yyLSLTokens : YyLexer { 3,98,0,345,3, 99,0,345,3,100, 0,345,3,101,0, -1199,12,1,15068,1200, +1199,12,1,15090,1200, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -15842,7 +15846,7 @@ public class yyLSLTokens : YyLexer { 3,88,0,345,3, 89,0,345,3,90, 0,345,3,95,0, -1201,12,1,15154,1202, +1201,12,1,15176,1202, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -15888,10 +15892,10 @@ public class yyLSLTokens : YyLexer { 3,98,0,345,3, 99,0,345,3,100, 0,345,3,101,0, -1203,12,1,15201,1204, +1203,12,1,15223,1204, 5,63,3,109,0, 345,3,110,0,1205, -12,1,15230,1206,5, +12,1,15252,1206,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -15899,13 +15903,13 @@ public class yyLSLTokens : YyLexer { 345,3,114,0,345, 3,115,0,345,3, 116,0,1207,12,1, -15265,1208,5,63,3, +15287,1208,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, 3,113,0,345,3, 114,0,1209,12,1, -15298,1210,5,63,3, +15320,1210,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -15916,7 +15920,7 @@ public class yyLSLTokens : YyLexer { 3,118,0,345,3, 119,0,345,3,120, 0,345,3,121,0, -1211,12,1,15338,1212, +1211,12,1,15360,1212, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -16017,7 +16021,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1215,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,115,0,345, 3,116,0,345,3, 117,0,345,3,118, @@ -16064,7 +16068,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,1216, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,117,0, 345,3,118,0,345, 3,119,0,345,3, @@ -16110,7 +16114,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1217,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, @@ -16119,7 +16123,7 @@ public class yyLSLTokens : YyLexer { 117,0,345,3,118, 0,345,3,119,0, 345,3,120,0,1218, -12,1,15720,1219,5, +12,1,15742,1219,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -16168,7 +16172,7 @@ public class yyLSLTokens : YyLexer { 3,102,0,345,3, 103,0,345,3,104, 0,345,3,105,0, -1220,12,1,15771,1221, +1220,12,1,15793,1221, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -16176,7 +16180,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,114,0, 345,3,115,0,345, 3,116,0,1222,12, -1,15806,1223,5,63, +1,15828,1223,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -16280,11 +16284,11 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,1226, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,106,0, 345,3,107,0,345, 3,108,0,345,1227, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,121,0, 345,3,122,0,345, 3,48,0,345,3, @@ -16326,7 +16330,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1228,11,1,845, +345,1228,11,1,867, 0,348,1,-1,3, 102,0,345,3,103, 0,345,3,104,0, @@ -16334,7 +16338,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1229,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,97,0,345,3, 98,0,345,3,99, 0,345,3,100,0, @@ -16354,7 +16358,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1232,11,1,845, +345,1232,11,1,867, 0,348,1,-1,3, 117,0,345,3,118, 0,345,3,119,0, @@ -16400,7 +16404,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,1233, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,98,0, 345,3,99,0,345, 3,100,0,345,3, @@ -16410,7 +16414,7 @@ public class yyLSLTokens : YyLexer { 3,105,0,345,3, 106,0,345,3,107, 0,345,3,108,0, -345,1234,11,1,845, +345,1234,11,1,867, 0,348,1,-1,3, 117,0,345,3,118, 0,345,3,119,0, @@ -16450,26 +16454,26 @@ public class yyLSLTokens : YyLexer { 3,98,0,345,3, 99,0,345,3,100, 0,345,3,101,0, -1235,12,1,16515,1236, +1235,12,1,16537,1236, 5,63,3,109,0, 345,3,110,0,1237, -12,1,16544,1238,5, +12,1,16566,1238,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, 0,345,3,113,0, 345,3,114,0,345, 3,115,0,1239,12, -1,16578,1240,5,63, +1,16600,1240,5,63, 3,109,0,345,3, 110,0,345,3,111, -0,1241,12,1,16608, +0,1241,12,1,16630, 1242,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, -0,1243,12,1,16641, +0,1243,12,1,16663, 1244,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -16574,7 +16578,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1247,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,112,0,345,3, 113,0,345,3,114, 0,345,3,115,0, @@ -16623,7 +16627,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1248,11,1,845,0, +1248,11,1,867,0, 348,1,-1,3,116, 0,345,3,117,0, 345,3,118,0,345, @@ -16670,7 +16674,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1249,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, @@ -16720,20 +16724,20 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,1250, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,102,0, 345,3,103,0,345, 3,104,0,345,3, 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1251,11,1,845,0, +1251,11,1,867,0, 348,1,-1,3,116, -0,1252,12,1,17189, +0,1252,12,1,17211, 1253,5,63,3,109, 0,345,3,110,0, 345,3,111,0,1254, -12,1,17219,1255,5, +12,1,17241,1255,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -16741,7 +16745,7 @@ public class yyLSLTokens : YyLexer { 345,3,114,0,345, 3,115,0,345,3, 116,0,345,3,117, -0,1256,12,1,17255, +0,1256,12,1,17277, 1257,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -16786,7 +16790,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,97,0, 345,3,98,0,345, 3,99,0,1258,12, -1,17300,1259,5,63, +1,17322,1259,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -16834,7 +16838,7 @@ public class yyLSLTokens : YyLexer { 3,101,0,345,3, 102,0,345,3,103, 0,345,3,104,0, -1260,12,1,17350,1261, +1260,12,1,17372,1261, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -16876,14 +16880,14 @@ public class yyLSLTokens : YyLexer { 3,88,0,345,3, 89,0,345,3,90, 0,345,3,95,0, -1262,12,1,17436,1263, +1262,12,1,17458,1263, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, 345,3,115,0,1264, -12,1,17470,1265,5, +12,1,17492,1265,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -16891,7 +16895,7 @@ public class yyLSLTokens : YyLexer { 345,3,114,0,345, 3,115,0,345,3, 116,0,1266,12,1, -17505,1267,5,63,3, +17527,1267,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -16933,13 +16937,13 @@ public class yyLSLTokens : YyLexer { 345,3,89,0,345, 3,90,0,345,3, 95,0,345,3,97, -0,1268,12,1,17548, +0,1268,12,1,17570, 1269,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, -0,1270,12,1,17581, +0,1270,12,1,17603, 1271,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -16947,7 +16951,7 @@ public class yyLSLTokens : YyLexer { 113,0,345,3,114, 0,345,3,115,0, 345,3,116,0,1272, -12,1,17616,1273,5, +12,1,17638,1273,5, 63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, @@ -17052,7 +17056,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1276,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,115,0,345,3, 116,0,345,3,117, 0,345,3,118,0, @@ -17099,7 +17103,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1277,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,98,0,345, 3,99,0,345,3, 100,0,345,3,101, @@ -17109,7 +17113,7 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1278,11,1,845,0, +1278,11,1,867,0, 348,1,-1,3,117, 0,345,3,118,0, 345,3,119,0,345, @@ -17155,7 +17159,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1279,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,116,0,345, 3,117,0,345,3, 118,0,345,3,119, @@ -17195,10 +17199,10 @@ public class yyLSLTokens : YyLexer { 345,3,98,0,345, 3,99,0,345,3, 100,0,345,3,101, -0,1280,12,1,18083, +0,1280,12,1,18105, 1281,5,63,3,109, 0,345,3,110,0, -1282,12,1,18112,1283, +1282,12,1,18134,1283, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -17243,7 +17247,7 @@ public class yyLSLTokens : YyLexer { 345,3,97,0,345, 3,98,0,345,3, 99,0,345,3,100, -0,1284,12,1,18158, +0,1284,12,1,18180, 1285,5,63,3,109, 0,345,3,110,0, 345,3,111,0,345, @@ -17310,7 +17314,7 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1288,11,1, -845,0,348,1,-1, +867,0,348,1,-1, 3,111,0,345,3, 112,0,345,3,113, 0,345,3,114,0, @@ -17360,14 +17364,14 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,1289, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,102,0, 345,3,103,0,345, 3,104,0,345,3, 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1290,11,1,845,0, +1290,11,1,867,0, 348,1,-1,3,97, 0,345,3,98,0, 345,3,99,0,345, @@ -17388,7 +17392,7 @@ public class yyLSLTokens : YyLexer { 0,345,3,106,0, 345,3,107,0,345, 3,108,0,345,1293, -11,1,845,0,348, +11,1,867,0,348, 1,-1,3,100,0, 345,3,101,0,345, 3,102,0,345,3, @@ -17397,7 +17401,7 @@ public class yyLSLTokens : YyLexer { 345,3,106,0,345, 3,107,0,345,3, 108,0,345,1294,11, -1,845,0,348,1, +1,867,0,348,1, -1,3,118,0,345, 3,119,0,345,3, 120,0,345,3,121, @@ -17442,7 +17446,13 @@ public class yyLSLTokens : YyLexer { 3,106,0,345,3, 107,0,345,3,108, 0,345,1295,11,1, -845,0,348,1,-1, +867,0,348,1,-1, +3,112,0,345,3, +113,0,345,3,114, +0,1296,12,1,18804, +1297,5,63,3,109, +0,345,3,110,0, +345,3,111,0,345, 3,112,0,345,3, 113,0,345,3,114, 0,345,3,115,0, @@ -17482,16 +17492,60 @@ public class yyLSLTokens : YyLexer { 3,89,0,345,3, 90,0,345,3,95, 0,345,3,97,0, -345,3,98,0,345, -3,99,0,345,3, -100,0,345,3,101, -0,345,3,102,0, -345,3,103,0,345, -3,104,0,345,3, -105,0,1296,12,1, -18800,1297,5,63,3, -109,0,1298,12,1, -18828,1299,5,63,3, +1298,12,1,18847,1299, +5,63,3,109,0, +345,3,110,0,1300, +12,1,18876,1301,5, +63,3,109,0,345, +3,110,0,345,3, +111,0,345,3,112, +0,345,3,113,0, +345,3,114,0,345, +3,115,0,1302,12, +1,18910,1303,5,63, +3,109,0,345,3, +110,0,345,3,111, +0,345,3,112,0, +345,3,113,0,345, +3,114,0,345,3, +115,0,345,3,116, +0,345,3,117,0, +345,3,118,0,345, +3,119,0,345,3, +120,0,345,3,121, +0,345,3,122,0, +345,3,48,0,345, +3,49,0,345,3, +50,0,345,3,51, +0,345,3,52,0, +345,3,53,0,345, +3,54,0,345,3, +55,0,345,3,56, +0,345,3,57,0, +345,3,65,0,345, +3,66,0,345,3, +67,0,345,3,68, +0,345,3,69,0, +345,3,70,0,345, +3,71,0,345,3, +72,0,345,3,73, +0,345,3,74,0, +345,3,75,0,345, +3,76,0,345,3, +77,0,345,3,78, +0,345,3,79,0, +345,3,80,0,345, +3,81,0,345,3, +82,0,345,3,83, +0,345,3,84,0, +345,3,85,0,345, +3,86,0,345,3, +87,0,345,3,88, +0,345,3,89,0, +345,3,90,0,345, +3,95,0,345,3, +97,0,1304,12,1, +18953,1305,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -17534,16 +17588,16 @@ public class yyLSLTokens : YyLexer { 3,90,0,345,3, 95,0,345,3,97, 0,345,3,98,0, -345,3,99,0,345, -3,100,0,345,3, -101,0,1300,12,1, -18875,1301,5,63,3, -109,0,345,3,110, -0,345,3,111,0, -345,3,112,0,345, -3,113,0,345,3, -114,0,1302,12,1, -18908,1303,5,63,3, +345,3,99,0,1306, +12,1,18998,1307,5, +63,3,109,0,345, +3,110,0,345,3, +111,0,345,3,112, +0,345,3,113,0, +345,3,114,0,345, +3,115,0,345,3, +116,0,1308,12,1, +19033,1309,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -17591,90 +17645,844 @@ public class yyLSLTokens : YyLexer { 101,0,345,3,102, 0,345,3,103,0, 345,3,104,0,345, -3,105,0,345,3, -106,0,345,3,107, -0,345,3,108,0, -345,1304,11,1,783, -0,1305,4,22,84, -0,73,0,77,0, -69,0,82,0,95, -0,69,0,86,0, -69,0,78,0,84, -0,1,-1,3,115, -0,345,3,116,0, -345,3,117,0,345, -3,118,0,345,3, -119,0,345,3,120, -0,345,3,121,0, -345,3,122,0,345, -3,48,0,345,3, -49,0,345,3,50, -0,345,3,51,0, -345,3,52,0,345, -3,53,0,345,3, -54,0,345,3,55, -0,345,3,56,0, -345,3,57,0,345, -3,65,0,345,3, -66,0,345,3,67, -0,345,3,68,0, -345,3,69,0,345, -3,70,0,345,3, -71,0,345,3,72, -0,345,3,73,0, -345,3,74,0,345, -3,75,0,345,3, -76,0,345,3,77, -0,345,3,78,0, -345,3,79,0,345, -3,80,0,345,3, -81,0,345,3,82, -0,345,3,83,0, -345,3,84,0,345, -3,85,0,345,3, -86,0,345,3,87, -0,345,3,88,0, -345,3,89,0,345, -3,90,0,345,3, -95,0,345,3,97, -0,345,3,98,0, -345,3,99,0,345, -3,100,0,345,3, -101,0,345,3,102, -0,345,3,103,0, -345,3,104,0,345, -3,105,0,345,3, -106,0,345,3,107, -0,345,3,108,0, -345,1306,11,1,845, -0,348,1,-1,3, -102,0,345,3,103, -0,345,3,104,0, -345,3,105,0,345, -3,106,0,345,3, -107,0,345,3,108, -0,345,1307,11,1, -845,0,348,1,-1, +3,105,0,1310,12, +1,19084,1311,5,63, +3,109,0,345,3, +110,0,345,3,111, +0,1312,12,1,19114, +1313,5,63,3,109, +0,345,3,110,0, +1314,12,1,19143,1315, +5,63,3,109,0, +345,3,110,0,345, +3,111,0,345,3, +112,0,345,3,113, +0,345,3,114,0, +345,3,115,0,345, +3,116,0,345,3, +117,0,345,3,118, +0,345,3,119,0, +345,3,120,0,345, +3,121,0,345,3, +122,0,345,3,48, +0,345,3,49,0, +345,3,50,0,345, +3,51,0,345,3, +52,0,345,3,53, +0,345,3,54,0, +345,3,55,0,345, +3,56,0,345,3, +57,0,345,3,65, +0,345,3,66,0, +345,3,67,0,345, +3,68,0,345,3, +69,0,345,3,70, +0,345,3,71,0, +345,3,72,0,345, +3,73,0,345,3, +74,0,345,3,75, +0,345,3,76,0, +345,3,77,0,345, +3,78,0,345,3, +79,0,345,3,80, +0,345,3,81,0, +345,3,82,0,345, +3,83,0,345,3, +84,0,345,3,85, +0,345,3,86,0, +345,3,87,0,345, +3,88,0,345,3, +89,0,345,3,90, +0,345,3,95,0, +1316,12,1,19229,1317, +5,63,3,109,0, +345,3,110,0,345, +3,111,0,345,3, +112,0,345,3,113, +0,345,3,114,0, +1318,12,1,19262,1319, +5,63,3,109,0, +345,3,110,0,345, +3,111,0,345,3, +112,0,345,3,113, +0,345,3,114,0, +345,3,115,0,345, +3,116,0,345,3, +117,0,345,3,118, +0,345,3,119,0, +345,3,120,0,345, +3,121,0,345,3, +122,0,345,3,48, +0,345,3,49,0, +345,3,50,0,345, +3,51,0,345,3, +52,0,345,3,53, +0,345,3,54,0, +345,3,55,0,345, +3,56,0,345,3, +57,0,345,3,65, +0,345,3,66,0, +345,3,67,0,345, +3,68,0,345,3, +69,0,345,3,70, +0,345,3,71,0, +345,3,72,0,345, +3,73,0,345,3, +74,0,345,3,75, +0,345,3,76,0, +345,3,77,0,345, +3,78,0,345,3, +79,0,345,3,80, +0,345,3,81,0, +345,3,82,0,345, +3,83,0,345,3, +84,0,345,3,85, +0,345,3,86,0, +345,3,87,0,345, +3,88,0,345,3, +89,0,345,3,90, +0,345,3,95,0, +345,3,97,0,345, +3,98,0,345,3, +99,0,345,3,100, +0,345,3,101,0, +1320,12,1,19309,1321, +5,63,3,109,0, +345,3,110,0,345, +3,111,0,345,3, +112,0,345,3,113, +0,345,3,114,0, +345,3,115,0,1322, +12,1,19343,1323,5, +63,3,109,0,345, 3,110,0,345,3, 111,0,345,3,112, 0,345,3,113,0, 345,3,114,0,345, 3,115,0,345,3, 116,0,345,3,117, -0,345,3,118,0, -345,3,119,0,345, -3,120,0,345,3, -121,0,345,3,122, -0,345,3,48,0, -345,3,49,0,345, -3,50,0,345,3, -51,0,345,3,52, -0,345,3,53,0, -345,3,54,0,345, -3,55,0,345,3, -56,0,345,3,57, -0,345,3,65,0, -345,3,66,0,345, +0,1324,12,1,19379, +1325,5,63,3,109, +0,345,3,110,0, +345,3,111,0,345, +3,112,0,345,3, +113,0,345,3,114, +0,345,3,115,0, +345,3,116,0,345, +3,117,0,345,3, +118,0,345,3,119, +0,345,3,120,0, +345,3,121,0,345, +3,122,0,345,3, +48,0,345,3,49, +0,345,3,50,0, +345,3,51,0,345, +3,52,0,345,3, +53,0,345,3,54, +0,345,3,55,0, +345,3,56,0,345, +3,57,0,345,3, +65,0,345,3,66, +0,345,3,67,0, +345,3,68,0,345, +3,69,0,345,3, +70,0,345,3,71, +0,345,3,72,0, +345,3,73,0,345, +3,74,0,345,3, +75,0,345,3,76, +0,345,3,77,0, +345,3,78,0,345, +3,79,0,345,3, +80,0,345,3,81, +0,345,3,82,0, +345,3,83,0,345, +3,84,0,345,3, +85,0,345,3,86, +0,345,3,87,0, +345,3,88,0,345, +3,89,0,345,3, +90,0,345,3,95, +0,345,3,97,0, +345,3,98,0,345, +3,99,0,345,3, +100,0,345,3,101, +0,345,3,102,0, +345,3,103,0,345, +3,104,0,345,3, +105,0,345,3,106, +0,345,3,107,0, +345,3,108,0,1326, +12,1,19433,1327,5, +63,3,109,0,345, +3,110,0,345,3, +111,0,345,3,112, +0,345,3,113,0, +345,3,114,0,345, +3,115,0,345,3, +116,0,1328,12,1, +19468,1329,5,63,3, +109,0,345,3,110, +0,345,3,111,0, +345,3,112,0,345, +3,113,0,345,3, +114,0,345,3,115, +0,345,3,116,0, +345,3,117,0,345, +3,118,0,345,3, +119,0,345,3,120, +0,345,3,121,0, +345,3,122,0,345, +3,48,0,345,3, +49,0,345,3,50, +0,345,3,51,0, +345,3,52,0,345, +3,53,0,345,3, +54,0,345,3,55, +0,345,3,56,0, +345,3,57,0,345, +3,65,0,345,3, +66,0,345,3,67, +0,345,3,68,0, +345,3,69,0,345, +3,70,0,345,3, +71,0,345,3,72, +0,345,3,73,0, +345,3,74,0,345, +3,75,0,345,3, +76,0,345,3,77, +0,345,3,78,0, +345,3,79,0,345, +3,80,0,345,3, +81,0,345,3,82, +0,345,3,83,0, +345,3,84,0,345, +3,85,0,345,3, +86,0,345,3,87, +0,345,3,88,0, +345,3,89,0,345, +3,90,0,345,3, +95,0,345,3,97, +0,345,3,98,0, +345,3,99,0,345, +3,100,0,345,3, +101,0,345,3,102, +0,345,3,103,0, +345,3,104,0,345, +3,105,0,345,3, +106,0,345,3,107, +0,345,3,108,0, +345,1330,11,1,845, +0,1331,4,48,84, +0,82,0,65,0, +78,0,83,0,65, +0,67,0,84,0, +73,0,79,0,78, +0,95,0,82,0, +69,0,83,0,85, +0,76,0,84,0, +95,0,69,0,86, +0,69,0,78,0, +84,0,1,-1,3, +117,0,345,3,118, +0,345,3,119,0, +345,3,120,0,345, +3,121,0,345,3, +122,0,345,3,48, +0,345,3,49,0, +345,3,50,0,345, +3,51,0,345,3, +52,0,345,3,53, +0,345,3,54,0, +345,3,55,0,345, +3,56,0,345,3, +57,0,345,3,65, +0,345,3,66,0, +345,3,67,0,345, +3,68,0,345,3, +69,0,345,3,70, +0,345,3,71,0, +345,3,72,0,345, +3,73,0,345,3, +74,0,345,3,75, +0,345,3,76,0, +345,3,77,0,345, +3,78,0,345,3, +79,0,345,3,80, +0,345,3,81,0, +345,3,82,0,345, +3,83,0,345,3, +84,0,345,3,85, +0,345,3,86,0, +345,3,87,0,345, +3,88,0,345,3, +89,0,345,3,90, +0,345,3,95,0, +345,3,97,0,345, +3,98,0,345,3, +99,0,345,3,100, +0,345,3,101,0, +345,3,102,0,345, +3,103,0,345,3, +104,0,345,3,105, +0,345,3,106,0, +345,3,107,0,345, +3,108,0,345,1332, +11,1,867,0,348, +1,-1,1333,11,1, +867,0,348,1,-1, +3,118,0,345,3, +119,0,345,3,120, +0,345,3,121,0, +345,3,122,0,345, +3,48,0,345,3, +49,0,345,3,50, +0,345,3,51,0, +345,3,52,0,345, +3,53,0,345,3, +54,0,345,3,55, +0,345,3,56,0, +345,3,57,0,345, +3,65,0,345,3, +66,0,345,3,67, +0,345,3,68,0, +345,3,69,0,345, +3,70,0,345,3, +71,0,345,3,72, +0,345,3,73,0, +345,3,74,0,345, +3,75,0,345,3, +76,0,345,3,77, +0,345,3,78,0, +345,3,79,0,345, +3,80,0,345,3, +81,0,345,3,82, +0,345,3,83,0, +345,3,84,0,345, +3,85,0,345,3, +86,0,345,3,87, +0,345,3,88,0, +345,3,89,0,345, +3,90,0,345,3, +95,0,345,3,97, +0,345,3,98,0, +345,3,99,0,345, +3,100,0,345,3, +101,0,345,3,102, +0,345,3,103,0, +345,3,104,0,345, +3,105,0,345,3, +106,0,345,3,107, +0,345,3,108,0, +345,1334,11,1,867, +0,348,1,-1,3, +116,0,345,3,117, +0,345,3,118,0, +345,3,119,0,345, +3,120,0,345,3, +121,0,345,3,122, +0,345,3,48,0, +345,3,49,0,345, +3,50,0,345,3, +51,0,345,3,52, +0,345,3,53,0, +345,3,54,0,345, +3,55,0,345,3, +56,0,345,3,57, +0,345,3,65,0, +345,3,66,0,345, +3,67,0,345,3, +68,0,345,3,69, +0,345,3,70,0, +345,3,71,0,345, +3,72,0,345,3, +73,0,345,3,74, +0,345,3,75,0, +345,3,76,0,345, +3,77,0,345,3, +78,0,345,3,79, +0,345,3,80,0, +345,3,81,0,345, +3,82,0,345,3, +83,0,345,3,84, +0,345,3,85,0, +345,3,86,0,345, +3,87,0,345,3, +88,0,345,3,89, +0,345,3,90,0, +345,3,95,0,345, +3,97,0,345,3, +98,0,345,3,99, +0,345,3,100,0, +345,3,101,0,345, +3,102,0,345,3, +103,0,345,3,104, +0,345,3,105,0, +345,3,106,0,345, +3,107,0,345,3, +108,0,345,1335,11, +1,867,0,348,1, +-1,3,102,0,345, +3,103,0,345,3, +104,0,345,3,105, +0,345,3,106,0, +345,3,107,0,345, +3,108,0,345,1336, +11,1,867,0,348, +1,-1,3,115,0, +345,3,116,0,345, +3,117,0,345,3, +118,0,345,3,119, +0,345,3,120,0, +345,3,121,0,345, +3,122,0,345,3, +48,0,345,3,49, +0,345,3,50,0, +345,3,51,0,345, +3,52,0,345,3, +53,0,345,3,54, +0,345,3,55,0, +345,3,56,0,345, +3,57,0,345,3, +65,0,345,3,66, +0,345,3,67,0, +345,3,68,0,345, +3,69,0,345,3, +70,0,345,3,71, +0,345,3,72,0, +345,3,73,0,345, +3,74,0,345,3, +75,0,345,3,76, +0,345,3,77,0, +345,3,78,0,345, +3,79,0,345,3, +80,0,345,3,81, +0,345,3,82,0, +345,3,83,0,345, +3,84,0,345,3, +85,0,345,3,86, +0,345,3,87,0, +345,3,88,0,345, +3,89,0,345,3, +90,0,345,3,95, +0,345,3,97,0, +345,3,98,0,345, +3,99,0,345,3, +100,0,345,3,101, +0,345,3,102,0, +345,3,103,0,345, +3,104,0,345,3, +105,0,345,3,106, +0,345,3,107,0, +345,3,108,0,345, +1337,11,1,867,0, +348,1,-1,3,97, +0,345,3,98,0, +345,3,99,0,345, +3,100,0,345,3, +101,0,345,3,102, +0,345,3,103,0, +345,3,104,0,345, +3,105,0,345,3, +106,0,345,3,107, +0,345,3,108,0, +345,1338,11,1,867, +0,348,1,-1,3, +111,0,345,3,112, +0,345,3,113,0, +345,3,114,0,345, +3,115,0,345,3, +116,0,345,3,117, +0,345,3,118,0, +345,3,119,0,345, +3,120,0,345,3, +121,0,345,3,122, +0,345,3,48,0, +345,3,49,0,345, +3,50,0,345,3, +51,0,345,3,52, +0,345,3,53,0, +345,3,54,0,345, +3,55,0,345,3, +56,0,345,3,57, +0,345,3,65,0, +345,3,66,0,345, +3,67,0,345,3, +68,0,345,3,69, +0,345,3,70,0, +345,3,71,0,345, +3,72,0,345,3, +73,0,345,3,74, +0,345,3,75,0, +345,3,76,0,345, +3,77,0,345,3, +78,0,345,3,79, +0,345,3,80,0, +345,3,81,0,345, +3,82,0,345,3, +83,0,345,3,84, +0,345,3,85,0, +345,3,86,0,345, +3,87,0,345,3, +88,0,345,3,89, +0,345,3,90,0, +345,3,95,0,345, +3,97,0,345,3, +98,0,345,3,99, +0,345,3,100,0, +345,3,101,0,345, +3,102,0,345,3, +103,0,345,3,104, +0,345,3,105,0, +345,3,106,0,345, +3,107,0,345,3, +108,0,345,1339,11, +1,867,0,348,1, +-1,3,112,0,345, +3,113,0,345,3, +114,0,345,3,115, +0,345,3,116,0, +345,3,117,0,345, +3,118,0,345,3, +119,0,345,3,120, +0,345,3,121,0, +345,3,122,0,345, +3,48,0,345,3, +49,0,345,3,50, +0,345,3,51,0, +345,3,52,0,345, +3,53,0,345,3, +54,0,345,3,55, +0,345,3,56,0, +345,3,57,0,345, +3,65,0,345,3, +66,0,345,3,67, +0,345,3,68,0, +345,3,69,0,345, +3,70,0,345,3, +71,0,345,3,72, +0,345,3,73,0, +345,3,74,0,345, +3,75,0,345,3, +76,0,345,3,77, +0,345,3,78,0, +345,3,79,0,345, +3,80,0,345,3, +81,0,345,3,82, +0,345,3,83,0, +345,3,84,0,345, +3,85,0,345,3, +86,0,345,3,87, +0,345,3,88,0, +345,3,89,0,345, +3,90,0,345,3, +95,0,345,3,97, +0,345,3,98,0, +345,3,99,0,345, +3,100,0,345,3, +101,0,345,3,102, +0,345,3,103,0, +345,3,104,0,345, +3,105,0,345,3, +106,0,345,3,107, +0,345,3,108,0, +345,1340,11,1,867, +0,348,1,-1,3, +106,0,345,3,107, +0,345,3,108,0, +345,1341,11,1,867, +0,348,1,-1,3, +117,0,345,3,118, +0,345,3,119,0, +345,3,120,0,345, +3,121,0,345,3, +122,0,345,3,48, +0,345,3,49,0, +345,3,50,0,345, +3,51,0,345,3, +52,0,345,3,53, +0,345,3,54,0, +345,3,55,0,345, +3,56,0,345,3, +57,0,345,3,65, +0,345,3,66,0, +345,3,67,0,345, +3,68,0,345,3, +69,0,345,3,70, +0,345,3,71,0, +345,3,72,0,345, +3,73,0,345,3, +74,0,345,3,75, +0,345,3,76,0, +345,3,77,0,345, +3,78,0,345,3, +79,0,345,3,80, +0,345,3,81,0, +345,3,82,0,345, +3,83,0,345,3, +84,0,345,3,85, +0,345,3,86,0, +345,3,87,0,345, +3,88,0,345,3, +89,0,345,3,90, +0,345,3,95,0, +345,3,97,0,345, +3,98,0,345,3, +99,0,345,3,100, +0,345,3,101,0, +345,3,102,0,345, +3,103,0,345,3, +104,0,345,3,105, +0,345,3,106,0, +345,3,107,0,345, +3,108,0,345,1342, +11,1,867,0,348, +1,-1,3,100,0, +345,3,101,0,345, +3,102,0,345,3, +103,0,345,3,104, +0,345,3,105,0, +345,3,106,0,345, +3,107,0,345,3, +108,0,345,1343,11, +1,867,0,348,1, +-1,3,98,0,345, +3,99,0,345,3, +100,0,345,3,101, +0,345,3,102,0, +345,3,103,0,345, +3,104,0,345,3, +105,0,345,3,106, +0,345,3,107,0, +345,3,108,0,345, +1344,11,1,867,0, +348,1,-1,3,116, +0,345,3,117,0, +345,3,118,0,345, +3,119,0,345,3, +120,0,345,3,121, +0,345,3,122,0, +345,3,48,0,345, +3,49,0,345,3, +50,0,345,3,51, +0,345,3,52,0, +345,3,53,0,345, +3,54,0,345,3, +55,0,345,3,56, +0,345,3,57,0, +345,3,65,0,345, +3,66,0,345,3, +67,0,345,3,68, +0,345,3,69,0, +345,3,70,0,345, +3,71,0,345,3, +72,0,345,3,73, +0,345,3,74,0, +345,3,75,0,345, +3,76,0,345,3, +77,0,345,3,78, +0,345,3,79,0, +345,3,80,0,345, +3,81,0,345,3, +82,0,345,3,83, +0,345,3,84,0, +345,3,85,0,345, +3,86,0,345,3, +87,0,345,3,88, +0,345,3,89,0, +345,3,90,0,345, +3,95,0,345,3, +97,0,345,3,98, +0,345,3,99,0, +345,3,100,0,345, +3,101,0,345,3, +102,0,345,3,103, +0,345,3,104,0, +345,3,105,0,345, +3,106,0,345,3, +107,0,345,3,108, +0,345,1345,11,1, +867,0,348,1,-1, +3,111,0,345,3, +112,0,345,3,113, +0,345,3,114,0, +345,3,115,0,345, +3,116,0,345,3, +117,0,345,3,118, +0,345,3,119,0, +345,3,120,0,345, +3,121,0,345,3, +122,0,345,3,48, +0,345,3,49,0, +345,3,50,0,345, +3,51,0,345,3, +52,0,345,3,53, +0,345,3,54,0, +345,3,55,0,345, +3,56,0,345,3, +57,0,345,3,65, +0,345,3,66,0, +345,3,67,0,345, +3,68,0,345,3, +69,0,345,3,70, +0,345,3,71,0, +345,3,72,0,345, +3,73,0,345,3, +74,0,345,3,75, +0,345,3,76,0, +345,3,77,0,345, +3,78,0,345,3, +79,0,345,3,80, +0,345,3,81,0, +345,3,82,0,345, +3,83,0,345,3, +84,0,345,3,85, +0,345,3,86,0, +345,3,87,0,345, +3,88,0,345,3, +89,0,345,3,90, +0,345,3,95,0, +345,3,97,0,345, +3,98,0,345,3, +99,0,345,3,100, +0,345,3,101,0, +345,3,102,0,345, +3,103,0,345,3, +104,0,345,3,105, +0,345,3,106,0, +345,3,107,0,345, +3,108,0,345,1346, +11,1,867,0,348, +1,-1,3,98,0, +345,3,99,0,345, +3,100,0,345,3, +101,0,345,3,102, +0,345,3,103,0, +345,3,104,0,345, +3,105,0,345,3, +106,0,345,3,107, +0,345,3,108,0, +345,1347,11,1,867, +0,348,1,-1,3, +115,0,345,3,116, +0,345,3,117,0, +345,3,118,0,345, +3,119,0,345,3, +120,0,345,3,121, +0,345,3,122,0, +345,3,48,0,345, +3,49,0,345,3, +50,0,345,3,51, +0,345,3,52,0, +345,3,53,0,345, +3,54,0,345,3, +55,0,345,3,56, +0,345,3,57,0, +345,3,65,0,345, +3,66,0,345,3, +67,0,345,3,68, +0,345,3,69,0, +345,3,70,0,345, +3,71,0,345,3, +72,0,345,3,73, +0,345,3,74,0, +345,3,75,0,345, +3,76,0,345,3, +77,0,345,3,78, +0,345,3,79,0, +345,3,80,0,345, +3,81,0,345,3, +82,0,345,3,83, +0,345,3,84,0, +345,3,85,0,345, +3,86,0,345,3, +87,0,345,3,88, +0,345,3,89,0, +345,3,90,0,345, +3,95,0,345,3, +97,0,345,3,98, +0,345,3,99,0, +345,3,100,0,345, +3,101,0,345,3, +102,0,345,3,103, +0,345,3,104,0, +345,3,105,0,1348, +12,1,20862,1349,5, +63,3,109,0,1350, +12,1,20890,1351,5, +63,3,109,0,345, +3,110,0,345,3, +111,0,345,3,112, +0,345,3,113,0, +345,3,114,0,345, +3,115,0,345,3, +116,0,345,3,117, +0,345,3,118,0, +345,3,119,0,345, +3,120,0,345,3, +121,0,345,3,122, +0,345,3,48,0, +345,3,49,0,345, +3,50,0,345,3, +51,0,345,3,52, +0,345,3,53,0, +345,3,54,0,345, +3,55,0,345,3, +56,0,345,3,57, +0,345,3,65,0, +345,3,66,0,345, +3,67,0,345,3, +68,0,345,3,69, +0,345,3,70,0, +345,3,71,0,345, +3,72,0,345,3, +73,0,345,3,74, +0,345,3,75,0, +345,3,76,0,345, +3,77,0,345,3, +78,0,345,3,79, +0,345,3,80,0, +345,3,81,0,345, +3,82,0,345,3, +83,0,345,3,84, +0,345,3,85,0, +345,3,86,0,345, +3,87,0,345,3, +88,0,345,3,89, +0,345,3,90,0, +345,3,95,0,345, +3,97,0,345,3, +98,0,345,3,99, +0,345,3,100,0, +345,3,101,0,1352, +12,1,20937,1353,5, +63,3,109,0,345, +3,110,0,345,3, +111,0,345,3,112, +0,345,3,113,0, +345,3,114,0,1354, +12,1,20970,1355,5, +63,3,109,0,345, +3,110,0,345,3, +111,0,345,3,112, +0,345,3,113,0, +345,3,114,0,345, +3,115,0,345,3, +116,0,345,3,117, +0,345,3,118,0, +345,3,119,0,345, +3,120,0,345,3, +121,0,345,3,122, +0,345,3,48,0, +345,3,49,0,345, +3,50,0,345,3, +51,0,345,3,52, +0,345,3,53,0, +345,3,54,0,345, +3,55,0,345,3, +56,0,345,3,57, +0,345,3,65,0, +345,3,66,0,345, 3,67,0,345,3, 68,0,345,3,69, 0,345,3,70,0, @@ -17704,15 +18512,233 @@ public class yyLSLTokens : YyLexer { 0,345,3,105,0, 345,3,106,0,345, 3,107,0,345,3, -108,0,345,1308,11, -1,845,0,348,1, --1,3,106,0,345, +108,0,345,1356,11, +1,783,0,1357,4, +22,84,0,73,0, +77,0,69,0,82, +0,95,0,69,0, +86,0,69,0,78, +0,84,0,1,-1, +3,115,0,345,3, +116,0,345,3,117, +0,345,3,118,0, +345,3,119,0,345, +3,120,0,345,3, +121,0,345,3,122, +0,345,3,48,0, +345,3,49,0,345, +3,50,0,345,3, +51,0,345,3,52, +0,345,3,53,0, +345,3,54,0,345, +3,55,0,345,3, +56,0,345,3,57, +0,345,3,65,0, +345,3,66,0,345, +3,67,0,345,3, +68,0,345,3,69, +0,345,3,70,0, +345,3,71,0,345, +3,72,0,345,3, +73,0,345,3,74, +0,345,3,75,0, +345,3,76,0,345, +3,77,0,345,3, +78,0,345,3,79, +0,345,3,80,0, +345,3,81,0,345, +3,82,0,345,3, +83,0,345,3,84, +0,345,3,85,0, +345,3,86,0,345, +3,87,0,345,3, +88,0,345,3,89, +0,345,3,90,0, +345,3,95,0,345, +3,97,0,345,3, +98,0,345,3,99, +0,345,3,100,0, +345,3,101,0,345, +3,102,0,345,3, +103,0,345,3,104, +0,345,3,105,0, +345,3,106,0,345, 3,107,0,345,3, -108,0,345,1309,11, -1,845,0,348,1, --1,3,117,0,343, -3,118,0,1310,12, -1,19351,1311,5,63, +108,0,345,1358,11, +1,867,0,348,1, +-1,3,102,0,345, +3,103,0,345,3, +104,0,345,3,105, +0,345,3,106,0, +345,3,107,0,345, +3,108,0,345,1359, +11,1,867,0,348, +1,-1,3,110,0, +345,3,111,0,345, +3,112,0,345,3, +113,0,345,3,114, +0,345,3,115,0, +345,3,116,0,345, +3,117,0,345,3, +118,0,345,3,119, +0,345,3,120,0, +345,3,121,0,345, +3,122,0,345,3, +48,0,345,3,49, +0,345,3,50,0, +345,3,51,0,345, +3,52,0,345,3, +53,0,345,3,54, +0,345,3,55,0, +345,3,56,0,345, +3,57,0,345,3, +65,0,345,3,66, +0,345,3,67,0, +345,3,68,0,345, +3,69,0,345,3, +70,0,345,3,71, +0,345,3,72,0, +345,3,73,0,345, +3,74,0,345,3, +75,0,345,3,76, +0,345,3,77,0, +345,3,78,0,345, +3,79,0,345,3, +80,0,345,3,81, +0,345,3,82,0, +345,3,83,0,345, +3,84,0,345,3, +85,0,345,3,86, +0,345,3,87,0, +345,3,88,0,345, +3,89,0,345,3, +90,0,345,3,95, +0,345,3,97,0, +345,3,98,0,345, +3,99,0,345,3, +100,0,345,3,101, +0,345,3,102,0, +345,3,103,0,345, +3,104,0,345,3, +105,0,345,3,106, +0,345,3,107,0, +345,3,108,0,345, +1360,11,1,867,0, +348,1,-1,3,106, +0,345,3,107,0, +345,3,108,0,345, +1361,11,1,867,0, +348,1,-1,3,117, +0,343,3,118,0, +1362,12,1,21413,1363, +5,63,3,109,0, +345,3,110,0,345, +3,111,0,345,3, +112,0,345,3,113, +0,345,3,114,0, +345,3,115,0,345, +3,116,0,345,3, +117,0,345,3,118, +0,345,3,119,0, +345,3,120,0,345, +3,121,0,345,3, +122,0,345,3,48, +0,345,3,49,0, +345,3,50,0,345, +3,51,0,345,3, +52,0,345,3,53, +0,345,3,54,0, +345,3,55,0,345, +3,56,0,345,3, +57,0,345,3,65, +0,345,3,66,0, +345,3,67,0,345, +3,68,0,345,3, +69,0,345,3,70, +0,345,3,71,0, +345,3,72,0,345, +3,73,0,345,3, +74,0,345,3,75, +0,345,3,76,0, +345,3,77,0,345, +3,78,0,345,3, +79,0,345,3,80, +0,345,3,81,0, +345,3,82,0,345, +3,83,0,345,3, +84,0,345,3,85, +0,345,3,86,0, +345,3,87,0,345, +3,88,0,345,3, +89,0,345,3,90, +0,345,3,95,0, +345,3,97,0,345, +3,98,0,345,3, +99,0,345,3,100, +0,345,3,101,0, +1364,12,1,21460,1365, +5,63,3,109,0, +345,3,110,0,345, +3,111,0,345,3, +112,0,345,3,113, +0,345,3,114,0, +345,3,115,0,345, +3,116,0,345,3, +117,0,345,3,118, +0,345,3,119,0, +345,3,120,0,345, +3,121,0,345,3, +122,0,345,3,48, +0,345,3,49,0, +345,3,50,0,345, +3,51,0,345,3, +52,0,345,3,53, +0,345,3,54,0, +345,3,55,0,345, +3,56,0,345,3, +57,0,345,3,65, +0,345,3,66,0, +345,3,67,0,345, +3,68,0,345,3, +69,0,345,3,70, +0,345,3,71,0, +345,3,72,0,345, +3,73,0,345,3, +74,0,345,3,75, +0,345,3,76,0, +345,3,77,0,345, +3,78,0,345,3, +79,0,345,3,80, +0,345,3,81,0, +345,3,82,0,345, +3,83,0,345,3, +84,0,345,3,85, +0,345,3,86,0, +345,3,87,0,345, +3,88,0,345,3, +89,0,345,3,90, +0,345,3,95,0, +345,3,97,0,345, +3,98,0,345,3, +99,0,1366,12,1, +21505,1367,5,63,3, +109,0,345,3,110, +0,345,3,111,0, +345,3,112,0,345, +3,113,0,345,3, +114,0,345,3,115, +0,345,3,116,0, +1368,12,1,21540,1369, +5,63,3,109,0, +345,3,110,0,345, +3,111,0,1370,12, +1,21570,1371,5,63, +3,109,0,345,3, +110,0,345,3,111, +0,345,3,112,0, +345,3,113,0,345, +3,114,0,1372,12, +1,21603,1373,5,63, 3,109,0,345,3, 110,0,345,3,111, 0,345,3,112,0, @@ -17757,13 +18783,19 @@ public class yyLSLTokens : YyLexer { 97,0,345,3,98, 0,345,3,99,0, 345,3,100,0,345, -3,101,0,1312,12, -1,19398,1313,5,63, -3,109,0,345,3, -110,0,345,3,111, -0,345,3,112,0, -345,3,113,0,345, -3,114,0,345,3, +3,101,0,345,3, +102,0,345,3,103, +0,345,3,104,0, +345,3,105,0,345, +3,106,0,345,3, +107,0,345,3,108, +0,345,1374,11,1, +320,0,1375,4,22, +86,0,69,0,67, +0,84,0,79,0, +82,0,95,0,84, +0,89,0,80,0, +69,0,1,-1,3, 115,0,345,3,116, 0,345,3,117,0, 345,3,118,0,345, @@ -17802,27 +18834,15 @@ public class yyLSLTokens : YyLexer { 3,95,0,345,3, 97,0,345,3,98, 0,345,3,99,0, -1314,12,1,19443,1315, -5,63,3,109,0, -345,3,110,0,345, -3,111,0,345,3, -112,0,345,3,113, -0,345,3,114,0, -345,3,115,0,345, -3,116,0,1316,12, -1,19478,1317,5,63, -3,109,0,345,3, -110,0,345,3,111, -0,1318,12,1,19508, -1319,5,63,3,109, -0,345,3,110,0, -345,3,111,0,345, -3,112,0,345,3, -113,0,345,3,114, -0,1320,12,1,19541, -1321,5,63,3,109, -0,345,3,110,0, -345,3,111,0,345, +345,3,100,0,345, +3,101,0,345,3, +102,0,345,3,103, +0,345,3,104,0, +345,3,105,0,345, +3,106,0,345,3, +107,0,345,3,108, +0,345,1376,11,1, +867,0,348,1,-1, 3,112,0,345,3, 113,0,345,3,114, 0,345,3,115,0, @@ -17871,60 +18891,74 @@ public class yyLSLTokens : YyLexer { 105,0,345,3,106, 0,345,3,107,0, 345,3,108,0,345, -1322,11,1,320,0, -1323,4,22,86,0, -69,0,67,0,84, -0,79,0,82,0, -95,0,84,0,89, -0,80,0,69,0, -1,-1,3,115,0, -345,3,116,0,345, -3,117,0,345,3, -118,0,345,3,119, -0,345,3,120,0, -345,3,121,0,345, -3,122,0,345,3, -48,0,345,3,49, -0,345,3,50,0, -345,3,51,0,345, -3,52,0,345,3, -53,0,345,3,54, -0,345,3,55,0, -345,3,56,0,345, -3,57,0,345,3, -65,0,345,3,66, -0,345,3,67,0, -345,3,68,0,345, -3,69,0,345,3, -70,0,345,3,71, -0,345,3,72,0, -345,3,73,0,345, -3,74,0,345,3, -75,0,345,3,76, -0,345,3,77,0, -345,3,78,0,345, -3,79,0,345,3, -80,0,345,3,81, -0,345,3,82,0, -345,3,83,0,345, -3,84,0,345,3, -85,0,345,3,86, -0,345,3,87,0, -345,3,88,0,345, -3,89,0,345,3, -90,0,345,3,95, -0,345,3,97,0, -345,3,98,0,345, -3,99,0,345,3, -100,0,345,3,101, -0,345,3,102,0, -345,3,103,0,345, -3,104,0,345,3, -105,0,345,3,106, -0,345,3,107,0, -345,3,108,0,345, -1324,11,1,845,0, -348,1,-1,3,112, +1377,11,1,867,0, +348,1,-1,3,117, +0,345,3,118,0, +345,3,119,0,345, +3,120,0,345,3, +121,0,345,3,122, +0,345,3,48,0, +345,3,49,0,345, +3,50,0,345,3, +51,0,345,3,52, +0,345,3,53,0, +345,3,54,0,345, +3,55,0,345,3, +56,0,345,3,57, +0,345,3,65,0, +345,3,66,0,345, +3,67,0,345,3, +68,0,345,3,69, +0,345,3,70,0, +345,3,71,0,345, +3,72,0,345,3, +73,0,345,3,74, +0,345,3,75,0, +345,3,76,0,345, +3,77,0,345,3, +78,0,345,3,79, +0,345,3,80,0, +345,3,81,0,345, +3,82,0,345,3, +83,0,345,3,84, +0,345,3,85,0, +345,3,86,0,345, +3,87,0,345,3, +88,0,345,3,89, +0,345,3,90,0, +345,3,95,0,345, +3,97,0,345,3, +98,0,345,3,99, +0,345,3,100,0, +345,3,101,0,345, +3,102,0,345,3, +103,0,345,3,104, +0,345,3,105,0, +345,3,106,0,345, +3,107,0,345,3, +108,0,345,1378,11, +1,867,0,348,1, +-1,3,100,0,345, +3,101,0,345,3, +102,0,345,3,103, +0,345,3,104,0, +345,3,105,0,345, +3,106,0,345,3, +107,0,345,3,108, +0,345,1379,11,1, +867,0,348,1,-1, +3,102,0,345,3, +103,0,345,3,104, +0,345,3,105,0, +345,3,106,0,345, +3,107,0,345,3, +108,0,345,1380,11, +1,867,0,348,1, +-1,3,119,0,1381, +12,1,22134,1382,5, +63,3,109,0,345, +3,110,0,345,3, +111,0,345,3,112, 0,345,3,113,0, 345,3,114,0,345, 3,115,0,345,3, @@ -17969,75 +19003,57 @@ public class yyLSLTokens : YyLexer { 345,3,101,0,345, 3,102,0,345,3, 103,0,345,3,104, -0,345,3,105,0, -345,3,106,0,345, -3,107,0,345,3, -108,0,345,1325,11, -1,845,0,348,1, --1,3,117,0,345, -3,118,0,345,3, -119,0,345,3,120, -0,345,3,121,0, -345,3,122,0,345, -3,48,0,345,3, -49,0,345,3,50, -0,345,3,51,0, -345,3,52,0,345, -3,53,0,345,3, -54,0,345,3,55, -0,345,3,56,0, -345,3,57,0,345, -3,65,0,345,3, -66,0,345,3,67, -0,345,3,68,0, -345,3,69,0,345, -3,70,0,345,3, -71,0,345,3,72, -0,345,3,73,0, -345,3,74,0,345, -3,75,0,345,3, -76,0,345,3,77, -0,345,3,78,0, -345,3,79,0,345, -3,80,0,345,3, -81,0,345,3,82, -0,345,3,83,0, -345,3,84,0,345, -3,85,0,345,3, -86,0,345,3,87, -0,345,3,88,0, -345,3,89,0,345, -3,90,0,345,3, -95,0,345,3,97, -0,345,3,98,0, -345,3,99,0,345, -3,100,0,345,3, -101,0,345,3,102, -0,345,3,103,0, -345,3,104,0,345, -3,105,0,345,3, -106,0,345,3,107, -0,345,3,108,0, -345,1326,11,1,845, -0,348,1,-1,3, +0,1383,12,1,22184, +1384,5,63,3,109, +0,345,3,110,0, +345,3,111,0,345, +3,112,0,345,3, +113,0,345,3,114, +0,345,3,115,0, +345,3,116,0,345, +3,117,0,345,3, +118,0,345,3,119, +0,345,3,120,0, +345,3,121,0,345, +3,122,0,345,3, +48,0,345,3,49, +0,345,3,50,0, +345,3,51,0,345, +3,52,0,345,3, +53,0,345,3,54, +0,345,3,55,0, +345,3,56,0,345, +3,57,0,345,3, +65,0,345,3,66, +0,345,3,67,0, +345,3,68,0,345, +3,69,0,345,3, +70,0,345,3,71, +0,345,3,72,0, +345,3,73,0,345, +3,74,0,345,3, +75,0,345,3,76, +0,345,3,77,0, +345,3,78,0,345, +3,79,0,345,3, +80,0,345,3,81, +0,345,3,82,0, +345,3,83,0,345, +3,84,0,345,3, +85,0,345,3,86, +0,345,3,87,0, +345,3,88,0,345, +3,89,0,345,3, +90,0,345,3,95, +0,345,3,97,0, +345,3,98,0,345, +3,99,0,345,3, 100,0,345,3,101, 0,345,3,102,0, 345,3,103,0,345, 3,104,0,345,3, -105,0,345,3,106, -0,345,3,107,0, -345,3,108,0,345, -1327,11,1,845,0, -348,1,-1,3,102, -0,345,3,103,0, -345,3,104,0,345, -3,105,0,345,3, -106,0,345,3,107, -0,345,3,108,0, -345,1328,11,1,845, -0,348,1,-1,3, -119,0,1329,12,1, -20072,1330,5,63,3, +105,0,1385,12,1, +22235,1386,5,63,3, 109,0,345,3,110, 0,345,3,111,0, 345,3,112,0,345, @@ -18084,57 +19100,57 @@ public class yyLSLTokens : YyLexer { 3,100,0,345,3, 101,0,345,3,102, 0,345,3,103,0, -345,3,104,0,1331, -12,1,20122,1332,5, -63,3,109,0,345, -3,110,0,345,3, -111,0,345,3,112, -0,345,3,113,0, -345,3,114,0,345, -3,115,0,345,3, -116,0,345,3,117, -0,345,3,118,0, -345,3,119,0,345, -3,120,0,345,3, -121,0,345,3,122, -0,345,3,48,0, -345,3,49,0,345, -3,50,0,345,3, -51,0,345,3,52, -0,345,3,53,0, -345,3,54,0,345, -3,55,0,345,3, -56,0,345,3,57, -0,345,3,65,0, -345,3,66,0,345, -3,67,0,345,3, -68,0,345,3,69, -0,345,3,70,0, -345,3,71,0,345, -3,72,0,345,3, -73,0,345,3,74, -0,345,3,75,0, -345,3,76,0,345, -3,77,0,345,3, -78,0,345,3,79, -0,345,3,80,0, -345,3,81,0,345, -3,82,0,345,3, -83,0,345,3,84, -0,345,3,85,0, -345,3,86,0,345, -3,87,0,345,3, -88,0,345,3,89, -0,345,3,90,0, -345,3,95,0,345, -3,97,0,345,3, -98,0,345,3,99, -0,345,3,100,0, -345,3,101,0,345, -3,102,0,345,3, -103,0,345,3,104, -0,345,3,105,0, -1333,12,1,20173,1334, +345,3,104,0,345, +3,105,0,345,3, +106,0,345,3,107, +0,345,3,108,0, +1387,12,1,22289,1388, +5,63,3,109,0, +345,3,110,0,345, +3,111,0,345,3, +112,0,345,3,113, +0,345,3,114,0, +345,3,115,0,345, +3,116,0,345,3, +117,0,345,3,118, +0,345,3,119,0, +345,3,120,0,345, +3,121,0,345,3, +122,0,345,3,48, +0,345,3,49,0, +345,3,50,0,345, +3,51,0,345,3, +52,0,345,3,53, +0,345,3,54,0, +345,3,55,0,345, +3,56,0,345,3, +57,0,345,3,65, +0,345,3,66,0, +345,3,67,0,345, +3,68,0,345,3, +69,0,345,3,70, +0,345,3,71,0, +345,3,72,0,345, +3,73,0,345,3, +74,0,345,3,75, +0,345,3,76,0, +345,3,77,0,345, +3,78,0,345,3, +79,0,345,3,80, +0,345,3,81,0, +345,3,82,0,345, +3,83,0,345,3, +84,0,345,3,85, +0,345,3,86,0, +345,3,87,0,345, +3,88,0,345,3, +89,0,345,3,90, +0,345,3,95,0, +345,3,97,0,345, +3,98,0,345,3, +99,0,345,3,100, +0,345,3,101,0, +1389,12,1,22336,1390, 5,63,3,109,0, 345,3,110,0,345, 3,111,0,345,3, @@ -18185,413 +19201,316 @@ public class yyLSLTokens : YyLexer { 104,0,345,3,105, 0,345,3,106,0, 345,3,107,0,345, -3,108,0,1335,12, -1,20227,1336,5,63, -3,109,0,345,3, -110,0,345,3,111, -0,345,3,112,0, -345,3,113,0,345, -3,114,0,345,3, -115,0,345,3,116, -0,345,3,117,0, -345,3,118,0,345, -3,119,0,345,3, -120,0,345,3,121, -0,345,3,122,0, -345,3,48,0,345, -3,49,0,345,3, -50,0,345,3,51, -0,345,3,52,0, -345,3,53,0,345, -3,54,0,345,3, -55,0,345,3,56, -0,345,3,57,0, -345,3,65,0,345, -3,66,0,345,3, -67,0,345,3,68, -0,345,3,69,0, -345,3,70,0,345, -3,71,0,345,3, -72,0,345,3,73, -0,345,3,74,0, -345,3,75,0,345, -3,76,0,345,3, -77,0,345,3,78, -0,345,3,79,0, -345,3,80,0,345, -3,81,0,345,3, -82,0,345,3,83, -0,345,3,84,0, -345,3,85,0,345, -3,86,0,345,3, -87,0,345,3,88, -0,345,3,89,0, -345,3,90,0,345, -3,95,0,345,3, -97,0,345,3,98, -0,345,3,99,0, -345,3,100,0,345, -3,101,0,1337,12, -1,20274,1338,5,63, -3,109,0,345,3, -110,0,345,3,111, -0,345,3,112,0, -345,3,113,0,345, -3,114,0,345,3, -115,0,345,3,116, -0,345,3,117,0, -345,3,118,0,345, -3,119,0,345,3, -120,0,345,3,121, -0,345,3,122,0, -345,3,48,0,345, -3,49,0,345,3, -50,0,345,3,51, -0,345,3,52,0, -345,3,53,0,345, -3,54,0,345,3, -55,0,345,3,56, -0,345,3,57,0, -345,3,65,0,345, -3,66,0,345,3, -67,0,345,3,68, -0,345,3,69,0, -345,3,70,0,345, -3,71,0,345,3, -72,0,345,3,73, -0,345,3,74,0, -345,3,75,0,345, -3,76,0,345,3, -77,0,345,3,78, -0,345,3,79,0, -345,3,80,0,345, -3,81,0,345,3, -82,0,345,3,83, -0,345,3,84,0, -345,3,85,0,345, -3,86,0,345,3, -87,0,345,3,88, -0,345,3,89,0, -345,3,90,0,345, -3,95,0,345,3, -97,0,345,3,98, -0,345,3,99,0, -345,3,100,0,345, -3,101,0,345,3, +3,108,0,345,1391, +11,1,229,0,1392, +4,10,87,0,72, +0,73,0,76,0, +69,0,1,-1,3, 102,0,345,3,103, 0,345,3,104,0, 345,3,105,0,345, 3,106,0,345,3, 107,0,345,3,108, -0,345,1339,11,1, -229,0,1340,4,10, -87,0,72,0,73, -0,76,0,69,0, -1,-1,3,102,0, -345,3,103,0,345, -3,104,0,345,3, -105,0,345,3,106, +0,345,1393,11,1, +867,0,348,1,-1, +1394,11,1,867,0, +348,1,-1,3,106, 0,345,3,107,0, 345,3,108,0,345, -1341,11,1,845,0, -348,1,-1,1342,11, -1,845,0,348,1, --1,3,106,0,345, -3,107,0,345,3, -108,0,345,1343,11, -1,845,0,348,1, --1,3,105,0,345, -3,106,0,345,3, -107,0,345,3,108, -0,345,1344,11,1, -845,0,348,1,-1, -3,120,0,343,3, -121,0,343,3,122, -0,343,3,123,0, -1345,12,1,41003,1346, -5,0,1347,11,1, -51,0,1348,4,20, -76,0,69,0,70, -0,84,0,95,0, -66,0,82,0,65, -0,67,0,69,0, -1,-1,3,124,0, -1349,12,1,43906,1350, -5,1,3,124,0, -1351,12,1,44018,1352, -5,0,1353,11,1, -191,0,1354,4,26, -83,0,84,0,82, -0,79,0,75,0, -69,0,95,0,83, -0,84,0,82,0, -79,0,75,0,69, -0,1,-1,1355,11, -1,165,0,1356,4, -12,83,0,84,0, +1395,11,1,867,0, +348,1,-1,3,105, +0,345,3,106,0, +345,3,107,0,345, +3,108,0,345,1396, +11,1,867,0,348, +1,-1,3,120,0, +343,3,121,0,343, +3,122,0,343,3, +123,0,1397,12,1, +43065,1398,5,0,1399, +11,1,51,0,1400, +4,20,76,0,69, +0,70,0,84,0, +95,0,66,0,82, +0,65,0,67,0, +69,0,1,-1,3, +124,0,1401,12,1, +45968,1402,5,1,3, +124,0,1403,12,1, +46080,1404,5,0,1405, +11,1,191,0,1406, +4,26,83,0,84, +0,82,0,79,0, +75,0,69,0,95, +0,83,0,84,0, 82,0,79,0,75, 0,69,0,1,-1, -3,125,0,1357,12, -1,41368,1358,5,0, -1359,11,1,56,0, -1360,4,22,82,0, -73,0,71,0,72, -0,84,0,95,0, -66,0,82,0,65, -0,67,0,69,0, -1,-1,3,126,0, -1361,12,1,44147,1362, -5,0,1363,11,1, -175,0,1364,4,10, -84,0,73,0,76, -0,68,0,69,0, -1,-1,0,165,1, --1,1365,4,12,83, -0,84,0,82,0, -73,0,78,0,71, -0,1366,12,1,45715, -1367,5,119,3,1, -0,1368,12,1,45716, -1369,5,0,1370,11, -1,946,0,165,1, --1,3,9,0,1368, -3,10,0,1371,12, -1,45917,1372,5,0, -1373,11,1,952,0, -165,1,-1,3,13, -0,1368,3,0,3, -1368,3,96,33,1368, -3,32,0,1368,3, -33,0,1368,3,34, -0,1374,12,1,46664, -1375,5,0,1376,11, -1,1010,0,165,1, --1,3,35,0,1368, -3,36,0,1368,3, -37,0,1368,3,38, -0,1368,3,40,0, -1368,3,41,0,1368, -3,42,0,1368,3, -43,0,1368,3,44, -0,1368,3,45,0, -1368,3,46,0,1368, -3,47,0,1368,3, -3,9,1368,3,49, -0,1368,3,50,0, -1368,3,48,0,1368, -3,52,0,1368,3, -53,0,1368,3,51, -0,1368,3,55,0, -1368,3,56,0,1368, -3,54,0,1368,3, -59,0,1368,3,57, -0,1368,3,61,0, -1368,3,62,0,1368, -3,60,0,1368,3, -64,0,1368,3,65, -0,1368,3,66,0, -1368,3,67,0,1368, -3,68,0,1368,3, -69,0,1368,3,70, -0,1368,3,71,0, -1368,3,72,0,1368, -3,73,0,1368,3, -74,0,1368,3,75, -0,1368,3,76,0, -1368,3,77,0,1368, -3,78,0,1368,3, -79,0,1368,3,80, -0,1368,3,81,0, -1368,3,82,0,1368, -3,83,0,1368,3, -84,0,1368,3,85, -0,1368,3,86,0, -1368,3,87,0,1368, -3,88,0,1368,3, -89,0,1368,3,90, -0,1368,3,91,0, -1368,3,92,0,1377, -12,1,46060,1378,5, -4,3,110,0,1379, -12,1,46089,1380,5, -0,1381,11,1,957, +1407,11,1,165,0, +1408,4,12,83,0, +84,0,82,0,79, +0,75,0,69,0, +1,-1,3,125,0, +1409,12,1,43430,1410, +5,0,1411,11,1, +56,0,1412,4,22, +82,0,73,0,71, +0,72,0,84,0, +95,0,66,0,82, +0,65,0,67,0, +69,0,1,-1,3, +126,0,1413,12,1, +46209,1414,5,0,1415, +11,1,175,0,1416, +4,10,84,0,73, +0,76,0,68,0, +69,0,1,-1,0, +165,1,-1,1417,4, +12,83,0,84,0, +82,0,73,0,78, +0,71,0,1418,12, +1,47777,1419,5,119, +3,1,0,1420,12, +1,47778,1421,5,0, +1422,11,1,968,0, +165,1,-1,3,9, +0,1420,3,10,0, +1423,12,1,47979,1424, +5,0,1425,11,1, +974,0,165,1,-1, +3,13,0,1420,3, +0,3,1420,3,0, +6,1420,3,32,0, +1420,3,33,0,1420, +3,34,0,1426,12, +1,48726,1427,5,0, +1428,11,1,1032,0, +165,1,-1,3,35, +0,1420,3,36,0, +1420,3,37,0,1420, +3,38,0,1420,3, +40,0,1420,3,41, +0,1420,3,42,0, +1420,3,43,0,1420, +3,44,0,1420,3, +45,0,1420,3,46, +0,1420,3,47,0, +1420,3,3,9,1420, +3,49,0,1420,3, +50,0,1420,3,48, +0,1420,3,52,0, +1420,3,53,0,1420, +3,51,0,1420,3, +55,0,1420,3,56, +0,1420,3,54,0, +1420,3,59,0,1420, +3,57,0,1420,3, +61,0,1420,3,62, +0,1420,3,60,0, +1420,3,64,0,1420, +3,65,0,1420,3, +66,0,1420,3,67, +0,1420,3,68,0, +1420,3,69,0,1420, +3,70,0,1420,3, +71,0,1420,3,72, +0,1420,3,73,0, +1420,3,74,0,1420, +3,75,0,1420,3, +76,0,1420,3,77, +0,1420,3,78,0, +1420,3,79,0,1420, +3,80,0,1420,3, +81,0,1420,3,82, +0,1420,3,83,0, +1420,3,84,0,1420, +3,85,0,1420,3, +86,0,1420,3,87, +0,1420,3,88,0, +1420,3,89,0,1420, +3,90,0,1420,3, +91,0,1420,3,92, +0,1429,12,1,48122, +1430,5,4,3,110, +0,1431,12,1,48151, +1432,5,0,1433,11, +1,979,0,165,1, +-1,3,34,0,1434, +12,1,48591,1435,5, +0,1436,11,1,1003, 0,165,1,-1,3, -34,0,1382,12,1, -46529,1383,5,0,1384, -11,1,981,0,165, -1,-1,3,92,0, -1385,12,1,46405,1386, -5,0,1387,11,1, -993,0,165,1,-1, -3,116,0,1388,12, -1,46215,1389,5,0, -1390,11,1,969,0, -165,1,-1,1391,11, -1,1005,0,165,1, --1,3,93,0,1368, -3,94,0,1368,3, -95,0,1368,3,96, -0,1368,3,97,0, -1368,3,98,0,1368, -3,99,0,1368,3, -100,0,1368,3,101, -0,1368,3,102,0, -1368,3,103,0,1368, -3,104,0,1368,3, -105,0,1368,3,106, -0,1368,3,107,0, -1368,3,108,0,1368, -3,109,0,1368,3, -110,0,1368,3,111, -0,1368,3,112,0, -1368,3,113,0,1368, -3,114,0,1368,3, -115,0,1368,3,116, -0,1368,3,117,0, -1368,3,118,0,1368, -3,119,0,1368,3, -120,0,1368,3,121, -0,1368,3,122,0, -1368,3,123,0,1368, -3,124,0,1368,3, -125,0,1368,3,96, -6,1368,3,126,0, -1368,3,58,15,1368, -3,59,15,1368,3, -136,4,1368,3,160, -0,1368,3,15,7, -1368,3,170,0,1368, -3,171,0,1368,3, -172,0,1368,3,173, -0,1368,3,178,0, -1368,3,176,2,1368, -3,187,0,1368,3, -187,1,1368,3,192, -0,1368,3,41,32, -1368,3,197,1,1368, -3,0,224,1368,3, -40,32,1368,3,63, -32,1368,0,165,1, --1,1392,5,93,251, -1393,10,251,1,19, -573,1394,10,573,1, -47,301,1395,10,301, -1,93,1172,1396,10, -1172,1,50,1041,1397, -10,1041,1,80,1191, -1398,10,1191,1,53, -188,1399,10,188,1, -37,602,1400,10,602, -1,43,700,1401,10, -700,1,51,613,1402, -10,613,1,46,211, -1403,10,211,1,16, -215,1404,10,215,1, -17,672,1405,10,672, -1,68,901,1406,10, -901,1,75,361,1407, -10,361,1,35,223, -1408,10,223,1,20, -229,1409,10,229,1, -6,199,1410,10,199, -1,22,286,1411,10, -286,1,21,265,1412, -10,265,1,95,1292, -1413,10,1292,1,88, -481,1414,10,481,1, -64,720,1415,10,720, -1,49,357,1416,10, -357,1,28,318,1417, -10,318,1,25,709, -1418,10,709,1,42, -792,1419,10,792,1, -69,1231,1420,10,1231, -1,48,336,1421,10, -336,1,41,850,1422, -10,850,1,57,654, -1423,10,654,1,91, -233,1424,10,233,1, -4,342,1425,10,342, -1,23,493,1426,10, -493,1,63,1246,1427, -10,1246,1,84,324, -1428,10,324,1,29, -245,1429,10,245,1, -5,316,1430,10,316, -1,31,624,1431,10, -624,1,52,889,1432, -10,889,1,76,1114, -1433,10,1114,1,83, -1017,1434,10,1017,1, -81,995,1435,10,995, -1,77,186,1436,10, -186,1,30,249,1437, -10,249,1,7,847, -1438,10,847,1,73, -197,1439,10,197,1, -10,353,1440,10,353, -1,27,294,1441,10, -294,1,94,239,1442, -10,239,1,14,269, -1443,10,269,1,24, -731,1444,10,731,1, -54,281,1445,10,281, -1,9,1225,1446,10, -1225,1,86,498,1447, -10,498,1,62,1448, -4,30,83,0,84, -0,82,0,73,0, -78,0,71,0,95, -0,67,0,79,0, -78,0,83,0,84, -0,65,0,78,0, -84,0,1449,10,1448, -1,3,1340,1450,10, -1340,1,45,348,1451, -10,348,1,92,551, -1452,10,551,1,66, -1068,1453,10,1068,1, -56,402,1454,10,402, -1,58,1348,1455,10, -1348,1,12,531,1456, -10,531,1,44,312, -1457,10,312,1,40, -1154,1458,10,1154,1, -82,591,1459,10,591, -1,67,946,1460,10, -946,1,78,1364,1461, -10,1364,1,36,1356, -1462,10,1356,1,34, -787,1463,10,787,1, -70,1305,1464,10,1305, -1,87,865,1465,10, -865,1,74,338,1466, -10,338,1,26,425, -1467,10,425,1,59, -207,1468,10,207,1, -33,306,1469,10,306, -1,11,205,1470,10, -205,1,38,519,1471, -10,519,1,61,828, -1472,10,828,1,72, -1287,1473,10,1287,1, -90,326,1474,10,326, -1,15,969,1475,10, -969,1,79,1354,1476, -10,1354,1,39,332, -1477,10,332,1,32, -1275,1478,10,1275,1, -89,375,1479,10,375, -1,60,1323,1480,10, -1323,1,55,1360,1481, -10,1360,1,13,1214, -1482,10,1214,1,85, -235,1483,10,235,1, -18,221,1484,10,221, -1,8,775,1485,10, -775,1,71,449,1486, -10,449,1,65,1487, -5,0,0}; +92,0,1437,12,1, +48467,1438,5,0,1439, +11,1,1015,0,165, +1,-1,3,116,0, +1440,12,1,48277,1441, +5,0,1442,11,1, +991,0,165,1,-1, +1443,11,1,1027,0, +165,1,-1,3,93, +0,1420,3,94,0, +1420,3,95,0,1420, +3,96,0,1420,3, +238,22,1420,3,98, +0,1420,3,99,0, +1420,3,100,0,1420, +3,101,0,1420,3, +97,0,1420,3,103, +0,1420,3,104,0, +1420,3,105,0,1420, +3,106,0,1420,3, +102,0,1420,3,108, +0,1420,3,109,0, +1420,3,110,0,1420, +3,111,0,1420,3, +112,0,1420,3,113, +0,1420,3,114,0, +1420,3,115,0,1420, +3,116,0,1420,3, +117,0,1420,3,118, +0,1420,3,119,0, +1420,3,120,0,1420, +3,121,0,1420,3, +122,0,1420,3,123, +0,1420,3,124,0, +1420,3,125,0,1420, +3,96,6,1420,3, +107,0,1420,3,126, +0,1420,3,58,15, +1420,3,59,15,1420, +3,136,4,1420,3, +160,0,1420,3,170, +0,1420,3,171,0, +1420,3,172,0,1420, +3,173,0,1420,3, +178,0,1420,3,176, +2,1420,3,187,0, +1420,3,187,1,1420, +3,192,0,1420,3, +41,32,1420,3,197, +1,1420,3,0,224, +1420,3,40,32,1420, +3,63,32,1420,0, +165,1,-1,1444,5, +94,251,1445,10,251, +1,19,573,1446,10, +573,1,47,301,1447, +10,301,1,94,1172, +1448,10,1172,1,50, +1041,1449,10,1041,1, +80,1191,1450,10,1191, +1,53,188,1451,10, +188,1,37,602,1452, +10,602,1,43,700, +1453,10,700,1,51, +613,1454,10,613,1, +46,1331,1455,10,1331, +1,92,211,1456,10, +211,1,16,215,1457, +10,215,1,17,672, +1458,10,672,1,68, +901,1459,10,901,1, +75,361,1460,10,361, +1,35,223,1461,10, +223,1,20,229,1462, +10,229,1,6,199, +1463,10,199,1,22, +286,1464,10,286,1, +21,265,1465,10,265, +1,96,1292,1466,10, +1292,1,88,481,1467, +10,481,1,64,720, +1468,10,720,1,49, +357,1469,10,357,1, +28,318,1470,10,318, +1,25,709,1471,10, +709,1,42,792,1472, +10,792,1,69,1231, +1473,10,1231,1,48, +336,1474,10,336,1, +41,850,1475,10,850, +1,57,654,1476,10, +654,1,91,233,1477, +10,233,1,4,342, +1478,10,342,1,23, +493,1479,10,493,1, +63,1246,1480,10,1246, +1,84,324,1481,10, +324,1,29,245,1482, +10,245,1,5,316, +1483,10,316,1,31, +624,1484,10,624,1, +52,889,1485,10,889, +1,76,1114,1486,10, +1114,1,83,1017,1487, +10,1017,1,81,995, +1488,10,995,1,77, +186,1489,10,186,1, +30,249,1490,10,249, +1,7,847,1491,10, +847,1,73,197,1492, +10,197,1,10,353, +1493,10,353,1,27, +294,1494,10,294,1, +95,239,1495,10,239, +1,14,269,1496,10, +269,1,24,731,1497, +10,731,1,54,281, +1498,10,281,1,9, +1225,1499,10,1225,1, +86,498,1500,10,498, +1,62,1501,4,30, +83,0,84,0,82, +0,73,0,78,0, +71,0,95,0,67, +0,79,0,78,0, +83,0,84,0,65, +0,78,0,84,0, +1502,10,1501,1,3, +1392,1503,10,1392,1, +45,348,1504,10,348, +1,93,551,1505,10, +551,1,66,1068,1506, +10,1068,1,56,402, +1507,10,402,1,58, +1400,1508,10,1400,1, +12,531,1509,10,531, +1,44,312,1510,10, +312,1,40,1154,1511, +10,1154,1,82,591, +1512,10,591,1,67, +946,1513,10,946,1, +78,1416,1514,10,1416, +1,36,1408,1515,10, +1408,1,34,787,1516, +10,787,1,70,1357, +1517,10,1357,1,87, +865,1518,10,865,1, +74,338,1519,10,338, +1,26,425,1520,10, +425,1,59,207,1521, +10,207,1,33,306, +1522,10,306,1,11, +205,1523,10,205,1, +38,519,1524,10,519, +1,61,828,1525,10, +828,1,72,1287,1526, +10,1287,1,90,326, +1527,10,326,1,15, +969,1528,10,969,1, +79,1406,1529,10,1406, +1,39,332,1530,10, +332,1,32,1275,1531, +10,1275,1,89,375, +1532,10,375,1,60, +1375,1533,10,1375,1, +55,1412,1534,10,1412, +1,13,1214,1535,10, +1214,1,85,235,1536, +10,235,1,18,221, +1537,10,221,1,8, +775,1538,10,775,1, +71,449,1539,10,449, +1,65,1540,5,0,0}; new Tfactory(this,"MINUS",new TCreator(MINUS_factory)); new Tfactory(this,"DEFAULT_STATE",new TCreator(DEFAULT_STATE_factory)); new Tfactory(this,"INTEGER_CONSTANT",new TCreator(INTEGER_CONSTANT_factory)); @@ -18602,6 +19521,7 @@ public class yyLSLTokens : YyLexer { new Tfactory(this,"ELSE",new TCreator(ELSE_factory)); new Tfactory(this,"INTEGER_TYPE",new TCreator(INTEGER_TYPE_factory)); new Tfactory(this,"FOR",new TCreator(FOR_factory)); + new Tfactory(this,"TRANSACTION_RESULT_EVENT",new TCreator(TRANSACTION_RESULT_EVENT_factory)); new Tfactory(this,"LEFT_PAREN",new TCreator(LEFT_PAREN_factory)); new Tfactory(this,"RIGHT_PAREN",new TCreator(RIGHT_PAREN_factory)); new Tfactory(this,"HTTP_RESPONSE_EVENT",new TCreator(HTTP_RESPONSE_EVENT_factory)); @@ -18696,6 +19616,7 @@ public static object EXCLAMATION_factory(Lexer yyl) { return new EXCLAMATION(yyl public static object ELSE_factory(Lexer yyl) { return new ELSE(yyl);} public static object INTEGER_TYPE_factory(Lexer yyl) { return new INTEGER_TYPE(yyl);} public static object FOR_factory(Lexer yyl) { return new FOR(yyl);} +public static object TRANSACTION_RESULT_EVENT_factory(Lexer yyl) { return new TRANSACTION_RESULT_EVENT(yyl);} public static object LEFT_PAREN_factory(Lexer yyl) { return new LEFT_PAREN(yyl);} public static object RIGHT_PAREN_factory(Lexer yyl) { return new RIGHT_PAREN(yyl);} public static object HTTP_RESPONSE_EVENT_factory(Lexer yyl) { return new HTTP_RESPONSE_EVENT(yyl);} @@ -18782,35 +19703,35 @@ public static object CONTROL_EVENT_factory(Lexer yyl) { return new CONTROL_EVENT public override TOKEN OldAction(Lexer yym,ref string yytext,int action, ref bool reject) { switch(action) { case -1: break; - case 946: { ((LSLTokens)yym).str += yytext; } + case 1015: { ((LSLTokens)yym).str += "\\\\"; } break; - case 1010: { yym.yy_begin("YYINITIAL"); ((LSLTokens)yym).yytext = ((LSLTokens)yym).str; ((LSLTokens)yym).str = String.Empty; return new STRING_CONSTANT(yym); } + case 991: { ((LSLTokens)yym).str += " "; } break; - case 1015: { yym.yy_begin("COMMENT"); } + case 963: { yym.yy_begin("STRING"); ((LSLTokens)yym).str = "";} break; - case 1027: { yym.yy_begin("YYINITIAL"); } + case 1037: { yym.yy_begin("COMMENT"); } break; - case 1041: ; + case 1049: { yym.yy_begin("YYINITIAL"); } break; - case 1045: ; + case 1027: { ((LSLTokens)yym).str += '\\'; } break; - case 1054: ; + case 1063: ; break; - case 1005: { ((LSLTokens)yym).str += '\\'; } + case 1076: ; break; - case 1050: ; + case 1032: { yym.yy_begin("YYINITIAL"); ((LSLTokens)yym).yytext = ((LSLTokens)yym).str; ((LSLTokens)yym).str = String.Empty; return new STRING_CONSTANT(yym); } break; - case 941: { yym.yy_begin("STRING"); ((LSLTokens)yym).str = "";} + case 1067: ; break; - case 957: { ((LSLTokens)yym).str += "\\n"; } + case 1072: ; break; - case 969: { ((LSLTokens)yym).str += " "; } + case 1003: { ((LSLTokens)yym).str += "\\\""; } break; - case 981: { ((LSLTokens)yym).str += "\\\""; } + case 974: { ((LSLTokens)yym).str += "\\n"; } break; - case 952: { ((LSLTokens)yym).str += "\\n"; } + case 979: { ((LSLTokens)yym).str += "\\n"; } break; - case 993: { ((LSLTokens)yym).str += "\\\\"; } + case 968: { ((LSLTokens)yym).str += yytext; } break; } return null; diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/lsl.parser.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/lsl.parser.cs index ca56cd6..5fef83c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/lsl.parser.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/lsl.parser.cs @@ -1,6 +1,6 @@ using System;using Tools; namespace OpenSim.Region.ScriptEngine.Shared.CodeTools { -//%+LSLProgramRoot+96 +//%+LSLProgramRoot+97 public class LSLProgramRoot : SYMBOL{ public LSLProgramRoot (Parser yyp, States s ):base(((LSLSyntax )yyp)){ while (0< s . kids . Count ) kids . Add ( s . kids . Pop ()); @@ -11,9 +11,9 @@ public class LSLProgramRoot : SYMBOL{ } public override string yyname { get { return "LSLProgramRoot"; }} -public override int yynum { get { return 96; }} +public override int yynum { get { return 97; }} public LSLProgramRoot(Parser yyp):base(yyp){}} -//%+GlobalDefinitions+97 +//%+GlobalDefinitions+98 public class GlobalDefinitions : SYMBOL{ public GlobalDefinitions (Parser yyp, GlobalVariableDeclaration gvd ):base(((LSLSyntax )yyp)){ kids . Add ( gvd ); @@ -31,9 +31,9 @@ public class GlobalDefinitions : SYMBOL{ } public override string yyname { get { return "GlobalDefinitions"; }} -public override int yynum { get { return 97; }} +public override int yynum { get { return 98; }} public GlobalDefinitions(Parser yyp):base(yyp){}} -//%+GlobalVariableDeclaration+98 +//%+GlobalVariableDeclaration+99 public class GlobalVariableDeclaration : SYMBOL{ public GlobalVariableDeclaration (Parser yyp, Declaration d ):base(((LSLSyntax )yyp)){ kids . Add ( d ); @@ -43,9 +43,9 @@ public class GlobalVariableDeclaration : SYMBOL{ } public override string yyname { get { return "GlobalVariableDeclaration"; }} -public override int yynum { get { return 98; }} +public override int yynum { get { return 99; }} public GlobalVariableDeclaration(Parser yyp):base(yyp){}} -//%+GlobalFunctionDefinition+99 +//%+GlobalFunctionDefinition+100 public class GlobalFunctionDefinition : SYMBOL{ private string m_returnType ; private string m_name ; @@ -65,9 +65,9 @@ public class GlobalFunctionDefinition : SYMBOL{ } public override string yyname { get { return "GlobalFunctionDefinition"; }} -public override int yynum { get { return 99; }} +public override int yynum { get { return 100; }} public GlobalFunctionDefinition(Parser yyp):base(yyp){}} -//%+States+100 +//%+States+101 public class States : SYMBOL{ public States (Parser yyp, State ds ):base(((LSLSyntax )yyp)){ kids . Add ( ds ); @@ -78,9 +78,9 @@ public class States : SYMBOL{ } public override string yyname { get { return "States"; }} -public override int yynum { get { return 100; }} +public override int yynum { get { return 101; }} public States(Parser yyp):base(yyp){}} -//%+State+101 +//%+State+102 public class State : SYMBOL{ private string m_name ; public State (Parser yyp, string name , StateBody sb ):base(((LSLSyntax @@ -94,9 +94,9 @@ public class State : SYMBOL{ } public override string yyname { get { return "State"; }} -public override int yynum { get { return 101; }} +public override int yynum { get { return 102; }} public State(Parser yyp):base(yyp){}} -//%+StateBody+102 +//%+StateBody+103 public class StateBody : SYMBOL{ public StateBody (Parser yyp, StateBody sb , StateEvent se ):base(((LSLSyntax )yyp)){ while (0< sb . kids . Count ) kids . Add ( sb . kids . Pop ()); @@ -107,18 +107,18 @@ public class StateBody : SYMBOL{ } public override string yyname { get { return "StateBody"; }} -public override int yynum { get { return 102; }} +public override int yynum { get { return 103; }} public StateBody(Parser yyp):base(yyp){}} -//%+StateEvent+103 +//%+StateEvent+104 public class StateEvent : SYMBOL{ private string m_name ; public StateEvent (Parser yyp, string name , CompoundStatement cs ):base(((LSLSyntax )yyp)){ m_name = name ; kids . Add ( cs ); } - public StateEvent (Parser yyp, string name , ArgumentDeclarationList dal , CompoundStatement cs ):base(((LSLSyntax + public StateEvent (Parser yyp, string name , ArgumentDeclarationList adl , CompoundStatement cs ):base(((LSLSyntax )yyp)){ m_name = name ; - if (0< dal . kids . Count ) kids . Add ( dal ); + if (0< adl . kids . Count ) kids . Add ( adl ); kids . Add ( cs ); } public override string ToString (){ return "EVENT<"+ m_name +">"; @@ -128,22 +128,135 @@ public class StateEvent : SYMBOL{ } public override string yyname { get { return "StateEvent"; }} -public override int yynum { get { return 103; }} +public override int yynum { get { return 104; }} public StateEvent(Parser yyp):base(yyp){}} -//%+ArgumentDeclarationList+104 +//%+VoidArgStateEvent+105 +public class VoidArgStateEvent : StateEvent{ + public VoidArgStateEvent (Parser yyp, string name , CompoundStatement cs ):base(((LSLSyntax +)yyp), name , cs ){} + +public override string yyname { get { return "VoidArgStateEvent"; }} +public override int yynum { get { return 105; }} +public VoidArgStateEvent(Parser yyp):base(yyp){}} +//%+KeyArgStateEvent+106 +public class KeyArgStateEvent : StateEvent{ + public KeyArgStateEvent (Parser yyp, string name , KeyArgumentDeclarationList adl , CompoundStatement cs ):base(((LSLSyntax +)yyp), name , adl , cs ){} + +public override string yyname { get { return "KeyArgStateEvent"; }} +public override int yynum { get { return 106; }} +public KeyArgStateEvent(Parser yyp):base(yyp){}} +//%+IntArgStateEvent+107 +public class IntArgStateEvent : StateEvent{ + public IntArgStateEvent (Parser yyp, string name , IntArgumentDeclarationList adl , CompoundStatement cs ):base(((LSLSyntax +)yyp), name , adl , cs ){} + +public override string yyname { get { return "IntArgStateEvent"; }} +public override int yynum { get { return 107; }} +public IntArgStateEvent(Parser yyp):base(yyp){}} +//%+VectorArgStateEvent+108 +public class VectorArgStateEvent : StateEvent{ + public VectorArgStateEvent (Parser yyp, string name , VectorArgumentDeclarationList adl , CompoundStatement cs ):base(((LSLSyntax +)yyp), name , adl , cs ){} + +public override string yyname { get { return "VectorArgStateEvent"; }} +public override int yynum { get { return 108; }} +public VectorArgStateEvent(Parser yyp):base(yyp){}} +//%+IntRotRotArgStateEvent+109 +public class IntRotRotArgStateEvent : StateEvent{ + public IntRotRotArgStateEvent (Parser yyp, string name , IntRotRotArgumentDeclarationList adl , CompoundStatement cs ):base(((LSLSyntax +)yyp), name , adl , cs ){} + +public override string yyname { get { return "IntRotRotArgStateEvent"; }} +public override int yynum { get { return 109; }} +public IntRotRotArgStateEvent(Parser yyp):base(yyp){}} +//%+IntVecVecArgStateEvent+110 +public class IntVecVecArgStateEvent : StateEvent{ + public IntVecVecArgStateEvent (Parser yyp, string name , IntVecVecArgumentDeclarationList adl , CompoundStatement cs ):base(((LSLSyntax +)yyp), name , adl , cs ){} + +public override string yyname { get { return "IntVecVecArgStateEvent"; }} +public override int yynum { get { return 110; }} +public IntVecVecArgStateEvent(Parser yyp):base(yyp){}} +//%+KeyIntIntArgStateEvent+111 +public class KeyIntIntArgStateEvent : StateEvent{ + public KeyIntIntArgStateEvent (Parser yyp, string name , KeyIntIntArgumentDeclarationList adl , CompoundStatement cs ):base(((LSLSyntax +)yyp), name , adl , cs ){} + +public override string yyname { get { return "KeyIntIntArgStateEvent"; }} +public override int yynum { get { return 111; }} +public KeyIntIntArgStateEvent(Parser yyp):base(yyp){}} +//%+ArgumentDeclarationList+112 public class ArgumentDeclarationList : SYMBOL{ public ArgumentDeclarationList (Parser yyp, Declaration d ):base(((LSLSyntax )yyp)){ kids . Add ( d ); } + public ArgumentDeclarationList (Parser yyp, Declaration d , Declaration d2 ):base(((LSLSyntax +)yyp)){ kids . Add ( d ); + kids . Add ( d2 ); +} + public ArgumentDeclarationList (Parser yyp, Declaration d , Declaration d2 , Declaration d3 ):base(((LSLSyntax +)yyp)){ kids . Add ( d ); + kids . Add ( d2 ); + kids . Add ( d3 ); +} public ArgumentDeclarationList (Parser yyp, ArgumentDeclarationList adl , Declaration d ):base(((LSLSyntax )yyp)){ while (0< adl . kids . Count ) kids . Add ( adl . kids . Pop ()); kids . Add ( d ); } public override string yyname { get { return "ArgumentDeclarationList"; }} -public override int yynum { get { return 104; }} +public override int yynum { get { return 112; }} public ArgumentDeclarationList(Parser yyp):base(yyp){}} -//%+Declaration+105 +//%+KeyArgumentDeclarationList+113 +public class KeyArgumentDeclarationList : ArgumentDeclarationList{ + public KeyArgumentDeclarationList (Parser yyp, KeyDeclaration d ):base(((LSLSyntax +)yyp), d ){} + +public override string yyname { get { return "KeyArgumentDeclarationList"; }} +public override int yynum { get { return 113; }} +public KeyArgumentDeclarationList(Parser yyp):base(yyp){}} +//%+IntArgumentDeclarationList+114 +public class IntArgumentDeclarationList : ArgumentDeclarationList{ + public IntArgumentDeclarationList (Parser yyp, IntDeclaration d ):base(((LSLSyntax +)yyp), d ){} + +public override string yyname { get { return "IntArgumentDeclarationList"; }} +public override int yynum { get { return 114; }} +public IntArgumentDeclarationList(Parser yyp):base(yyp){}} +//%+VectorArgumentDeclarationList+115 +public class VectorArgumentDeclarationList : ArgumentDeclarationList{ + public VectorArgumentDeclarationList (Parser yyp, VecDeclaration d ):base(((LSLSyntax +)yyp), d ){} + +public override string yyname { get { return "VectorArgumentDeclarationList"; }} +public override int yynum { get { return 115; }} +public VectorArgumentDeclarationList(Parser yyp):base(yyp){}} +//%+IntRotRotArgumentDeclarationList+116 +public class IntRotRotArgumentDeclarationList : ArgumentDeclarationList{ + public IntRotRotArgumentDeclarationList (Parser yyp, Declaration d1 , Declaration d2 , Declaration d3 ):base(((LSLSyntax +)yyp), d1 , d2 , d3 ){} + +public override string yyname { get { return "IntRotRotArgumentDeclarationList"; }} +public override int yynum { get { return 116; }} +public IntRotRotArgumentDeclarationList(Parser yyp):base(yyp){}} +//%+IntVecVecArgumentDeclarationList+117 +public class IntVecVecArgumentDeclarationList : ArgumentDeclarationList{ + public IntVecVecArgumentDeclarationList (Parser yyp, Declaration d1 , Declaration d2 , Declaration d3 ):base(((LSLSyntax +)yyp), d1 , d2 , d3 ){} + +public override string yyname { get { return "IntVecVecArgumentDeclarationList"; }} +public override int yynum { get { return 117; }} +public IntVecVecArgumentDeclarationList(Parser yyp):base(yyp){}} +//%+KeyIntIntArgumentDeclarationList+118 +public class KeyIntIntArgumentDeclarationList : ArgumentDeclarationList{ + public KeyIntIntArgumentDeclarationList (Parser yyp, Declaration d1 , Declaration d2 , Declaration d3 ):base(((LSLSyntax +)yyp), d1 , d2 , d3 ){} + +public override string yyname { get { return "KeyIntIntArgumentDeclarationList"; }} +public override int yynum { get { return 118; }} +public KeyIntIntArgumentDeclarationList(Parser yyp):base(yyp){}} +//%+Declaration+119 public class Declaration : SYMBOL{ private string m_datatype ; private string m_id ; @@ -163,9 +276,41 @@ public class Declaration : SYMBOL{ } public override string yyname { get { return "Declaration"; }} -public override int yynum { get { return 105; }} +public override int yynum { get { return 119; }} public Declaration(Parser yyp):base(yyp){}} -//%+Typename+106 +//%+KeyDeclaration+120 +public class KeyDeclaration : Declaration{ + public KeyDeclaration (Parser yyp, string type , string id ):base(((LSLSyntax +)yyp), type , id ){} + +public override string yyname { get { return "KeyDeclaration"; }} +public override int yynum { get { return 120; }} +public KeyDeclaration(Parser yyp):base(yyp){}} +//%+IntDeclaration+121 +public class IntDeclaration : Declaration{ + public IntDeclaration (Parser yyp, string type , string id ):base(((LSLSyntax +)yyp), type , id ){} + +public override string yyname { get { return "IntDeclaration"; }} +public override int yynum { get { return 121; }} +public IntDeclaration(Parser yyp):base(yyp){}} +//%+VecDeclaration+122 +public class VecDeclaration : Declaration{ + public VecDeclaration (Parser yyp, string type , string id ):base(((LSLSyntax +)yyp), type , id ){} + +public override string yyname { get { return "VecDeclaration"; }} +public override int yynum { get { return 122; }} +public VecDeclaration(Parser yyp):base(yyp){}} +//%+RotDeclaration+123 +public class RotDeclaration : Declaration{ + public RotDeclaration (Parser yyp, string type , string id ):base(((LSLSyntax +)yyp), type , id ){} + +public override string yyname { get { return "RotDeclaration"; }} +public override int yynum { get { return 123; }} +public RotDeclaration(Parser yyp):base(yyp){}} +//%+Typename+124 public class Typename : SYMBOL{ public string yytext ; public Typename (Parser yyp, string text ):base(((LSLSyntax @@ -173,9 +318,9 @@ public class Typename : SYMBOL{ } public override string yyname { get { return "Typename"; }} -public override int yynum { get { return 106; }} +public override int yynum { get { return 124; }} public Typename(Parser yyp):base(yyp){}} -//%+Event+107 +//%+Event+125 public class Event : SYMBOL{ public string yytext ; public Event (Parser yyp, string text ):base(((LSLSyntax @@ -183,9 +328,65 @@ public class Event : SYMBOL{ } public override string yyname { get { return "Event"; }} -public override int yynum { get { return 107; }} +public override int yynum { get { return 125; }} public Event(Parser yyp):base(yyp){}} -//%+CompoundStatement+108 +//%+VoidArgEvent+126 +public class VoidArgEvent : Event{ + public VoidArgEvent (Parser yyp, string text ):base(((LSLSyntax +)yyp), text ){} + +public override string yyname { get { return "VoidArgEvent"; }} +public override int yynum { get { return 126; }} +public VoidArgEvent(Parser yyp):base(yyp){}} +//%+KeyArgEvent+127 +public class KeyArgEvent : Event{ + public KeyArgEvent (Parser yyp, string text ):base(((LSLSyntax +)yyp), text ){} + +public override string yyname { get { return "KeyArgEvent"; }} +public override int yynum { get { return 127; }} +public KeyArgEvent(Parser yyp):base(yyp){}} +//%+IntArgEvent+128 +public class IntArgEvent : Event{ + public IntArgEvent (Parser yyp, string text ):base(((LSLSyntax +)yyp), text ){} + +public override string yyname { get { return "IntArgEvent"; }} +public override int yynum { get { return 128; }} +public IntArgEvent(Parser yyp):base(yyp){}} +//%+VectorArgEvent+129 +public class VectorArgEvent : Event{ + public VectorArgEvent (Parser yyp, string text ):base(((LSLSyntax +)yyp), text ){} + +public override string yyname { get { return "VectorArgEvent"; }} +public override int yynum { get { return 129; }} +public VectorArgEvent(Parser yyp):base(yyp){}} +//%+IntRotRotArgEvent+130 +public class IntRotRotArgEvent : Event{ + public IntRotRotArgEvent (Parser yyp, string text ):base(((LSLSyntax +)yyp), text ){} + +public override string yyname { get { return "IntRotRotArgEvent"; }} +public override int yynum { get { return 130; }} +public IntRotRotArgEvent(Parser yyp):base(yyp){}} +//%+IntVecVecArgEvent+131 +public class IntVecVecArgEvent : Event{ + public IntVecVecArgEvent (Parser yyp, string text ):base(((LSLSyntax +)yyp), text ){} + +public override string yyname { get { return "IntVecVecArgEvent"; }} +public override int yynum { get { return 131; }} +public IntVecVecArgEvent(Parser yyp):base(yyp){}} +//%+KeyIntIntArgEvent+132 +public class KeyIntIntArgEvent : Event{ + public KeyIntIntArgEvent (Parser yyp, string text ):base(((LSLSyntax +)yyp), text ){} + +public override string yyname { get { return "KeyIntIntArgEvent"; }} +public override int yynum { get { return 132; }} +public KeyIntIntArgEvent(Parser yyp):base(yyp){}} +//%+CompoundStatement+133 public class CompoundStatement : SYMBOL{ public CompoundStatement (Parser yyp):base(((LSLSyntax )yyp)){} @@ -194,9 +395,9 @@ public class CompoundStatement : SYMBOL{ } public override string yyname { get { return "CompoundStatement"; }} -public override int yynum { get { return 108; }} +public override int yynum { get { return 133; }} } -//%+StatementList+109 +//%+StatementList+134 public class StatementList : SYMBOL{ private void AddStatement ( Statement s ){ if ( s . kids . Top is IfStatement || s . kids . Top is WhileStatement || s . kids . Top is DoWhileStatement || s . kids . Top is ForLoop ) kids . Add ( s . kids . Pop ()); else kids . Add ( s ); @@ -210,9 +411,9 @@ public class StatementList : SYMBOL{ } public override string yyname { get { return "StatementList"; }} -public override int yynum { get { return 109; }} +public override int yynum { get { return 134; }} public StatementList(Parser yyp):base(yyp){}} -//%+Statement+110 +//%+Statement+135 public class Statement : SYMBOL{ public Statement (Parser yyp, Declaration d ):base(((LSLSyntax )yyp)){ kids . Add ( d ); @@ -258,9 +459,9 @@ public class Statement : SYMBOL{ } public override string yyname { get { return "Statement"; }} -public override int yynum { get { return 110; }} +public override int yynum { get { return 135; }} public Statement(Parser yyp):base(yyp){}} -//%+EmptyStatement+111 +//%+EmptyStatement+136 public class EmptyStatement : SYMBOL{ public EmptyStatement (Parser yyp):base(((LSLSyntax )yyp)){} @@ -268,9 +469,9 @@ public class EmptyStatement : SYMBOL{ } public override string yyname { get { return "EmptyStatement"; }} -public override int yynum { get { return 111; }} +public override int yynum { get { return 136; }} } -//%+Assignment+112 +//%+Assignment+137 public class Assignment : SYMBOL{ protected string m_assignmentType ; public Assignment (Parser yyp, SYMBOL lhs , SYMBOL rhs , string assignmentType ):base(((LSLSyntax @@ -290,9 +491,9 @@ public class Assignment : SYMBOL{ } public override string yyname { get { return "Assignment"; }} -public override int yynum { get { return 112; }} +public override int yynum { get { return 137; }} public Assignment(Parser yyp):base(yyp){}} -//%+SimpleAssignment+113 +//%+SimpleAssignment+138 public class SimpleAssignment : Assignment{ public SimpleAssignment (Parser yyp, SYMBOL lhs , SYMBOL rhs , string assignmentType ):base(((LSLSyntax )yyp)){ m_assignmentType = assignmentType ; @@ -302,9 +503,9 @@ public class SimpleAssignment : Assignment{ } public override string yyname { get { return "SimpleAssignment"; }} -public override int yynum { get { return 113; }} +public override int yynum { get { return 138; }} public SimpleAssignment(Parser yyp):base(yyp){}} -//%+ReturnStatement+114 +//%+ReturnStatement+139 public class ReturnStatement : SYMBOL{ public ReturnStatement (Parser yyp):base(((LSLSyntax )yyp)){} @@ -314,9 +515,9 @@ public class ReturnStatement : SYMBOL{ } public override string yyname { get { return "ReturnStatement"; }} -public override int yynum { get { return 114; }} +public override int yynum { get { return 139; }} } -//%+JumpLabel+115 +//%+JumpLabel+140 public class JumpLabel : SYMBOL{ private string m_labelName ; public JumpLabel (Parser yyp, string labelName ):base(((LSLSyntax @@ -329,9 +530,9 @@ public class JumpLabel : SYMBOL{ } public override string yyname { get { return "JumpLabel"; }} -public override int yynum { get { return 115; }} +public override int yynum { get { return 140; }} public JumpLabel(Parser yyp):base(yyp){}} -//%+JumpStatement+116 +//%+JumpStatement+141 public class JumpStatement : SYMBOL{ private string m_targetName ; public JumpStatement (Parser yyp, string targetName ):base(((LSLSyntax @@ -344,9 +545,9 @@ public class JumpStatement : SYMBOL{ } public override string yyname { get { return "JumpStatement"; }} -public override int yynum { get { return 116; }} +public override int yynum { get { return 141; }} public JumpStatement(Parser yyp):base(yyp){}} -//%+StateChange+117 +//%+StateChange+142 public class StateChange : SYMBOL{ private string m_newState ; public StateChange (Parser yyp, string newState ):base(((LSLSyntax @@ -357,9 +558,9 @@ public class StateChange : SYMBOL{ } public override string yyname { get { return "StateChange"; }} -public override int yynum { get { return 117; }} +public override int yynum { get { return 142; }} public StateChange(Parser yyp):base(yyp){}} -//%+IfStatement+118 +//%+IfStatement+143 public class IfStatement : SYMBOL{ private void AddStatement ( Statement s ){ if (0< s . kids . Count && s . kids . Top is CompoundStatement ) kids . Add ( s . kids . Pop ()); else kids . Add ( s ); @@ -376,9 +577,9 @@ public class IfStatement : SYMBOL{ } public override string yyname { get { return "IfStatement"; }} -public override int yynum { get { return 118; }} +public override int yynum { get { return 143; }} public IfStatement(Parser yyp):base(yyp){}} -//%+WhileStatement+119 +//%+WhileStatement+144 public class WhileStatement : SYMBOL{ public WhileStatement (Parser yyp, SYMBOL s , Statement st ):base(((LSLSyntax )yyp)){ kids . Add ( s ); @@ -387,9 +588,9 @@ public class WhileStatement : SYMBOL{ } public override string yyname { get { return "WhileStatement"; }} -public override int yynum { get { return 119; }} +public override int yynum { get { return 144; }} public WhileStatement(Parser yyp):base(yyp){}} -//%+DoWhileStatement+120 +//%+DoWhileStatement+145 public class DoWhileStatement : SYMBOL{ public DoWhileStatement (Parser yyp, SYMBOL s , Statement st ):base(((LSLSyntax )yyp)){ if (0< st . kids . Count && st . kids . Top is CompoundStatement ) kids . Add ( st . kids . Pop ()); @@ -398,9 +599,9 @@ public class DoWhileStatement : SYMBOL{ } public override string yyname { get { return "DoWhileStatement"; }} -public override int yynum { get { return 120; }} +public override int yynum { get { return 145; }} public DoWhileStatement(Parser yyp):base(yyp){}} -//%+ForLoop+121 +//%+ForLoop+146 public class ForLoop : SYMBOL{ public ForLoop (Parser yyp, ForLoopStatement flsa , Expression e , ForLoopStatement flsb , Statement s ):base(((LSLSyntax )yyp)){ kids . Add ( flsa ); @@ -411,9 +612,9 @@ public class ForLoop : SYMBOL{ } public override string yyname { get { return "ForLoop"; }} -public override int yynum { get { return 121; }} +public override int yynum { get { return 146; }} public ForLoop(Parser yyp):base(yyp){}} -//%+ForLoopStatement+122 +//%+ForLoopStatement+147 public class ForLoopStatement : SYMBOL{ public ForLoopStatement (Parser yyp, Expression e ):base(((LSLSyntax )yyp)){ kids . Add ( e ); @@ -431,9 +632,9 @@ public class ForLoopStatement : SYMBOL{ } public override string yyname { get { return "ForLoopStatement"; }} -public override int yynum { get { return 122; }} +public override int yynum { get { return 147; }} public ForLoopStatement(Parser yyp):base(yyp){}} -//%+FunctionCall+123 +//%+FunctionCall+148 public class FunctionCall : SYMBOL{ private string m_id ; public FunctionCall (Parser yyp, string id , ArgumentList al ):base(((LSLSyntax @@ -447,9 +648,9 @@ public class FunctionCall : SYMBOL{ } public override string yyname { get { return "FunctionCall"; }} -public override int yynum { get { return 123; }} +public override int yynum { get { return 148; }} public FunctionCall(Parser yyp):base(yyp){}} -//%+ArgumentList+124 +//%+ArgumentList+149 public class ArgumentList : SYMBOL{ public ArgumentList (Parser yyp, Argument a ):base(((LSLSyntax )yyp)){ AddArgument ( a ); @@ -463,14 +664,14 @@ public class ArgumentList : SYMBOL{ } public override string yyname { get { return "ArgumentList"; }} -public override int yynum { get { return 124; }} +public override int yynum { get { return 149; }} public ArgumentList(Parser yyp):base(yyp){}} -//%+Argument+125 +//%+Argument+150 public class Argument : SYMBOL{ public override string yyname { get { return "Argument"; }} -public override int yynum { get { return 125; }} +public override int yynum { get { return 150; }} public Argument(Parser yyp):base(yyp){}} -//%+ExpressionArgument+126 +//%+ExpressionArgument+151 public class ExpressionArgument : Argument{ public ExpressionArgument (Parser yyp, Expression e ):base(((LSLSyntax )yyp)){ if ( e is ConstantExpression ) while (0< e . kids . Count ) kids . Add ( e . kids . Pop ()); @@ -478,9 +679,9 @@ public class ExpressionArgument : Argument{ } public override string yyname { get { return "ExpressionArgument"; }} -public override int yynum { get { return 126; }} +public override int yynum { get { return 151; }} public ExpressionArgument(Parser yyp):base(yyp){}} -//%+Constant+127 +//%+Constant+152 public class Constant : SYMBOL{ private string m_type ; private string m_val ; @@ -502,9 +703,9 @@ public class Constant : SYMBOL{ } public override string yyname { get { return "Constant"; }} -public override int yynum { get { return 127; }} +public override int yynum { get { return 152; }} public Constant(Parser yyp):base(yyp){}} -//%+VectorConstant+128 +//%+VectorConstant+153 public class VectorConstant : Constant{ public VectorConstant (Parser yyp, Expression valX , Expression valY , Expression valZ ):base(((LSLSyntax )yyp),"vector", null ){ kids . Add ( valX ); @@ -513,9 +714,9 @@ public class VectorConstant : Constant{ } public override string yyname { get { return "VectorConstant"; }} -public override int yynum { get { return 128; }} +public override int yynum { get { return 153; }} public VectorConstant(Parser yyp):base(yyp){}} -//%+RotationConstant+129 +//%+RotationConstant+154 public class RotationConstant : Constant{ public RotationConstant (Parser yyp, Expression valX , Expression valY , Expression valZ , Expression valS ):base(((LSLSyntax )yyp),"rotation", null ){ kids . Add ( valX ); @@ -525,36 +726,36 @@ public class RotationConstant : Constant{ } public override string yyname { get { return "RotationConstant"; }} -public override int yynum { get { return 129; }} +public override int yynum { get { return 154; }} public RotationConstant(Parser yyp):base(yyp){}} -//%+ListConstant+130 +//%+ListConstant+155 public class ListConstant : Constant{ public ListConstant (Parser yyp, ArgumentList al ):base(((LSLSyntax )yyp),"list", null ){ kids . Add ( al ); } public override string yyname { get { return "ListConstant"; }} -public override int yynum { get { return 130; }} +public override int yynum { get { return 155; }} public ListConstant(Parser yyp):base(yyp){}} -//%+Expression+131 +//%+Expression+156 public class Expression : SYMBOL{ protected void AddExpression ( Expression e ){ if ( e is ConstantExpression ) while (0< e . kids . Count ) kids . Add ( e . kids . Pop ()); else kids . Add ( e ); } public override string yyname { get { return "Expression"; }} -public override int yynum { get { return 131; }} +public override int yynum { get { return 156; }} public Expression(Parser yyp):base(yyp){}} -//%+ConstantExpression+132 +//%+ConstantExpression+157 public class ConstantExpression : Expression{ public ConstantExpression (Parser yyp, Constant c ):base(((LSLSyntax )yyp)){ kids . Add ( c ); } public override string yyname { get { return "ConstantExpression"; }} -public override int yynum { get { return 132; }} +public override int yynum { get { return 157; }} public ConstantExpression(Parser yyp):base(yyp){}} -//%+IdentExpression+133 +//%+IdentExpression+158 public class IdentExpression : Expression{ protected string m_name ; public IdentExpression (Parser yyp, string name ):base(((LSLSyntax @@ -567,9 +768,9 @@ public class IdentExpression : Expression{ } public override string yyname { get { return "IdentExpression"; }} -public override int yynum { get { return 133; }} +public override int yynum { get { return 158; }} public IdentExpression(Parser yyp):base(yyp){}} -//%+IdentDotExpression+134 +//%+IdentDotExpression+159 public class IdentDotExpression : IdentExpression{ private string m_member ; public IdentDotExpression (Parser yyp, string name , string member ):base(((LSLSyntax @@ -583,18 +784,18 @@ public class IdentDotExpression : IdentExpression{ } public override string yyname { get { return "IdentDotExpression"; }} -public override int yynum { get { return 134; }} +public override int yynum { get { return 159; }} public IdentDotExpression(Parser yyp):base(yyp){}} -//%+FunctionCallExpression+135 +//%+FunctionCallExpression+160 public class FunctionCallExpression : Expression{ public FunctionCallExpression (Parser yyp, FunctionCall fc ):base(((LSLSyntax )yyp)){ kids . Add ( fc ); } public override string yyname { get { return "FunctionCallExpression"; }} -public override int yynum { get { return 135; }} +public override int yynum { get { return 160; }} public FunctionCallExpression(Parser yyp):base(yyp){}} -//%+BinaryExpression+136 +//%+BinaryExpression+161 public class BinaryExpression : Expression{ private string m_expressionSymbol ; public BinaryExpression (Parser yyp, Expression lhs , Expression rhs , string expressionSymbol ):base(((LSLSyntax @@ -609,9 +810,9 @@ public class BinaryExpression : Expression{ } public override string yyname { get { return "BinaryExpression"; }} -public override int yynum { get { return 136; }} +public override int yynum { get { return 161; }} public BinaryExpression(Parser yyp):base(yyp){}} -//%+UnaryExpression+137 +//%+UnaryExpression+162 public class UnaryExpression : Expression{ private string m_unarySymbol ; public UnaryExpression (Parser yyp, string unarySymbol , Expression e ):base(((LSLSyntax @@ -625,9 +826,9 @@ public class UnaryExpression : Expression{ } public override string yyname { get { return "UnaryExpression"; }} -public override int yynum { get { return 137; }} +public override int yynum { get { return 162; }} public UnaryExpression(Parser yyp):base(yyp){}} -//%+TypecastExpression+138 +//%+TypecastExpression+163 public class TypecastExpression : Expression{ private string m_typecastType ; public TypecastExpression (Parser yyp, string typecastType , SYMBOL rhs ):base(((LSLSyntax @@ -641,18 +842,18 @@ public class TypecastExpression : Expression{ } public override string yyname { get { return "TypecastExpression"; }} -public override int yynum { get { return 138; }} +public override int yynum { get { return 163; }} public TypecastExpression(Parser yyp):base(yyp){}} -//%+ParenthesisExpression+139 +//%+ParenthesisExpression+164 public class ParenthesisExpression : Expression{ public ParenthesisExpression (Parser yyp, SYMBOL s ):base(((LSLSyntax )yyp)){ kids . Add ( s ); } public override string yyname { get { return "ParenthesisExpression"; }} -public override int yynum { get { return 139; }} +public override int yynum { get { return 164; }} public ParenthesisExpression(Parser yyp):base(yyp){}} -//%+IncrementDecrementExpression+140 +//%+IncrementDecrementExpression+165 public class IncrementDecrementExpression : Expression{ private string m_name ; private string m_operation ; @@ -680,7 +881,7 @@ public class IncrementDecrementExpression : Expression{ } public override string yyname { get { return "IncrementDecrementExpression"; }} -public override int yynum { get { return 140; }} +public override int yynum { get { return 165; }} public IncrementDecrementExpression(Parser yyp):base(yyp){}} public class LSLProgramRoot_1 : LSLProgramRoot { @@ -792,6 +993,90 @@ public class StateBody_2 : StateBody { ((StateEvent)(yyq.StackAt(0).m_value)) ){}} +public class StateBody_3 : StateBody { + public StateBody_3(Parser yyq):base(yyq, + ((VoidArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + +public class StateBody_4 : StateBody { + public StateBody_4(Parser yyq):base(yyq, + ((StateBody)(yyq.StackAt(1).m_value)) + , + ((VoidArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + +public class StateBody_5 : StateBody { + public StateBody_5(Parser yyq):base(yyq, + ((KeyArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + +public class StateBody_6 : StateBody { + public StateBody_6(Parser yyq):base(yyq, + ((StateBody)(yyq.StackAt(1).m_value)) + , + ((KeyArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + +public class StateBody_7 : StateBody { + public StateBody_7(Parser yyq):base(yyq, + ((IntArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + +public class StateBody_8 : StateBody { + public StateBody_8(Parser yyq):base(yyq, + ((StateBody)(yyq.StackAt(1).m_value)) + , + ((IntArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + +public class StateBody_9 : StateBody { + public StateBody_9(Parser yyq):base(yyq, + ((VectorArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + +public class StateBody_10 : StateBody { + public StateBody_10(Parser yyq):base(yyq, + ((StateBody)(yyq.StackAt(1).m_value)) + , + ((VectorArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + +public class StateBody_11 : StateBody { + public StateBody_11(Parser yyq):base(yyq, + ((IntRotRotArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + +public class StateBody_12 : StateBody { + public StateBody_12(Parser yyq):base(yyq, + ((StateBody)(yyq.StackAt(1).m_value)) + , + ((IntRotRotArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + +public class StateBody_13 : StateBody { + public StateBody_13(Parser yyq):base(yyq, + ((IntVecVecArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + +public class StateBody_14 : StateBody { + public StateBody_14(Parser yyq):base(yyq, + ((StateBody)(yyq.StackAt(1).m_value)) + , + ((IntVecVecArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + +public class StateBody_15 : StateBody { + public StateBody_15(Parser yyq):base(yyq, + ((KeyIntIntArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + +public class StateBody_16 : StateBody { + public StateBody_16(Parser yyq):base(yyq, + ((StateBody)(yyq.StackAt(1).m_value)) + , + ((KeyIntIntArgStateEvent)(yyq.StackAt(0).m_value)) + ){}} + public class StateEvent_1 : StateEvent { public StateEvent_1(Parser yyq):base(yyq, ((Event)(yyq.StackAt(4).m_value)) @@ -801,6 +1086,67 @@ public class StateEvent_1 : StateEvent { ((CompoundStatement)(yyq.StackAt(0).m_value)) ){}} +public class VoidArgStateEvent_1 : VoidArgStateEvent { + public VoidArgStateEvent_1(Parser yyq):base(yyq, + ((VoidArgEvent)(yyq.StackAt(3).m_value)) + .yytext, + ((CompoundStatement)(yyq.StackAt(0).m_value)) + ){}} + +public class KeyArgStateEvent_1 : KeyArgStateEvent { + public KeyArgStateEvent_1(Parser yyq):base(yyq, + ((KeyArgEvent)(yyq.StackAt(4).m_value)) + .yytext, + ((KeyArgumentDeclarationList)(yyq.StackAt(2).m_value)) + , + ((CompoundStatement)(yyq.StackAt(0).m_value)) + ){}} + +public class IntArgStateEvent_1 : IntArgStateEvent { + public IntArgStateEvent_1(Parser yyq):base(yyq, + ((IntArgEvent)(yyq.StackAt(4).m_value)) + .yytext, + ((IntArgumentDeclarationList)(yyq.StackAt(2).m_value)) + , + ((CompoundStatement)(yyq.StackAt(0).m_value)) + ){}} + +public class VectorArgStateEvent_1 : VectorArgStateEvent { + public VectorArgStateEvent_1(Parser yyq):base(yyq, + ((VectorArgEvent)(yyq.StackAt(4).m_value)) + .yytext, + ((VectorArgumentDeclarationList)(yyq.StackAt(2).m_value)) + , + ((CompoundStatement)(yyq.StackAt(0).m_value)) + ){}} + +public class IntRotRotArgStateEvent_1 : IntRotRotArgStateEvent { + public IntRotRotArgStateEvent_1(Parser yyq):base(yyq, + ((IntRotRotArgEvent)(yyq.StackAt(4).m_value)) + .yytext, + ((IntRotRotArgumentDeclarationList)(yyq.StackAt(2).m_value)) + , + ((CompoundStatement)(yyq.StackAt(0).m_value)) + ){}} + +public class IntVecVecArgStateEvent_1 : IntVecVecArgStateEvent { + public IntVecVecArgStateEvent_1(Parser yyq):base(yyq, + ((IntVecVecArgEvent)(yyq.StackAt(4).m_value)) + .yytext, + ((IntVecVecArgumentDeclarationList)(yyq.StackAt(2).m_value)) + , + ((CompoundStatement)(yyq.StackAt(0).m_value)) + ){}} + +public class KeyIntIntArgStateEvent_1 : KeyIntIntArgStateEvent { + public KeyIntIntArgStateEvent_1(Parser yyq):base(yyq, + ((KeyIntIntArgEvent)(yyq.StackAt(4).m_value)) + .yytext, + ((KeyIntIntArgumentDeclarationList)(yyq.StackAt(2).m_value)) + , + ((CompoundStatement)(yyq.StackAt(0).m_value)) + ){}} + public class ArgumentDeclarationList_1 : ArgumentDeclarationList { public ArgumentDeclarationList_1(Parser yyq):base(yyq, ((Declaration)(yyq.StackAt(0).m_value)) @@ -813,6 +1159,48 @@ public class ArgumentDeclarationList_2 : ArgumentDeclarationList { ((Declaration)(yyq.StackAt(0).m_value)) ){}} +public class KeyArgumentDeclarationList_1 : KeyArgumentDeclarationList { + public KeyArgumentDeclarationList_1(Parser yyq):base(yyq, + ((KeyDeclaration)(yyq.StackAt(0).m_value)) + ){}} + +public class IntArgumentDeclarationList_1 : IntArgumentDeclarationList { + public IntArgumentDeclarationList_1(Parser yyq):base(yyq, + ((IntDeclaration)(yyq.StackAt(0).m_value)) + ){}} + +public class VectorArgumentDeclarationList_1 : VectorArgumentDeclarationList { + public VectorArgumentDeclarationList_1(Parser yyq):base(yyq, + ((VecDeclaration)(yyq.StackAt(0).m_value)) + ){}} + +public class IntRotRotArgumentDeclarationList_1 : IntRotRotArgumentDeclarationList { + public IntRotRotArgumentDeclarationList_1(Parser yyq):base(yyq, + ((IntDeclaration)(yyq.StackAt(4).m_value)) + , + ((RotDeclaration)(yyq.StackAt(2).m_value)) + , + ((RotDeclaration)(yyq.StackAt(0).m_value)) + ){}} + +public class IntVecVecArgumentDeclarationList_1 : IntVecVecArgumentDeclarationList { + public IntVecVecArgumentDeclarationList_1(Parser yyq):base(yyq, + ((IntDeclaration)(yyq.StackAt(4).m_value)) + , + ((VecDeclaration)(yyq.StackAt(2).m_value)) + , + ((VecDeclaration)(yyq.StackAt(0).m_value)) + ){}} + +public class KeyIntIntArgumentDeclarationList_1 : KeyIntIntArgumentDeclarationList { + public KeyIntIntArgumentDeclarationList_1(Parser yyq):base(yyq, + ((KeyDeclaration)(yyq.StackAt(4).m_value)) + , + ((IntDeclaration)(yyq.StackAt(2).m_value)) + , + ((IntDeclaration)(yyq.StackAt(0).m_value)) + ){}} + public class Declaration_1 : Declaration { public Declaration_1(Parser yyq):base(yyq, ((Typename)(yyq.StackAt(1).m_value)) @@ -820,6 +1208,34 @@ public class Declaration_1 : Declaration { ((IDENT)(yyq.StackAt(0).m_value)) .yytext){}} +public class KeyDeclaration_1 : KeyDeclaration { + public KeyDeclaration_1(Parser yyq):base(yyq, + ((KEY_TYPE)(yyq.StackAt(1).m_value)) + .yytext, + ((IDENT)(yyq.StackAt(0).m_value)) + .yytext){}} + +public class IntDeclaration_1 : IntDeclaration { + public IntDeclaration_1(Parser yyq):base(yyq, + ((INTEGER_TYPE)(yyq.StackAt(1).m_value)) + .yytext, + ((IDENT)(yyq.StackAt(0).m_value)) + .yytext){}} + +public class VecDeclaration_1 : VecDeclaration { + public VecDeclaration_1(Parser yyq):base(yyq, + ((VECTOR_TYPE)(yyq.StackAt(1).m_value)) + .yytext, + ((IDENT)(yyq.StackAt(0).m_value)) + .yytext){}} + +public class RotDeclaration_1 : RotDeclaration { + public RotDeclaration_1(Parser yyq):base(yyq, + ((ROTATION_TYPE)(yyq.StackAt(1).m_value)) + .yytext, + ((IDENT)(yyq.StackAt(0).m_value)) + .yytext){}} + public class CompoundStatement_1 : CompoundStatement { public CompoundStatement_1(Parser yyq):base(yyq){}} @@ -1780,172 +2196,177 @@ public class Typename_7 : Typename { public class Event_1 : Event { public Event_1(Parser yyq):base(yyq, - ((AT_ROT_TARGET_EVENT)(yyq.StackAt(0).m_value)) + ((DATASERVER_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} public class Event_2 : Event { public Event_2(Parser yyq):base(yyq, - ((AT_TARGET_EVENT)(yyq.StackAt(0).m_value)) + ((EMAIL_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} public class Event_3 : Event { public Event_3(Parser yyq):base(yyq, - ((ATTACH_EVENT)(yyq.StackAt(0).m_value)) + ((HTTP_RESPONSE_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} public class Event_4 : Event { public Event_4(Parser yyq):base(yyq, - ((CHANGED_EVENT)(yyq.StackAt(0).m_value)) + ((LINK_MESSAGE_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} public class Event_5 : Event { public Event_5(Parser yyq):base(yyq, - ((COLLISION_EVENT)(yyq.StackAt(0).m_value)) + ((LISTEN_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} public class Event_6 : Event { public Event_6(Parser yyq):base(yyq, - ((COLLISION_END_EVENT)(yyq.StackAt(0).m_value)) + ((MONEY_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} public class Event_7 : Event { public Event_7(Parser yyq):base(yyq, - ((COLLISION_START_EVENT)(yyq.StackAt(0).m_value)) + ((REMOTE_DATA_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} public class Event_8 : Event { public Event_8(Parser yyq):base(yyq, - ((CONTROL_EVENT)(yyq.StackAt(0).m_value)) + ((HTTP_REQUEST_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} public class Event_9 : Event { public Event_9(Parser yyq):base(yyq, - ((DATASERVER_EVENT)(yyq.StackAt(0).m_value)) + ((TRANSACTION_RESULT_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_10 : Event { - public Event_10(Parser yyq):base(yyq, - ((EMAIL_EVENT)(yyq.StackAt(0).m_value)) +public class VoidArgEvent_1 : VoidArgEvent { + public VoidArgEvent_1(Parser yyq):base(yyq, + ((STATE_ENTRY_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_11 : Event { - public Event_11(Parser yyq):base(yyq, - ((HTTP_RESPONSE_EVENT)(yyq.StackAt(0).m_value)) +public class VoidArgEvent_2 : VoidArgEvent { + public VoidArgEvent_2(Parser yyq):base(yyq, + ((STATE_EXIT_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_12 : Event { - public Event_12(Parser yyq):base(yyq, - ((LAND_COLLISION_EVENT)(yyq.StackAt(0).m_value)) +public class VoidArgEvent_3 : VoidArgEvent { + public VoidArgEvent_3(Parser yyq):base(yyq, + ((MOVING_END_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_13 : Event { - public Event_13(Parser yyq):base(yyq, - ((LAND_COLLISION_END_EVENT)(yyq.StackAt(0).m_value)) +public class VoidArgEvent_4 : VoidArgEvent { + public VoidArgEvent_4(Parser yyq):base(yyq, + ((MOVING_START_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_14 : Event { - public Event_14(Parser yyq):base(yyq, - ((LAND_COLLISION_START_EVENT)(yyq.StackAt(0).m_value)) +public class VoidArgEvent_5 : VoidArgEvent { + public VoidArgEvent_5(Parser yyq):base(yyq, + ((NO_SENSOR_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_15 : Event { - public Event_15(Parser yyq):base(yyq, - ((LINK_MESSAGE_EVENT)(yyq.StackAt(0).m_value)) +public class VoidArgEvent_6 : VoidArgEvent { + public VoidArgEvent_6(Parser yyq):base(yyq, + ((NOT_AT_ROT_TARGET_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_16 : Event { - public Event_16(Parser yyq):base(yyq, - ((LISTEN_EVENT)(yyq.StackAt(0).m_value)) +public class VoidArgEvent_7 : VoidArgEvent { + public VoidArgEvent_7(Parser yyq):base(yyq, + ((NOT_AT_TARGET_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_17 : Event { - public Event_17(Parser yyq):base(yyq, - ((MONEY_EVENT)(yyq.StackAt(0).m_value)) +public class VoidArgEvent_8 : VoidArgEvent { + public VoidArgEvent_8(Parser yyq):base(yyq, + ((TIMER_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_18 : Event { - public Event_18(Parser yyq):base(yyq, - ((MOVING_END_EVENT)(yyq.StackAt(0).m_value)) +public class KeyArgEvent_1 : KeyArgEvent { + public KeyArgEvent_1(Parser yyq):base(yyq, + ((ATTACH_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_19 : Event { - public Event_19(Parser yyq):base(yyq, - ((MOVING_START_EVENT)(yyq.StackAt(0).m_value)) +public class KeyArgEvent_2 : KeyArgEvent { + public KeyArgEvent_2(Parser yyq):base(yyq, + ((OBJECT_REZ_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_20 : Event { - public Event_20(Parser yyq):base(yyq, - ((NO_SENSOR_EVENT)(yyq.StackAt(0).m_value)) +public class IntArgEvent_1 : IntArgEvent { + public IntArgEvent_1(Parser yyq):base(yyq, + ((CHANGED_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_21 : Event { - public Event_21(Parser yyq):base(yyq, - ((NOT_AT_ROT_TARGET_EVENT)(yyq.StackAt(0).m_value)) +public class IntArgEvent_2 : IntArgEvent { + public IntArgEvent_2(Parser yyq):base(yyq, + ((COLLISION_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_22 : Event { - public Event_22(Parser yyq):base(yyq, - ((NOT_AT_TARGET_EVENT)(yyq.StackAt(0).m_value)) +public class IntArgEvent_3 : IntArgEvent { + public IntArgEvent_3(Parser yyq):base(yyq, + ((COLLISION_END_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_23 : Event { - public Event_23(Parser yyq):base(yyq, - ((OBJECT_REZ_EVENT)(yyq.StackAt(0).m_value)) +public class IntArgEvent_4 : IntArgEvent { + public IntArgEvent_4(Parser yyq):base(yyq, + ((COLLISION_START_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_24 : Event { - public Event_24(Parser yyq):base(yyq, +public class IntArgEvent_5 : IntArgEvent { + public IntArgEvent_5(Parser yyq):base(yyq, ((ON_REZ_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_25 : Event { - public Event_25(Parser yyq):base(yyq, - ((REMOTE_DATA_EVENT)(yyq.StackAt(0).m_value)) - .yytext){}} - -public class Event_26 : Event { - public Event_26(Parser yyq):base(yyq, +public class IntArgEvent_6 : IntArgEvent { + public IntArgEvent_6(Parser yyq):base(yyq, ((RUN_TIME_PERMISSIONS_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_27 : Event { - public Event_27(Parser yyq):base(yyq, +public class IntArgEvent_7 : IntArgEvent { + public IntArgEvent_7(Parser yyq):base(yyq, ((SENSOR_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_28 : Event { - public Event_28(Parser yyq):base(yyq, - ((STATE_ENTRY_EVENT)(yyq.StackAt(0).m_value)) +public class IntArgEvent_8 : IntArgEvent { + public IntArgEvent_8(Parser yyq):base(yyq, + ((TOUCH_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_29 : Event { - public Event_29(Parser yyq):base(yyq, - ((STATE_EXIT_EVENT)(yyq.StackAt(0).m_value)) +public class IntArgEvent_9 : IntArgEvent { + public IntArgEvent_9(Parser yyq):base(yyq, + ((TOUCH_END_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_30 : Event { - public Event_30(Parser yyq):base(yyq, - ((TIMER_EVENT)(yyq.StackAt(0).m_value)) +public class IntArgEvent_10 : IntArgEvent { + public IntArgEvent_10(Parser yyq):base(yyq, + ((TOUCH_START_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_31 : Event { - public Event_31(Parser yyq):base(yyq, - ((TOUCH_EVENT)(yyq.StackAt(0).m_value)) +public class VectorArgEvent_1 : VectorArgEvent { + public VectorArgEvent_1(Parser yyq):base(yyq, + ((LAND_COLLISION_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_32 : Event { - public Event_32(Parser yyq):base(yyq, - ((TOUCH_END_EVENT)(yyq.StackAt(0).m_value)) +public class VectorArgEvent_2 : VectorArgEvent { + public VectorArgEvent_2(Parser yyq):base(yyq, + ((LAND_COLLISION_END_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_33 : Event { - public Event_33(Parser yyq):base(yyq, - ((TOUCH_START_EVENT)(yyq.StackAt(0).m_value)) +public class VectorArgEvent_3 : VectorArgEvent { + public VectorArgEvent_3(Parser yyq):base(yyq, + ((LAND_COLLISION_START_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} -public class Event_34 : Event { - public Event_34(Parser yyq):base(yyq, - ((HTTP_REQUEST_EVENT)(yyq.StackAt(0).m_value)) +public class IntRotRotArgEvent_1 : IntRotRotArgEvent { + public IntRotRotArgEvent_1(Parser yyq):base(yyq, + ((AT_ROT_TARGET_EVENT)(yyq.StackAt(0).m_value)) + .yytext){}} + +public class IntVecVecArgEvent_1 : IntVecVecArgEvent { + public IntVecVecArgEvent_1(Parser yyq):base(yyq, + ((AT_TARGET_EVENT)(yyq.StackAt(0).m_value)) + .yytext){}} + +public class KeyIntIntArgEvent_1 : KeyIntIntArgEvent { + public KeyIntIntArgEvent_1(Parser yyq):base(yyq, + ((CONTROL_EVENT)(yyq.StackAt(0).m_value)) .yytext){}} public class yyLSLSyntax : YyParser { @@ -1960,12 +2381,12 @@ public class ArgumentDeclarationList_3 : ArgumentDeclarationList { public class ArgumentList_3 : ArgumentList { public ArgumentList_3(Parser yyq):base(yyq){}} -public class ArgumentDeclarationList_4 : ArgumentDeclarationList { - public ArgumentDeclarationList_4(Parser yyq):base(yyq){}} - public class ArgumentList_4 : ArgumentList { public ArgumentList_4(Parser yyq):base(yyq){}} +public class ArgumentDeclarationList_4 : ArgumentDeclarationList { + public ArgumentDeclarationList_4(Parser yyq):base(yyq){}} + public class ArgumentDeclarationList_5 : ArgumentDeclarationList { public ArgumentDeclarationList_5(Parser yyq):base(yyq){}} public yyLSLSyntax @@ -1978,10 +2399,10 @@ public yyLSLSyntax 0,103,0,114,0, 97,0,109,0,82, 0,111,0,111,0, -116,0,1,96,1, -2,104,18,1,2717, +116,0,1,97,1, +2,104,18,1,2845, 102,2,0,105,5, -320,1,0,106,18, +395,1,0,106,18, 1,0,0,2,0, 1,1,107,18,1, 1,108,20,109,4, @@ -2042,12 +2463,12 @@ public yyLSLSyntax 121,0,112,0,101, 0,110,0,97,0, 109,0,101,0,1, -106,1,2,2,0, +124,1,2,2,0, 1,9,131,18,1, 9,132,20,133,4, 10,73,0,68,0, 69,0,78,0,84, -0,1,92,1,1, +0,1,93,1,1, 2,0,1,10,134, 18,1,10,135,20, 136,4,20,76,0, @@ -2071,7 +2492,7 @@ public yyLSLSyntax 105,0,111,0,110, 0,76,0,105,0, 115,0,116,0,1, -104,1,2,2,0, +112,1,2,2,0, 1,21,142,18,1, 21,143,20,144,4, 10,67,0,79,0, @@ -2086,222 +2507,310 @@ public yyLSLSyntax 0,97,0,116,0, 101,0,109,0,101, 0,110,0,116,0, -1,122,1,2,2, +1,147,1,2,2, 0,1,1695,148,18, 1,1695,143,2,0, -1,30,149,18,1, -30,150,20,151,4, -22,68,0,101,0, -99,0,108,0,97, -0,114,0,97,0, -116,0,105,0,111, -0,110,0,1,105, +1,2811,149,18,1, +2811,150,20,151,4, +18,83,0,69,0, +77,0,73,0,67, +0,79,0,76,0, +79,0,78,0,1, +11,1,1,2,0, +1,2645,152,18,1, +2645,153,20,154,4, +32,73,0,110,0, +116,0,65,0,114, +0,103,0,83,0, +116,0,97,0,116, +0,101,0,69,0, +118,0,101,0,110, +0,116,0,1,107, 1,2,2,0,1, -31,152,18,1,31, -153,20,154,4,22, -82,0,73,0,71, -0,72,0,84,0, -95,0,80,0,65, -0,82,0,69,0, -78,0,1,17,1, -1,2,0,1,32, -155,18,1,32,156, -20,157,4,20,76, -0,69,0,70,0, -84,0,95,0,66, -0,82,0,65,0, -67,0,69,0,1, -12,1,1,2,0, -1,1114,158,18,1, -1114,132,2,0,1, -1152,159,18,1,1152, -160,20,161,4,32, -83,0,105,0,109, -0,112,0,108,0, -101,0,65,0,115, -0,115,0,105,0, -103,0,110,0,109, +2646,155,18,1,2646, +156,20,157,4,32, +75,0,101,0,121, +0,65,0,114,0, +103,0,83,0,116, +0,97,0,116,0, +101,0,69,0,118, 0,101,0,110,0, -116,0,1,113,1, -2,2,0,1,1117, -162,18,1,1117,163, -20,164,4,28,80, -0,69,0,82,0, -67,0,69,0,78, +116,0,1,106,1, +2,2,0,1,30, +158,18,1,30,159, +20,160,4,22,68, +0,101,0,99,0, +108,0,97,0,114, +0,97,0,116,0, +105,0,111,0,110, +0,1,119,1,2, +2,0,1,31,161, +18,1,31,162,20, +163,4,22,82,0, +73,0,71,0,72, 0,84,0,95,0, -69,0,81,0,85, -0,65,0,76,0, -83,0,1,10,1, -1,2,0,1,40, -165,18,1,40,132, -2,0,1,41,166, -18,1,41,135,2, -0,1,42,167,18, -1,42,168,20,169, -4,20,69,0,120, -0,112,0,114,0, -101,0,115,0,115, -0,105,0,111,0, -110,0,1,131,1, -2,2,0,1,43, -170,18,1,43,171, -20,172,4,22,82, -0,73,0,71,0, -72,0,84,0,95, -0,83,0,72,0, -73,0,70,0,84, -0,1,41,1,1, -2,0,1,44,173, -18,1,44,132,2, -0,1,1159,174,18, -1,1159,168,2,0, -1,46,175,18,1, -46,176,20,177,4, -12,80,0,69,0, -82,0,73,0,79, -0,68,0,1,24, -1,1,2,0,1, -47,178,18,1,47, -132,2,0,1,48, -179,18,1,48,180, -20,181,4,18,68, -0,69,0,67,0, -82,0,69,0,77, +80,0,65,0,82, 0,69,0,78,0, -84,0,1,5,1, -1,2,0,1,49, -182,18,1,49,183, -20,184,4,18,73, -0,78,0,67,0, -82,0,69,0,77, +1,17,1,1,2, +0,1,32,164,18, +1,32,165,20,166, +4,20,76,0,69, +0,70,0,84,0, +95,0,66,0,82, +0,65,0,67,0, +69,0,1,12,1, +1,2,0,1,2650, +167,18,1,2650,168, +20,169,4,44,75, +0,101,0,121,0, +73,0,110,0,116, +0,73,0,110,0, +116,0,65,0,114, +0,103,0,83,0, +116,0,97,0,116, +0,101,0,69,0, +118,0,101,0,110, +0,116,0,1,111, +1,2,2,0,1, +2651,170,18,1,2651, +171,20,172,4,44, +73,0,110,0,116, +0,86,0,101,0, +99,0,86,0,101, +0,99,0,65,0, +114,0,103,0,83, +0,116,0,97,0, +116,0,101,0,69, +0,118,0,101,0, +110,0,116,0,1, +110,1,2,2,0, +1,1114,173,18,1, +1114,132,2,0,1, +2654,174,18,1,2654, +153,2,0,1,1152, +175,18,1,1152,176, +20,177,4,32,83, +0,105,0,109,0, +112,0,108,0,101, +0,65,0,115,0, +115,0,105,0,103, +0,110,0,109,0, +101,0,110,0,116, +0,1,138,1,2, +2,0,1,1117,178, +18,1,1117,179,20, +180,4,28,80,0, +69,0,82,0,67, 0,69,0,78,0, -84,0,1,4,1, -1,2,0,1,50, -185,18,1,50,180, -2,0,1,51,186, -18,1,51,183,2, -0,1,52,187,18, -1,52,135,2,0, -1,2281,188,18,1, -2281,160,2,0,1, -1730,189,18,1,1730, -160,2,0,1,1731, -190,18,1,1731,191, -20,192,4,18,83, +84,0,95,0,69, +0,81,0,85,0, +65,0,76,0,83, +0,1,10,1,1, +2,0,1,40,181, +18,1,40,132,2, +0,1,41,182,18, +1,41,135,2,0, +1,42,183,18,1, +42,184,20,185,4, +20,69,0,120,0, +112,0,114,0,101, +0,115,0,115,0, +105,0,111,0,110, +0,1,156,1,2, +2,0,1,43,186, +18,1,43,187,20, +188,4,22,82,0, +73,0,71,0,72, +0,84,0,95,0, +83,0,72,0,73, +0,70,0,84,0, +1,41,1,1,2, +0,1,44,189,18, +1,44,132,2,0, +1,1159,190,18,1, +1159,184,2,0,1, +46,191,18,1,46, +192,20,193,4,12, +80,0,69,0,82, +0,73,0,79,0, +68,0,1,24,1, +1,2,0,1,47, +194,18,1,47,132, +2,0,1,48,195, +18,1,48,196,20, +197,4,18,68,0, +69,0,67,0,82, 0,69,0,77,0, -73,0,67,0,79, -0,76,0,79,0, -78,0,1,11,1, -1,2,0,1,61, -193,18,1,61,129, -2,0,1,62,194, -18,1,62,153,2, -0,1,63,195,18, -1,63,132,2,0, -1,65,196,18,1, -65,176,2,0,1, -66,197,18,1,66, -132,2,0,1,67, -198,18,1,67,180, -2,0,1,68,199, -18,1,68,183,2, -0,1,69,200,18, -1,69,180,2,0, -1,70,201,18,1, -70,183,2,0,1, -71,202,18,1,71, -135,2,0,1,73, -203,18,1,73,168, -2,0,1,74,204, -18,1,74,153,2, -0,1,1189,205,18, -1,1189,206,20,207, -4,22,83,0,84, -0,65,0,82,0, -95,0,69,0,81, -0,85,0,65,0, -76,0,83,0,1, -8,1,1,2,0, -1,76,208,18,1, -76,209,20,210,4, -20,76,0,69,0, -70,0,84,0,95, -0,83,0,72,0, -73,0,70,0,84, -0,1,40,1,1, -2,0,1,1153,211, -18,1,1153,212,20, -213,4,24,83,0, -76,0,65,0,83, -0,72,0,95,0, -69,0,81,0,85, -0,65,0,76,0, -83,0,1,9,1, -1,2,0,1,79, -214,18,1,79,215, -20,216,4,10,84, -0,73,0,76,0, -68,0,69,0,1, -36,1,1,2,0, -1,1195,217,18,1, -1195,168,2,0,1, -82,218,18,1,82, -168,2,0,1,1123, -219,18,1,1123,168, -2,0,1,85,220, -18,1,85,221,20, -222,4,26,83,0, -84,0,82,0,79, -0,75,0,69,0, -95,0,83,0,84, +69,0,78,0,84, +0,1,5,1,1, +2,0,1,49,198, +18,1,49,199,20, +200,4,18,73,0, +78,0,67,0,82, +0,69,0,77,0, +69,0,78,0,84, +0,1,4,1,1, +2,0,1,50,201, +18,1,50,196,2, +0,1,51,202,18, +1,51,199,2,0, +1,52,203,18,1, +52,135,2,0,1, +2281,204,18,1,2281, +176,2,0,1,2841, +205,18,1,2841,206, +20,207,4,48,71, +0,108,0,111,0, +98,0,97,0,108, +0,70,0,117,0, +110,0,99,0,116, +0,105,0,111,0, +110,0,68,0,101, +0,102,0,105,0, +110,0,105,0,116, +0,105,0,111,0, +110,0,1,100,1, +2,2,0,1,2842, +208,18,1,2842,209, +20,210,4,50,71, +0,108,0,111,0, +98,0,97,0,108, +0,86,0,97,0, +114,0,105,0,97, +0,98,0,108,0, +101,0,68,0,101, +0,99,0,108,0, +97,0,114,0,97, +0,116,0,105,0, +111,0,110,0,1, +99,1,2,2,0, +1,2755,211,18,1, +2755,212,20,213,4, +22,82,0,73,0, +71,0,72,0,84, +0,95,0,66,0, +82,0,65,0,67, +0,69,0,1,13, +1,1,2,0,1, +1730,214,18,1,1730, +176,2,0,1,1731, +215,18,1,1731,150, +2,0,1,61,216, +18,1,61,129,2, +0,1,62,217,18, +1,62,162,2,0, +1,63,218,18,1, +63,132,2,0,1, +65,219,18,1,65, +192,2,0,1,66, +220,18,1,66,132, +2,0,1,67,221, +18,1,67,196,2, +0,1,68,222,18, +1,68,199,2,0, +1,69,223,18,1, +69,196,2,0,1, +70,224,18,1,70, +199,2,0,1,71, +225,18,1,71,135, +2,0,1,73,226, +18,1,73,184,2, +0,1,74,227,18, +1,74,162,2,0, +1,1189,228,18,1, +1189,229,20,230,4, +22,83,0,84,0, +65,0,82,0,95, +0,69,0,81,0, +85,0,65,0,76, +0,83,0,1,8, +1,1,2,0,1, +76,231,18,1,76, +232,20,233,4,20, +76,0,69,0,70, +0,84,0,95,0, +83,0,72,0,73, +0,70,0,84,0, +1,40,1,1,2, +0,1,1153,234,18, +1,1153,235,20,236, +4,24,83,0,76, +0,65,0,83,0, +72,0,95,0,69, +0,81,0,85,0, +65,0,76,0,83, +0,1,9,1,1, +2,0,1,79,237, +18,1,79,238,20, +239,4,10,84,0, +73,0,76,0,68, +0,69,0,1,36, +1,1,2,0,1, +1195,240,18,1,1195, +184,2,0,1,82, +241,18,1,82,184, +2,0,1,1123,242, +18,1,1123,184,2, +0,1,85,243,18, +1,85,244,20,245, +4,26,83,0,84, 0,82,0,79,0, -75,0,69,0,1, -39,1,1,2,0, -1,89,223,18,1, -89,224,20,225,4, -10,77,0,73,0, -78,0,85,0,83, -0,1,19,1,1, -2,0,1,2318,226, -18,1,2318,191,2, -0,1,93,227,18, -1,93,168,2,0, -1,97,228,18,1, -97,229,20,230,4, -14,65,0,77,0, -80,0,95,0,65, +75,0,69,0,95, +0,83,0,84,0, +82,0,79,0,75, +0,69,0,1,39, +1,1,2,0,1, +2547,246,18,1,2547, +247,20,248,4,28, +82,0,111,0,116, +0,68,0,101,0, +99,0,108,0,97, +0,114,0,97,0, +116,0,105,0,111, +0,110,0,1,123, +1,2,2,0,1, +89,249,18,1,89, +250,20,251,4,10, +77,0,73,0,78, +0,85,0,83,0, +1,19,1,1,2, +0,1,2318,252,18, +1,2318,150,2,0, +1,93,253,18,1, +93,184,2,0,1, +2792,254,18,1,2792, +184,2,0,1,97, +255,18,1,97,256, +20,257,4,14,65, 0,77,0,80,0, -1,38,1,1,2, -0,1,102,231,18, -1,102,232,20,233, -4,22,69,0,88, -0,67,0,76,0, -65,0,77,0,65, -0,84,0,73,0, -79,0,78,0,1, -37,1,1,2,0, -1,1775,234,18,1, -1775,153,2,0,1, -2718,235,18,1,2718, -236,23,237,4,6, -69,0,79,0,70, -0,1,2,1,6, -2,0,1,107,238, -18,1,107,168,2, -0,1,2337,239,18, -1,2337,153,2,0, -1,1224,240,18,1, -1224,160,2,0,1, -1225,241,18,1,1225, -242,20,243,4,24, +95,0,65,0,77, +0,80,0,1,38, +1,1,2,0,1, +102,258,18,1,102, +259,20,260,4,22, +69,0,88,0,67, +0,76,0,65,0, +77,0,65,0,84, +0,73,0,79,0, +78,0,1,37,1, +1,2,0,1,1775, +261,18,1,1775,162, +2,0,1,107,262, +18,1,107,184,2, +0,1,2337,263,18, +1,2337,162,2,0, +1,1224,264,18,1, +1224,176,2,0,1, +1225,265,18,1,1225, +266,20,267,4,24, 77,0,73,0,78, 0,85,0,83,0, 95,0,69,0,81, 0,85,0,65,0, 76,0,83,0,1, 7,1,1,2,0, -1,112,244,18,1, -112,245,20,246,4, +1,112,268,18,1, +112,269,20,270,4, 28,71,0,82,0, 69,0,65,0,84, 0,69,0,82,0, @@ -2309,576 +2818,496 @@ public yyLSLSyntax 0,85,0,65,0, 76,0,83,0,1, 32,1,1,2,0, -1,1188,247,18,1, -1188,160,2,0,1, -1231,248,18,1,1231, -168,2,0,1,118, -249,18,1,118,168, -2,0,1,1737,250, -18,1,1737,168,2, -0,1,124,251,18, -1,124,252,20,253, +1,1188,271,18,1, +1188,176,2,0,1, +1231,272,18,1,1231, +184,2,0,1,118, +273,18,1,118,184, +2,0,1,1737,274, +18,1,1737,184,2, +0,1,124,275,18, +1,124,276,20,277, 4,22,76,0,69, 0,83,0,83,0, 95,0,69,0,81, 0,85,0,65,0, 76,0,83,0,1, 31,1,1,2,0, -1,2657,254,18,1, -2657,150,2,0,1, -2658,255,18,1,2658, -256,20,257,4,12, -69,0,81,0,85, -0,65,0,76,0, -83,0,1,15,1, -1,2,0,1,130, -258,18,1,130,168, -2,0,1,1803,259, -18,1,1803,260,20, -261,4,18,83,0, +1,2657,278,18,1, +2657,279,20,280,4, +20,83,0,116,0, +97,0,116,0,101, +0,69,0,118,0, +101,0,110,0,116, +0,1,104,1,2, +2,0,1,2658,281, +18,1,2658,282,20, +283,4,26,68,0, +69,0,70,0,65, +0,85,0,76,0, +84,0,95,0,83, +0,84,0,65,0, +84,0,69,0,1, +47,1,1,2,0, +1,2659,284,18,1, +2659,165,2,0,1, +130,285,18,1,130, +184,2,0,1,2843, +286,18,1,2843,206, +2,0,1,1803,287, +18,1,1803,288,20, +289,4,18,83,0, 116,0,97,0,116, 0,101,0,109,0, 101,0,110,0,116, -0,1,110,1,2, -2,0,1,1804,262, -18,1,1804,263,20, -264,4,4,68,0, +0,1,135,1,2, +2,0,1,1804,290, +18,1,1804,291,20, +292,4,4,68,0, 79,0,1,44,1, -1,2,0,1,2364, -265,18,1,2364,260, -2,0,1,137,266, -18,1,137,267,20, -268,4,36,69,0, -88,0,67,0,76, -0,65,0,77,0, -65,0,84,0,73, -0,79,0,78,0, +1,2,0,1,2591, +293,18,1,2591,140, +2,0,1,2364,294, +18,1,2364,288,2, +0,1,137,295,18, +1,137,296,20,297, +4,36,69,0,88, +0,67,0,76,0, +65,0,77,0,65, +0,84,0,73,0, +79,0,78,0,95, +0,69,0,81,0, +85,0,65,0,76, +0,83,0,1,30, +1,1,2,0,1, +2293,298,18,1,2293, +150,2,0,1,2834, +299,18,1,2834,300, +20,301,4,12,83, +0,116,0,97,0, +116,0,101,0,115, +0,1,101,1,2, +2,0,1,1701,302, +18,1,1701,184,2, +0,1,1756,303,18, +1,1756,150,2,0, +1,2527,304,18,1, +2527,114,2,0,1, +143,305,18,1,143, +184,2,0,1,2299, +306,18,1,2299,184, +2,0,1,1260,307, +18,1,1260,176,2, +0,1,1261,308,18, +1,1261,309,20,310, +4,22,80,0,76, +0,85,0,83,0, 95,0,69,0,81, 0,85,0,65,0, 76,0,83,0,1, -30,1,1,2,0, -1,2293,269,18,1, -2293,191,2,0,1, -1701,270,18,1,1701, -168,2,0,1,1756, -271,18,1,1756,191, -2,0,1,143,272, -18,1,143,168,2, -0,1,2299,273,18, -1,2299,168,2,0, -1,1260,274,18,1, -1260,160,2,0,1, -1261,275,18,1,1261, -276,20,277,4,22, -80,0,76,0,85, -0,83,0,95,0, -69,0,81,0,85, -0,65,0,76,0, -83,0,1,6,1, -1,2,0,1,151, -278,18,1,151,279, -20,280,4,26,69, -0,81,0,85,0, -65,0,76,0,83, -0,95,0,69,0, -81,0,85,0,65, -0,76,0,83,0, -1,29,1,1,2, -0,1,1267,281,18, -1,1267,168,2,0, -1,157,282,18,1, -157,168,2,0,1, -1773,283,18,1,1773, +6,1,1,2,0, +1,2528,311,18,1, +2528,132,2,0,1, +2844,312,18,1,2844, +209,2,0,1,2845, +104,1,151,313,18, +1,151,314,20,315, +4,26,69,0,81, +0,85,0,65,0, +76,0,83,0,95, +0,69,0,81,0, +85,0,65,0,76, +0,83,0,1,29, +1,1,2,0,1, +1267,316,18,1,1267, +184,2,0,1,157, +317,18,1,157,184, +2,0,1,2767,318, +18,1,2767,319,20, +320,4,10,83,0, +116,0,97,0,116, +0,101,0,1,102, +1,2,2,0,1, +1773,321,18,1,1773, 146,2,0,1,1832, -284,18,1,1832,260, -2,0,1,1833,285, -18,1,1833,286,20, -287,4,10,87,0, +322,18,1,1832,288, +2,0,1,1833,323, +18,1,1833,324,20, +325,4,10,87,0, 72,0,73,0,76, 0,69,0,1,45, 1,1,2,0,1, -1834,288,18,1,1834, +1834,326,18,1,1834, 135,2,0,1,166, -289,18,1,166,290, -20,291,4,20,76, +327,18,1,166,328, +20,329,4,20,76, 0,69,0,70,0, 84,0,95,0,65, 0,78,0,71,0, 76,0,69,0,1, 25,1,1,2,0, -1,1840,292,18,1, -1840,168,2,0,1, -172,293,18,1,172, -168,2,0,1,2706, -294,18,1,2706,295, -20,296,4,12,83, -0,116,0,97,0, -116,0,101,0,115, -0,1,100,1,2, -2,0,1,2335,297, -18,1,2335,146,2, -0,1,1296,298,18, -1,1296,160,2,0, -1,1297,299,18,1, -1297,256,2,0,1, -2413,300,18,1,2413, -301,20,302,4,26, -83,0,116,0,97, -0,116,0,101,0, -109,0,101,0,110, -0,116,0,76,0, -105,0,115,0,116, -0,1,109,1,2, -2,0,1,1859,303, -18,1,1859,153,2, -0,1,1860,304,18, -1,1860,191,2,0, -1,188,305,18,1, -188,168,2,0,1, -182,306,18,1,182, -307,20,308,4,22, -82,0,73,0,71, -0,72,0,84,0, -95,0,65,0,78, -0,71,0,76,0, -69,0,1,26,1, -1,2,0,1,199, -309,18,1,199,310, -20,311,4,10,67, -0,65,0,82,0, -69,0,84,0,1, -35,1,1,2,0, -1,1871,312,18,1, -1871,160,2,0,1, -1872,313,18,1,1872, -153,2,0,1,1873, -314,18,1,1873,191, -2,0,1,1875,315, -18,1,1875,286,2, -0,1,205,316,18, -1,205,168,2,0, -1,2515,317,18,1, -2515,140,2,0,1, -1882,318,18,1,1882, -168,2,0,1,2227, -319,18,1,2227,260, -2,0,1,217,320, -18,1,217,321,20, -322,4,12,83,0, +1,1840,330,18,1, +1840,184,2,0,1, +2779,331,18,1,2779, +140,2,0,1,172, +332,18,1,172,184, +2,0,1,2785,333, +18,1,2785,159,2, +0,1,2786,334,18, +1,2786,335,20,336, +4,12,69,0,81, +0,85,0,65,0, +76,0,83,0,1, +15,1,1,2,0, +1,2335,337,18,1, +2335,146,2,0,1, +1296,338,18,1,1296, +176,2,0,1,1297, +339,18,1,1297,335, +2,0,1,2413,340, +18,1,2413,341,20, +342,4,26,83,0, +116,0,97,0,116, +0,101,0,109,0, +101,0,110,0,116, +0,76,0,105,0, +115,0,116,0,1, +134,1,2,2,0, +1,1859,343,18,1, +1859,162,2,0,1, +1860,344,18,1,1860, +150,2,0,1,188, +345,18,1,188,184, +2,0,1,182,346, +18,1,182,347,20, +348,4,22,82,0, +73,0,71,0,72, +0,84,0,95,0, +65,0,78,0,71, +0,76,0,69,0, +1,26,1,1,2, +0,1,199,349,18, +1,199,350,20,351, +4,10,67,0,65, +0,82,0,69,0, +84,0,1,35,1, +1,2,0,1,1871, +352,18,1,1871,176, +2,0,1,1872,353, +18,1,1872,162,2, +0,1,1873,354,18, +1,1873,150,2,0, +1,1875,355,18,1, +1875,324,2,0,1, +205,356,18,1,205, +184,2,0,1,2581, +357,18,1,2581,358, +20,359,4,10,69, +0,118,0,101,0, +110,0,116,0,1, +125,1,2,2,0, +1,2515,360,18,1, +2515,143,2,0,1, +1882,361,18,1,1882, +184,2,0,1,2227, +362,18,1,2227,288, +2,0,1,217,363, +18,1,217,364,20, +365,4,12,83,0, 84,0,82,0,79, 0,75,0,69,0, 1,34,1,1,2, -0,1,1332,323,18, -1,1332,160,2,0, -1,1335,324,18,1, -1335,163,2,0,1, -223,325,18,1,223, -168,2,0,1,1341, -326,18,1,1341,168, -2,0,1,1901,327, -18,1,1901,153,2, -0,1,1303,328,18, -1,1303,168,2,0, -1,2462,329,18,1, -2462,260,2,0,1, -236,330,18,1,236, -331,20,332,4,6, -65,0,77,0,80, -0,1,33,1,1, -2,0,1,2466,333, -18,1,2466,334,20, -335,4,34,67,0, -111,0,109,0,112, -0,111,0,117,0, -110,0,100,0,83, -0,116,0,97,0, -116,0,101,0,109, -0,101,0,110,0, -116,0,1,108,1, -2,2,0,1,2467, -336,18,1,2467,150, -2,0,1,2468,337, -18,1,2468,338,20, -339,4,10,83,0, -84,0,65,0,84, -0,69,0,1,48, -1,1,2,0,1, -2469,340,18,1,2469, -132,2,0,1,242, -341,18,1,242,168, -2,0,1,2471,342, -18,1,2471,343,20, -344,4,36,72,0, -84,0,84,0,80, -0,95,0,82,0, -69,0,81,0,85, -0,69,0,83,0, +0,1,1332,366,18, +1,1332,176,2,0, +1,1335,367,18,1, +1335,179,2,0,1, +223,368,18,1,223, +184,2,0,1,2846, +369,18,1,2846,370, +23,371,4,6,69, +0,79,0,70,0, +1,2,1,6,2, +0,1,1341,372,18, +1,1341,184,2,0, +1,1901,373,18,1, +1901,162,2,0,1, +1303,374,18,1,1303, +184,2,0,1,2462, +375,18,1,2462,288, +2,0,1,236,376, +18,1,236,377,20, +378,4,6,65,0, +77,0,80,0,1, +33,1,1,2,0, +1,2466,379,18,1, +2466,380,20,381,4, +34,67,0,111,0, +109,0,112,0,111, +0,117,0,110,0, +100,0,83,0,116, +0,97,0,116,0, +101,0,109,0,101, +0,110,0,116,0, +1,133,1,2,2, +0,1,2467,382,18, +1,2467,159,2,0, +1,2468,383,18,1, +2468,384,20,385,4, +10,83,0,84,0, +65,0,84,0,69, +0,1,48,1,1, +2,0,1,2469,386, +18,1,2469,132,2, +0,1,242,387,18, +1,242,184,2,0, +1,2471,388,18,1, +2471,389,20,390,4, +26,67,0,79,0, +78,0,84,0,82, +0,79,0,76,0, +95,0,69,0,86, +0,69,0,78,0, +84,0,1,65,1, +1,2,0,1,2472, +391,18,1,2472,392, +20,393,4,30,65, +0,84,0,95,0, +84,0,65,0,82, +0,71,0,69,0, 84,0,95,0,69, 0,86,0,69,0, 78,0,84,0,1, -91,1,1,2,0, -1,2472,345,18,1, -2472,346,20,347,4, -34,84,0,79,0, -85,0,67,0,72, -0,95,0,83,0, -84,0,65,0,82, +59,1,1,2,0, +1,2473,394,18,1, +2473,395,20,396,4, +38,65,0,84,0, +95,0,82,0,79, 0,84,0,95,0, -69,0,86,0,69, -0,78,0,84,0, -1,89,1,1,2, -0,1,2473,348,18, -1,2473,349,20,350, -4,30,84,0,79, -0,85,0,67,0, -72,0,95,0,69, -0,78,0,68,0, -95,0,69,0,86, -0,69,0,78,0, -84,0,1,90,1, -1,2,0,1,2474, -351,18,1,2474,352, -20,353,4,22,84, -0,79,0,85,0, -67,0,72,0,95, -0,69,0,86,0, -69,0,78,0,84, -0,1,88,1,1, -2,0,1,2475,354, -18,1,2475,355,20, -356,4,22,84,0, -73,0,77,0,69, -0,82,0,95,0, -69,0,86,0,69, -0,78,0,84,0, -1,87,1,1,2, -0,1,2476,357,18, -1,2476,358,20,359, -4,32,83,0,84, -0,65,0,84,0, -69,0,95,0,69, -0,88,0,73,0, +84,0,65,0,82, +0,71,0,69,0, 84,0,95,0,69, 0,86,0,69,0, 78,0,84,0,1, -86,1,1,2,0, -1,2477,360,18,1, -2477,361,20,362,4, -34,83,0,84,0, -65,0,84,0,69, +58,1,1,2,0, +1,2474,397,18,1, +2474,398,20,399,4, +52,76,0,65,0, +78,0,68,0,95, +0,67,0,79,0, +76,0,76,0,73, +0,83,0,73,0, +79,0,78,0,95, +0,83,0,84,0, +65,0,82,0,84, 0,95,0,69,0, -78,0,84,0,82, -0,89,0,95,0, +86,0,69,0,78, +0,84,0,1,71, +1,1,2,0,1, +2475,400,18,1,2475, +401,20,402,4,48, +76,0,65,0,78, +0,68,0,95,0, +67,0,79,0,76, +0,76,0,73,0, +83,0,73,0,79, +0,78,0,95,0, +69,0,78,0,68, +0,95,0,69,0, +86,0,69,0,78, +0,84,0,1,70, +1,1,2,0,1, +2476,403,18,1,2476, +404,20,405,4,40, +76,0,65,0,78, +0,68,0,95,0, +67,0,79,0,76, +0,76,0,73,0, +83,0,73,0,79, +0,78,0,95,0, 69,0,86,0,69, 0,78,0,84,0, -1,85,1,1,2, -0,1,2478,363,18, -1,2478,364,20,365, -4,24,83,0,69, -0,78,0,83,0, -79,0,82,0,95, -0,69,0,86,0, -69,0,78,0,84, -0,1,84,1,1, -2,0,1,2479,366, -18,1,2479,367,20, -368,4,52,82,0, -85,0,78,0,95, -0,84,0,73,0, -77,0,69,0,95, -0,80,0,69,0, -82,0,77,0,73, -0,83,0,83,0, -73,0,79,0,78, -0,83,0,95,0, -69,0,86,0,69, -0,78,0,84,0, -1,83,1,1,2, -0,1,2480,369,18, -1,2480,370,20,371, -4,34,82,0,69, -0,77,0,79,0, -84,0,69,0,95, -0,68,0,65,0, -84,0,65,0,95, +1,69,1,1,2, +0,1,2477,406,18, +1,2477,407,20,408, +4,34,84,0,79, +0,85,0,67,0, +72,0,95,0,83, +0,84,0,65,0, +82,0,84,0,95, 0,69,0,86,0, 69,0,78,0,84, -0,1,82,1,1, -2,0,1,2481,372, -18,1,2481,373,20, -374,4,24,79,0, -78,0,95,0,82, -0,69,0,90,0, +0,1,89,1,1, +2,0,1,2478,409, +18,1,2478,410,20, +411,4,30,84,0, +79,0,85,0,67, +0,72,0,95,0, +69,0,78,0,68, +0,95,0,69,0, +86,0,69,0,78, +0,84,0,1,90, +1,1,2,0,1, +2479,412,18,1,2479, +413,20,414,4,22, +84,0,79,0,85, +0,67,0,72,0, 95,0,69,0,86, 0,69,0,78,0, -84,0,1,81,1, -1,2,0,1,2482, -375,18,1,2482,376, -20,377,4,32,79, -0,66,0,74,0, -69,0,67,0,84, -0,95,0,82,0, -69,0,90,0,95, -0,69,0,86,0, -69,0,78,0,84, -0,1,80,1,1, -2,0,1,2483,378, -18,1,2483,379,20, -380,4,38,78,0, -79,0,84,0,95, -0,65,0,84,0, -95,0,84,0,65, -0,82,0,71,0, -69,0,84,0,95, -0,69,0,86,0, -69,0,78,0,84, -0,1,79,1,1, -2,0,1,256,381, -18,1,256,382,20, -383,4,14,80,0, -69,0,82,0,67, +84,0,1,88,1, +1,2,0,1,2480, +415,18,1,2480,416, +20,417,4,24,83, 0,69,0,78,0, -84,0,1,22,1, -1,2,0,1,1371, -384,18,1,1371,212, -2,0,1,2486,385, -18,1,2486,386,20, -387,4,36,77,0, -79,0,86,0,73, -0,78,0,71,0, -95,0,83,0,84, -0,65,0,82,0, -84,0,95,0,69, -0,86,0,69,0, -78,0,84,0,1, -76,1,1,2,0, -1,2487,388,18,1, -2487,389,20,390,4, -32,77,0,79,0, -86,0,73,0,78, -0,71,0,95,0, -69,0,78,0,68, +83,0,79,0,82, 0,95,0,69,0, 86,0,69,0,78, -0,84,0,1,75, -1,1,2,0,1, -1931,391,18,1,1931, -260,2,0,1,1932, -392,18,1,1932,393, -20,394,4,4,73, -0,70,0,1,42, +0,84,0,1,84, 1,1,2,0,1, -262,395,18,1,262, -168,2,0,1,1377, -396,18,1,1377,168, -2,0,1,2492,397, -18,1,2492,398,20, -399,4,48,76,0, -65,0,78,0,68, -0,95,0,67,0, -79,0,76,0,76, +2481,418,18,1,2481, +419,20,420,4,52, +82,0,85,0,78, +0,95,0,84,0, +73,0,77,0,69, +0,95,0,80,0, +69,0,82,0,77, 0,73,0,83,0, -73,0,79,0,78, +83,0,73,0,79, +0,78,0,83,0, +95,0,69,0,86, +0,69,0,78,0, +84,0,1,83,1, +1,2,0,1,2482, +421,18,1,2482,422, +20,423,4,24,79, +0,78,0,95,0, +82,0,69,0,90, 0,95,0,69,0, -78,0,68,0,95, -0,69,0,86,0, -69,0,78,0,84, -0,1,70,1,1, -2,0,1,1876,400, -18,1,1876,135,2, -0,1,2494,401,18, -1,2494,402,20,403, -4,38,72,0,84, -0,84,0,80,0, -95,0,82,0,69, -0,83,0,80,0, -79,0,78,0,83, -0,69,0,95,0, -69,0,86,0,69, -0,78,0,84,0, -1,68,1,1,2, -0,1,2495,404,18, -1,2495,405,20,406, -4,22,69,0,77, -0,65,0,73,0, -76,0,95,0,69, -0,86,0,69,0, -78,0,84,0,1, -67,1,1,2,0, -1,1939,407,18,1, -1939,168,2,0,1, -2497,408,18,1,2497, -409,20,410,4,26, -67,0,79,0,78, -0,84,0,82,0, -79,0,76,0,95, -0,69,0,86,0, -69,0,78,0,84, -0,1,65,1,1, -2,0,1,827,411, -18,1,827,168,2, -0,1,2499,412,18, -1,2499,413,20,414, -4,38,67,0,79, -0,76,0,76,0, -73,0,83,0,73, -0,79,0,78,0, -95,0,69,0,78, -0,68,0,95,0, -69,0,86,0,69, -0,78,0,84,0, -1,63,1,1,2, -0,1,2500,415,18, -1,2500,416,20,417, -4,30,67,0,79, -0,76,0,76,0, -73,0,83,0,73, -0,79,0,78,0, +86,0,69,0,78, +0,84,0,1,81, +1,1,2,0,1, +2483,424,18,1,2483, +425,20,426,4,42, +67,0,79,0,76, +0,76,0,73,0, +83,0,73,0,79, +0,78,0,95,0, +83,0,84,0,65, +0,82,0,84,0, 95,0,69,0,86, 0,69,0,78,0, -84,0,1,62,1, -1,2,0,1,2501, -418,18,1,2501,419, -20,420,4,26,67, +84,0,1,64,1, +1,2,0,1,256, +427,18,1,256,428, +20,429,4,14,80, +0,69,0,82,0, +67,0,69,0,78, +0,84,0,1,22, +1,1,2,0,1, +1371,430,18,1,1371, +235,2,0,1,2486, +431,18,1,2486,432, +20,433,4,26,67, 0,72,0,65,0, 78,0,71,0,69, 0,68,0,95,0, 69,0,86,0,69, 0,78,0,84,0, 1,61,1,1,2, -0,1,2502,421,18, -1,2502,422,20,423, -4,24,65,0,84, +0,1,2487,434,18, +1,2487,435,20,436, +4,32,79,0,66, +0,74,0,69,0, +67,0,84,0,95, +0,82,0,69,0, +90,0,95,0,69, +0,86,0,69,0, +78,0,84,0,1, +80,1,1,2,0, +1,1931,437,18,1, +1931,288,2,0,1, +1932,438,18,1,1932, +439,20,440,4,4, +73,0,70,0,1, +42,1,1,2,0, +1,262,441,18,1, +262,184,2,0,1, +1377,442,18,1,1377, +184,2,0,1,2492, +443,18,1,2492,444, +20,445,4,30,78, +0,79,0,95,0, +83,0,69,0,78, +0,83,0,79,0, +82,0,95,0,69, +0,86,0,69,0, +78,0,84,0,1, +77,1,1,2,0, +1,1876,446,18,1, +1876,135,2,0,1, +2494,447,18,1,2494, +448,20,449,4,32, +77,0,79,0,86, +0,73,0,78,0, +71,0,95,0,69, +0,78,0,68,0, +95,0,69,0,86, +0,69,0,78,0, +84,0,1,75,1, +1,2,0,1,2495, +450,18,1,2495,451, +20,452,4,32,83, 0,84,0,65,0, -67,0,72,0,95, +84,0,69,0,95, +0,69,0,88,0, +73,0,84,0,95, 0,69,0,86,0, 69,0,78,0,84, -0,1,60,1,1, -2,0,1,2503,424, -18,1,2503,425,20, -426,4,30,65,0, -84,0,95,0,84, -0,65,0,82,0, -71,0,69,0,84, -0,95,0,69,0, -86,0,69,0,78, -0,84,0,1,59, -1,1,2,0,1, -2504,427,18,1,2504, -428,20,429,4,38, -65,0,84,0,95, -0,82,0,79,0, -84,0,95,0,84, -0,65,0,82,0, -71,0,69,0,84, -0,95,0,69,0, -86,0,69,0,78, -0,84,0,1,58, -1,1,2,0,1, -277,430,18,1,277, -431,20,432,4,10, -83,0,76,0,65, -0,83,0,72,0, -1,21,1,1,2, -0,1,2506,433,18, -1,2506,135,2,0, -1,283,434,18,1, -283,168,2,0,1, -1958,435,18,1,1958, -153,2,0,1,2517, -436,18,1,2517,153, -2,0,1,2519,437, -18,1,2519,334,2, -0,1,1406,438,18, -1,1406,160,2,0, -1,1407,439,18,1, -1407,206,2,0,1, -299,440,18,1,299, -441,20,442,4,8, -83,0,84,0,65, -0,82,0,1,20, -1,1,2,0,1, -1370,443,18,1,1370, -160,2,0,1,305, -444,18,1,305,168, -2,0,1,2458,445, -18,1,2458,260,2, -0,1,2459,446,18, -1,2459,447,20,448, -4,22,82,0,73, -0,71,0,72,0, -84,0,95,0,66, -0,82,0,65,0, -67,0,69,0,1, -13,1,1,2,0, -1,2464,449,18,1, -2464,447,2,0,1, -1989,450,18,1,1989, -260,2,0,1,1990, -451,18,1,1990,452, -20,453,4,8,69, -0,76,0,83,0, -69,0,1,43,1, -1,2,0,1,2470, -454,18,1,2470,156, -2,0,1,322,455, -18,1,322,224,2, -0,1,1933,456,18, -1,1933,135,2,0, -1,883,457,18,1, -883,168,2,0,1, -328,458,18,1,328, -168,2,0,1,1443, -459,18,1,1443,242, -2,0,1,2558,460, -18,1,2558,447,2, -0,1,2559,461,18, -1,2559,462,20,463, -4,20,83,0,116, -0,97,0,116,0, -101,0,69,0,118, -0,101,0,110,0, -116,0,1,103,1, -2,2,0,1,2560, -464,18,1,2560,465, -20,466,4,26,68, -0,69,0,70,0, -65,0,85,0,76, +0,1,86,1,1, +2,0,1,1939,453, +18,1,1939,184,2, +0,1,2497,454,18, +1,2497,455,20,456, +4,48,84,0,82, +0,65,0,78,0, +83,0,65,0,67, +0,84,0,73,0, +79,0,78,0,95, +0,82,0,69,0, +83,0,85,0,76, 0,84,0,95,0, -83,0,84,0,65, -0,84,0,69,0, -1,47,1,1,2, -0,1,2561,467,18, -1,2561,156,2,0, -1,1449,468,18,1, -1449,168,2,0,1, -2485,469,18,1,2485, -470,20,471,4,30, -78,0,79,0,95, -0,83,0,69,0, -78,0,83,0,79, -0,82,0,95,0, 69,0,86,0,69, 0,78,0,84,0, -1,77,1,1,2, -0,1,2488,472,18, -1,2488,473,20,474, +1,92,1,1,2, +0,1,827,457,18, +1,827,184,2,0, +1,2499,458,18,1, +2499,459,20,460,4, +34,82,0,69,0, +77,0,79,0,84, +0,69,0,95,0, +68,0,65,0,84, +0,65,0,95,0, +69,0,86,0,69, +0,78,0,84,0, +1,82,1,1,2, +0,1,2500,461,18, +1,2500,462,20,463, 4,22,77,0,79, 0,78,0,69,0, 89,0,95,0,69, 0,86,0,69,0, 78,0,84,0,1, 74,1,1,2,0, -1,2489,475,18,1, -2489,476,20,477,4, +1,2501,464,18,1, +2501,465,20,466,4, 24,76,0,73,0, 83,0,84,0,69, 0,78,0,95,0, 69,0,86,0,69, 0,78,0,84,0, 1,73,1,1,2, -0,1,2490,478,18, -1,2490,479,20,480, +0,1,2502,467,18, +1,2502,468,20,469, 4,36,76,0,73, 0,78,0,75,0, 95,0,77,0,69, @@ -2888,746 +3317,1109 @@ public yyLSLSyntax 86,0,69,0,78, 0,84,0,1,72, 1,1,2,0,1, -2491,481,18,1,2491, -482,20,483,4,52, -76,0,65,0,78, -0,68,0,95,0, -67,0,79,0,76, -0,76,0,73,0, -83,0,73,0,79, -0,78,0,95,0, -83,0,84,0,65, -0,82,0,84,0, -95,0,69,0,86, -0,69,0,78,0, -84,0,1,71,1, -1,2,0,1,2493, -484,18,1,2493,485, -20,486,4,40,76, -0,65,0,78,0, -68,0,95,0,67, -0,79,0,76,0, -76,0,73,0,83, -0,73,0,79,0, -78,0,95,0,69, -0,86,0,69,0, -78,0,84,0,1, -69,1,1,2,0, -1,1413,487,18,1, -1413,168,2,0,1, -346,488,18,1,346, -489,20,490,4,8, -80,0,76,0,85, -0,83,0,1,18, -1,1,2,0,1, -2496,491,18,1,2496, -492,20,493,4,32, -68,0,65,0,84, -0,65,0,83,0, -69,0,82,0,86, -0,69,0,82,0, -95,0,69,0,86, -0,69,0,78,0, -84,0,1,66,1, -1,2,0,1,2021, -494,18,1,2021,260, -2,0,1,2022,495, -18,1,2022,338,2, -0,1,352,496,18, -1,352,168,2,0, -1,2024,497,18,1, -2024,132,2,0,1, -2025,498,18,1,2025, -499,20,500,4,8, -74,0,85,0,77, -0,80,0,1,49, -1,1,2,0,1, -2026,501,18,1,2026, -132,2,0,1,2027, -502,18,1,2027,503, -20,504,4,4,65, -0,84,0,1,23, -1,1,2,0,1, -2028,505,18,1,2028, -132,2,0,1,2029, -506,18,1,2029,334, -2,0,1,2030,507, -18,1,2030,508,20, -509,4,14,70,0, -111,0,114,0,76, -0,111,0,111,0, -112,0,1,121,1, -2,2,0,1,2031, -510,18,1,2031,511, -20,512,4,32,68, -0,111,0,87,0, -104,0,105,0,108, -0,101,0,83,0, -116,0,97,0,116, -0,101,0,109,0, -101,0,110,0,116, -0,1,120,1,2, -2,0,1,2032,513, -18,1,2032,514,20, -515,4,28,87,0, -104,0,105,0,108, -0,101,0,83,0, -116,0,97,0,116, -0,101,0,109,0, -101,0,110,0,116, -0,1,119,1,2, -2,0,1,2033,516, -18,1,2033,517,20, -518,4,22,73,0, -102,0,83,0,116, -0,97,0,116,0, -101,0,109,0,101, -0,110,0,116,0, -1,118,1,2,2, -0,1,2034,519,18, -1,2034,520,20,521, -4,22,83,0,116, -0,97,0,116,0, -101,0,67,0,104, -0,97,0,110,0, -103,0,101,0,1, -117,1,2,2,0, -1,1478,522,18,1, -1478,160,2,0,1, -1479,523,18,1,1479, -276,2,0,1,2037, -524,18,1,2037,191, -2,0,1,2038,525, -18,1,2038,526,20, -527,4,18,74,0, -117,0,109,0,112, -0,76,0,97,0, -98,0,101,0,108, -0,1,115,1,2, -2,0,1,2039,528, -18,1,2039,191,2, -0,1,2040,529,18, -1,2040,530,20,531, -4,30,82,0,101, -0,116,0,117,0, -114,0,110,0,83, -0,116,0,97,0, -116,0,101,0,109, -0,101,0,110,0, -116,0,1,114,1, -2,2,0,1,2041, -532,18,1,2041,191, -2,0,1,1485,533, -18,1,1485,168,2, -0,1,372,534,18, -1,372,180,2,0, -1,373,535,18,1, -373,132,2,0,1, -374,536,18,1,374, -176,2,0,1,375, -537,18,1,375,132, -2,0,1,376,538, -18,1,376,183,2, -0,1,377,539,18, -1,377,132,2,0, -1,378,540,18,1, -378,176,2,0,1, -379,541,18,1,379, -132,2,0,1,380, -542,18,1,380,543, -20,544,4,16,67, -0,111,0,110,0, -115,0,116,0,97, -0,110,0,116,0, -1,127,1,2,2, -0,1,381,545,18, -1,381,290,2,0, -1,371,546,18,1, -371,547,20,548,4, -24,70,0,117,0, -110,0,99,0,116, -0,105,0,111,0, -110,0,67,0,97, -0,108,0,108,0, -1,123,1,2,2, -0,1,942,549,18, -1,942,168,2,0, -1,387,550,18,1, -387,168,2,0,1, -1514,551,18,1,1514, -160,2,0,1,1515, -552,18,1,1515,256, -2,0,1,2074,553, -18,1,2074,160,2, -0,1,2075,554,18, -1,2075,153,2,0, -1,406,555,18,1, -406,143,2,0,1, -1521,556,18,1,1521, -168,2,0,1,2636, -557,18,1,2636,295, -2,0,1,2557,558, -18,1,2557,462,2, -0,1,2639,559,18, -1,2639,560,20,561, -4,10,83,0,116, -0,97,0,116,0, -101,0,1,101,1, -2,2,0,1,412, -562,18,1,412,168, -2,0,1,2641,563, -18,1,2641,132,2, -0,1,2484,564,18, -1,2484,565,20,566, -4,46,78,0,79, -0,84,0,95,0, -65,0,84,0,95, -0,82,0,79,0, -84,0,95,0,84, -0,65,0,82,0, -71,0,69,0,84, +2503,470,18,1,2503, +471,20,472,4,38, +72,0,84,0,84, +0,80,0,95,0, +82,0,69,0,83, +0,80,0,79,0, +78,0,83,0,69, 0,95,0,69,0, 86,0,69,0,78, -0,84,0,1,78, +0,84,0,1,68, 1,1,2,0,1, -2023,567,18,1,2023, -465,2,0,1,1442, -568,18,1,1442,160, -2,0,1,2651,569, -18,1,2651,140,2, -0,1,2653,570,18, -1,2653,153,2,0, -1,2655,571,18,1, -2655,334,2,0,1, -2035,572,18,1,2035, -191,2,0,1,2036, -573,18,1,2036,574, -20,575,4,26,74, -0,117,0,109,0, -112,0,83,0,116, -0,97,0,116,0, -101,0,109,0,101, -0,110,0,116,0, -1,116,1,2,2, -0,1,431,576,18, -1,431,143,2,0, -1,2105,577,18,1, -2105,260,2,0,1, -2106,578,18,1,2106, -452,2,0,1,1550, -579,18,1,1550,160, -2,0,1,437,580, -18,1,437,168,2, -0,1,2044,581,18, -1,2044,582,20,583, -4,28,69,0,109, -0,112,0,116,0, -121,0,83,0,116, -0,97,0,116,0, -101,0,109,0,101, +2504,473,18,1,2504, +474,20,475,4,22, +69,0,77,0,65, +0,73,0,76,0, +95,0,69,0,86, +0,69,0,78,0, +84,0,1,67,1, +1,2,0,1,277, +476,18,1,277,477, +20,478,4,10,83, +0,76,0,65,0, +83,0,72,0,1, +21,1,1,2,0, +1,2506,479,18,1, +2506,480,20,481,4, +34,75,0,101,0, +121,0,73,0,110, +0,116,0,73,0, +110,0,116,0,65, +0,114,0,103,0, +69,0,118,0,101, 0,110,0,116,0, -1,111,1,2,2, -0,1,2045,584,18, -1,2045,191,2,0, -1,1555,585,18,1, -1555,168,2,0,1, -1001,586,18,1,1001, -547,2,0,1,1002, -587,18,1,1002,543, -2,0,1,447,588, -18,1,447,307,2, -0,1,2597,589,18, -1,2597,590,20,591, -4,18,83,0,116, -0,97,0,116,0, -101,0,66,0,111, -0,100,0,121,0, -1,102,1,2,2, -0,1,1010,592,18, -1,1010,160,2,0, -1,1011,593,18,1, -1011,153,2,0,1, -1012,594,18,1,1012, -168,2,0,1,1013, -595,18,1,1013,153, -2,0,1,459,596, -18,1,459,597,20, -598,4,24,76,0, -69,0,70,0,84, -0,95,0,66,0, -82,0,65,0,67, -0,75,0,69,0, -84,0,1,27,1, -1,2,0,1,1574, -599,18,1,1574,191, -2,0,1,461,600, -18,1,461,601,20, -602,4,24,65,0, -114,0,103,0,117, -0,109,0,101,0, -110,0,116,0,76, -0,105,0,115,0, -116,0,1,124,1, -2,2,0,1,462, -603,18,1,462,143, -2,0,1,464,604, -18,1,464,605,20, -606,4,16,65,0, -114,0,103,0,117, -0,109,0,101,0, -110,0,116,0,1, -125,1,2,2,0, -1,2136,607,18,1, -2136,260,2,0,1, -2694,608,18,1,2694, -191,2,0,1,2695, -609,18,1,2695,610, -20,611,4,34,71, -0,108,0,111,0, -98,0,97,0,108, -0,68,0,101,0, -102,0,105,0,110, -0,105,0,116,0, -105,0,111,0,110, -0,115,0,1,97, -1,2,2,0,1, -1585,612,18,1,1585, -613,20,614,4,12, -82,0,69,0,84, -0,85,0,82,0, -78,0,1,50,1, -1,2,0,1,476, -615,18,1,476,616, -20,617,4,30,83, -0,84,0,82,0, -73,0,78,0,71, -0,95,0,67,0, -79,0,78,0,83, -0,84,0,65,0, -78,0,84,0,1, -3,1,1,2,0, -1,477,618,18,1, -477,619,20,620,4, -28,70,0,76,0, -79,0,65,0,84, -0,95,0,67,0, -79,0,78,0,83, -0,84,0,65,0, -78,0,84,0,1, -95,1,1,2,0, -1,478,621,18,1, -478,622,20,623,4, -40,72,0,69,0, -88,0,95,0,73, -0,78,0,84,0, -69,0,71,0,69, -0,82,0,95,0, -67,0,79,0,78, -0,83,0,84,0, -65,0,78,0,84, -0,1,94,1,1, -2,0,1,479,624, -18,1,479,625,20, -626,4,32,73,0, -78,0,84,0,69, -0,71,0,69,0, -82,0,95,0,67, -0,79,0,78,0, -83,0,84,0,65, -0,78,0,84,0, -1,93,1,1,2, -0,1,480,627,18, -1,480,628,20,629, -4,26,82,0,73, -0,71,0,72,0, -84,0,95,0,66, -0,82,0,65,0, -67,0,75,0,69, -0,84,0,1,28, -1,1,2,0,1, -481,630,18,1,481, -605,2,0,1,2713, -631,18,1,2713,632, -20,633,4,48,71, -0,108,0,111,0, -98,0,97,0,108, -0,70,0,117,0, -110,0,99,0,116, -0,105,0,111,0, -110,0,68,0,101, -0,102,0,105,0, -110,0,105,0,116, +1,132,1,2,2, +0,1,2507,482,18, +1,2507,135,2,0, +1,2508,483,18,1, +2508,117,2,0,1, +2509,484,18,1,2509, +132,2,0,1,2510, +485,18,1,2510,486, +20,487,4,28,75, +0,101,0,121,0, +68,0,101,0,99, +0,108,0,97,0, +114,0,97,0,116, 0,105,0,111,0, -110,0,1,99,1, -2,2,0,1,2714, -634,18,1,2714,635, -20,636,4,50,71, -0,108,0,111,0, -98,0,97,0,108, -0,86,0,97,0, -114,0,105,0,97, -0,98,0,108,0, -101,0,68,0,101, +110,0,1,120,1, +2,2,0,1,283, +488,18,1,283,184, +2,0,1,2512,489, +18,1,2512,126,2, +0,1,2513,490,18, +1,2513,132,2,0, +1,2514,491,18,1, +2514,492,20,493,4, +28,73,0,110,0, +116,0,68,0,101, 0,99,0,108,0, 97,0,114,0,97, 0,116,0,105,0, 111,0,110,0,1, -98,1,2,2,0, -1,2715,637,18,1, -2715,632,2,0,1, -2716,638,18,1,2716, -635,2,0,1,2717, -104,1,2634,639,18, -1,2634,447,2,0, -1,1048,640,18,1, -1048,168,2,0,1, -2640,641,18,1,2640, -560,2,0,1,2642, -642,18,1,2642,135, -2,0,1,2042,643, -18,1,2042,644,20, -645,4,20,65,0, -115,0,115,0,105, -0,103,0,110,0, +121,1,2,2,0, +1,1958,494,18,1, +1958,162,2,0,1, +2517,495,18,1,2517, +492,2,0,1,2518, +496,18,1,2518,497, +20,498,4,64,75, +0,101,0,121,0, +73,0,110,0,116, +0,73,0,110,0, +116,0,65,0,114, +0,103,0,117,0, 109,0,101,0,110, -0,116,0,1,112, -1,2,2,0,1, -2043,646,18,1,2043, -191,2,0,1,1620, -647,18,1,1620,160, -2,0,1,1621,648, -18,1,1621,150,2, -0,1,1622,649,18, -1,1622,256,2,0, -1,509,650,18,1, -509,143,2,0,1, -2498,651,18,1,2498, -652,20,653,4,42, -67,0,79,0,76, -0,76,0,73,0, -83,0,73,0,79, -0,78,0,95,0, +0,116,0,68,0, +101,0,99,0,108, +0,97,0,114,0, +97,0,116,0,105, +0,111,0,110,0, +76,0,105,0,115, +0,116,0,1,118, +1,2,2,0,1, +2519,499,18,1,2519, +162,2,0,1,1406, +500,18,1,1406,176, +2,0,1,1407,501, +18,1,1407,229,2, +0,1,2522,502,18, +1,2522,503,20,504, +4,34,73,0,110, +0,116,0,86,0, +101,0,99,0,86, +0,101,0,99,0, +65,0,114,0,103, +0,69,0,118,0, +101,0,110,0,116, +0,1,131,1,2, +2,0,1,2523,505, +18,1,2523,135,2, +0,1,2525,506,18, +1,2525,492,2,0, +1,2526,507,18,1, +2526,143,2,0,1, +299,508,18,1,299, +509,20,510,4,8, 83,0,84,0,65, -0,82,0,84,0, +0,82,0,1,20, +1,1,2,0,1, +1370,511,18,1,1370, +176,2,0,1,2529, +512,18,1,2529,513, +20,514,4,28,86, +0,101,0,99,0, +68,0,101,0,99, +0,108,0,97,0, +114,0,97,0,116, +0,105,0,111,0, +110,0,1,122,1, +2,2,0,1,2530, +515,18,1,2530,143, +2,0,1,2532,516, +18,1,2532,513,2, +0,1,305,517,18, +1,305,184,2,0, +1,2534,518,18,1, +2534,162,2,0,1, +2822,519,18,1,2822, +150,2,0,1,2458, +520,18,1,2458,288, +2,0,1,2459,521, +18,1,2459,212,2, +0,1,2538,522,18, +1,2538,135,2,0, +1,2540,523,18,1, +2540,492,2,0,1, +2541,524,18,1,2541, +143,2,0,1,2542, +525,18,1,2542,111, +2,0,1,2464,526, +18,1,2464,212,2, +0,1,2544,527,18, +1,2544,247,2,0, +1,2545,528,18,1, +2545,143,2,0,1, +1989,529,18,1,1989, +288,2,0,1,1990, +530,18,1,1990,531, +20,532,4,8,69, +0,76,0,83,0, +69,0,1,43,1, +1,2,0,1,2548, +533,18,1,2548,534, +20,535,4,64,73, +0,110,0,116,0, +82,0,111,0,116, +0,82,0,111,0, +116,0,65,0,114, +0,103,0,117,0, +109,0,101,0,110, +0,116,0,68,0, +101,0,99,0,108, +0,97,0,114,0, +97,0,116,0,105, +0,111,0,110,0, +76,0,105,0,115, +0,116,0,1,116, +1,2,2,0,1, +2470,536,18,1,2470, +165,2,0,1,322, +537,18,1,322,250, +2,0,1,2551,538, +18,1,2551,380,2, +0,1,1933,539,18, +1,1933,135,2,0, +1,2553,540,18,1, +2553,135,2,0,1, +883,541,18,1,883, +184,2,0,1,2555, +542,18,1,2555,513, +2,0,1,328,543, +18,1,328,184,2, +0,1,1443,544,18, +1,1443,266,2,0, +1,2559,545,18,1, +2559,380,2,0,1, +2560,546,18,1,2560, +547,20,548,4,22, +73,0,110,0,116, +0,65,0,114,0, +103,0,69,0,118, +0,101,0,110,0, +116,0,1,128,1, +2,2,0,1,2561, +549,18,1,2561,135, +2,0,1,1449,550, +18,1,1449,184,2, +0,1,2485,551,18, +1,2485,552,20,553, +4,30,67,0,79, +0,76,0,76,0, +73,0,83,0,73, +0,79,0,78,0, 95,0,69,0,86, 0,69,0,78,0, -84,0,1,64,1, -1,2,0,1,1628, -654,18,1,1628,168, -2,0,1,515,655, -18,1,515,168,2, -0,1,2505,656,18, -1,2505,657,20,658, -4,10,69,0,118, +84,0,1,62,1, +1,2,0,1,2565, +554,18,1,2565,162, +2,0,1,2488,555, +18,1,2488,556,20, +557,4,24,65,0, +84,0,84,0,65, +0,67,0,72,0, +95,0,69,0,86, +0,69,0,78,0, +84,0,1,60,1, +1,2,0,1,2489, +558,18,1,2489,559, +20,560,4,22,84, +0,73,0,77,0, +69,0,82,0,95, +0,69,0,86,0, +69,0,78,0,84, +0,1,87,1,1, +2,0,1,2490,561, +18,1,2490,562,20, +563,4,38,78,0, +79,0,84,0,95, +0,65,0,84,0, +95,0,84,0,65, +0,82,0,71,0, +69,0,84,0,95, +0,69,0,86,0, +69,0,78,0,84, +0,1,79,1,1, +2,0,1,2491,564, +18,1,2491,565,20, +566,4,46,78,0, +79,0,84,0,95, +0,65,0,84,0, +95,0,82,0,79, +0,84,0,95,0, +84,0,65,0,82, +0,71,0,69,0, +84,0,95,0,69, +0,86,0,69,0, +78,0,84,0,1, +78,1,1,2,0, +1,2571,567,18,1, +2571,486,2,0,1, +2493,568,18,1,2493, +569,20,570,4,36, +77,0,79,0,86, +0,73,0,78,0, +71,0,95,0,83, +0,84,0,65,0, +82,0,84,0,95, +0,69,0,86,0, +69,0,78,0,84, +0,1,76,1,1, +2,0,1,1413,571, +18,1,1413,184,2, +0,1,346,572,18, +1,346,573,20,574, +4,8,80,0,76, +0,85,0,83,0, +1,18,1,1,2, +0,1,2575,575,18, +1,2575,380,2,0, +1,2496,576,18,1, +2496,577,20,578,4, +34,83,0,84,0, +65,0,84,0,69, +0,95,0,69,0, +78,0,84,0,82, +0,89,0,95,0, +69,0,86,0,69, +0,78,0,84,0, +1,85,1,1,2, +0,1,2577,579,18, +1,2577,135,2,0, +1,2021,580,18,1, +2021,288,2,0,1, +2022,581,18,1,2022, +384,2,0,1,352, +582,18,1,352,184, +2,0,1,2024,583, +18,1,2024,132,2, +0,1,2025,584,18, +1,2025,585,20,586, +4,8,74,0,85, +0,77,0,80,0, +1,49,1,1,2, +0,1,2026,587,18, +1,2026,132,2,0, +1,2027,588,18,1, +2027,589,20,590,4, +4,65,0,84,0, +1,23,1,1,2, +0,1,2028,591,18, +1,2028,132,2,0, +1,2029,592,18,1, +2029,380,2,0,1, +2030,593,18,1,2030, +594,20,595,4,14, +70,0,111,0,114, +0,76,0,111,0, +111,0,112,0,1, +146,1,2,2,0, +1,2031,596,18,1, +2031,597,20,598,4, +32,68,0,111,0, +87,0,104,0,105, +0,108,0,101,0, +83,0,116,0,97, +0,116,0,101,0, +109,0,101,0,110, +0,116,0,1,145, +1,2,2,0,1, +2032,599,18,1,2032, +600,20,601,4,28, +87,0,104,0,105, +0,108,0,101,0, +83,0,116,0,97, +0,116,0,101,0, +109,0,101,0,110, +0,116,0,1,144, +1,2,2,0,1, +2033,602,18,1,2033, +603,20,604,4,22, +73,0,102,0,83, +0,116,0,97,0, +116,0,101,0,109, +0,101,0,110,0, +116,0,1,143,1, +2,2,0,1,2034, +605,18,1,2034,606, +20,607,4,22,83, +0,116,0,97,0, +116,0,101,0,67, +0,104,0,97,0, +110,0,103,0,101, +0,1,142,1,2, +2,0,1,1478,608, +18,1,1478,176,2, +0,1,1479,609,18, +1,1479,309,2,0, +1,2037,610,18,1, +2037,150,2,0,1, +2038,611,18,1,2038, +612,20,613,4,18, +74,0,117,0,109, +0,112,0,76,0, +97,0,98,0,101, +0,108,0,1,140, +1,2,2,0,1, +2039,614,18,1,2039, +150,2,0,1,2040, +615,18,1,2040,616, +20,617,4,30,82, +0,101,0,116,0, +117,0,114,0,110, +0,83,0,116,0, +97,0,116,0,101, +0,109,0,101,0, +110,0,116,0,1, +139,1,2,2,0, +1,2041,618,18,1, +2041,150,2,0,1, +1485,619,18,1,1485, +184,2,0,1,372, +620,18,1,372,196, +2,0,1,373,621, +18,1,373,132,2, +0,1,374,622,18, +1,374,192,2,0, +1,375,623,18,1, +375,132,2,0,1, +376,624,18,1,376, +199,2,0,1,377, +625,18,1,377,132, +2,0,1,378,626, +18,1,378,192,2, +0,1,379,627,18, +1,379,132,2,0, +1,380,628,18,1, +380,629,20,630,4, +16,67,0,111,0, +110,0,115,0,116, +0,97,0,110,0, +116,0,1,152,1, +2,2,0,1,381, +631,18,1,381,328, +2,0,1,371,632, +18,1,371,633,20, +634,4,24,70,0, +117,0,110,0,99, +0,116,0,105,0, +111,0,110,0,67, +0,97,0,108,0, +108,0,1,148,1, +2,2,0,1,942, +635,18,1,942,184, +2,0,1,2533,636, +18,1,2533,637,20, +638,4,64,73,0, +110,0,116,0,86, +0,101,0,99,0, +86,0,101,0,99, +0,65,0,114,0, +103,0,117,0,109, 0,101,0,110,0, -116,0,1,107,1, -2,2,0,1,2664, -659,18,1,2664,168, -2,0,1,525,660, -18,1,525,307,2, -0,1,2197,661,18, -1,2197,160,2,0, -1,2198,662,18,1, -2198,153,2,0,1, -1591,663,18,1,1591, -168,2,0,1,2521, -664,18,1,2521,590, -2,0,1,1094,665, -18,1,1094,601,2, -0,1,1096,666,18, -1,1096,153,2,0, -1,2683,667,18,1, -2683,191,2,0,1, -1657,668,18,1,1657, -191,2,0,1,1658, -669,18,1,1658,670, -20,671,4,6,70, -0,79,0,82,0, -1,46,1,1,2, -0,1,1659,672,18, -1,1659,135,2,0, -1,1665,673,18,1, -1665,168,2,0,1, -1113,674,18,1,1113, -176,2,0,675,5, -0,676,5,324,1, -2,677,19,237,1, -2,678,5,6,1, -2706,679,17,680,15, -681,4,30,37,0, +116,0,68,0,101, +0,99,0,108,0, +97,0,114,0,97, +0,116,0,105,0, +111,0,110,0,76, +0,105,0,115,0, +116,0,1,117,1, +2,2,0,1,387, +639,18,1,387,184, +2,0,1,2536,640, +18,1,2536,380,2, +0,1,2537,641,18, +1,2537,642,20,643, +4,34,73,0,110, +0,116,0,82,0, +111,0,116,0,82, +0,111,0,116,0, +65,0,114,0,103, +0,69,0,118,0, +101,0,110,0,116, +0,1,130,1,2, +2,0,1,2543,644, +18,1,2543,132,2, +0,1,2823,645,18, +1,2823,646,20,647, +4,34,71,0,108, +0,111,0,98,0, +97,0,108,0,68, +0,101,0,102,0, +105,0,110,0,105, +0,116,0,105,0, +111,0,110,0,115, +0,1,98,1,2, +2,0,1,1514,648, +18,1,1514,176,2, +0,1,1515,649,18, +1,1515,335,2,0, +1,2549,650,18,1, +2549,162,2,0,1, +2074,651,18,1,2074, +176,2,0,1,2075, +652,18,1,2075,162, +2,0,1,2552,653, +18,1,2552,654,20, +655,4,28,86,0, +101,0,99,0,116, +0,111,0,114,0, +65,0,114,0,103, +0,69,0,118,0, +101,0,110,0,116, +0,1,129,1,2, +2,0,1,406,656, +18,1,406,143,2, +0,1,1521,657,18, +1,1521,184,2,0, +1,2556,658,18,1, +2556,659,20,660,4, +58,86,0,101,0, +99,0,116,0,111, +0,114,0,65,0, +114,0,103,0,117, +0,109,0,101,0, +110,0,116,0,68, +0,101,0,99,0, +108,0,97,0,114, +0,97,0,116,0, +105,0,111,0,110, +0,76,0,105,0, +115,0,116,0,1, +115,1,2,2,0, +1,2557,661,18,1, +2557,162,2,0,1, +412,662,18,1,412, +184,2,0,1,2641, +663,18,1,2641,168, +2,0,1,2484,664, +18,1,2484,665,20, +666,4,38,67,0, +79,0,76,0,76, +0,73,0,83,0, +73,0,79,0,78, +0,95,0,69,0, +78,0,68,0,95, +0,69,0,86,0, +69,0,78,0,84, +0,1,63,1,1, +2,0,1,2643,667, +18,1,2643,668,20, +669,4,44,73,0, +110,0,116,0,82, +0,111,0,116,0, +82,0,111,0,116, +0,65,0,114,0, +103,0,83,0,116, +0,97,0,116,0, +101,0,69,0,118, +0,101,0,110,0, +116,0,1,109,1, +2,2,0,1,2644, +670,18,1,2644,671, +20,672,4,38,86, +0,101,0,99,0, +116,0,111,0,114, +0,65,0,114,0, +103,0,83,0,116, +0,97,0,116,0, +101,0,69,0,118, +0,101,0,110,0, +116,0,1,108,1, +2,2,0,1,2023, +673,18,1,2023,282, +2,0,1,2564,674, +18,1,2564,675,20, +676,4,52,73,0, +110,0,116,0,65, +0,114,0,103,0, +117,0,109,0,101, +0,110,0,116,0, +68,0,101,0,99, +0,108,0,97,0, +114,0,97,0,116, +0,105,0,111,0, +110,0,76,0,105, +0,115,0,116,0, +1,114,1,2,2, +0,1,2647,677,18, +1,2647,678,20,679, +4,34,86,0,111, +0,105,0,100,0, +65,0,114,0,103, +0,83,0,116,0, +97,0,116,0,101, +0,69,0,118,0, +101,0,110,0,116, +0,1,105,1,2, +2,0,1,2648,680, +18,1,2648,279,2, +0,1,2567,681,18, +1,2567,380,2,0, +1,1442,682,18,1, +1442,176,2,0,1, +2569,683,18,1,2569, +135,2,0,1,2652, +684,18,1,2652,668, +2,0,1,2653,685, +18,1,2653,671,2, +0,1,2572,686,18, +1,2572,687,20,688, +4,52,75,0,101, +0,121,0,65,0, +114,0,103,0,117, +0,109,0,101,0, +110,0,116,0,68, +0,101,0,99,0, +108,0,97,0,114, +0,97,0,116,0, +105,0,111,0,110, +0,76,0,105,0, +115,0,116,0,1, +113,1,2,2,0, +1,2573,689,18,1, +2573,162,2,0,1, +2656,690,18,1,2656, +678,2,0,1,2035, +691,18,1,2035,150, +2,0,1,2036,692, +18,1,2036,693,20, +694,4,26,74,0, +117,0,109,0,112, +0,83,0,116,0, +97,0,116,0,101, +0,109,0,101,0, +110,0,116,0,1, +141,1,2,2,0, +1,431,695,18,1, +431,143,2,0,1, +2578,696,18,1,2578, +162,2,0,1,2105, +697,18,1,2105,288, +2,0,1,2106,698, +18,1,2106,531,2, +0,1,1550,699,18, +1,1550,176,2,0, +1,437,700,18,1, +437,184,2,0,1, +2044,701,18,1,2044, +702,20,703,4,28, +69,0,109,0,112, +0,116,0,121,0, +83,0,116,0,97, +0,116,0,101,0, +109,0,101,0,110, +0,116,0,1,136, +1,2,2,0,1, +2045,704,18,1,2045, +150,2,0,1,1555, +705,18,1,1555,184, +2,0,1,2511,706, +18,1,2511,143,2, +0,1,1001,707,18, +1,1001,633,2,0, +1,1002,708,18,1, +1002,629,2,0,1, +447,709,18,1,447, +347,2,0,1,2593, +710,18,1,2593,162, +2,0,1,2595,711, +18,1,2595,380,2, +0,1,2597,712,18, +1,2597,713,20,714, +4,18,83,0,116, +0,97,0,116,0, +101,0,66,0,111, +0,100,0,121,0, +1,103,1,2,2, +0,1,1010,715,18, +1,1010,176,2,0, +1,1011,716,18,1, +1011,162,2,0,1, +1012,717,18,1,1012, +184,2,0,1,1013, +718,18,1,1013,162, +2,0,1,459,719, +18,1,459,720,20, +721,4,24,76,0, +69,0,70,0,84, +0,95,0,66,0, +82,0,65,0,67, +0,75,0,69,0, +84,0,1,27,1, +1,2,0,1,1574, +722,18,1,1574,150, +2,0,1,461,723, +18,1,461,724,20, +725,4,24,65,0, +114,0,103,0,117, +0,109,0,101,0, +110,0,116,0,76, +0,105,0,115,0, +116,0,1,149,1, +2,2,0,1,462, +726,18,1,462,143, +2,0,1,464,727, +18,1,464,728,20, +729,4,16,65,0, +114,0,103,0,117, +0,109,0,101,0, +110,0,116,0,1, +150,1,2,2,0, +1,2136,730,18,1, +2136,288,2,0,1, +1585,731,18,1,1585, +732,20,733,4,12, +82,0,69,0,84, +0,85,0,82,0, +78,0,1,50,1, +1,2,0,1,2703, +734,18,1,2703,713, +2,0,1,476,735, +18,1,476,736,20, +737,4,30,83,0, +84,0,82,0,73, +0,78,0,71,0, +95,0,67,0,79, +0,78,0,83,0, +84,0,65,0,78, +0,84,0,1,3, +1,1,2,0,1, +477,738,18,1,477, +739,20,740,4,28, +70,0,76,0,79, +0,65,0,84,0, +95,0,67,0,79, +0,78,0,83,0, +84,0,65,0,78, +0,84,0,1,96, +1,1,2,0,1, +478,741,18,1,478, +742,20,743,4,40, +72,0,69,0,88, +0,95,0,73,0, +78,0,84,0,69, +0,71,0,69,0, +82,0,95,0,67, +0,79,0,78,0, +83,0,84,0,65, +0,78,0,84,0, +1,95,1,1,2, +0,1,479,744,18, +1,479,745,20,746, +4,32,73,0,78, +0,84,0,69,0, +71,0,69,0,82, +0,95,0,67,0, +79,0,78,0,83, +0,84,0,65,0, +78,0,84,0,1, +94,1,1,2,0, +1,480,747,18,1, +480,748,20,749,4, +26,82,0,73,0, +71,0,72,0,84, +0,95,0,66,0, +82,0,65,0,67, +0,75,0,69,0, +84,0,1,28,1, +1,2,0,1,481, +750,18,1,481,728, +2,0,1,1048,751, +18,1,1048,184,2, +0,1,2642,752,18, +1,2642,171,2,0, +1,2563,753,18,1, +2563,492,2,0,1, +2042,754,18,1,2042, +755,20,756,4,20, +65,0,115,0,115, +0,105,0,103,0, +110,0,109,0,101, +0,110,0,116,0, +1,137,1,2,2, +0,1,2043,757,18, +1,2043,150,2,0, +1,2568,758,18,1, +2568,759,20,760,4, +22,75,0,101,0, +121,0,65,0,114, +0,103,0,69,0, +118,0,101,0,110, +0,116,0,1,127, +1,2,2,0,1, +2649,761,18,1,2649, +212,2,0,1,1620, +762,18,1,1620,176, +2,0,1,1621,763, +18,1,1621,159,2, +0,1,1622,764,18, +1,1622,335,2,0, +1,509,765,18,1, +509,143,2,0,1, +2498,766,18,1,2498, +767,20,768,4,36, +72,0,84,0,84, +0,80,0,95,0, +82,0,69,0,81, +0,85,0,69,0, +83,0,84,0,95, +0,69,0,86,0, +69,0,78,0,84, +0,1,91,1,1, +2,0,1,2655,769, +18,1,2655,156,2, +0,1,2576,770,18, +1,2576,771,20,772, +4,24,86,0,111, +0,105,0,100,0, +65,0,114,0,103, +0,69,0,118,0, +101,0,110,0,116, +0,1,126,1,2, +2,0,1,1628,773, +18,1,1628,184,2, +0,1,515,774,18, +1,515,184,2,0, +1,2580,775,18,1, +2580,380,2,0,1, +2505,776,18,1,2505, +777,20,778,4,32, +68,0,65,0,84, +0,65,0,83,0, +69,0,82,0,86, +0,69,0,82,0, +95,0,69,0,86, +0,69,0,78,0, +84,0,1,66,1, +1,2,0,1,2582, +779,18,1,2582,135, +2,0,1,525,780, +18,1,525,347,2, +0,1,2197,781,18, +1,2197,176,2,0, +1,2198,782,18,1, +2198,162,2,0,1, +1591,783,18,1,1591, +184,2,0,1,2521, +784,18,1,2521,380, +2,0,1,2764,785, +18,1,2764,300,2, +0,1,1094,786,18, +1,1094,724,2,0, +1,1096,787,18,1, +1096,162,2,0,1, +2768,788,18,1,2768, +319,2,0,1,2769, +789,18,1,2769,132, +2,0,1,2770,790, +18,1,2770,135,2, +0,1,1657,791,18, +1,1657,150,2,0, +1,1658,792,18,1, +1658,793,20,794,4, +6,70,0,79,0, +82,0,1,46,1, +1,2,0,1,1659, +795,18,1,1659,135, +2,0,1,1665,796, +18,1,1665,184,2, +0,1,2781,797,18, +1,2781,162,2,0, +1,2783,798,18,1, +2783,380,2,0,1, +1113,799,18,1,1113, +192,2,0,800,5, +0,801,5,381,1, +2,802,19,371,1, +2,803,5,6,1, +2764,804,17,805,15, +806,4,30,37,0, 76,0,83,0,76, 0,80,0,114,0, 111,0,103,0,114, 0,97,0,109,0, 82,0,111,0,111, 0,116,0,1,-1, -1,5,682,20,683, +1,5,807,20,808, 4,32,76,0,83, 0,76,0,80,0, 114,0,111,0,103, 0,114,0,97,0, 109,0,82,0,111, 0,111,0,116,0, -95,0,49,0,1, -142,1,3,1,3, -1,2,684,22,1, -1,1,2640,685,17, -686,15,687,4,14, +95,0,50,0,1, +168,1,3,1,2, +1,1,809,22,1, +2,1,2768,810,17, +811,15,812,4,14, 37,0,83,0,116, 0,97,0,116,0, 101,0,115,0,1, --1,1,5,688,20, -689,4,16,83,0, +-1,1,5,813,20, +814,4,16,83,0, 116,0,97,0,116, 0,101,0,115,0, 95,0,49,0,1, -152,1,3,1,2, -1,1,690,22,1, -11,1,2634,691,17, -692,15,693,4,12, +177,1,3,1,2, +1,1,815,22,1, +11,1,2755,816,17, +817,15,818,4,12, 37,0,83,0,116, 0,97,0,116,0, 101,0,1,-1,1, -5,694,20,695,4, +5,819,20,820,4, 14,83,0,116,0, 97,0,116,0,101, 0,95,0,49,0, -1,154,1,3,1, -5,1,4,696,22, -1,13,1,2558,697, -17,698,15,693,1, --1,1,5,699,20, -700,4,14,83,0, +1,179,1,3,1, +5,1,4,821,22, +1,13,1,2767,822, +17,823,15,812,1, +-1,1,5,824,20, +825,4,16,83,0, 116,0,97,0,116, -0,101,0,95,0, -50,0,1,155,1, -3,1,6,1,5, -701,22,1,14,1, -2636,702,17,703,15, -681,1,-1,1,5, -704,20,705,4,32, -76,0,83,0,76, -0,80,0,114,0, -111,0,103,0,114, -0,97,0,109,0, -82,0,111,0,111, -0,116,0,95,0, -50,0,1,143,1, -3,1,2,1,1, -706,22,1,2,1, -2639,707,17,708,15, -687,1,-1,1,5, -709,20,710,4,16, -83,0,116,0,97, -0,116,0,101,0, -115,0,95,0,50, -0,1,153,1,3, -1,3,1,2,711, -22,1,12,1,3, -712,19,617,1,3, -713,5,95,1,256, -714,16,0,615,1, -1261,715,16,0,615, -1,509,716,16,0, -615,1,1515,717,16, -0,615,1,2021,718, -17,719,15,720,4, +0,101,0,115,0, +95,0,50,0,1, +178,1,3,1,3, +1,2,826,22,1, +12,1,2834,827,17, +828,15,806,1,-1, +1,5,829,20,830, +4,32,76,0,83, +0,76,0,80,0, +114,0,111,0,103, +0,114,0,97,0, +109,0,82,0,111, +0,111,0,116,0, +95,0,49,0,1, +167,1,3,1,3, +1,2,831,22,1, +1,1,2649,832,17, +833,15,818,1,-1, +1,5,834,20,835, +4,14,83,0,116, +0,97,0,116,0, +101,0,95,0,50, +0,1,180,1,3, +1,6,1,5,836, +22,1,14,1,3, +837,19,737,1,3, +838,5,95,1,256, +839,16,0,735,1, +1261,840,16,0,735, +1,509,841,16,0, +735,1,1515,842,16, +0,735,1,2021,843, +17,844,15,845,4, 24,37,0,73,0, 102,0,83,0,116, 0,97,0,116,0, 101,0,109,0,101, 0,110,0,116,0, -1,-1,1,5,721, -20,722,4,26,73, +1,-1,1,5,846, +20,847,4,26,73, 0,102,0,83,0, 116,0,97,0,116, 0,101,0,109,0, 101,0,110,0,116, 0,95,0,50,0, -1,185,1,3,1, -8,1,7,723,22, -1,45,1,1775,724, -16,0,615,1,2029, -725,17,726,15,727, +1,241,1,3,1, +8,1,7,848,22, +1,76,1,1775,849, +16,0,735,1,2029, +850,17,851,15,852, 4,20,37,0,83, 0,116,0,97,0, 116,0,101,0,109, 0,101,0,110,0, 116,0,1,-1,1, -5,728,20,729,4, +5,853,20,854,4, 24,83,0,116,0, 97,0,116,0,101, 0,109,0,101,0, 110,0,116,0,95, 0,49,0,51,0, -1,179,1,3,1, -2,1,1,730,22, -1,39,1,2030,731, -17,732,15,727,1, --1,1,5,733,20, -734,4,24,83,0, +1,235,1,3,1, +2,1,1,855,22, +1,70,1,2030,856, +17,857,15,852,1, +-1,1,5,858,20, +859,4,24,83,0, 116,0,97,0,116, 0,101,0,109,0, 101,0,110,0,116, 0,95,0,49,0, -50,0,1,178,1, +50,0,1,234,1, 3,1,2,1,1, -735,22,1,38,1, -2031,736,17,737,15, -727,1,-1,1,5, -738,20,739,4,24, +860,22,1,69,1, +2031,861,17,862,15, +852,1,-1,1,5, +863,20,864,4,24, 83,0,116,0,97, 0,116,0,101,0, 109,0,101,0,110, 0,116,0,95,0, 49,0,49,0,1, -177,1,3,1,2, -1,1,740,22,1, -37,1,2032,741,17, -742,15,727,1,-1, -1,5,743,20,744, +233,1,3,1,2, +1,1,865,22,1, +68,1,2032,866,17, +867,15,852,1,-1, +1,5,868,20,869, 4,24,83,0,116, 0,97,0,116,0, 101,0,109,0,101, 0,110,0,116,0, 95,0,49,0,48, -0,1,176,1,3, -1,2,1,1,745, -22,1,36,1,2033, -746,17,747,15,727, -1,-1,1,5,748, -20,749,4,22,83, +0,1,232,1,3, +1,2,1,1,870, +22,1,67,1,2033, +871,17,872,15,852, +1,-1,1,5,873, +20,874,4,22,83, 0,116,0,97,0, 116,0,101,0,109, 0,101,0,110,0, 116,0,95,0,57, -0,1,175,1,3, -1,2,1,1,750, -22,1,35,1,277, -751,16,0,615,1, -2035,752,17,753,15, -727,1,-1,1,5, -754,20,755,4,22, +0,1,231,1,3, +1,2,1,1,875, +22,1,66,1,277, +876,16,0,735,1, +2035,877,17,878,15, +852,1,-1,1,5, +879,20,880,4,22, 83,0,116,0,97, 0,116,0,101,0, 109,0,101,0,110, 0,116,0,95,0, -56,0,1,174,1, +56,0,1,230,1, 3,1,3,1,2, -756,22,1,34,1, -2037,757,17,758,15, -727,1,-1,1,5, -759,20,760,4,22, +881,22,1,65,1, +2037,882,17,883,15, +852,1,-1,1,5, +884,20,885,4,22, 83,0,116,0,97, 0,116,0,101,0, 109,0,101,0,110, 0,116,0,95,0, -55,0,1,173,1, +55,0,1,229,1, 3,1,3,1,2, -761,22,1,33,1, -2039,762,17,763,15, -727,1,-1,1,5, -764,20,765,4,22, +886,22,1,64,1, +2039,887,17,888,15, +852,1,-1,1,5, +889,20,890,4,22, 83,0,116,0,97, 0,116,0,101,0, 109,0,101,0,110, 0,116,0,95,0, -54,0,1,172,1, +54,0,1,228,1, 3,1,3,1,2, -766,22,1,32,1, -32,767,16,0,615, -1,2041,768,17,769, -15,727,1,-1,1, -5,770,20,771,4, +891,22,1,63,1, +32,892,16,0,735, +1,2041,893,17,894, +15,852,1,-1,1, +5,895,20,896,4, 22,83,0,116,0, 97,0,116,0,101, 0,109,0,101,0, 110,0,116,0,95, -0,53,0,1,171, +0,53,0,1,227, 1,3,1,3,1, -2,772,22,1,31, -1,2293,773,16,0, -615,1,2043,774,17, -775,15,727,1,-1, -1,5,776,20,777, +2,897,22,1,62, +1,2293,898,16,0, +735,1,2043,899,17, +900,15,852,1,-1, +1,5,901,20,902, 4,22,83,0,116, 0,97,0,116,0, 101,0,109,0,101, 0,110,0,116,0, 95,0,51,0,1, -169,1,3,1,3, -1,2,778,22,1, -29,1,2045,779,17, -780,15,727,1,-1, -1,5,781,20,782, +225,1,3,1,3, +1,2,903,22,1, +60,1,2045,904,17, +905,15,852,1,-1, +1,5,906,20,907, 4,22,83,0,116, 0,97,0,116,0, 101,0,109,0,101, 0,110,0,116,0, 95,0,49,0,1, -167,1,3,1,3, -1,2,783,22,1, -27,1,41,784,16, -0,615,1,1297,785, -16,0,615,1,43, -786,16,0,615,1, -1803,787,17,788,15, -789,4,16,37,0, +223,1,3,1,3, +1,2,908,22,1, +58,1,41,909,16, +0,735,1,1297,910, +16,0,735,1,43, +911,16,0,735,1, +1803,912,17,913,15, +914,4,16,37,0, 70,0,111,0,114, 0,76,0,111,0, 111,0,112,0,1, --1,1,5,790,20, -791,4,18,70,0, +-1,1,5,915,20, +916,4,18,70,0, 111,0,114,0,76, 0,111,0,111,0, 112,0,95,0,49, -0,1,192,1,3, -1,10,1,9,792, -22,1,52,1,1804, -793,16,0,615,1, -299,794,16,0,615, -1,52,795,16,0, -615,1,2318,796,16, -0,615,1,62,797, -16,0,615,1,2075, -798,16,0,615,1, -1574,799,17,800,15, -727,1,-1,1,5, -801,20,802,4,22, +0,1,248,1,3, +1,10,1,9,917, +22,1,83,1,1804, +918,16,0,735,1, +299,919,16,0,735, +1,52,920,16,0, +735,1,2318,921,16, +0,735,1,62,922, +16,0,735,1,2075, +923,16,0,735,1, +1574,924,17,925,15, +852,1,-1,1,5, +926,20,927,4,22, 83,0,116,0,97, 0,116,0,101,0, 109,0,101,0,110, 0,116,0,95,0, -52,0,1,170,1, +52,0,1,226,1, 3,1,3,1,2, -803,22,1,30,1, -71,804,16,0,615, -1,76,805,16,0, -615,1,1834,806,16, -0,615,1,2337,807, -16,0,615,1,79, -808,16,0,615,1, -1335,809,16,0,615, -1,322,810,16,0, -615,1,85,811,16, -0,615,1,89,812, -16,0,615,1,346, -813,16,0,615,1, -2105,814,17,815,15, -720,1,-1,1,5, -816,20,817,4,26, +928,22,1,61,1, +71,929,16,0,735, +1,76,930,16,0, +735,1,1834,931,16, +0,735,1,2337,932, +16,0,735,1,79, +933,16,0,735,1, +1335,934,16,0,735, +1,322,935,16,0, +735,1,85,936,16, +0,735,1,89,937, +16,0,735,1,346, +938,16,0,735,1, +2105,939,17,940,15, +845,1,-1,1,5, +941,20,942,4,26, 73,0,102,0,83, 0,116,0,97,0, 116,0,101,0,109, 0,101,0,110,0, 116,0,95,0,51, -0,1,186,1,3, -1,6,1,5,818, -22,1,46,1,2106, -819,16,0,615,1, -97,820,16,0,615, -1,1860,821,17,822, -15,823,4,34,37, +0,1,242,1,3, +1,6,1,5,943, +22,1,77,1,2106, +944,16,0,735,1, +97,945,16,0,735, +1,1860,946,17,947, +15,948,4,34,37, 0,68,0,111,0, 87,0,104,0,105, 0,108,0,101,0, @@ -3635,7 +4427,7 @@ public yyLSLSyntax 0,116,0,101,0, 109,0,101,0,110, 0,116,0,1,-1, -1,5,824,20,825, +1,5,949,20,950, 4,36,68,0,111, 0,87,0,104,0, 105,0,108,0,101, @@ -3643,66 +4435,66 @@ public yyLSLSyntax 97,0,116,0,101, 0,109,0,101,0, 110,0,116,0,95, -0,49,0,1,190, +0,49,0,1,246, 1,3,1,8,1, -7,826,22,1,50, -1,2364,827,17,828, -15,789,1,-1,1, -5,829,20,830,4, +7,951,22,1,81, +1,2364,952,17,953, +15,914,1,-1,1, +5,954,20,955,4, 18,70,0,111,0, 114,0,76,0,111, 0,111,0,112,0, 95,0,50,0,1, -193,1,3,1,9, -1,8,831,22,1, -53,1,102,832,16, -0,615,1,112,833, -16,0,615,1,1117, -834,16,0,615,1, -1873,835,17,836,15, -823,1,-1,1,5, -837,20,838,4,36, -68,0,111,0,87, -0,104,0,105,0, -108,0,101,0,83, -0,116,0,97,0, -116,0,101,0,109, -0,101,0,110,0, -116,0,95,0,50, -0,1,191,1,3, -1,8,1,7,839, -22,1,51,1,1876, -840,16,0,615,1, -124,841,16,0,615, -1,2136,842,17,843, -15,720,1,-1,1, -5,844,20,845,4, -26,73,0,102,0, +249,1,3,1,9, +1,8,956,22,1, +84,1,102,957,16, +0,735,1,112,958, +16,0,735,1,1117, +959,16,0,735,1, +2786,960,16,0,735, +1,1873,961,17,962, +15,948,1,-1,1, +5,963,20,964,4, +36,68,0,111,0, +87,0,104,0,105, +0,108,0,101,0, 83,0,116,0,97, 0,116,0,101,0, 109,0,101,0,110, 0,116,0,95,0, -52,0,1,187,1, +50,0,1,247,1, 3,1,8,1,7, -846,22,1,47,1, -381,847,16,0,615, -1,525,848,16,0, -615,1,137,849,16, -0,615,1,1901,850, -16,0,615,1,2658, -851,16,0,615,1, -1153,852,16,0,615, -1,151,853,16,0, -615,1,1407,854,16, -0,615,1,1659,855, -16,0,615,1,2413, -856,16,0,615,1, -406,857,16,0,615, -1,1371,858,16,0, -615,1,166,859,16, -0,615,1,1622,860, -16,0,615,1,1931, -861,17,862,15,863, +965,22,1,82,1, +1876,966,16,0,735, +1,124,967,16,0, +735,1,2136,968,17, +969,15,845,1,-1, +1,5,970,20,971, +4,26,73,0,102, +0,83,0,116,0, +97,0,116,0,101, +0,109,0,101,0, +110,0,116,0,95, +0,52,0,1,243, +1,3,1,8,1, +7,972,22,1,78, +1,381,973,16,0, +735,1,525,974,16, +0,735,1,137,975, +16,0,735,1,1901, +976,16,0,735,1, +1153,977,16,0,735, +1,151,978,16,0, +735,1,1407,979,16, +0,735,1,1659,980, +16,0,735,1,2413, +981,16,0,735,1, +406,982,16,0,735, +1,1371,983,16,0, +735,1,166,984,16, +0,735,1,1622,985, +16,0,735,1,1931, +986,17,987,15,988, 4,30,37,0,87, 0,104,0,105,0, 108,0,101,0,83, @@ -3710,46 +4502,46 @@ public yyLSLSyntax 116,0,101,0,109, 0,101,0,110,0, 116,0,1,-1,1, -5,864,20,865,4, +5,989,20,990,4, 32,87,0,104,0, 105,0,108,0,101, 0,83,0,116,0, 97,0,116,0,101, 0,109,0,101,0, 110,0,116,0,95, -0,49,0,1,188, +0,49,0,1,244, 1,3,1,6,1, -5,866,22,1,48, -1,1933,867,16,0, -615,1,431,868,16, -0,615,1,1585,869, -16,0,615,1,182, -870,16,0,615,1, -1189,871,16,0,615, -1,1443,872,16,0, -615,1,1695,873,16, -0,615,1,2198,874, -16,0,615,1,447, -875,16,0,615,1, -2458,876,17,877,15, -878,4,28,37,0, +5,991,22,1,79, +1,1933,992,16,0, +735,1,431,993,16, +0,735,1,1585,994, +16,0,735,1,182, +995,16,0,735,1, +1189,996,16,0,735, +1,1443,997,16,0, +735,1,1695,998,16, +0,735,1,2198,999, +16,0,735,1,447, +1000,16,0,735,1, +2458,1001,17,1002,15, +1003,4,28,37,0, 83,0,116,0,97, 0,116,0,101,0, 109,0,101,0,110, 0,116,0,76,0, 105,0,115,0,116, 0,1,-1,1,5, -879,20,880,4,30, +1004,20,1005,4,30, 83,0,116,0,97, 0,116,0,101,0, 109,0,101,0,110, 0,116,0,76,0, 105,0,115,0,116, 0,95,0,50,0, -1,165,1,3,1, -3,1,2,881,22, -1,25,1,2459,882, -17,883,15,884,4, +1,221,1,3,1, +3,1,2,1006,22, +1,56,1,2459,1007, +17,1008,15,1009,4, 36,37,0,67,0, 111,0,109,0,112, 0,111,0,117,0, @@ -3758,7 +4550,7 @@ public yyLSLSyntax 116,0,101,0,109, 0,101,0,110,0, 116,0,1,-1,1, -5,885,20,886,4, +5,1010,20,1011,4, 38,67,0,111,0, 109,0,112,0,111, 0,117,0,110,0, @@ -3767,34 +4559,34 @@ public yyLSLSyntax 101,0,109,0,101, 0,110,0,116,0, 95,0,50,0,1, -163,1,3,1,4, -1,3,887,22,1, -23,1,1958,888,16, -0,615,1,2462,889, -17,890,15,878,1, --1,1,5,891,20, -892,4,30,83,0, +219,1,3,1,4, +1,3,1012,22,1, +54,1,1958,1013,16, +0,735,1,2462,1014, +17,1015,15,1003,1, +-1,1,5,1016,20, +1017,4,30,83,0, 116,0,97,0,116, 0,101,0,109,0, 101,0,110,0,116, 0,76,0,105,0, 115,0,116,0,95, -0,49,0,1,164, +0,49,0,1,220, 1,3,1,2,1, -1,893,22,1,24, -1,1657,894,17,895, -15,727,1,-1,1, -5,896,20,897,4, +1,1018,22,1,55, +1,1657,1019,17,1020, +15,852,1,-1,1, +5,1021,20,1022,4, 22,83,0,116,0, 97,0,116,0,101, 0,109,0,101,0, 110,0,116,0,95, -0,50,0,1,168, +0,50,0,1,224, 1,3,1,3,1, -2,898,22,1,28, -1,2464,899,17,900, -15,884,1,-1,1, -5,901,20,902,4, +2,1023,22,1,59, +1,2464,1024,17,1025, +15,1009,1,-1,1, +5,1026,20,1027,4, 38,67,0,111,0, 109,0,112,0,111, 0,117,0,110,0, @@ -3803,280 +4595,280 @@ public yyLSLSyntax 101,0,109,0,101, 0,110,0,116,0, 95,0,49,0,1, -162,1,3,1,3, -1,2,903,22,1, -22,1,199,904,16, -0,615,1,459,905, -16,0,615,1,462, -906,16,0,615,1, -217,907,16,0,615, -1,2227,908,17,909, -15,863,1,-1,1, -5,910,20,911,4, +218,1,3,1,3, +1,2,1028,22,1, +53,1,199,1029,16, +0,735,1,459,1030, +16,0,735,1,462, +1031,16,0,735,1, +217,1032,16,0,735, +1,2227,1033,17,1034, +15,988,1,-1,1, +5,1035,20,1036,4, 32,87,0,104,0, 105,0,108,0,101, 0,83,0,116,0, 97,0,116,0,101, 0,109,0,101,0, 110,0,116,0,95, -0,50,0,1,189, +0,50,0,1,245, 1,3,1,6,1, -5,912,22,1,49, -1,1225,913,16,0, -615,1,1479,914,16, -0,615,1,1731,915, -16,0,615,1,1989, -916,17,917,15,720, -1,-1,1,5,918, -20,919,4,26,73, +5,1037,22,1,80, +1,1225,1038,16,0, +735,1,1479,1039,16, +0,735,1,1731,1040, +16,0,735,1,1989, +1041,17,1042,15,845, +1,-1,1,5,1043, +20,1044,4,26,73, 0,102,0,83,0, 116,0,97,0,116, 0,101,0,109,0, 101,0,110,0,116, 0,95,0,49,0, -1,184,1,3,1, -6,1,5,920,22, -1,44,1,1990,921, -16,0,615,1,236, -922,16,0,615,1, -1756,923,16,0,615, -1,4,924,19,184, -1,4,925,5,100, -1,256,926,16,0, -538,1,1261,927,16, -0,538,1,509,928, -16,0,538,1,1515, -929,16,0,538,1, -2021,718,1,1775,930, -16,0,538,1,2029, -725,1,2030,731,1, -2031,736,1,2032,741, -1,2033,746,1,277, -931,16,0,538,1, -2035,752,1,2037,757, -1,2039,762,1,32, -932,16,0,538,1, -2041,768,1,2293,933, -16,0,538,1,2043, -774,1,2045,779,1, -40,934,16,0,186, -1,41,935,16,0, -538,1,1297,936,16, -0,538,1,43,937, -16,0,538,1,44, -938,16,0,186,1, -1803,787,1,1804,939, -16,0,538,1,299, -940,16,0,538,1, -47,941,16,0,182, -1,52,942,16,0, -538,1,2318,943,16, -0,538,1,63,944, -16,0,201,1,66, -945,16,0,199,1, -2075,946,16,0,538, -1,1574,799,1,71, -947,16,0,538,1, -76,948,16,0,538, -1,1834,949,16,0, -538,1,2337,950,16, -0,538,1,79,951, -16,0,538,1,1335, -952,16,0,538,1, -322,953,16,0,538, -1,85,954,16,0, -538,1,89,955,16, -0,538,1,346,956, -16,0,538,1,97, -957,16,0,538,1, -2106,958,16,0,538, -1,102,959,16,0, -538,1,1860,821,1, -2364,827,1,1114,960, -16,0,182,1,112, -961,16,0,538,1, -1117,962,16,0,538, -1,1873,835,1,1876, -963,16,0,538,1, -124,964,16,0,538, -1,2136,842,1,381, -965,16,0,538,1, -525,966,16,0,538, -1,137,967,16,0, -538,1,1901,968,16, -0,538,1,2658,969, -16,0,538,1,1153, -970,16,0,538,1, -151,971,16,0,538, -1,1407,972,16,0, -538,1,1659,973,16, -0,538,1,2413,974, -16,0,538,1,406, -975,16,0,538,1, -1371,976,16,0,538, -1,2105,814,1,166, -977,16,0,538,1, -1622,978,16,0,538, -1,1931,861,1,1933, -979,16,0,538,1, -431,980,16,0,538, -1,1585,981,16,0, -538,1,182,982,16, -0,538,1,1189,983, -16,0,538,1,1443, -984,16,0,538,1, -1695,985,16,0,538, -1,2198,986,16,0, -538,1,447,987,16, -0,538,1,2458,876, -1,2459,882,1,1958, -988,16,0,538,1, -2462,889,1,1657,894, -1,2464,899,1,199, -989,16,0,538,1, -459,990,16,0,538, -1,462,991,16,0, -538,1,217,992,16, -0,538,1,2227,908, -1,1225,993,16,0, -538,1,1479,994,16, -0,538,1,1731,995, -16,0,538,1,1989, -916,1,1990,996,16, -0,538,1,236,997, -16,0,538,1,1756, -998,16,0,538,1, -5,999,19,181,1, -5,1000,5,100,1, -256,1001,16,0,534, -1,1261,1002,16,0, -534,1,509,1003,16, -0,534,1,1515,1004, -16,0,534,1,2021, -718,1,1775,1005,16, -0,534,1,2029,725, -1,2030,731,1,2031, -736,1,2032,741,1, -2033,746,1,277,1006, -16,0,534,1,2035, -752,1,2037,757,1, -2039,762,1,32,1007, -16,0,534,1,2041, -768,1,2293,1008,16, -0,534,1,2043,774, -1,2045,779,1,40, -1009,16,0,185,1, -41,1010,16,0,534, -1,1297,1011,16,0, -534,1,43,1012,16, -0,534,1,44,1013, -16,0,185,1,1803, -787,1,1804,1014,16, -0,534,1,299,1015, -16,0,534,1,47, -1016,16,0,179,1, -52,1017,16,0,534, -1,2318,1018,16,0, -534,1,63,1019,16, -0,200,1,66,1020, -16,0,198,1,2075, -1021,16,0,534,1, -1574,799,1,71,1022, -16,0,534,1,76, -1023,16,0,534,1, -1834,1024,16,0,534, -1,2337,1025,16,0, -534,1,79,1026,16, -0,534,1,1335,1027, -16,0,534,1,322, -1028,16,0,534,1, -85,1029,16,0,534, -1,89,1030,16,0, -534,1,346,1031,16, -0,534,1,97,1032, -16,0,534,1,2106, -1033,16,0,534,1, -102,1034,16,0,534, -1,1860,821,1,2364, -827,1,1114,1035,16, -0,179,1,112,1036, -16,0,534,1,1117, -1037,16,0,534,1, -1873,835,1,1876,1038, -16,0,534,1,124, -1039,16,0,534,1, -2136,842,1,381,1040, -16,0,534,1,525, -1041,16,0,534,1, -137,1042,16,0,534, -1,1901,1043,16,0, -534,1,2658,1044,16, -0,534,1,1153,1045, -16,0,534,1,151, -1046,16,0,534,1, -1407,1047,16,0,534, -1,1659,1048,16,0, -534,1,2413,1049,16, -0,534,1,406,1050, -16,0,534,1,1371, -1051,16,0,534,1, -2105,814,1,166,1052, -16,0,534,1,1622, -1053,16,0,534,1, -1931,861,1,1933,1054, -16,0,534,1,431, -1055,16,0,534,1, -1585,1056,16,0,534, -1,182,1057,16,0, -534,1,1189,1058,16, -0,534,1,1443,1059, -16,0,534,1,1695, -1060,16,0,534,1, -2198,1061,16,0,534, -1,447,1062,16,0, -534,1,2458,876,1, -2459,882,1,1958,1063, -16,0,534,1,2462, -889,1,1657,894,1, -2464,899,1,199,1064, -16,0,534,1,459, -1065,16,0,534,1, -462,1066,16,0,534, -1,217,1067,16,0, -534,1,2227,908,1, -1225,1068,16,0,534, -1,1479,1069,16,0, -534,1,1731,1070,16, -0,534,1,1989,916, -1,1990,1071,16,0, -534,1,236,1072,16, -0,534,1,1756,1073, -16,0,534,1,6, -1074,19,277,1,6, -1075,5,2,1,1114, -1076,16,0,275,1, -40,1077,16,0,523, -1,7,1078,19,243, -1,7,1079,5,2, -1,1114,1080,16,0, -241,1,40,1081,16, -0,459,1,8,1082, -19,207,1,8,1083, -5,2,1,1114,1084, -16,0,205,1,40, -1085,16,0,439,1, -9,1086,19,213,1, -9,1087,5,2,1, -1114,1088,16,0,211, -1,40,1089,16,0, -384,1,10,1090,19, -164,1,10,1091,5, -2,1,1114,1092,16, -0,162,1,40,1093, -16,0,324,1,11, -1094,19,192,1,11, -1095,5,146,1,1260, -1096,17,1097,15,1098, +1,240,1,3,1, +6,1,5,1045,22, +1,75,1,1990,1046, +16,0,735,1,236, +1047,16,0,735,1, +1756,1048,16,0,735, +1,4,1049,19,200, +1,4,1050,5,100, +1,256,1051,16,0, +624,1,1261,1052,16, +0,624,1,509,1053, +16,0,624,1,1515, +1054,16,0,624,1, +2021,843,1,1775,1055, +16,0,624,1,2029, +850,1,2030,856,1, +2031,861,1,2032,866, +1,2033,871,1,277, +1056,16,0,624,1, +2035,877,1,2037,882, +1,2039,887,1,32, +1057,16,0,624,1, +2041,893,1,2293,1058, +16,0,624,1,2043, +899,1,2045,904,1, +40,1059,16,0,202, +1,41,1060,16,0, +624,1,1297,1061,16, +0,624,1,43,1062, +16,0,624,1,44, +1063,16,0,202,1, +1803,912,1,1804,1064, +16,0,624,1,299, +1065,16,0,624,1, +47,1066,16,0,198, +1,52,1067,16,0, +624,1,2318,1068,16, +0,624,1,63,1069, +16,0,224,1,66, +1070,16,0,222,1, +2075,1071,16,0,624, +1,1574,924,1,71, +1072,16,0,624,1, +76,1073,16,0,624, +1,1834,1074,16,0, +624,1,2337,1075,16, +0,624,1,79,1076, +16,0,624,1,1335, +1077,16,0,624,1, +322,1078,16,0,624, +1,85,1079,16,0, +624,1,89,1080,16, +0,624,1,346,1081, +16,0,624,1,97, +1082,16,0,624,1, +2106,1083,16,0,624, +1,102,1084,16,0, +624,1,1860,946,1, +2364,952,1,1114,1085, +16,0,198,1,112, +1086,16,0,624,1, +1117,1087,16,0,624, +1,2786,1088,16,0, +624,1,1873,961,1, +1876,1089,16,0,624, +1,124,1090,16,0, +624,1,2136,968,1, +381,1091,16,0,624, +1,525,1092,16,0, +624,1,137,1093,16, +0,624,1,1901,1094, +16,0,624,1,1153, +1095,16,0,624,1, +151,1096,16,0,624, +1,1407,1097,16,0, +624,1,1659,1098,16, +0,624,1,2413,1099, +16,0,624,1,406, +1100,16,0,624,1, +1371,1101,16,0,624, +1,2105,939,1,166, +1102,16,0,624,1, +1622,1103,16,0,624, +1,1931,986,1,1933, +1104,16,0,624,1, +431,1105,16,0,624, +1,1585,1106,16,0, +624,1,182,1107,16, +0,624,1,1189,1108, +16,0,624,1,1443, +1109,16,0,624,1, +1695,1110,16,0,624, +1,2198,1111,16,0, +624,1,447,1112,16, +0,624,1,2458,1001, +1,2459,1007,1,1958, +1113,16,0,624,1, +2462,1014,1,1657,1019, +1,2464,1024,1,199, +1114,16,0,624,1, +459,1115,16,0,624, +1,462,1116,16,0, +624,1,217,1117,16, +0,624,1,2227,1033, +1,1225,1118,16,0, +624,1,1479,1119,16, +0,624,1,1731,1120, +16,0,624,1,1989, +1041,1,1990,1121,16, +0,624,1,236,1122, +16,0,624,1,1756, +1123,16,0,624,1, +5,1124,19,197,1, +5,1125,5,100,1, +256,1126,16,0,620, +1,1261,1127,16,0, +620,1,509,1128,16, +0,620,1,1515,1129, +16,0,620,1,2021, +843,1,1775,1130,16, +0,620,1,2029,850, +1,2030,856,1,2031, +861,1,2032,866,1, +2033,871,1,277,1131, +16,0,620,1,2035, +877,1,2037,882,1, +2039,887,1,32,1132, +16,0,620,1,2041, +893,1,2293,1133,16, +0,620,1,2043,899, +1,2045,904,1,40, +1134,16,0,201,1, +41,1135,16,0,620, +1,1297,1136,16,0, +620,1,43,1137,16, +0,620,1,44,1138, +16,0,201,1,1803, +912,1,1804,1139,16, +0,620,1,299,1140, +16,0,620,1,47, +1141,16,0,195,1, +52,1142,16,0,620, +1,2318,1143,16,0, +620,1,63,1144,16, +0,223,1,66,1145, +16,0,221,1,2075, +1146,16,0,620,1, +1574,924,1,71,1147, +16,0,620,1,76, +1148,16,0,620,1, +1834,1149,16,0,620, +1,2337,1150,16,0, +620,1,79,1151,16, +0,620,1,1335,1152, +16,0,620,1,322, +1153,16,0,620,1, +85,1154,16,0,620, +1,89,1155,16,0, +620,1,346,1156,16, +0,620,1,97,1157, +16,0,620,1,2106, +1158,16,0,620,1, +102,1159,16,0,620, +1,1860,946,1,2364, +952,1,1114,1160,16, +0,195,1,112,1161, +16,0,620,1,1117, +1162,16,0,620,1, +2786,1163,16,0,620, +1,1873,961,1,1876, +1164,16,0,620,1, +124,1165,16,0,620, +1,2136,968,1,381, +1166,16,0,620,1, +525,1167,16,0,620, +1,137,1168,16,0, +620,1,1901,1169,16, +0,620,1,1153,1170, +16,0,620,1,151, +1171,16,0,620,1, +1407,1172,16,0,620, +1,1659,1173,16,0, +620,1,2413,1174,16, +0,620,1,406,1175, +16,0,620,1,1371, +1176,16,0,620,1, +2105,939,1,166,1177, +16,0,620,1,1622, +1178,16,0,620,1, +1931,986,1,1933,1179, +16,0,620,1,431, +1180,16,0,620,1, +1585,1181,16,0,620, +1,182,1182,16,0, +620,1,1189,1183,16, +0,620,1,1443,1184, +16,0,620,1,1695, +1185,16,0,620,1, +2198,1186,16,0,620, +1,447,1187,16,0, +620,1,2458,1001,1, +2459,1007,1,1958,1188, +16,0,620,1,2462, +1014,1,1657,1019,1, +2464,1024,1,199,1189, +16,0,620,1,459, +1190,16,0,620,1, +462,1191,16,0,620, +1,217,1192,16,0, +620,1,2227,1033,1, +1225,1193,16,0,620, +1,1479,1194,16,0, +620,1,1731,1195,16, +0,620,1,1989,1041, +1,1990,1196,16,0, +620,1,236,1197,16, +0,620,1,1756,1198, +16,0,620,1,6, +1199,19,310,1,6, +1200,5,2,1,1114, +1201,16,0,308,1, +40,1202,16,0,609, +1,7,1203,19,267, +1,7,1204,5,2, +1,1114,1205,16,0, +265,1,40,1206,16, +0,544,1,8,1207, +19,230,1,8,1208, +5,2,1,1114,1209, +16,0,228,1,40, +1210,16,0,501,1, +9,1211,19,236,1, +9,1212,5,2,1, +1114,1213,16,0,234, +1,40,1214,16,0, +430,1,10,1215,19, +180,1,10,1216,5, +2,1,1114,1217,16, +0,178,1,40,1218, +16,0,367,1,11, +1219,19,151,1,11, +1220,5,146,1,1260, +1221,17,1222,15,1223, 4,34,37,0,83, 0,105,0,109,0, 112,0,108,0,101, @@ -4085,7 +4877,7 @@ public yyLSLSyntax 0,110,0,109,0, 101,0,110,0,116, 0,1,-1,1,5, -1099,20,1100,4,38, +1224,20,1225,4,38, 83,0,105,0,109, 0,112,0,108,0, 101,0,65,0,115, @@ -4093,11 +4885,11 @@ public yyLSLSyntax 103,0,110,0,109, 0,101,0,110,0, 116,0,95,0,50, -0,49,0,1,220, +0,49,0,1,276, 1,3,1,6,1, -5,1101,22,1,80, -1,1011,1102,17,1103, -15,1104,4,44,37, +5,1226,22,1,111, +1,1011,1227,17,1228, +15,1229,4,44,37, 0,80,0,97,0, 114,0,101,0,110, 0,116,0,104,0, @@ -4107,7 +4899,7 @@ public yyLSLSyntax 0,101,0,115,0, 115,0,105,0,111, 0,110,0,1,-1, -1,5,1105,20,1106, +1,5,1230,20,1231, 4,46,80,0,97, 0,114,0,101,0, 110,0,116,0,104, @@ -4117,12 +4909,12 @@ public yyLSLSyntax 114,0,101,0,115, 0,115,0,105,0, 111,0,110,0,95, -0,50,0,1,267, +0,50,0,1,323, 1,3,1,4,1, -3,1107,22,1,127, -1,1514,1108,17,1109, -15,1098,1,-1,1, -5,1110,20,1111,4, +3,1232,22,1,158, +1,1514,1233,17,1234, +15,1223,1,-1,1, +5,1235,20,1236,4, 38,83,0,105,0, 109,0,112,0,108, 0,101,0,65,0, @@ -4131,26 +4923,26 @@ public yyLSLSyntax 109,0,101,0,110, 0,116,0,95,0, 49,0,52,0,1, -213,1,3,1,4, -1,3,1112,22,1, -73,1,9,1113,17, -1114,15,1115,4,24, +269,1,3,1,4, +1,3,1237,22,1, +104,1,9,1238,17, +1239,15,1240,4,24, 37,0,68,0,101, 0,99,0,108,0, 97,0,114,0,97, 0,116,0,105,0, 111,0,110,0,1, --1,1,5,1116,20, -1117,4,26,68,0, +-1,1,5,1241,20, +1242,4,26,68,0, 101,0,99,0,108, 0,97,0,114,0, 97,0,116,0,105, 0,111,0,110,0, 95,0,49,0,1, -161,1,3,1,3, -1,2,1118,22,1, -21,1,262,1119,17, -1120,15,1121,4,34, +213,1,3,1,3, +1,2,1243,22,1, +48,1,262,1244,17, +1245,15,1246,4,34, 37,0,66,0,105, 0,110,0,97,0, 114,0,121,0,69, @@ -4158,8 +4950,8 @@ public yyLSLSyntax 114,0,101,0,115, 0,115,0,105,0, 111,0,110,0,1, --1,1,5,1122,20, -1123,4,36,66,0, +-1,1,5,1247,20, +1248,4,36,66,0, 105,0,110,0,97, 0,114,0,121,0, 69,0,120,0,112, @@ -4167,11 +4959,11 @@ public yyLSLSyntax 115,0,115,0,105, 0,111,0,110,0, 95,0,53,0,1, -249,1,3,1,4, -1,3,1124,22,1, -109,1,1267,1125,17, -1126,15,1098,1,-1, -1,5,1127,20,1128, +305,1,3,1,4, +1,3,1249,22,1, +140,1,1267,1250,17, +1251,15,1223,1,-1, +1,5,1252,20,1253, 4,36,83,0,105, 0,109,0,112,0, 108,0,101,0,65, @@ -4179,13 +4971,13 @@ public yyLSLSyntax 105,0,103,0,110, 0,109,0,101,0, 110,0,116,0,95, -0,56,0,1,207, +0,56,0,1,263, 1,3,1,6,1, -5,1129,22,1,67, -1,2021,718,1,1521, -1130,17,1131,15,1098, -1,-1,1,5,1132, -20,1133,4,36,83, +5,1254,22,1,98, +1,2021,843,1,1521, +1255,17,1256,15,1223, +1,-1,1,5,1257, +20,1258,4,36,83, 0,105,0,109,0, 112,0,108,0,101, 0,65,0,115,0, @@ -4193,26 +4985,26 @@ public yyLSLSyntax 0,110,0,109,0, 101,0,110,0,116, 0,95,0,49,0, -1,200,1,3,1, -4,1,3,1134,22, -1,60,1,2024,1135, -17,1136,15,1137,4, +1,256,1,3,1, +4,1,3,1259,22, +1,91,1,2024,1260, +17,1261,15,1262,4, 24,37,0,83,0, 116,0,97,0,116, 0,101,0,67,0, 104,0,97,0,110, 0,103,0,101,0, -1,-1,1,5,1138, -20,1139,4,26,83, +1,-1,1,5,1263, +20,1264,4,26,83, 0,116,0,97,0, 116,0,101,0,67, 0,104,0,97,0, 110,0,103,0,101, 0,95,0,49,0, -1,182,1,3,1, -3,1,2,1140,22, -1,42,1,1775,1141, -17,1142,15,1143,4, +1,238,1,3,1, +3,1,2,1265,22, +1,73,1,1775,1266, +17,1267,15,1268,4, 30,37,0,69,0, 109,0,112,0,116, 0,121,0,83,0, @@ -4220,34 +5012,34 @@ public yyLSLSyntax 0,101,0,109,0, 101,0,110,0,116, 0,1,-1,1,5, -1144,20,1145,4,32, +1269,20,1270,4,32, 69,0,109,0,112, 0,116,0,121,0, 83,0,116,0,97, 0,116,0,101,0, 109,0,101,0,110, 0,116,0,95,0, -49,0,1,166,1, +49,0,1,222,1, 3,1,1,1,0, -1146,22,1,26,1, -19,1147,17,1114,1, -2,1118,1,2028,1148, -17,1149,15,1150,4, +1271,22,1,57,1, +19,1272,17,1239,1, +2,1243,1,2028,1273, +17,1274,15,1275,4, 20,37,0,74,0, 117,0,109,0,112, 0,76,0,97,0, 98,0,101,0,108, 0,1,-1,1,5, -1151,20,1152,4,22, +1276,20,1277,4,22, 74,0,117,0,109, 0,112,0,76,0, 97,0,98,0,101, 0,108,0,95,0, -49,0,1,180,1, +49,0,1,236,1, 3,1,3,1,2, -1153,22,1,40,1, -2029,725,1,2281,1154, -17,1155,15,1156,4, +1278,22,1,71,1, +2029,850,1,2281,1279, +17,1280,15,1281,4, 34,37,0,70,0, 111,0,114,0,76, 0,111,0,111,0, @@ -4255,8 +5047,8 @@ public yyLSLSyntax 0,97,0,116,0, 101,0,109,0,101, 0,110,0,116,0, -1,-1,1,5,1157, -20,1158,4,36,70, +1,-1,1,5,1282, +20,1283,4,36,70, 0,111,0,114,0, 76,0,111,0,111, 0,112,0,83,0, @@ -4264,142 +5056,95 @@ public yyLSLSyntax 0,101,0,109,0, 101,0,110,0,116, 0,95,0,50,0, -1,195,1,3,1, -2,1,1,1159,22, -1,55,1,2031,736, -1,2032,741,1,2033, -746,1,2034,1160,16, -0,572,1,2035,752, -1,2036,1161,16,0, -524,1,2037,757,1, -2038,1162,16,0,528, -1,2039,762,1,32, -1163,17,1142,1,0, -1146,1,2041,768,1, -2042,1164,16,0,646, -1,2043,774,1,2044, -1165,16,0,584,1, -2045,779,1,2299,1166, -16,0,226,1,1296, -1167,17,1168,15,1098, -1,-1,1,5,1169, -20,1170,4,38,83, -0,105,0,109,0, -112,0,108,0,101, -0,65,0,115,0, -115,0,105,0,103, -0,110,0,109,0, -101,0,110,0,116, -0,95,0,50,0, -48,0,1,219,1, -3,1,6,1,5, -1171,22,1,79,1, -283,1172,17,1173,15, -1121,1,-1,1,5, -1174,20,1175,4,36, -66,0,105,0,110, -0,97,0,114,0, -121,0,69,0,120, -0,112,0,114,0, -101,0,115,0,115, -0,105,0,111,0, -110,0,95,0,52, -0,1,248,1,3, -1,4,1,3,1176, -22,1,108,1,40, -1177,17,1178,15,1179, -4,32,37,0,73, -0,100,0,101,0, -110,0,116,0,69, -0,120,0,112,0, -114,0,101,0,115, +1,251,1,3,1, +2,1,1,1284,22, +1,86,1,2031,861, +1,2785,1285,16,0, +519,1,2033,871,1, +2034,1286,16,0,691, +1,2035,877,1,2036, +1287,16,0,610,1, +2037,882,1,2038,1288, +16,0,614,1,2792, +1289,16,0,149,1, +32,1290,17,1267,1, +0,1271,1,2032,866, +1,2042,1291,16,0, +757,1,2043,899,1, +2044,1292,16,0,704, +1,2045,904,1,2299, +1293,16,0,252,1, +1296,1294,17,1295,15, +1223,1,-1,1,5, +1296,20,1297,4,38, +83,0,105,0,109, +0,112,0,108,0, +101,0,65,0,115, 0,115,0,105,0, -111,0,110,0,1, --1,1,5,1180,20, -1181,4,34,73,0, -100,0,101,0,110, -0,116,0,69,0, +103,0,110,0,109, +0,101,0,110,0, +116,0,95,0,50, +0,48,0,1,275, +1,3,1,6,1, +5,1298,22,1,110, +1,283,1299,17,1300, +15,1246,1,-1,1, +5,1301,20,1302,4, +36,66,0,105,0, +110,0,97,0,114, +0,121,0,69,0, 120,0,112,0,114, 0,101,0,115,0, 115,0,105,0,111, 0,110,0,95,0, -49,0,1,234,1, -3,1,2,1,1, -1182,22,1,94,1, -44,1183,17,1178,1, -1,1182,1,1803,787, -1,47,1184,17,1185, -15,1186,4,38,37, -0,73,0,100,0, -101,0,110,0,116, -0,68,0,111,0, -116,0,69,0,120, -0,112,0,114,0, -101,0,115,0,115, -0,105,0,111,0, -110,0,1,-1,1, -5,1187,20,1188,4, -40,73,0,100,0, -101,0,110,0,116, -0,68,0,111,0, -116,0,69,0,120, -0,112,0,114,0, -101,0,115,0,115, -0,105,0,111,0, -110,0,95,0,49, -0,1,235,1,3, -1,4,1,3,1189, -22,1,95,1,48, -1190,17,1191,15,1192, -4,58,37,0,73, -0,110,0,99,0, -114,0,101,0,109, -0,101,0,110,0, -116,0,68,0,101, -0,99,0,114,0, -101,0,109,0,101, -0,110,0,116,0, -69,0,120,0,112, -0,114,0,101,0, -115,0,115,0,105, -0,111,0,110,0, -1,-1,1,5,1193, -20,1194,4,60,73, -0,110,0,99,0, -114,0,101,0,109, -0,101,0,110,0, -116,0,68,0,101, -0,99,0,114,0, -101,0,109,0,101, +52,0,1,304,1, +3,1,4,1,3, +1303,22,1,139,1, +40,1304,17,1305,15, +1306,4,32,37,0, +73,0,100,0,101, 0,110,0,116,0, 69,0,120,0,112, 0,114,0,101,0, 115,0,115,0,105, 0,111,0,110,0, -95,0,52,0,1, -239,1,3,1,5, -1,4,1195,22,1, -99,1,49,1196,17, -1197,15,1192,1,-1, -1,5,1198,20,1199, -4,60,73,0,110, -0,99,0,114,0, -101,0,109,0,101, -0,110,0,116,0, -68,0,101,0,99, -0,114,0,101,0, -109,0,101,0,110, +1,-1,1,5,1307, +20,1308,4,34,73, +0,100,0,101,0, +110,0,116,0,69, +0,120,0,112,0, +114,0,101,0,115, +0,115,0,105,0, +111,0,110,0,95, +0,49,0,1,290, +1,3,1,2,1, +1,1309,22,1,125, +1,44,1310,17,1305, +1,1,1309,1,1803, +912,1,47,1311,17, +1312,15,1313,4,38, +37,0,73,0,100, +0,101,0,110,0, +116,0,68,0,111, +0,116,0,69,0, +120,0,112,0,114, +0,101,0,115,0, +115,0,105,0,111, +0,110,0,1,-1, +1,5,1314,20,1315, +4,40,73,0,100, +0,101,0,110,0, +116,0,68,0,111, 0,116,0,69,0, 120,0,112,0,114, 0,101,0,115,0, 115,0,105,0,111, 0,110,0,95,0, -51,0,1,238,1, -3,1,5,1,4, -1200,22,1,98,1, -50,1201,17,1202,15, -1192,1,-1,1,5, -1203,20,1204,4,60, +49,0,1,291,1, +3,1,4,1,3, +1316,22,1,126,1, +48,1317,17,1318,15, +1319,4,58,37,0, 73,0,110,0,99, 0,114,0,101,0, 109,0,101,0,110, @@ -4411,13 +5156,26 @@ public yyLSLSyntax 112,0,114,0,101, 0,115,0,115,0, 105,0,111,0,110, -0,95,0,50,0, -1,237,1,3,1, -3,1,2,1205,22, -1,97,1,51,1206, -17,1207,15,1192,1, --1,1,5,1208,20, -1209,4,60,73,0, +0,1,-1,1,5, +1320,20,1321,4,60, +73,0,110,0,99, +0,114,0,101,0, +109,0,101,0,110, +0,116,0,68,0, +101,0,99,0,114, +0,101,0,109,0, +101,0,110,0,116, +0,69,0,120,0, +112,0,114,0,101, +0,115,0,115,0, +105,0,111,0,110, +0,95,0,52,0, +1,295,1,3,1, +5,1,4,1322,22, +1,130,1,49,1323, +17,1324,15,1319,1, +-1,1,5,1325,20, +1326,4,60,73,0, 110,0,99,0,114, 0,101,0,109,0, 101,0,110,0,116, @@ -4429,80 +5187,88 @@ public yyLSLSyntax 114,0,101,0,115, 0,115,0,105,0, 111,0,110,0,95, -0,49,0,1,236, -1,3,1,3,1, -2,1210,22,1,96, -1,305,1211,17,1212, -15,1121,1,-1,1, -5,1213,20,1214,4, -36,66,0,105,0, -110,0,97,0,114, -0,121,0,69,0, -120,0,112,0,114, -0,101,0,115,0, -115,0,105,0,111, -0,110,0,95,0, -51,0,1,247,1, -3,1,4,1,3, -1215,22,1,107,1, -525,1216,17,1217,15, -1218,4,34,37,0, -82,0,111,0,116, -0,97,0,116,0, -105,0,111,0,110, -0,67,0,111,0, -110,0,115,0,116, -0,97,0,110,0, -116,0,1,-1,1, -5,1219,20,1220,4, -36,82,0,111,0, -116,0,97,0,116, -0,105,0,111,0, -110,0,67,0,111, -0,110,0,115,0, -116,0,97,0,110, -0,116,0,95,0, -49,0,1,232,1, -3,1,10,1,9, -1221,22,1,92,1, -63,1222,17,1223,15, -1224,4,38,37,0, -84,0,121,0,112, -0,101,0,99,0, -97,0,115,0,116, -0,69,0,120,0, -112,0,114,0,101, -0,115,0,115,0, -105,0,111,0,110, -0,1,-1,1,5, -1225,20,1226,4,40, -84,0,121,0,112, +0,51,0,1,294, +1,3,1,5,1, +4,1327,22,1,129, +1,50,1328,17,1329, +15,1319,1,-1,1, +5,1330,20,1331,4, +60,73,0,110,0, +99,0,114,0,101, +0,109,0,101,0, +110,0,116,0,68, 0,101,0,99,0, -97,0,115,0,116, -0,69,0,120,0, -112,0,114,0,101, -0,115,0,115,0, -105,0,111,0,110, -0,95,0,50,0, -1,269,1,3,1, -5,1,4,1227,22, -1,129,1,66,1228, -17,1229,15,1224,1, --1,1,5,1230,20, -1231,4,40,84,0, -121,0,112,0,101, -0,99,0,97,0, -115,0,116,0,69, +114,0,101,0,109, +0,101,0,110,0, +116,0,69,0,120, +0,112,0,114,0, +101,0,115,0,115, +0,105,0,111,0, +110,0,95,0,50, +0,1,293,1,3, +1,3,1,2,1332, +22,1,128,1,51, +1333,17,1334,15,1319, +1,-1,1,5,1335, +20,1336,4,60,73, +0,110,0,99,0, +114,0,101,0,109, +0,101,0,110,0, +116,0,68,0,101, +0,99,0,114,0, +101,0,109,0,101, +0,110,0,116,0, +69,0,120,0,112, +0,114,0,101,0, +115,0,115,0,105, +0,111,0,110,0, +95,0,49,0,1, +292,1,3,1,3, +1,2,1337,22,1, +127,1,305,1338,17, +1339,15,1246,1,-1, +1,5,1340,20,1341, +4,36,66,0,105, +0,110,0,97,0, +114,0,121,0,69, 0,120,0,112,0, 114,0,101,0,115, 0,115,0,105,0, 111,0,110,0,95, -0,51,0,1,270, -1,3,1,7,1, -6,1232,22,1,130, -1,67,1233,17,1234, -15,1224,1,-1,1, -5,1235,20,1236,4, +0,51,0,1,303, +1,3,1,4,1, +3,1342,22,1,138, +1,525,1343,17,1344, +15,1345,4,34,37, +0,82,0,111,0, +116,0,97,0,116, +0,105,0,111,0, +110,0,67,0,111, +0,110,0,115,0, +116,0,97,0,110, +0,116,0,1,-1, +1,5,1346,20,1347, +4,36,82,0,111, +0,116,0,97,0, +116,0,105,0,111, +0,110,0,67,0, +111,0,110,0,115, +0,116,0,97,0, +110,0,116,0,95, +0,49,0,1,288, +1,3,1,10,1, +9,1348,22,1,123, +1,63,1349,17,1350, +15,1351,4,38,37, +0,84,0,121,0, +112,0,101,0,99, +0,97,0,115,0, +116,0,69,0,120, +0,112,0,114,0, +101,0,115,0,115, +0,105,0,111,0, +110,0,1,-1,1, +5,1352,20,1353,4, 40,84,0,121,0, 112,0,101,0,99, 0,97,0,115,0, @@ -4510,13 +5276,13 @@ public yyLSLSyntax 0,112,0,114,0, 101,0,115,0,115, 0,105,0,111,0, -110,0,95,0,55, -0,1,274,1,3, -1,8,1,7,1237, -22,1,134,1,68, -1238,17,1239,15,1224, -1,-1,1,5,1240, -20,1241,4,40,84, +110,0,95,0,50, +0,1,325,1,3, +1,5,1,4,1354, +22,1,160,1,66, +1355,17,1356,15,1351, +1,-1,1,5,1357, +20,1358,4,40,84, 0,121,0,112,0, 101,0,99,0,97, 0,115,0,116,0, @@ -4524,12 +5290,12 @@ public yyLSLSyntax 0,114,0,101,0, 115,0,115,0,105, 0,111,0,110,0, -95,0,53,0,1, -272,1,3,1,8, -1,7,1242,22,1, -132,1,69,1243,17, -1244,15,1224,1,-1, -1,5,1245,20,1246, +95,0,51,0,1, +326,1,3,1,7, +1,6,1359,22,1, +161,1,67,1360,17, +1361,15,1351,1,-1, +1,5,1362,20,1363, 4,40,84,0,121, 0,112,0,101,0, 99,0,97,0,115, @@ -4538,12 +5304,12 @@ public yyLSLSyntax 0,101,0,115,0, 115,0,105,0,111, 0,110,0,95,0, -54,0,1,273,1, -3,1,6,1,5, -1247,22,1,133,1, -70,1248,17,1249,15, -1224,1,-1,1,5, -1250,20,1251,4,40, +55,0,1,330,1, +3,1,8,1,7, +1364,22,1,165,1, +68,1365,17,1366,15, +1351,1,-1,1,5, +1367,20,1368,4,40, 84,0,121,0,112, 0,101,0,99,0, 97,0,115,0,116, @@ -4551,13 +5317,13 @@ public yyLSLSyntax 112,0,114,0,101, 0,115,0,115,0, 105,0,111,0,110, -0,95,0,52,0, -1,271,1,3,1, -6,1,5,1252,22, -1,131,1,74,1253, -17,1254,15,1224,1, --1,1,5,1255,20, -1256,4,40,84,0, +0,95,0,53,0, +1,328,1,3,1, +8,1,7,1369,22, +1,163,1,69,1370, +17,1371,15,1351,1, +-1,1,5,1372,20, +1373,4,40,84,0, 121,0,112,0,101, 0,99,0,97,0, 115,0,116,0,69, @@ -4565,251 +5331,234 @@ public yyLSLSyntax 114,0,101,0,115, 0,115,0,105,0, 111,0,110,0,95, -0,57,0,1,276, -1,3,1,7,1, -6,1257,22,1,136, -1,1013,1258,17,1259, -15,1104,1,-1,1, -5,1260,20,1261,4, -46,80,0,97,0, -114,0,101,0,110, -0,116,0,104,0, -101,0,115,0,105, -0,115,0,69,0, -120,0,112,0,114, -0,101,0,115,0, -115,0,105,0,111, -0,110,0,95,0, -49,0,1,266,1, -3,1,4,1,3, -1262,22,1,126,1, -1332,1263,17,1264,15, -1098,1,-1,1,5, -1265,20,1266,4,38, -83,0,105,0,109, -0,112,0,108,0, -101,0,65,0,115, -0,115,0,105,0, -103,0,110,0,109, -0,101,0,110,0, -116,0,95,0,49, -0,57,0,1,218, +0,54,0,1,329, 1,3,1,6,1, -5,1267,22,1,78, -1,2337,1268,17,1142, -1,0,1146,1,1585, -1269,17,1270,15,1271, -4,32,37,0,82, -0,101,0,116,0, -117,0,114,0,110, -0,83,0,116,0, -97,0,116,0,101, -0,109,0,101,0, -110,0,116,0,1, --1,1,5,1272,20, -1273,4,34,82,0, -101,0,116,0,117, -0,114,0,110,0, -83,0,116,0,97, -0,116,0,101,0, -109,0,101,0,110, -0,116,0,95,0, -50,0,1,225,1, -3,1,2,1,1, -1274,22,1,85,1, -2023,1275,17,1276,15, -1137,1,-1,1,5, -1277,20,1278,4,26, -83,0,116,0,97, -0,116,0,101,0, -67,0,104,0,97, -0,110,0,103,0, -101,0,95,0,50, -0,1,183,1,3, -1,3,1,2,1279, -22,1,43,1,2136, -842,1,82,1280,17, -1281,15,1282,4,32, -37,0,85,0,110, -0,97,0,114,0, -121,0,69,0,120, +5,1374,22,1,164, +1,70,1375,17,1376, +15,1351,1,-1,1, +5,1377,20,1378,4, +40,84,0,121,0, +112,0,101,0,99, +0,97,0,115,0, +116,0,69,0,120, 0,112,0,114,0, 101,0,115,0,115, 0,105,0,111,0, -110,0,1,-1,1, -5,1283,20,1284,4, -34,85,0,110,0, -97,0,114,0,121, -0,69,0,120,0, -112,0,114,0,101, -0,115,0,115,0, -105,0,111,0,110, -0,95,0,51,0, -1,265,1,3,1, -3,1,2,1285,22, -1,125,1,2026,1286, -17,1287,15,1288,4, -28,37,0,74,0, -117,0,109,0,112, -0,83,0,116,0, -97,0,116,0,101, -0,109,0,101,0, -110,0,116,0,1, --1,1,5,1289,20, -1290,4,30,74,0, -117,0,109,0,112, +110,0,95,0,52, +0,1,327,1,3, +1,6,1,5,1379, +22,1,162,1,74, +1380,17,1381,15,1351, +1,-1,1,5,1382, +20,1383,4,40,84, +0,121,0,112,0, +101,0,99,0,97, +0,115,0,116,0, +69,0,120,0,112, +0,114,0,101,0, +115,0,115,0,105, +0,111,0,110,0, +95,0,57,0,1, +332,1,3,1,7, +1,6,1384,22,1, +167,1,1013,1385,17, +1386,15,1229,1,-1, +1,5,1387,20,1388, +4,46,80,0,97, +0,114,0,101,0, +110,0,116,0,104, +0,101,0,115,0, +105,0,115,0,69, +0,120,0,112,0, +114,0,101,0,115, +0,115,0,105,0, +111,0,110,0,95, +0,49,0,1,322, +1,3,1,4,1, +3,1389,22,1,157, +1,1332,1390,17,1391, +15,1223,1,-1,1, +5,1392,20,1393,4, +38,83,0,105,0, +109,0,112,0,108, +0,101,0,65,0, +115,0,115,0,105, +0,103,0,110,0, +109,0,101,0,110, +0,116,0,95,0, +49,0,57,0,1, +274,1,3,1,6, +1,5,1394,22,1, +109,1,2337,1395,17, +1267,1,0,1271,1, +1585,1396,17,1397,15, +1398,4,32,37,0, +82,0,101,0,116, +0,117,0,114,0, +110,0,83,0,116, +0,97,0,116,0, +101,0,109,0,101, +0,110,0,116,0, +1,-1,1,5,1399, +20,1400,4,34,82, +0,101,0,116,0, +117,0,114,0,110, 0,83,0,116,0, 97,0,116,0,101, 0,109,0,101,0, 110,0,116,0,95, -0,49,0,1,181, -1,3,1,3,1, -2,1291,22,1,41, -1,1591,1292,17,1293, -15,1271,1,-1,1, -5,1294,20,1295,4, -34,82,0,101,0, -116,0,117,0,114, -0,110,0,83,0, -116,0,97,0,116, -0,101,0,109,0, -101,0,110,0,116, -0,95,0,49,0, -1,224,1,3,1, -3,1,2,1296,22, -1,84,1,1341,1297, -17,1298,15,1098,1, --1,1,5,1299,20, -1300,4,36,83,0, -105,0,109,0,112, -0,108,0,101,0, -65,0,115,0,115, -0,105,0,103,0, -110,0,109,0,101, -0,110,0,116,0, -95,0,54,0,1, -205,1,3,1,4, -1,3,1301,22,1, -65,1,2030,731,1, -328,1302,17,1303,15, -1121,1,-1,1,5, -1304,20,1305,4,36, -66,0,105,0,110, -0,97,0,114,0, -121,0,69,0,120, -0,112,0,114,0, -101,0,115,0,115, -0,105,0,111,0, -110,0,95,0,50, -0,1,246,1,3, -1,4,1,3,1306, -22,1,106,1,1303, -1307,17,1308,15,1098, -1,-1,1,5,1309, -20,1310,4,36,83, -0,105,0,109,0, -112,0,108,0,101, -0,65,0,115,0, -115,0,105,0,103, -0,110,0,109,0, -101,0,110,0,116, -0,95,0,55,0, -1,206,1,3,1, -6,1,5,1311,22, -1,66,1,1096,1312, -17,1313,15,1314,4, -26,37,0,70,0, -117,0,110,0,99, -0,116,0,105,0, -111,0,110,0,67, -0,97,0,108,0, -108,0,1,-1,1, -5,1315,20,1316,4, -28,70,0,117,0, -110,0,99,0,116, -0,105,0,111,0, -110,0,67,0,97, -0,108,0,108,0, -95,0,49,0,1, -277,1,3,1,5, -1,4,1317,22,1, -137,1,93,1318,17, -1319,15,1282,1,-1, -1,5,1320,20,1321, +0,50,0,1,281, +1,3,1,2,1, +1,1401,22,1,116, +1,2023,1402,17,1403, +15,1262,1,-1,1, +5,1404,20,1405,4, +26,83,0,116,0, +97,0,116,0,101, +0,67,0,104,0, +97,0,110,0,103, +0,101,0,95,0, +50,0,1,239,1, +3,1,3,1,2, +1406,22,1,74,1, +2136,968,1,82,1407, +17,1408,15,1409,4, +32,37,0,85,0, +110,0,97,0,114, +0,121,0,69,0, +120,0,112,0,114, +0,101,0,115,0, +115,0,105,0,111, +0,110,0,1,-1, +1,5,1410,20,1411, 4,34,85,0,110, 0,97,0,114,0, 121,0,69,0,120, 0,112,0,114,0, 101,0,115,0,115, 0,105,0,111,0, -110,0,95,0,50, -0,1,264,1,3, -1,3,1,2,1322, -22,1,124,1,1550, -1323,17,1324,15,1098, -1,-1,1,5,1325, -20,1326,4,38,83, +110,0,95,0,51, +0,1,321,1,3, +1,3,1,2,1412, +22,1,156,1,2026, +1413,17,1414,15,1415, +4,28,37,0,74, +0,117,0,109,0, +112,0,83,0,116, +0,97,0,116,0, +101,0,109,0,101, +0,110,0,116,0, +1,-1,1,5,1416, +20,1417,4,30,74, +0,117,0,109,0, +112,0,83,0,116, +0,97,0,116,0, +101,0,109,0,101, +0,110,0,116,0, +95,0,49,0,1, +237,1,3,1,3, +1,2,1418,22,1, +72,1,1591,1419,17, +1420,15,1398,1,-1, +1,5,1421,20,1422, +4,34,82,0,101, +0,116,0,117,0, +114,0,110,0,83, +0,116,0,97,0, +116,0,101,0,109, +0,101,0,110,0, +116,0,95,0,49, +0,1,280,1,3, +1,3,1,2,1423, +22,1,115,1,1341, +1424,17,1425,15,1223, +1,-1,1,5,1426, +20,1427,4,36,83, 0,105,0,109,0, 112,0,108,0,101, 0,65,0,115,0, 115,0,105,0,103, 0,110,0,109,0, 101,0,110,0,116, -0,95,0,49,0, -51,0,1,212,1, +0,95,0,54,0, +1,261,1,3,1, +4,1,3,1428,22, +1,96,1,2030,856, +1,328,1429,17,1430, +15,1246,1,-1,1, +5,1431,20,1432,4, +36,66,0,105,0, +110,0,97,0,114, +0,121,0,69,0, +120,0,112,0,114, +0,101,0,115,0, +115,0,105,0,111, +0,110,0,95,0, +50,0,1,302,1, 3,1,4,1,3, -1327,22,1,72,1, -2040,1328,16,0,532, -1,2106,1329,17,1142, -1,0,1146,1,1555, -1330,16,0,599,1, -827,1331,17,1332,15, -1121,1,-1,1,5, -1333,20,1334,4,38, -66,0,105,0,110, -0,97,0,114,0, -121,0,69,0,120, -0,112,0,114,0, -101,0,115,0,115, -0,105,0,111,0, -110,0,95,0,49, -0,53,0,1,259, -1,3,1,4,1, -3,1335,22,1,119, -1,1859,1336,16,0, -304,1,1860,821,1, -1804,1337,17,1142,1, -0,1146,1,107,1338, -17,1339,15,1282,1, --1,1,5,1340,20, -1341,4,34,85,0, +1433,22,1,137,1, +1303,1434,17,1435,15, +1223,1,-1,1,5, +1436,20,1437,4,36, +83,0,105,0,109, +0,112,0,108,0, +101,0,65,0,115, +0,115,0,105,0, +103,0,110,0,109, +0,101,0,110,0, +116,0,95,0,55, +0,1,262,1,3, +1,6,1,5,1438, +22,1,97,1,1096, +1439,17,1440,15,1441, +4,26,37,0,70, +0,117,0,110,0, +99,0,116,0,105, +0,111,0,110,0, +67,0,97,0,108, +0,108,0,1,-1, +1,5,1442,20,1443, +4,28,70,0,117, +0,110,0,99,0, +116,0,105,0,111, +0,110,0,67,0, +97,0,108,0,108, +0,95,0,49,0, +1,333,1,3,1, +5,1,4,1444,22, +1,168,1,93,1445, +17,1446,15,1409,1, +-1,1,5,1447,20, +1448,4,34,85,0, 110,0,97,0,114, 0,121,0,69,0, 120,0,112,0,114, 0,101,0,115,0, 115,0,105,0,111, 0,110,0,95,0, -49,0,1,263,1, +50,0,1,320,1, 3,1,3,1,2, -1342,22,1,123,1, -1114,1343,17,1185,1, -3,1189,1,1048,1344, -17,1345,15,1121,1, --1,1,5,1346,20, -1347,4,38,66,0, -105,0,110,0,97, -0,114,0,121,0, -69,0,120,0,112, -0,114,0,101,0, -115,0,115,0,105, -0,111,0,110,0, -95,0,49,0,56, -0,1,262,1,3, -1,4,1,3,1348, -22,1,122,1,352, -1349,17,1350,15,1121, -1,-1,1,5,1351, -20,1352,4,36,66, +1449,22,1,155,1, +1550,1450,17,1451,15, +1223,1,-1,1,5, +1452,20,1453,4,38, +83,0,105,0,109, +0,112,0,108,0, +101,0,65,0,115, +0,115,0,105,0, +103,0,110,0,109, +0,101,0,110,0, +116,0,95,0,49, +0,51,0,1,268, +1,3,1,4,1, +3,1454,22,1,103, +1,2039,887,1,2040, +1455,16,0,618,1, +2041,893,1,1555,1456, +16,0,722,1,827, +1457,17,1458,15,1246, +1,-1,1,5,1459, +20,1460,4,38,66, 0,105,0,110,0, 97,0,114,0,121, 0,69,0,120,0, @@ -4817,13 +5566,29 @@ public yyLSLSyntax 0,115,0,115,0, 105,0,111,0,110, 0,95,0,49,0, -1,245,1,3,1, -4,1,3,1353,22, -1,105,1,1872,1354, -16,0,314,1,1873, -835,1,118,1355,17, -1356,15,1121,1,-1, -1,5,1357,20,1358, +53,0,1,315,1, +3,1,4,1,3, +1461,22,1,150,1, +1859,1462,16,0,344, +1,1860,946,1,1804, +1463,17,1267,1,0, +1271,1,107,1464,17, +1465,15,1409,1,-1, +1,5,1466,20,1467, +4,34,85,0,110, +0,97,0,114,0, +121,0,69,0,120, +0,112,0,114,0, +101,0,115,0,115, +0,105,0,111,0, +110,0,95,0,49, +0,1,319,1,3, +1,3,1,2,1468, +22,1,154,1,1114, +1469,17,1312,1,3, +1316,1,1048,1470,17, +1471,15,1246,1,-1, +1,5,1472,20,1473, 4,38,66,0,105, 0,110,0,97,0, 114,0,121,0,69, @@ -4831,63 +5596,126 @@ public yyLSLSyntax 114,0,101,0,115, 0,115,0,105,0, 111,0,110,0,95, -0,49,0,52,0, -1,258,1,3,1, -4,1,3,1359,22, -1,118,1,1123,1360, -17,1361,15,1098,1, --1,1,5,1362,20, -1363,4,38,83,0, -105,0,109,0,112, -0,108,0,101,0, -65,0,115,0,115, -0,105,0,103,0, -110,0,109,0,101, -0,110,0,116,0, -95,0,49,0,50, -0,1,211,1,3, -1,6,1,5,1364, -22,1,71,1,371, -1365,17,1366,15,1367, -4,46,37,0,70, -0,117,0,110,0, -99,0,116,0,105, +0,49,0,56,0, +1,318,1,3,1, +4,1,3,1474,22, +1,153,1,352,1475, +17,1476,15,1246,1, +-1,1,5,1477,20, +1478,4,36,66,0, +105,0,110,0,97, +0,114,0,121,0, +69,0,120,0,112, +0,114,0,101,0, +115,0,115,0,105, 0,111,0,110,0, -67,0,97,0,108, -0,108,0,69,0, +95,0,49,0,1, +301,1,3,1,4, +1,3,1479,22,1, +136,1,1872,1480,16, +0,354,1,1873,961, +1,118,1481,17,1482, +15,1246,1,-1,1, +5,1483,20,1484,4, +38,66,0,105,0, +110,0,97,0,114, +0,121,0,69,0, 120,0,112,0,114, 0,101,0,115,0, 115,0,105,0,111, -0,110,0,1,-1, -1,5,1368,20,1369, -4,48,70,0,117, -0,110,0,99,0, -116,0,105,0,111, -0,110,0,67,0, -97,0,108,0,108, -0,69,0,120,0, -112,0,114,0,101, +0,110,0,95,0, +49,0,52,0,1, +314,1,3,1,4, +1,3,1485,22,1, +149,1,1123,1486,17, +1487,15,1223,1,-1, +1,5,1488,20,1489, +4,38,83,0,105, +0,109,0,112,0, +108,0,101,0,65, 0,115,0,115,0, -105,0,111,0,110, -0,95,0,49,0, -1,244,1,3,1, -2,1,1,1370,22, -1,104,1,1377,1371, -17,1372,15,1098,1, --1,1,5,1373,20, -1374,4,36,83,0, -105,0,109,0,112, -0,108,0,101,0, -65,0,115,0,115, -0,105,0,103,0, -110,0,109,0,101, +105,0,103,0,110, +0,109,0,101,0, +110,0,116,0,95, +0,49,0,50,0, +1,267,1,3,1, +6,1,5,1490,22, +1,102,1,371,1491, +17,1492,15,1493,4, +46,37,0,70,0, +117,0,110,0,99, +0,116,0,105,0, +111,0,110,0,67, +0,97,0,108,0, +108,0,69,0,120, +0,112,0,114,0, +101,0,115,0,115, +0,105,0,111,0, +110,0,1,-1,1, +5,1494,20,1495,4, +48,70,0,117,0, +110,0,99,0,116, +0,105,0,111,0, +110,0,67,0,97, +0,108,0,108,0, +69,0,120,0,112, +0,114,0,101,0, +115,0,115,0,105, +0,111,0,110,0, +95,0,49,0,1, +300,1,3,1,2, +1,1,1496,22,1, +135,1,1377,1497,17, +1498,15,1223,1,-1, +1,5,1499,20,1500, +4,36,83,0,105, +0,109,0,112,0, +108,0,101,0,65, +0,115,0,115,0, +105,0,103,0,110, +0,109,0,101,0, +110,0,116,0,95, +0,53,0,1,260, +1,3,1,4,1, +3,1501,22,1,95, +1,375,1502,17,1503, +15,1319,1,-1,1, +5,1504,20,1505,4, +60,73,0,110,0, +99,0,114,0,101, +0,109,0,101,0, +110,0,116,0,68, +0,101,0,99,0, +114,0,101,0,109, +0,101,0,110,0, +116,0,69,0,120, +0,112,0,114,0, +101,0,115,0,115, +0,105,0,111,0, +110,0,95,0,56, +0,1,299,1,3, +1,5,1,4,1506, +22,1,134,1,377, +1507,17,1508,15,1319, +1,-1,1,5,1509, +20,1510,4,60,73, +0,110,0,99,0, +114,0,101,0,109, +0,101,0,110,0, +116,0,68,0,101, +0,99,0,114,0, +101,0,109,0,101, 0,110,0,116,0, +69,0,120,0,112, +0,114,0,101,0, +115,0,115,0,105, +0,111,0,110,0, 95,0,53,0,1, -204,1,3,1,4, -1,3,1375,22,1, -64,1,375,1376,17, -1377,15,1192,1,-1, -1,5,1378,20,1379, +296,1,3,1,3, +1,2,1511,22,1, +131,1,379,1512,17, +1513,15,1319,1,-1, +1,5,1514,20,1515, 4,60,73,0,110, 0,99,0,114,0, 101,0,109,0,101, @@ -4900,30 +5728,64 @@ public yyLSLSyntax 0,101,0,115,0, 115,0,105,0,111, 0,110,0,95,0, -56,0,1,243,1, +55,0,1,298,1, 3,1,5,1,4, -1380,22,1,103,1, -377,1381,17,1382,15, -1192,1,-1,1,5, -1383,20,1384,4,60, -73,0,110,0,99, -0,114,0,101,0, -109,0,101,0,110, -0,116,0,68,0, -101,0,99,0,114, -0,101,0,109,0, -101,0,110,0,116, +1516,22,1,133,1, +380,1517,17,1518,15, +1519,4,38,37,0, +67,0,111,0,110, +0,115,0,116,0, +97,0,110,0,116, 0,69,0,120,0, 112,0,114,0,101, 0,115,0,115,0, 105,0,111,0,110, -0,95,0,53,0, -1,240,1,3,1, -3,1,2,1385,22, -1,100,1,379,1386, -17,1387,15,1192,1, --1,1,5,1388,20, -1389,4,60,73,0, +0,1,-1,1,5, +1520,20,1521,4,40, +67,0,111,0,110, +0,115,0,116,0, +97,0,110,0,116, +0,69,0,120,0, +112,0,114,0,101, +0,115,0,115,0, +105,0,111,0,110, +0,95,0,49,0, +1,289,1,3,1, +2,1,1,1522,22, +1,124,1,883,1523, +17,1524,15,1246,1, +-1,1,5,1525,20, +1526,4,38,66,0, +105,0,110,0,97, +0,114,0,121,0, +69,0,120,0,112, +0,114,0,101,0, +115,0,115,0,105, +0,111,0,110,0, +95,0,49,0,54, +0,1,316,1,3, +1,4,1,3,1527, +22,1,151,1,1628, +1528,17,1529,15,1530, +4,22,37,0,65, +0,115,0,115,0, +105,0,103,0,110, +0,109,0,101,0, +110,0,116,0,1, +-1,1,5,1531,20, +1532,4,24,65,0, +115,0,115,0,105, +0,103,0,110,0, +109,0,101,0,110, +0,116,0,95,0, +49,0,1,254,1, +3,1,4,1,3, +1533,22,1,89,1, +2075,1534,17,1267,1, +0,1271,1,373,1535, +17,1536,15,1319,1, +-1,1,5,1537,20, +1538,4,60,73,0, 110,0,99,0,114, 0,101,0,109,0, 101,0,110,0,116, @@ -4935,81 +5797,25 @@ public yyLSLSyntax 114,0,101,0,115, 0,115,0,105,0, 111,0,110,0,95, -0,55,0,1,242, -1,3,1,5,1, -4,1390,22,1,102, -1,380,1391,17,1392, -15,1393,4,38,37, -0,67,0,111,0, -110,0,115,0,116, -0,97,0,110,0, -116,0,69,0,120, -0,112,0,114,0, -101,0,115,0,115, -0,105,0,111,0, -110,0,1,-1,1, -5,1394,20,1395,4, -40,67,0,111,0, -110,0,115,0,116, -0,97,0,110,0, -116,0,69,0,120, -0,112,0,114,0, -101,0,115,0,115, -0,105,0,111,0, -110,0,95,0,49, -0,1,233,1,3, -1,2,1,1,1396, -22,1,93,1,883, -1397,17,1398,15,1121, -1,-1,1,5,1399, -20,1400,4,38,66, -0,105,0,110,0, -97,0,114,0,121, -0,69,0,120,0, -112,0,114,0,101, -0,115,0,115,0, -105,0,111,0,110, -0,95,0,49,0, -54,0,1,260,1, -3,1,4,1,3, -1401,22,1,120,1, -1628,1402,17,1403,15, -1404,4,22,37,0, -65,0,115,0,115, -0,105,0,103,0, -110,0,109,0,101, -0,110,0,116,0, -1,-1,1,5,1405, -20,1406,4,24,65, -0,115,0,115,0, -105,0,103,0,110, -0,109,0,101,0, -110,0,116,0,95, -0,49,0,1,198, -1,3,1,4,1, -3,1407,22,1,58, -1,2075,1408,17,1142, -1,0,1146,1,373, -1409,17,1410,15,1192, -1,-1,1,5,1411, -20,1412,4,60,73, -0,110,0,99,0, -114,0,101,0,109, -0,101,0,110,0, -116,0,68,0,101, -0,99,0,114,0, -101,0,109,0,101, -0,110,0,116,0, -69,0,120,0,112, -0,114,0,101,0, -115,0,115,0,105, -0,111,0,110,0, -95,0,54,0,1, -241,1,3,1,3, -1,2,1413,22,1, -101,1,130,1414,17, -1415,15,1121,1,-1, -1,5,1416,20,1417, +0,54,0,1,297, +1,3,1,3,1, +2,1539,22,1,132, +1,130,1540,17,1541, +15,1246,1,-1,1, +5,1542,20,1543,4, +38,66,0,105,0, +110,0,97,0,114, +0,121,0,69,0, +120,0,112,0,114, +0,101,0,115,0, +115,0,105,0,111, +0,110,0,95,0, +49,0,51,0,1, +313,1,3,1,4, +1,3,1544,22,1, +148,1,143,1545,17, +1546,15,1246,1,-1, +1,5,1547,20,1548, 4,38,66,0,105, 0,110,0,97,0, 114,0,121,0,69, @@ -5017,42 +5823,96 @@ public yyLSLSyntax 114,0,101,0,115, 0,115,0,105,0, 111,0,110,0,95, -0,49,0,51,0, -1,257,1,3,1, -4,1,3,1418,22, -1,117,1,143,1419, -17,1420,15,1121,1, --1,1,5,1421,20, -1422,4,38,66,0, +0,49,0,50,0, +1,312,1,3,1, +4,1,3,1549,22, +1,147,1,1901,1550, +17,1267,1,0,1271, +1,1152,1551,17,1552, +15,1223,1,-1,1, +5,1553,20,1554,4, +38,83,0,105,0, +109,0,112,0,108, +0,101,0,65,0, +115,0,115,0,105, +0,103,0,110,0, +109,0,101,0,110, +0,116,0,95,0, +50,0,52,0,1, +279,1,3,1,6, +1,5,1555,22,1, +114,1,1406,1556,17, +1557,15,1223,1,-1, +1,5,1558,20,1559, +4,38,83,0,105, +0,109,0,112,0, +108,0,101,0,65, +0,115,0,115,0, +105,0,103,0,110, +0,109,0,101,0, +110,0,116,0,95, +0,49,0,55,0, +1,272,1,3,1, +4,1,3,1560,22, +1,107,1,1659,1561, +16,0,298,1,2413, +1562,17,1267,1,0, +1271,1,1159,1563,17, +1564,15,1223,1,-1, +1,5,1565,20,1566, +4,38,83,0,105, +0,109,0,112,0, +108,0,101,0,65, +0,115,0,115,0, +105,0,103,0,110, +0,109,0,101,0, +110,0,116,0,95, +0,49,0,49,0, +1,266,1,3,1, +6,1,5,1567,22, +1,101,1,157,1568, +17,1569,15,1246,1, +-1,1,5,1570,20, +1571,4,38,66,0, 105,0,110,0,97, 0,114,0,121,0, 69,0,120,0,112, 0,114,0,101,0, 115,0,115,0,105, 0,111,0,110,0, -95,0,49,0,50, -0,1,256,1,3, -1,4,1,3,1423, -22,1,116,1,1901, -1424,17,1142,1,0, -1146,1,2657,1425,16, -0,608,1,1152,1426, -17,1427,15,1098,1, --1,1,5,1428,20, -1429,4,38,83,0, +95,0,49,0,49, +0,1,311,1,3, +1,4,1,3,1572, +22,1,146,1,1413, +1573,17,1574,15,1223, +1,-1,1,5,1575, +20,1576,4,36,83, +0,105,0,109,0, +112,0,108,0,101, +0,65,0,115,0, +115,0,105,0,103, +0,110,0,109,0, +101,0,110,0,116, +0,95,0,52,0, +1,259,1,3,1, +4,1,3,1577,22, +1,94,1,1370,1578, +17,1579,15,1223,1, +-1,1,5,1580,20, +1581,4,38,83,0, 105,0,109,0,112, 0,108,0,101,0, 65,0,115,0,115, 0,105,0,103,0, 110,0,109,0,101, 0,110,0,116,0, -95,0,50,0,52, -0,1,223,1,3, -1,6,1,5,1430, -22,1,83,1,1406, -1431,17,1432,15,1098, -1,-1,1,5,1433, -20,1434,4,38,83, +95,0,49,0,56, +0,1,273,1,3, +1,4,1,3,1582, +22,1,108,1,1478, +1583,17,1584,15,1223, +1,-1,1,5,1585, +20,1586,4,38,83, 0,105,0,109,0, 112,0,108,0,101, 0,65,0,115,0, @@ -5060,15 +5920,67 @@ public yyLSLSyntax 0,110,0,109,0, 101,0,110,0,116, 0,95,0,49,0, -55,0,1,216,1, +53,0,1,270,1, +3,1,4,1,3, +1587,22,1,105,1, +2106,1588,17,1267,1, +0,1271,1,1620,1589, +17,1590,15,1530,1, +-1,1,5,1591,20, +1592,4,24,65,0, +115,0,115,0,105, +0,103,0,110,0, +109,0,101,0,110, +0,116,0,95,0, +50,0,1,255,1, +3,1,2,1,1, +1593,22,1,90,1, +1621,1594,16,0,791, +1,1574,924,1,172, +1595,17,1596,15,1246, +1,-1,1,5,1597, +20,1598,4,38,66, +0,105,0,110,0, +97,0,114,0,121, +0,69,0,120,0, +112,0,114,0,101, +0,115,0,115,0, +105,0,111,0,110, +0,95,0,49,0, +48,0,1,310,1, 3,1,4,1,3, -1435,22,1,76,1, -1659,1436,16,0,269, -1,2413,1437,17,1142, -1,0,1146,1,1159, -1438,17,1439,15,1098, -1,-1,1,5,1440, -20,1441,4,38,83, +1599,22,1,145,1, +1931,986,1,1665,1600, +17,1601,15,1281,1, +-1,1,5,1602,20, +1603,4,36,70,0, +111,0,114,0,76, +0,111,0,111,0, +112,0,83,0,116, +0,97,0,116,0, +101,0,109,0,101, +0,110,0,116,0, +95,0,49,0,1, +250,1,3,1,2, +1,1,1604,22,1, +85,1,2364,952,1, +2105,939,1,1188,1605, +17,1606,15,1223,1, +-1,1,5,1607,20, +1608,4,38,83,0, +105,0,109,0,112, +0,108,0,101,0, +65,0,115,0,115, +0,105,0,103,0, +110,0,109,0,101, +0,110,0,116,0, +95,0,50,0,51, +0,1,278,1,3, +1,6,1,5,1609, +22,1,113,1,1442, +1610,17,1611,15,1223, +1,-1,1,5,1612, +20,1613,4,38,83, 0,105,0,109,0, 112,0,108,0,101, 0,65,0,115,0, @@ -5076,38 +5988,28 @@ public yyLSLSyntax 0,110,0,109,0, 101,0,110,0,116, 0,95,0,49,0, -49,0,1,210,1, -3,1,6,1,5, -1442,22,1,70,1, -157,1443,17,1444,15, -1121,1,-1,1,5, -1445,20,1446,4,38, -66,0,105,0,110, -0,97,0,114,0, -121,0,69,0,120, -0,112,0,114,0, -101,0,115,0,115, -0,105,0,111,0, -110,0,95,0,49, -0,49,0,1,255, -1,3,1,4,1, -3,1447,22,1,115, -1,1413,1448,17,1449, -15,1098,1,-1,1, -5,1450,20,1451,4, -36,83,0,105,0, -109,0,112,0,108, -0,101,0,65,0, -115,0,115,0,105, -0,103,0,110,0, -109,0,101,0,110, -0,116,0,95,0, -52,0,1,203,1, +54,0,1,271,1, 3,1,4,1,3, -1452,22,1,63,1, -1370,1453,17,1454,15, -1098,1,-1,1,5, -1455,20,1456,4,38, +1614,22,1,106,1, +1694,1615,16,0,215, +1,942,1616,17,1617, +15,1246,1,-1,1, +5,1618,20,1619,4, +38,66,0,105,0, +110,0,97,0,114, +0,121,0,69,0, +120,0,112,0,114, +0,101,0,115,0, +115,0,105,0,111, +0,110,0,95,0, +49,0,55,0,1, +317,1,3,1,4, +1,3,1620,22,1, +152,1,2198,1621,17, +1267,1,0,1271,1, +1195,1622,17,1623,15, +1223,1,-1,1,5, +1624,20,1625,4,38, 83,0,105,0,109, 0,112,0,108,0, 101,0,65,0,115, @@ -5115,314 +6017,204 @@ public yyLSLSyntax 103,0,110,0,109, 0,101,0,110,0, 116,0,95,0,49, -0,56,0,1,217, -1,3,1,4,1, -3,1457,22,1,77, -1,1478,1458,17,1459, -15,1098,1,-1,1, -5,1460,20,1461,4, -38,83,0,105,0, +0,48,0,1,265, +1,3,1,6,1, +5,1626,22,1,100, +1,1449,1627,17,1628, +15,1223,1,-1,1, +5,1629,20,1630,4, +36,83,0,105,0, 109,0,112,0,108, 0,101,0,65,0, 115,0,115,0,105, 0,103,0,110,0, 109,0,101,0,110, 0,116,0,95,0, -49,0,53,0,1, -214,1,3,1,4, -1,3,1462,22,1, -74,1,1620,1463,17, -1464,15,1404,1,-1, -1,5,1465,20,1466, -4,24,65,0,115, -0,115,0,105,0, -103,0,110,0,109, +51,0,1,258,1, +3,1,4,1,3, +1631,22,1,93,1, +1701,1632,17,1633,15, +1281,1,-1,1,5, +1634,20,1635,4,36, +70,0,111,0,114, +0,76,0,111,0, +111,0,112,0,83, +0,116,0,97,0, +116,0,101,0,109, 0,101,0,110,0, -116,0,95,0,50, -0,1,199,1,3, -1,2,1,1,1467, -22,1,59,1,1621, -1468,16,0,668,1, -1574,799,1,172,1469, -17,1470,15,1121,1, --1,1,5,1471,20, -1472,4,38,66,0, -105,0,110,0,97, -0,114,0,121,0, -69,0,120,0,112, -0,114,0,101,0, -115,0,115,0,105, -0,111,0,110,0, -95,0,49,0,48, -0,1,254,1,3, -1,4,1,3,1473, -22,1,114,1,1931, -861,1,1665,1474,17, -1475,15,1156,1,-1, -1,5,1476,20,1477, -4,36,70,0,111, -0,114,0,76,0, -111,0,111,0,112, -0,83,0,116,0, -97,0,116,0,101, -0,109,0,101,0, -110,0,116,0,95, -0,49,0,1,194, -1,3,1,2,1, -1,1478,22,1,54, -1,2364,827,1,2105, -814,1,1188,1479,17, -1480,15,1098,1,-1, -1,5,1481,20,1482, -4,38,83,0,105, -0,109,0,112,0, -108,0,101,0,65, -0,115,0,115,0, -105,0,103,0,110, -0,109,0,101,0, +116,0,95,0,51, +0,1,252,1,3, +1,4,1,3,1636, +22,1,87,1,447, +1637,17,1638,15,1639, +4,30,37,0,86, +0,101,0,99,0, +116,0,111,0,114, +0,67,0,111,0, +110,0,115,0,116, +0,97,0,110,0, +116,0,1,-1,1, +5,1640,20,1641,4, +32,86,0,101,0, +99,0,116,0,111, +0,114,0,67,0, +111,0,110,0,115, +0,116,0,97,0, 110,0,116,0,95, -0,50,0,51,0, -1,222,1,3,1, -6,1,5,1483,22, -1,82,1,1442,1484, -17,1485,15,1098,1, --1,1,5,1486,20, -1487,4,38,83,0, -105,0,109,0,112, -0,108,0,101,0, -65,0,115,0,115, -0,105,0,103,0, -110,0,109,0,101, -0,110,0,116,0, -95,0,49,0,54, -0,1,215,1,3, -1,4,1,3,1488, -22,1,75,1,1694, -1489,16,0,190,1, -942,1490,17,1491,15, -1121,1,-1,1,5, -1492,20,1493,4,38, +0,49,0,1,287, +1,3,1,8,1, +7,1642,22,1,122, +1,2458,1001,1,2459, +1007,1,1958,1643,17, +1267,1,0,1271,1, +188,1644,17,1645,15, +1246,1,-1,1,5, +1646,20,1647,4,36, 66,0,105,0,110, 0,97,0,114,0, 121,0,69,0,120, 0,112,0,114,0, 101,0,115,0,115, 0,105,0,111,0, -110,0,95,0,49, -0,55,0,1,261, -1,3,1,4,1, -3,1494,22,1,121, -1,2198,1495,17,1142, -1,0,1146,1,1195, -1496,17,1497,15,1098, -1,-1,1,5,1498, -20,1499,4,38,83, -0,105,0,109,0, -112,0,108,0,101, -0,65,0,115,0, -115,0,105,0,103, -0,110,0,109,0, -101,0,110,0,116, -0,95,0,49,0, -48,0,1,209,1, -3,1,6,1,5, -1500,22,1,69,1, -1449,1501,17,1502,15, -1098,1,-1,1,5, -1503,20,1504,4,36, +110,0,95,0,57, +0,1,309,1,3, +1,4,1,3,1648, +22,1,144,1,2462, +1014,1,1657,1019,1, +2464,1024,1,205,1649, +17,1650,15,1246,1, +-1,1,5,1651,20, +1652,4,36,66,0, +105,0,110,0,97, +0,114,0,121,0, +69,0,120,0,112, +0,114,0,101,0, +115,0,115,0,105, +0,111,0,110,0, +95,0,56,0,1, +308,1,3,1,4, +1,3,1653,22,1, +143,1,2227,1033,1, +1224,1654,17,1655,15, +1223,1,-1,1,5, +1656,20,1657,4,38, 83,0,105,0,109, 0,112,0,108,0, 101,0,65,0,115, 0,115,0,105,0, 103,0,110,0,109, 0,101,0,110,0, -116,0,95,0,51, -0,1,202,1,3, -1,4,1,3,1505, -22,1,62,1,1701, -1506,17,1507,15,1156, -1,-1,1,5,1508, -20,1509,4,36,70, -0,111,0,114,0, -76,0,111,0,111, -0,112,0,83,0, -116,0,97,0,116, -0,101,0,109,0, -101,0,110,0,116, -0,95,0,51,0, -1,196,1,3,1, -4,1,3,1510,22, -1,56,1,447,1511, -17,1512,15,1513,4, -30,37,0,86,0, -101,0,99,0,116, -0,111,0,114,0, -67,0,111,0,110, -0,115,0,116,0, -97,0,110,0,116, -0,1,-1,1,5, -1514,20,1515,4,32, -86,0,101,0,99, -0,116,0,111,0, -114,0,67,0,111, -0,110,0,115,0, -116,0,97,0,110, -0,116,0,95,0, -49,0,1,231,1, -3,1,8,1,7, -1516,22,1,91,1, -2458,876,1,2459,882, -1,1958,1517,17,1142, -1,0,1146,1,188, -1518,17,1519,15,1121, -1,-1,1,5,1520, -20,1521,4,36,66, -0,105,0,110,0, -97,0,114,0,121, -0,69,0,120,0, -112,0,114,0,101, -0,115,0,115,0, -105,0,111,0,110, -0,95,0,57,0, -1,253,1,3,1, -4,1,3,1522,22, -1,113,1,2462,889, -1,1657,894,1,2464, -899,1,205,1523,17, -1524,15,1121,1,-1, -1,5,1525,20,1526, -4,36,66,0,105, -0,110,0,97,0, -114,0,121,0,69, -0,120,0,112,0, -114,0,101,0,115, -0,115,0,105,0, -111,0,110,0,95, -0,56,0,1,252, -1,3,1,4,1, -3,1527,22,1,112, -1,2227,908,1,1224, -1528,17,1529,15,1098, -1,-1,1,5,1530, -20,1531,4,38,83, -0,105,0,109,0, -112,0,108,0,101, -0,65,0,115,0, -115,0,105,0,103, -0,110,0,109,0, -101,0,110,0,116, -0,95,0,50,0, -50,0,1,221,1, -3,1,6,1,5, -1532,22,1,81,1, -223,1533,17,1534,15, -1121,1,-1,1,5, -1535,20,1536,4,36, -66,0,105,0,110, -0,97,0,114,0, -121,0,69,0,120, -0,112,0,114,0, -101,0,115,0,115, -0,105,0,111,0, -110,0,95,0,55, -0,1,251,1,3, -1,4,1,3,1537, -22,1,111,1,1730, -1538,17,1539,15,1156, -1,-1,1,5,1540, -20,1541,4,36,70, -0,111,0,114,0, -76,0,111,0,111, -0,112,0,83,0, -116,0,97,0,116, -0,101,0,109,0, -101,0,110,0,116, -0,95,0,52,0, -1,197,1,3,1, -4,1,3,1542,22, -1,57,1,476,1543, -17,1544,15,1545,4, -18,37,0,67,0, -111,0,110,0,115, -0,116,0,97,0, -110,0,116,0,1, --1,1,5,1546,20, -1547,4,20,67,0, -111,0,110,0,115, -0,116,0,97,0, -110,0,116,0,95, -0,52,0,1,229, -1,3,1,2,1, -1,1548,22,1,89, -1,477,1549,17,1550, -15,1545,1,-1,1, -5,1551,20,1552,4, -20,67,0,111,0, -110,0,115,0,116, -0,97,0,110,0, -116,0,95,0,51, -0,1,228,1,3, -1,2,1,1,1553, -22,1,88,1,1231, -1554,17,1555,15,1098, -1,-1,1,5,1556, -20,1557,4,36,83, -0,105,0,109,0, -112,0,108,0,101, -0,65,0,115,0, -115,0,105,0,103, -0,110,0,109,0, -101,0,110,0,116, -0,95,0,57,0, -1,208,1,3,1, -6,1,5,1558,22, -1,68,1,479,1559, -17,1560,15,1545,1, --1,1,5,1561,20, -1562,4,20,67,0, -111,0,110,0,115, +116,0,95,0,50, +0,50,0,1,277, +1,3,1,6,1, +5,1658,22,1,112, +1,223,1659,17,1660, +15,1246,1,-1,1, +5,1661,20,1662,4, +36,66,0,105,0, +110,0,97,0,114, +0,121,0,69,0, +120,0,112,0,114, +0,101,0,115,0, +115,0,105,0,111, +0,110,0,95,0, +55,0,1,307,1, +3,1,4,1,3, +1663,22,1,142,1, +1730,1664,17,1665,15, +1281,1,-1,1,5, +1666,20,1667,4,36, +70,0,111,0,114, +0,76,0,111,0, +111,0,112,0,83, 0,116,0,97,0, -110,0,116,0,95, -0,49,0,1,226, -1,3,1,2,1, -1,1563,22,1,86, -1,480,1564,17,1565, -15,1566,4,26,37, -0,76,0,105,0, -115,0,116,0,67, +116,0,101,0,109, +0,101,0,110,0, +116,0,95,0,52, +0,1,253,1,3, +1,4,1,3,1668, +22,1,88,1,476, +1669,17,1670,15,1671, +4,18,37,0,67, 0,111,0,110,0, 115,0,116,0,97, 0,110,0,116,0, -1,-1,1,5,1567, -20,1568,4,28,76, -0,105,0,115,0, -116,0,67,0,111, +1,-1,1,5,1672, +20,1673,4,20,67, +0,111,0,110,0, +115,0,116,0,97, +0,110,0,116,0, +95,0,52,0,1, +285,1,3,1,2, +1,1,1674,22,1, +120,1,477,1675,17, +1676,15,1671,1,-1, +1,5,1677,20,1678, +4,20,67,0,111, 0,110,0,115,0, 116,0,97,0,110, 0,116,0,95,0, -49,0,1,230,1, -3,1,4,1,3, -1569,22,1,90,1, -1485,1570,17,1571,15, -1098,1,-1,1,5, -1572,20,1573,4,36, +51,0,1,284,1, +3,1,2,1,1, +1679,22,1,119,1, +1231,1680,17,1681,15, +1223,1,-1,1,5, +1682,20,1683,4,36, 83,0,105,0,109, 0,112,0,108,0, 101,0,65,0,115, 0,115,0,105,0, 103,0,110,0,109, 0,101,0,110,0, -116,0,95,0,50, -0,1,201,1,3, -1,4,1,3,1574, -22,1,61,1,1737, -1575,16,0,271,1, -1989,916,1,1990,1576, -17,1142,1,0,1146, -1,2664,1577,16,0, -667,1,242,1578,17, -1579,15,1121,1,-1, -1,5,1580,20,1581, +116,0,95,0,57, +0,1,264,1,3, +1,6,1,5,1684, +22,1,99,1,479, +1685,17,1686,15,1671, +1,-1,1,5,1687, +20,1688,4,20,67, +0,111,0,110,0, +115,0,116,0,97, +0,110,0,116,0, +95,0,49,0,1, +282,1,3,1,2, +1,1,1689,22,1, +117,1,480,1690,17, +1691,15,1692,4,26, +37,0,76,0,105, +0,115,0,116,0, +67,0,111,0,110, +0,115,0,116,0, +97,0,110,0,116, +0,1,-1,1,5, +1693,20,1694,4,28, +76,0,105,0,115, +0,116,0,67,0, +111,0,110,0,115, +0,116,0,97,0, +110,0,116,0,95, +0,49,0,1,286, +1,3,1,4,1, +3,1695,22,1,121, +1,1485,1696,17,1697, +15,1223,1,-1,1, +5,1698,20,1699,4, +36,83,0,105,0, +109,0,112,0,108, +0,101,0,65,0, +115,0,115,0,105, +0,103,0,110,0, +109,0,101,0,110, +0,116,0,95,0, +50,0,1,257,1, +3,1,4,1,3, +1700,22,1,92,1, +1737,1701,16,0,303, +1,1989,1041,1,1990, +1702,17,1267,1,0, +1271,1,242,1703,17, +1704,15,1246,1,-1, +1,5,1705,20,1706, 4,36,66,0,105, 0,110,0,97,0, 114,0,121,0,69, @@ -5430,22 +6222,22 @@ public yyLSLSyntax 114,0,101,0,115, 0,115,0,105,0, 111,0,110,0,95, -0,54,0,1,250, +0,54,0,1,306, 1,3,1,4,1, -3,1582,22,1,110, -1,478,1583,17,1584, -15,1545,1,-1,1, -5,1585,20,1586,4, +3,1707,22,1,141, +1,478,1708,17,1709, +15,1671,1,-1,1, +5,1710,20,1711,4, 20,67,0,111,0, 110,0,115,0,116, 0,97,0,110,0, 116,0,95,0,50, -0,1,227,1,3, -1,2,1,1,1587, -22,1,87,1,1001, -1588,17,1589,15,1224, -1,-1,1,5,1590, -20,1591,4,40,84, +0,1,283,1,3, +1,2,1,1,1712, +22,1,118,1,1001, +1713,17,1714,15,1351, +1,-1,1,5,1715, +20,1716,4,40,84, 0,121,0,112,0, 101,0,99,0,97, 0,115,0,116,0, @@ -5454,11 +6246,11 @@ public yyLSLSyntax 115,0,115,0,105, 0,111,0,110,0, 95,0,56,0,1, -275,1,3,1,5, -1,4,1592,22,1, -135,1,1002,1593,17, -1594,15,1224,1,-1, -1,5,1595,20,1596, +331,1,3,1,5, +1,4,1717,22,1, +166,1,1002,1718,17, +1719,15,1351,1,-1, +1,5,1720,20,1721, 4,40,84,0,121, 0,112,0,101,0, 99,0,97,0,115, @@ -5467,116 +6259,445 @@ public yyLSLSyntax 0,101,0,115,0, 115,0,105,0,111, 0,110,0,95,0, -49,0,1,268,1, +49,0,1,324,1, 3,1,5,1,4, -1597,22,1,128,1, -12,1598,19,157,1, -12,1599,5,43,1, -1901,1600,16,0,155, -1,2075,1601,16,0, -155,1,1860,821,1, -1803,787,1,1804,1602, -16,0,155,1,2517, -1603,16,0,155,1, -2413,1604,16,0,155, -1,2198,1605,16,0, -155,1,1873,835,1, -1657,894,1,1989,916, -1,1990,1606,16,0, -155,1,31,1607,16, -0,155,1,32,1608, -16,0,155,1,2105, -814,1,2106,1609,16, -0,155,1,2653,1610, -16,0,155,1,2227, -908,1,2337,1611,16, -0,155,1,2560,1612, -16,0,467,1,2021, -718,1,2458,876,1, -2459,882,1,2462,889, -1,2136,842,1,2464, -899,1,2029,725,1, -2030,731,1,2031,736, -1,2032,741,1,2469, -1613,16,0,454,1, -2035,752,1,2364,827, -1,2039,762,1,1931, -861,1,2041,768,1, -2043,774,1,2045,779, -1,1775,1614,16,0, -155,1,2033,746,1, -2037,757,1,1574,799, -1,1958,1615,16,0, -155,1,13,1616,19, -448,1,13,1617,5, -34,1,1860,821,1, -1803,787,1,2519,1618, -17,1619,15,1620,4, -22,37,0,83,0, +1722,22,1,159,1, +12,1723,19,166,1, +12,1724,5,50,1, +1901,1725,16,0,164, +1,2075,1726,16,0, +164,1,1860,946,1, +1803,912,1,1804,1727, +16,0,164,1,2519, +1728,16,0,164,1, +2549,1729,16,0,164, +1,2413,1730,16,0, +164,1,2198,1731,16, +0,164,1,1873,961, +1,1657,1019,1,2534, +1732,16,0,164,1, +1990,1733,16,0,164, +1,31,1734,16,0, +164,1,32,1735,16, +0,164,1,2105,939, +1,2106,1736,16,0, +164,1,2573,1737,16, +0,164,1,2658,1738, +16,0,284,1,2578, +1739,16,0,164,1, +2227,1033,1,2337,1740, +16,0,164,1,2557, +1741,16,0,164,1, +2781,1742,16,0,164, +1,2565,1743,16,0, +164,1,2021,843,1, +2458,1001,1,2459,1007, +1,2462,1014,1,2136, +968,1,2464,1024,1, +2029,850,1,2030,856, +1,2031,861,1,2032, +866,1,2469,1744,16, +0,536,1,2035,877, +1,2364,952,1,2039, +887,1,1931,986,1, +2041,893,1,2043,899, +1,2045,904,1,2593, +1745,16,0,164,1, +1775,1746,16,0,164, +1,1989,1041,1,2033, +871,1,2037,882,1, +1574,924,1,1958,1747, +16,0,164,1,13, +1748,19,213,1,13, +1749,5,55,1,2536, +1750,17,1751,15,1752, +4,46,37,0,73, +0,110,0,116,0, +86,0,101,0,99, +0,86,0,101,0, +99,0,65,0,114, +0,103,0,83,0, 116,0,97,0,116, 0,101,0,69,0, 118,0,101,0,110, 0,116,0,1,-1, -1,5,1621,20,1622, -4,24,83,0,116, -0,97,0,116,0, -101,0,69,0,118, -0,101,0,110,0, -116,0,95,0,49, -0,1,158,1,3, -1,6,1,5,1623, -22,1,17,1,2521, -1624,16,0,460,1, -2413,1625,16,0,446, -1,1873,835,1,1657, -894,1,1989,916,1, -32,1626,16,0,449, -1,2105,814,1,2364, -827,1,2227,908,1, -1574,799,1,2557,1627, -17,1628,15,1629,4, +1,5,1753,20,1754, +4,48,73,0,110, +0,116,0,86,0, +101,0,99,0,86, +0,101,0,99,0, +65,0,114,0,103, +0,83,0,116,0, +97,0,116,0,101, +0,69,0,118,0, +101,0,110,0,116, +0,95,0,49,0, +1,203,1,3,1, +6,1,5,1755,22, +1,37,1,2643,1756, +17,1757,15,1758,4, 20,37,0,83,0, 116,0,97,0,116, 0,101,0,66,0, 111,0,100,0,121, 0,1,-1,1,5, -1630,20,1631,4,22, +1759,20,1760,4,24, 83,0,116,0,97, 0,116,0,101,0, 66,0,111,0,100, 0,121,0,95,0, -50,0,1,157,1, -3,1,3,1,2, -1632,22,1,16,1, -2559,1633,17,1634,15, -1629,1,-1,1,5, -1635,20,1636,4,22, +49,0,50,0,1, +192,1,3,1,3, +1,2,1761,22,1, +26,1,2647,1762,17, +1763,15,1758,1,-1, +1,5,1764,20,1765, +4,22,83,0,116, +0,97,0,116,0, +101,0,66,0,111, +0,100,0,121,0, +95,0,52,0,1, +184,1,3,1,3, +1,2,1766,22,1, +18,1,1860,946,1, +1803,912,1,2521,1767, +17,1768,15,1769,4, +46,37,0,75,0, +101,0,121,0,73, +0,110,0,116,0, +73,0,110,0,116, +0,65,0,114,0, +103,0,83,0,116, +0,97,0,116,0, +101,0,69,0,118, +0,101,0,110,0, +116,0,1,-1,1, +5,1770,20,1771,4, +48,75,0,101,0, +121,0,73,0,110, +0,116,0,73,0, +110,0,116,0,65, +0,114,0,103,0, 83,0,116,0,97, 0,116,0,101,0, -66,0,111,0,100, -0,121,0,95,0, -49,0,1,156,1, -3,1,2,1,1, -1637,22,1,15,1, -2021,718,1,2458,876, -1,2459,882,1,2462, -889,1,2136,842,1, -2464,899,1,2029,725, -1,2030,731,1,2031, -736,1,2032,741,1, -2033,746,1,2035,752, -1,2037,757,1,2039, -762,1,1931,861,1, -2041,768,1,2043,774, -1,2045,779,1,2597, -1638,16,0,639,1, -14,1639,19,144,1, -14,1640,5,105,1, -2515,1641,16,0,142, -1,1011,1102,1,1514, -1108,1,9,1113,1, -10,1642,17,1643,15, -1644,4,48,37,0, +69,0,118,0,101, +0,110,0,116,0, +95,0,49,0,1, +204,1,3,1,6, +1,5,1772,22,1, +38,1,2413,1773,16, +0,521,1,2657,1774, +17,1775,15,1758,1, +-1,1,5,1776,20, +1777,4,22,83,0, +116,0,97,0,116, +0,101,0,66,0, +111,0,100,0,121, +0,95,0,49,0, +1,181,1,3,1, +2,1,1,1778,22, +1,15,1,1873,961, +1,1657,1019,1,2641, +1779,17,1780,15,1758, +1,-1,1,5,1781, +20,1782,4,24,83, +0,116,0,97,0, +116,0,101,0,66, +0,111,0,100,0, +121,0,95,0,49, +0,54,0,1,196, +1,3,1,3,1, +2,1783,22,1,30, +1,2642,1784,17,1785, +15,1758,1,-1,1, +5,1786,20,1787,4, +24,83,0,116,0, +97,0,116,0,101, +0,66,0,111,0, +100,0,121,0,95, +0,49,0,52,0, +1,194,1,3,1, +3,1,2,1788,22, +1,28,1,1989,1041, +1,2644,1789,17,1790, +15,1758,1,-1,1, +5,1791,20,1792,4, +24,83,0,116,0, +97,0,116,0,101, +0,66,0,111,0, +100,0,121,0,95, +0,49,0,48,0, +1,190,1,3,1, +3,1,2,1793,22, +1,24,1,2645,1794, +17,1795,15,1758,1, +-1,1,5,1796,20, +1797,4,22,83,0, +116,0,97,0,116, +0,101,0,66,0, +111,0,100,0,121, +0,95,0,56,0, +1,188,1,3,1, +3,1,2,1798,22, +1,22,1,2646,1799, +17,1800,15,1758,1, +-1,1,5,1801,20, +1802,4,22,83,0, +116,0,97,0,116, +0,101,0,66,0, +111,0,100,0,121, +0,95,0,54,0, +1,186,1,3,1, +3,1,2,1803,22, +1,20,1,2037,882, +1,32,1804,16,0, +526,1,2567,1805,17, +1806,15,1807,4,34, +37,0,73,0,110, +0,116,0,65,0, +114,0,103,0,83, +0,116,0,97,0, +116,0,101,0,69, +0,118,0,101,0, +110,0,116,0,1, +-1,1,5,1808,20, +1809,4,36,73,0, +110,0,116,0,65, +0,114,0,103,0, +83,0,116,0,97, +0,116,0,101,0, +69,0,118,0,101, +0,110,0,116,0, +95,0,49,0,1, +200,1,3,1,6, +1,5,1810,22,1, +34,1,2650,1811,17, +1812,15,1758,1,-1, +1,5,1813,20,1814, +4,24,83,0,116, +0,97,0,116,0, +101,0,66,0,111, +0,100,0,121,0, +95,0,49,0,53, +0,1,195,1,3, +1,2,1,1,1815, +22,1,29,1,2651, +1816,17,1817,15,1758, +1,-1,1,5,1818, +20,1819,4,24,83, +0,116,0,97,0, +116,0,101,0,66, +0,111,0,100,0, +121,0,95,0,49, +0,51,0,1,193, +1,3,1,2,1, +1,1820,22,1,27, +1,2652,1821,17,1822, +15,1758,1,-1,1, +5,1823,20,1824,4, +24,83,0,116,0, +97,0,116,0,101, +0,66,0,111,0, +100,0,121,0,95, +0,49,0,49,0, +1,191,1,3,1, +2,1,1,1825,22, +1,25,1,2653,1826, +17,1827,15,1758,1, +-1,1,5,1828,20, +1829,4,22,83,0, +116,0,97,0,116, +0,101,0,66,0, +111,0,100,0,121, +0,95,0,57,0, +1,189,1,3,1, +2,1,1,1830,22, +1,23,1,2654,1831, +17,1832,15,1758,1, +-1,1,5,1833,20, +1834,4,22,83,0, +116,0,97,0,116, +0,101,0,66,0, +111,0,100,0,121, +0,95,0,55,0, +1,187,1,3,1, +2,1,1,1835,22, +1,21,1,2655,1836, +17,1837,15,1758,1, +-1,1,5,1838,20, +1839,4,22,83,0, +116,0,97,0,116, +0,101,0,66,0, +111,0,100,0,121, +0,95,0,53,0, +1,185,1,3,1, +2,1,1,1840,22, +1,19,1,2656,1841, +17,1842,15,1758,1, +-1,1,5,1843,20, +1844,4,22,83,0, +116,0,97,0,116, +0,101,0,66,0, +111,0,100,0,121, +0,95,0,51,0, +1,183,1,3,1, +2,1,1,1845,22, +1,17,1,2575,1846, +17,1847,15,1848,4, +34,37,0,75,0, +101,0,121,0,65, +0,114,0,103,0, +83,0,116,0,97, +0,116,0,101,0, +69,0,118,0,101, +0,110,0,116,0, +1,-1,1,5,1849, +20,1850,4,36,75, +0,101,0,121,0, +65,0,114,0,103, +0,83,0,116,0, +97,0,116,0,101, +0,69,0,118,0, +101,0,110,0,116, +0,95,0,49,0, +1,199,1,3,1, +6,1,5,1851,22, +1,33,1,2551,1852, +17,1853,15,1854,4, +46,37,0,73,0, +110,0,116,0,82, +0,111,0,116,0, +82,0,111,0,116, +0,65,0,114,0, +103,0,83,0,116, +0,97,0,116,0, +101,0,69,0,118, +0,101,0,110,0, +116,0,1,-1,1, +5,1855,20,1856,4, +48,73,0,110,0, +116,0,82,0,111, +0,116,0,82,0, +111,0,116,0,65, +0,114,0,103,0, +83,0,116,0,97, +0,116,0,101,0, +69,0,118,0,101, +0,110,0,116,0, +95,0,49,0,1, +202,1,3,1,6, +1,5,1857,22,1, +36,1,2580,1858,17, +1859,15,1860,4,36, +37,0,86,0,111, +0,105,0,100,0, +65,0,114,0,103, +0,83,0,116,0, +97,0,116,0,101, +0,69,0,118,0, +101,0,110,0,116, +0,1,-1,1,5, +1861,20,1862,4,38, +86,0,111,0,105, +0,100,0,65,0, +114,0,103,0,83, +0,116,0,97,0, +116,0,101,0,69, +0,118,0,101,0, +110,0,116,0,95, +0,49,0,1,198, +1,3,1,5,1, +4,1863,22,1,32, +1,2227,1033,1,1574, +924,1,2559,1864,17, +1865,15,1866,4,40, +37,0,86,0,101, +0,99,0,116,0, +111,0,114,0,65, +0,114,0,103,0, +83,0,116,0,97, +0,116,0,101,0, +69,0,118,0,101, +0,110,0,116,0, +1,-1,1,5,1867, +20,1868,4,42,86, +0,101,0,99,0, +116,0,111,0,114, +0,65,0,114,0, +103,0,83,0,116, +0,97,0,116,0, +101,0,69,0,118, +0,101,0,110,0, +116,0,95,0,49, +0,1,201,1,3, +1,6,1,5,1869, +22,1,35,1,2021, +843,1,2458,1001,1, +2459,1007,1,2462,1014, +1,2136,968,1,2464, +1024,1,2029,850,1, +2030,856,1,2031,861, +1,2032,866,1,2033, +871,1,2035,877,1, +2364,952,1,2039,887, +1,1931,986,1,2041, +893,1,2043,899,1, +2045,904,1,2703,1870, +16,0,211,1,2595, +1871,17,1872,15,1873, +4,22,37,0,83, +0,116,0,97,0, +116,0,101,0,69, +0,118,0,101,0, +110,0,116,0,1, +-1,1,5,1874,20, +1875,4,24,83,0, +116,0,97,0,116, +0,101,0,69,0, +118,0,101,0,110, +0,116,0,95,0, +49,0,1,197,1, +3,1,6,1,5, +1876,22,1,31,1, +2597,1877,16,0,761, +1,2648,1878,17,1879, +15,1758,1,-1,1, +5,1880,20,1881,4, +22,83,0,116,0, +97,0,116,0,101, +0,66,0,111,0, +100,0,121,0,95, +0,50,0,1,182, +1,3,1,3,1, +2,1882,22,1,16, +1,2105,939,1,14, +1883,19,144,1,14, +1884,5,115,1,2510, +1885,16,0,706,1, +2513,1886,17,1887,15, +1888,4,30,37,0, +73,0,110,0,116, +0,68,0,101,0, +99,0,108,0,97, +0,114,0,97,0, +116,0,105,0,111, +0,110,0,1,-1, +1,5,1889,20,1890, +4,32,73,0,110, +0,116,0,68,0, +101,0,99,0,108, +0,97,0,114,0, +97,0,116,0,105, +0,111,0,110,0, +95,0,49,0,1, +215,1,3,1,3, +1,2,1891,22,1, +50,1,2514,1892,16, +0,360,1,1260,1221, +1,1011,1227,1,1514, +1233,1,9,1238,1, +10,1893,17,1894,15, +1895,4,48,37,0, 65,0,114,0,103, 0,117,0,109,0, 101,0,110,0,116, @@ -5588,2885 +6709,3266 @@ public yyLSLSyntax 105,0,115,0,116, 0,1,-1,1,5, 140,1,0,1,0, -1645,22,1,18,1, -262,1119,1,1267,1125, -1,481,1646,17,1647, -15,1648,4,26,37, +1896,22,1,39,1, +262,1244,1,1267,1250, +1,2525,1897,16,0, +507,1,1773,1898,16, +0,148,1,2779,1899, +16,0,142,1,19, +1272,1,20,1900,16, +0,142,1,2281,1279, +1,525,1343,1,30, +1901,17,1902,15,1895, +1,-1,1,5,1903, +20,1904,4,50,65, +0,114,0,103,0, +117,0,109,0,101, +0,110,0,116,0, +68,0,101,0,99, +0,108,0,97,0, +114,0,97,0,116, +0,105,0,111,0, +110,0,76,0,105, +0,115,0,116,0, +95,0,50,0,1, +206,1,3,1,4, +1,3,1905,22,1, +41,1,283,1299,1, +2543,1906,17,1907,15, +1908,4,30,37,0, +82,0,111,0,116, +0,68,0,101,0, +99,0,108,0,97, +0,114,0,97,0, +116,0,105,0,111, +0,110,0,1,-1, +1,5,1909,20,1910, +4,32,82,0,111, +0,116,0,68,0, +101,0,99,0,108, +0,97,0,114,0, +97,0,116,0,105, +0,111,0,110,0, +95,0,49,0,1, +217,1,3,1,3, +1,2,1911,22,1, +52,1,2544,1912,16, +0,528,1,40,1304, +1,41,1913,17,1914, +15,1915,4,26,37, 0,65,0,114,0, 103,0,117,0,109, 0,101,0,110,0, 116,0,76,0,105, 0,115,0,116,0, -1,-1,1,5,1649, -20,1650,4,28,65, +1,-1,1,5,724, +1,0,1,0,1916, +22,1,169,1,42, +1917,17,1918,15,1919, +4,38,37,0,69, +0,120,0,112,0, +114,0,101,0,115, +0,115,0,105,0, +111,0,110,0,65, 0,114,0,103,0, 117,0,109,0,101, 0,110,0,116,0, -76,0,105,0,115, -0,116,0,95,0, -49,0,1,278,1, -3,1,2,1,1, -1651,22,1,139,1, -1521,1130,1,1773,1652, -16,0,148,1,19, -1147,1,20,1653,16, -0,142,1,2281,1154, -1,525,1216,1,30, -1654,17,1655,15,1644, -1,-1,1,5,1656, -20,1657,4,50,65, +1,-1,1,5,1920, +20,1921,4,40,69, +0,120,0,112,0, +114,0,101,0,115, +0,115,0,105,0, +111,0,110,0,65, 0,114,0,103,0, 117,0,109,0,101, 0,110,0,116,0, +95,0,49,0,1, +336,1,3,1,2, +1,1,1922,22,1, +172,1,44,1310,1, +47,1311,1,48,1317, +1,49,1323,1,50, +1328,1,51,1333,1, +305,1338,1,63,1349, +1,1521,1255,1,66, +1355,1,67,1360,1, +1478,1583,1,69,1370, +1,70,1375,1,68, +1365,1,74,1380,1, +1013,1385,1,2335,1923, +16,0,148,1,1332, +1390,1,1048,1470,1, +2591,1924,16,0,142, +1,82,1407,1,1296, +1294,1,1341,1424,1, +328,1429,1,1303,1434, +1,1096,1439,1,93, +1445,1,1550,1450,1, +2770,1925,17,1926,15, +1895,1,-1,1,5, +140,1,0,1,0, +1896,1,2528,1927,17, +1928,15,1929,4,30, +37,0,86,0,101, +0,99,0,68,0, +101,0,99,0,108, +0,97,0,114,0, +97,0,116,0,105, +0,111,0,110,0, +1,-1,1,5,1930, +20,1931,4,32,86, +0,101,0,99,0, 68,0,101,0,99, 0,108,0,97,0, 114,0,97,0,116, 0,105,0,111,0, -110,0,76,0,105, +110,0,95,0,49, +0,1,216,1,3, +1,3,1,2,1932, +22,1,51,1,2529, +1933,16,0,515,1, +352,1475,1,107,1464, +1,1114,1469,1,2540, +1934,16,0,524,1, +1370,1578,1,118,1481, +1,1123,1486,1,371, +1491,1,1377,1497,1, +375,1502,1,377,1507, +1,827,1457,1,380, +1517,1,883,1523,1, +373,1535,1,130,1540, +1,379,1512,1,143, +1545,1,1152,1551,1, +387,1935,16,0,656, +1,1406,1556,1,2582, +1936,17,1937,15,1895, +1,-1,1,5,140, +1,0,1,0,1896, +1,1159,1563,1,157, +1568,1,1413,1573,1, +1665,1600,1,412,1938, +16,0,695,1,1094, +1939,16,0,726,1, +172,1595,1,1188,1605, +1,437,1940,16,0, +765,1,1442,1610,1, +1694,1941,16,0,148, +1,942,1616,1,1195, +1622,1,1449,1627,1, +1701,1632,1,447,1637, +1,188,1644,1,205, +1649,1,2467,1942,17, +1943,15,1895,1,-1, +1,5,1944,20,1945, +4,50,65,0,114, +0,103,0,117,0, +109,0,101,0,110, +0,116,0,68,0, +101,0,99,0,108, +0,97,0,114,0, +97,0,116,0,105, +0,111,0,110,0, +76,0,105,0,115, +0,116,0,95,0, +49,0,1,205,1, +3,1,2,1,1, +1946,22,1,40,1, +461,1947,16,0,726, +1,464,1948,17,1949, +15,1915,1,-1,1, +5,1950,20,1951,4, +28,65,0,114,0, +103,0,117,0,109, +0,101,0,110,0, +116,0,76,0,105, 0,115,0,116,0, 95,0,50,0,1, -160,1,3,1,4, -1,3,1658,22,1, -20,1,283,1172,1, -40,1177,1,41,1659, -17,1660,15,1648,1, --1,1,5,601,1, -0,1,0,1661,22, -1,138,1,42,1662, -17,1663,15,1664,4, -38,37,0,69,0, -120,0,112,0,114, -0,101,0,115,0, -115,0,105,0,111, -0,110,0,65,0, -114,0,103,0,117, -0,109,0,101,0, -110,0,116,0,1, --1,1,5,1665,20, -1666,4,40,69,0, -120,0,112,0,114, -0,101,0,115,0, -115,0,105,0,111, -0,110,0,65,0, -114,0,103,0,117, -0,109,0,101,0, -110,0,116,0,95, -0,49,0,1,280, -1,3,1,2,1, -1,1667,22,1,141, -1,44,1183,1,1260, -1096,1,47,1184,1, -48,1190,1,49,1196, -1,50,1201,1,51, -1206,1,305,1211,1, -63,1222,1,66,1228, -1,67,1233,1,1478, -1458,1,69,1243,1, -70,1248,1,68,1238, -1,74,1253,1,1013, -1258,1,2335,1668,16, -0,148,1,1332,1263, -1,1048,1344,1,82, -1280,1,1296,1167,1, -1341,1297,1,328,1302, -1,1303,1307,1,1096, -1312,1,93,1318,1, -1550,1323,1,352,1349, -1,107,1338,1,1114, -1343,1,1370,1453,1, -118,1355,1,1123,1360, -1,371,1365,1,1377, -1371,1,375,1376,1, -377,1381,1,379,1386, -1,380,1391,1,883, -1397,1,2642,1669,17, -1670,15,1644,1,-1, -1,5,140,1,0, -1,0,1645,1,373, -1409,1,130,1414,1, -2651,1671,16,0,142, -1,143,1419,1,1152, -1426,1,387,1672,16, -0,555,1,1406,1431, -1,1159,1438,1,157, -1443,1,1413,1448,1, -1665,1474,1,412,1673, -16,0,576,1,1094, -1674,16,0,603,1, -172,1469,1,827,1331, -1,1188,1479,1,437, -1675,16,0,650,1, -1442,1484,1,1694,1676, -16,0,148,1,942, -1490,1,1195,1496,1, -1449,1501,1,1701,1506, -1,447,1511,1,188, -1518,1,205,1523,1, -2467,1677,17,1678,15, -1644,1,-1,1,5, -1679,20,1680,4,50, -65,0,114,0,103, -0,117,0,109,0, -101,0,110,0,116, -0,68,0,101,0, -99,0,108,0,97, -0,114,0,97,0, -116,0,105,0,111, -0,110,0,76,0, +335,1,3,1,4, +1,3,1952,22,1, +171,1,1224,1654,1, +223,1659,1,1730,1664, +1,476,1669,1,477, +1675,1,1231,1680,1, +479,1685,1,480,1690, +1,1485,1696,1,459, +1953,17,1954,15,1915, +1,-1,1,5,724, +1,0,1,0,1916, +1,242,1703,1,478, +1708,1,481,1955,17, +1956,15,1915,1,-1, +1,5,1957,20,1958, +4,28,65,0,114, +0,103,0,117,0, +109,0,101,0,110, +0,116,0,76,0, 105,0,115,0,116, 0,95,0,49,0, -1,159,1,3,1, -2,1,1,1681,22, -1,19,1,461,1682, -16,0,603,1,464, -1683,17,1684,15,1648, -1,-1,1,5,1685, -20,1686,4,28,65, +1,334,1,3,1, +2,1,1,1959,22, +1,170,1,1001,1713, +1,1002,1718,1,2509, +1960,17,1961,15,1962, +4,30,37,0,75, +0,101,0,121,0, +68,0,101,0,99, +0,108,0,97,0, +114,0,97,0,116, +0,105,0,111,0, +110,0,1,-1,1, +5,1963,20,1964,4, +32,75,0,101,0, +121,0,68,0,101, +0,99,0,108,0, +97,0,114,0,97, +0,116,0,105,0, +111,0,110,0,95, +0,49,0,1,214, +1,3,1,3,1, +2,1965,22,1,49, +1,15,1966,19,336, +1,15,1967,5,6, +1,2785,1968,16,0, +334,1,1114,1969,16, +0,339,1,1621,1970, +16,0,764,1,40, +1971,16,0,649,1, +19,1272,1,9,1238, +1,16,1972,19,136, +1,16,1973,5,147, +1,256,1974,16,0, +203,1,1261,1975,16, +0,203,1,509,1976, +16,0,203,1,2769, +1977,16,0,790,1, +9,1978,16,0,134, +1,2522,1979,16,0, +505,1,2021,843,1, +1775,1980,16,0,203, +1,2029,850,1,2030, +856,1,2031,861,1, +2032,866,1,2786,1981, +16,0,203,1,277, +1982,16,0,203,1, +2537,1983,16,0,522, +1,2037,882,1,2039, +887,1,32,1984,16, +0,203,1,2041,893, +1,2293,1985,16,0, +203,1,2043,899,1, +2045,904,1,40,1986, +16,0,182,1,41, +1987,16,0,203,1, +1297,1988,16,0,203, +1,43,1989,16,0, +203,1,44,1990,16, +0,182,1,1803,912, +1,1804,1991,16,0, +203,1,299,1992,16, +0,203,1,2480,1993, +17,1994,15,1995,4, +24,37,0,73,0, +110,0,116,0,65, +0,114,0,103,0, +69,0,118,0,101, +0,110,0,116,0, +1,-1,1,5,1996, +20,1997,4,26,73, +0,110,0,116,0, +65,0,114,0,103, +0,69,0,118,0, +101,0,110,0,116, +0,95,0,55,0, +1,369,1,3,1, +2,1,1,1998,22, +1,205,1,2560,1999, +16,0,549,1,52, +2000,16,0,203,1, +2484,2001,17,2002,15, +1995,1,-1,1,5, +2003,20,2004,4,26, +73,0,110,0,116, +0,65,0,114,0, +103,0,69,0,118, +0,101,0,110,0, +116,0,95,0,51, +0,1,365,1,3, +1,2,1,1,2005, +22,1,201,1,1515, +2006,16,0,203,1, +2318,2007,16,0,203, +1,2491,2008,17,2009, +15,2010,4,26,37, +0,86,0,111,0, +105,0,100,0,65, 0,114,0,103,0, -117,0,109,0,101, +69,0,118,0,101, 0,110,0,116,0, -76,0,105,0,115, +1,-1,1,5,2011, +20,2012,4,28,86, +0,111,0,105,0, +100,0,65,0,114, +0,103,0,69,0, +118,0,101,0,110, 0,116,0,95,0, -50,0,1,279,1, -3,1,4,1,3, -1687,22,1,140,1, -1224,1528,1,223,1533, -1,1730,1538,1,476, -1543,1,477,1549,1, -1231,1554,1,479,1559, -1,480,1564,1,1485, -1570,1,459,1688,17, -1689,15,1648,1,-1, -1,5,601,1,0, -1,0,1661,1,242, -1578,1,478,1583,1, -2506,1690,17,1691,15, -1644,1,-1,1,5, -140,1,0,1,0, -1645,1,1001,1588,1, -1002,1593,1,15,1692, -19,257,1,15,1693, -5,6,1,1114,1694, -16,0,299,1,1621, -1695,16,0,649,1, -2657,1696,16,0,255, -1,40,1697,16,0, -552,1,19,1147,1, -9,1113,1,16,1698, -19,136,1,16,1699, -5,139,1,256,1700, -16,0,187,1,1261, -1701,16,0,187,1, -509,1702,16,0,187, -1,9,1703,16,0, -134,1,2021,718,1, -1775,1704,16,0,187, -1,2029,725,1,2030, -731,1,2031,736,1, -2032,741,1,2033,746, -1,277,1705,16,0, -187,1,2035,752,1, -2037,757,1,2039,762, -1,32,1706,16,0, -187,1,2041,768,1, -2293,1707,16,0,187, -1,2043,774,1,2045, -779,1,40,1708,16, -0,166,1,41,1709, -16,0,187,1,1297, -1710,16,0,187,1, -43,1711,16,0,187, -1,44,1712,16,0, -166,1,1803,787,1, -1804,1713,16,0,187, -1,299,1714,16,0, -187,1,2480,1715,17, -1716,15,1717,4,12, -37,0,69,0,118, -0,101,0,110,0, -116,0,1,-1,1, -5,1718,20,1719,4, -16,69,0,118,0, -101,0,110,0,116, -0,95,0,50,0, -53,0,1,312,1, +54,0,1,358,1, 3,1,2,1,1, -1720,22,1,173,1, -52,1721,16,0,187, -1,2484,1722,17,1723, -15,1717,1,-1,1, -5,1724,20,1725,4, -16,69,0,118,0, +2013,22,1,194,1, +62,2014,16,0,225, +1,63,2015,16,0, +182,1,2495,2016,17, +2017,15,2010,1,-1, +1,5,2018,20,2019, +4,28,86,0,111, +0,105,0,100,0, +65,0,114,0,103, +0,69,0,118,0, 101,0,110,0,116, 0,95,0,50,0, -49,0,1,308,1, -3,1,2,1,1, -1726,22,1,169,1, -1515,1727,16,0,187, -1,2318,1728,16,0, -187,1,2491,1729,17, -1730,15,1717,1,-1, -1,5,1731,20,1732, -4,16,69,0,118, +1,354,1,3,1, +2,1,1,2020,22, +1,190,1,2576,2021, +16,0,579,1,2075, +2022,16,0,203,1, +1574,924,1,1479,2023, +16,0,203,1,71, +2024,16,0,203,1, +1658,2025,16,0,795, +1,1833,2026,16,0, +326,1,1834,2027,16, +0,203,1,2337,2028, +16,0,203,1,79, +2029,16,0,203,1, +1335,2030,16,0,203, +1,322,2031,16,0, +203,1,76,2032,16, +0,203,1,85,2033, +16,0,203,1,89, +2034,16,0,203,1, +2033,871,1,2035,877, +1,346,2035,16,0, +203,1,97,2036,16, +0,203,1,2106,2037, +16,0,203,1,102, +2038,16,0,203,1, +1860,946,1,2458,1001, +1,2364,952,1,1990, +2039,16,0,203,1, +112,2040,16,0,203, +1,1117,2041,16,0, +203,1,1873,961,1, +1875,2042,16,0,446, +1,1876,2043,16,0, +203,1,2552,2044,16, +0,540,1,124,2045, +16,0,203,1,2478, +2046,17,2047,15,1995, +1,-1,1,5,2048, +20,2049,4,26,73, +0,110,0,116,0, +65,0,114,0,103, +0,69,0,118,0, +101,0,110,0,116, +0,95,0,57,0, +1,371,1,3,1, +2,1,1,2050,22, +1,207,1,2136,968, +1,381,2051,16,0, +203,1,525,2052,16, +0,203,1,137,2053, +16,0,203,1,2568, +2054,16,0,683,1, +1901,2055,16,0,203, +1,1153,2056,16,0, +203,1,151,2057,16, +0,203,1,1407,2058, +16,0,203,1,2581, +2059,16,0,779,1, +2413,2060,16,0,203, +1,406,2061,16,0, +203,1,1371,2062,16, +0,203,1,2105,939, +1,166,2063,16,0, +203,1,1622,2064,16, +0,203,1,1931,986, +1,1932,2065,16,0, +539,1,1933,2066,16, +0,203,1,431,2067, +16,0,203,1,1585, +2068,16,0,203,1, +182,2069,16,0,203, +1,1189,2070,16,0, +203,1,1443,2071,16, +0,203,1,1695,2072, +16,0,203,1,2198, +2073,16,0,203,1, +447,2074,16,0,203, +1,199,2075,16,0, +203,1,2459,1007,1, +1958,2076,16,0,203, +1,2462,1014,1,1657, +1019,1,2464,1024,1, +1659,2077,16,0,203, +1,459,2078,16,0, +203,1,462,2079,16, +0,203,1,2471,2080, +17,2081,15,2082,4, +36,37,0,75,0, +101,0,121,0,73, +0,110,0,116,0, +73,0,110,0,116, +0,65,0,114,0, +103,0,69,0,118, 0,101,0,110,0, -116,0,95,0,49, -0,52,0,1,301, -1,3,1,2,1, -1,1733,22,1,162, -1,62,1734,16,0, -202,1,63,1735,16, -0,166,1,2495,1736, -17,1737,15,1717,1, --1,1,5,1738,20, -1739,4,16,69,0, -118,0,101,0,110, -0,116,0,95,0, -49,0,48,0,1, -297,1,3,1,2, -1,1,1740,22,1, -158,1,2075,1741,16, -0,187,1,1574,799, -1,1479,1742,16,0, -187,1,71,1743,16, -0,187,1,1658,1744, -16,0,672,1,1833, -1745,16,0,288,1, -1834,1746,16,0,187, -1,2337,1747,16,0, -187,1,79,1748,16, -0,187,1,1335,1749, -16,0,187,1,322, -1750,16,0,187,1, -76,1751,16,0,187, -1,85,1752,16,0, -187,1,89,1753,16, -0,187,1,346,1754, -16,0,187,1,97, -1755,16,0,187,1, -2106,1756,16,0,187, -1,102,1757,16,0, -187,1,1860,821,1, -2458,876,1,2364,827, -1,1990,1758,16,0, -187,1,112,1759,16, -0,187,1,1117,1760, -16,0,187,1,1873, -835,1,1875,1761,16, -0,400,1,1876,1762, -16,0,187,1,124, -1763,16,0,187,1, -2478,1764,17,1765,15, -1717,1,-1,1,5, -1766,20,1767,4,16, +116,0,1,-1,1, +5,2083,20,2084,4, +38,75,0,101,0, +121,0,73,0,110, +0,116,0,73,0, +110,0,116,0,65, +0,114,0,103,0, 69,0,118,0,101, 0,110,0,116,0, -95,0,50,0,55, -0,1,314,1,3, -1,2,1,1,1768, -22,1,175,1,2136, -842,1,381,1769,16, -0,187,1,2641,1770, -16,0,642,1,137, -1771,16,0,187,1, -1901,1772,16,0,187, -1,2658,1773,16,0, -187,1,1153,1774,16, -0,187,1,151,1775, -16,0,187,1,1407, -1776,16,0,187,1, -1659,1777,16,0,187, -1,2413,1778,16,0, -187,1,406,1779,16, -0,187,1,1371,1780, -16,0,187,1,2105, -814,1,166,1781,16, -0,187,1,525,1782, -16,0,187,1,1622, -1783,16,0,187,1, -1931,861,1,1932,1784, -16,0,456,1,1933, -1785,16,0,187,1, -431,1786,16,0,187, -1,1585,1787,16,0, -187,1,182,1788,16, -0,187,1,1189,1789, -16,0,187,1,1443, -1790,16,0,187,1, -1695,1791,16,0,187, -1,2198,1792,16,0, -187,1,447,1793,16, -0,187,1,199,1794, -16,0,187,1,2459, -882,1,1958,1795,16, -0,187,1,2462,889, -1,1657,894,1,2464, -899,1,459,1796,16, -0,187,1,462,1797, -16,0,187,1,2471, -1798,17,1799,15,1717, -1,-1,1,5,1800, -20,1801,4,16,69, +95,0,49,0,1, +378,1,3,1,2, +1,1,2085,22,1, +214,1,2472,2086,17, +2087,15,2088,4,36, +37,0,73,0,110, +0,116,0,86,0, +101,0,99,0,86, +0,101,0,99,0, +65,0,114,0,103, +0,69,0,118,0, +101,0,110,0,116, +0,1,-1,1,5, +2089,20,2090,4,38, +73,0,110,0,116, +0,86,0,101,0, +99,0,86,0,101, +0,99,0,65,0, +114,0,103,0,69, 0,118,0,101,0, 110,0,116,0,95, -0,51,0,52,0, -1,321,1,3,1, -2,1,1,1802,22, -1,182,1,2472,1803, -17,1804,15,1717,1, --1,1,5,1805,20, -1806,4,16,69,0, -118,0,101,0,110, -0,116,0,95,0, -51,0,51,0,1, -320,1,3,1,2, -1,1,1807,22,1, -181,1,2473,1808,17, -1809,15,1717,1,-1, -1,5,1810,20,1811, -4,16,69,0,118, -0,101,0,110,0, -116,0,95,0,51, -0,50,0,1,319, +0,49,0,1,377, 1,3,1,2,1, -1,1812,22,1,180, -1,2474,1813,17,1814, -15,1717,1,-1,1, -5,1815,20,1816,4, -16,69,0,118,0, -101,0,110,0,116, -0,95,0,51,0, -49,0,1,318,1, -3,1,2,1,1, -1817,22,1,179,1, -2475,1818,17,1819,15, -1717,1,-1,1,5, -1820,20,1821,4,16, +1,2091,22,1,213, +1,2473,2092,17,2093, +15,2094,4,36,37, +0,73,0,110,0, +116,0,82,0,111, +0,116,0,82,0, +111,0,116,0,65, +0,114,0,103,0, 69,0,118,0,101, 0,110,0,116,0, -95,0,51,0,48, -0,1,317,1,3, -1,2,1,1,1822, -22,1,178,1,2476, -1823,17,1824,15,1717, -1,-1,1,5,1825, -20,1826,4,16,69, -0,118,0,101,0, -110,0,116,0,95, -0,50,0,57,0, -1,316,1,3,1, -2,1,1,1827,22, -1,177,1,2477,1828, -17,1829,15,1717,1, --1,1,5,1830,20, -1831,4,16,69,0, +1,-1,1,5,2095, +20,2096,4,38,73, +0,110,0,116,0, +82,0,111,0,116, +0,82,0,111,0, +116,0,65,0,114, +0,103,0,69,0, 118,0,101,0,110, 0,116,0,95,0, -50,0,56,0,1, -315,1,3,1,2, -1,1,1832,22,1, -176,1,2227,908,1, -2479,1833,17,1834,15, -1717,1,-1,1,5, -1835,20,1836,4,16, +49,0,1,376,1, +3,1,2,1,1, +2097,22,1,212,1, +2474,2098,17,2099,15, +2100,4,30,37,0, +86,0,101,0,99, +0,116,0,111,0, +114,0,65,0,114, +0,103,0,69,0, +118,0,101,0,110, +0,116,0,1,-1, +1,5,2101,20,2102, +4,32,86,0,101, +0,99,0,116,0, +111,0,114,0,65, +0,114,0,103,0, +69,0,118,0,101, +0,110,0,116,0, +95,0,51,0,1, +375,1,3,1,2, +1,1,2103,22,1, +211,1,2475,2104,17, +2105,15,2100,1,-1, +1,5,2106,20,2107, +4,32,86,0,101, +0,99,0,116,0, +111,0,114,0,65, +0,114,0,103,0, 69,0,118,0,101, 0,110,0,116,0, -95,0,50,0,54, -0,1,313,1,3, -1,2,1,1,1837, -22,1,174,1,1225, -1838,16,0,187,1, -2481,1839,17,1840,15, -1717,1,-1,1,5, -1841,20,1842,4,16, +95,0,50,0,1, +374,1,3,1,2, +1,1,2108,22,1, +210,1,2476,2109,17, +2110,15,2100,1,-1, +1,5,2111,20,2112, +4,32,86,0,101, +0,99,0,116,0, +111,0,114,0,65, +0,114,0,103,0, 69,0,118,0,101, 0,110,0,116,0, -95,0,50,0,52, -0,1,311,1,3, -1,2,1,1,1843, -22,1,172,1,2482, -1844,17,1845,15,1717, -1,-1,1,5,1846, -20,1847,4,16,69, +95,0,49,0,1, +373,1,3,1,2, +1,1,2113,22,1, +209,1,2477,2114,17, +2115,15,1995,1,-1, +1,5,2116,20,2117, +4,28,73,0,110, +0,116,0,65,0, +114,0,103,0,69, 0,118,0,101,0, 110,0,116,0,95, -0,50,0,51,0, -1,310,1,3,1, -2,1,1,1848,22, -1,171,1,2483,1849, -17,1850,15,1717,1, --1,1,5,1851,20, -1852,4,16,69,0, +0,49,0,48,0, +1,372,1,3,1, +2,1,1,2118,22, +1,208,1,2227,1033, +1,2479,2119,17,2120, +15,1995,1,-1,1, +5,2121,20,2122,4, +26,73,0,110,0, +116,0,65,0,114, +0,103,0,69,0, 118,0,101,0,110, 0,116,0,95,0, -50,0,50,0,1, -309,1,3,1,2, -1,1,1853,22,1, -170,1,1731,1854,16, -0,187,1,2485,1855, -17,1856,15,1717,1, --1,1,5,1857,20, -1858,4,16,69,0, +56,0,1,370,1, +3,1,2,1,1, +2123,22,1,206,1, +1225,2124,16,0,203, +1,2481,2125,17,2126, +15,1995,1,-1,1, +5,2127,20,2128,4, +26,73,0,110,0, +116,0,65,0,114, +0,103,0,69,0, 118,0,101,0,110, 0,116,0,95,0, -50,0,48,0,1, -307,1,3,1,2, -1,1,1859,22,1, -168,1,2486,1860,17, -1861,15,1717,1,-1, -1,5,1862,20,1863, -4,16,69,0,118, +54,0,1,368,1, +3,1,2,1,1, +2129,22,1,204,1, +2482,2130,17,2131,15, +1995,1,-1,1,5, +2132,20,2133,4,26, +73,0,110,0,116, +0,65,0,114,0, +103,0,69,0,118, 0,101,0,110,0, -116,0,95,0,49, -0,57,0,1,306, +116,0,95,0,53, +0,1,367,1,3, +1,2,1,1,2134, +22,1,203,1,2483, +2135,17,2136,15,1995, +1,-1,1,5,2137, +20,2138,4,26,73, +0,110,0,116,0, +65,0,114,0,103, +0,69,0,118,0, +101,0,110,0,116, +0,95,0,52,0, +1,366,1,3,1, +2,1,1,2139,22, +1,202,1,1731,2140, +16,0,203,1,2485, +2141,17,2142,15,1995, +1,-1,1,5,2143, +20,2144,4,26,73, +0,110,0,116,0, +65,0,114,0,103, +0,69,0,118,0, +101,0,110,0,116, +0,95,0,50,0, +1,364,1,3,1, +2,1,1,2145,22, +1,200,1,2486,2146, +17,2147,15,1995,1, +-1,1,5,2148,20, +2149,4,26,73,0, +110,0,116,0,65, +0,114,0,103,0, +69,0,118,0,101, +0,110,0,116,0, +95,0,49,0,1, +363,1,3,1,2, +1,1,2150,22,1, +199,1,2487,2151,17, +2152,15,2153,4,24, +37,0,75,0,101, +0,121,0,65,0, +114,0,103,0,69, +0,118,0,101,0, +110,0,116,0,1, +-1,1,5,2154,20, +2155,4,26,75,0, +101,0,121,0,65, +0,114,0,103,0, +69,0,118,0,101, +0,110,0,116,0, +95,0,50,0,1, +362,1,3,1,2, +1,1,2156,22,1, +198,1,2488,2157,17, +2158,15,2153,1,-1, +1,5,2159,20,2160, +4,26,75,0,101, +0,121,0,65,0, +114,0,103,0,69, +0,118,0,101,0, +110,0,116,0,95, +0,49,0,1,361, 1,3,1,2,1, -1,1864,22,1,167, -1,2487,1865,17,1866, -15,1717,1,-1,1, -5,1867,20,1868,4, -16,69,0,118,0, +1,2161,22,1,197, +1,2489,2162,17,2163, +15,2010,1,-1,1, +5,2164,20,2165,4, +28,86,0,111,0, +105,0,100,0,65, +0,114,0,103,0, +69,0,118,0,101, +0,110,0,116,0, +95,0,56,0,1, +360,1,3,1,2, +1,1,2166,22,1, +196,1,2490,2167,17, +2168,15,2010,1,-1, +1,5,2169,20,2170, +4,28,86,0,111, +0,105,0,100,0, +65,0,114,0,103, +0,69,0,118,0, 101,0,110,0,116, -0,95,0,49,0, -56,0,1,305,1, -3,1,2,1,1, -1869,22,1,166,1, -2488,1870,17,1871,15, -1717,1,-1,1,5, -1872,20,1873,4,16, +0,95,0,55,0, +1,359,1,3,1, +2,1,1,2171,22, +1,195,1,1989,1041, +1,2492,2172,17,2173, +15,2010,1,-1,1, +5,2174,20,2175,4, +28,86,0,111,0, +105,0,100,0,65, +0,114,0,103,0, 69,0,118,0,101, 0,110,0,116,0, -95,0,49,0,55, -0,1,304,1,3, -1,2,1,1,1874, -22,1,165,1,2489, -1875,17,1876,15,1717, -1,-1,1,5,1877, -20,1878,4,16,69, +95,0,53,0,1, +357,1,3,1,2, +1,1,2176,22,1, +193,1,2493,2177,17, +2178,15,2010,1,-1, +1,5,2179,20,2180, +4,28,86,0,111, +0,105,0,100,0, +65,0,114,0,103, +0,69,0,118,0, +101,0,110,0,116, +0,95,0,52,0, +1,356,1,3,1, +2,1,1,2181,22, +1,192,1,2494,2182, +17,2183,15,2010,1, +-1,1,5,2184,20, +2185,4,28,86,0, +111,0,105,0,100, +0,65,0,114,0, +103,0,69,0,118, +0,101,0,110,0, +116,0,95,0,51, +0,1,355,1,3, +1,2,1,1,2186, +22,1,191,1,236, +2187,16,0,203,1, +2496,2188,17,2189,15, +2010,1,-1,1,5, +2190,20,2191,4,28, +86,0,111,0,105, +0,100,0,65,0, +114,0,103,0,69, 0,118,0,101,0, 110,0,116,0,95, -0,49,0,54,0, -1,303,1,3,1, -2,1,1,1879,22, -1,164,1,2490,1880, -17,1881,15,1717,1, --1,1,5,1882,20, -1883,4,16,69,0, -118,0,101,0,110, -0,116,0,95,0, -49,0,53,0,1, -302,1,3,1,2, -1,1,1884,22,1, -163,1,1989,916,1, -2492,1885,17,1886,15, -1717,1,-1,1,5, -1887,20,1888,4,16, +0,49,0,1,353, +1,3,1,2,1, +1,2192,22,1,189, +1,2497,2193,17,2194, +15,2195,4,12,37, +0,69,0,118,0, +101,0,110,0,116, +0,1,-1,1,5, +2196,20,2197,4,14, 69,0,118,0,101, 0,110,0,116,0, -95,0,49,0,51, -0,1,300,1,3, -1,2,1,1,1889, -22,1,161,1,2493, -1890,17,1891,15,1717, -1,-1,1,5,1892, -20,1893,4,16,69, +95,0,57,0,1, +352,1,3,1,2, +1,1,2198,22,1, +188,1,2498,2199,17, +2200,15,2195,1,-1, +1,5,2201,20,2202, +4,14,69,0,118, +0,101,0,110,0, +116,0,95,0,56, +0,1,351,1,3, +1,2,1,1,2203, +22,1,187,1,2499, +2204,17,2205,15,2195, +1,-1,1,5,2206, +20,2207,4,14,69, 0,118,0,101,0, 110,0,116,0,95, -0,49,0,50,0, -1,299,1,3,1, -2,1,1,1894,22, -1,160,1,2494,1895, -17,1896,15,1717,1, --1,1,5,1897,20, -1898,4,16,69,0, -118,0,101,0,110, -0,116,0,95,0, -49,0,49,0,1, -298,1,3,1,2, -1,1,1899,22,1, -159,1,236,1900,16, -0,187,1,2496,1901, -17,1902,15,1717,1, --1,1,5,1903,20, -1904,4,14,69,0, +0,55,0,1,350, +1,3,1,2,1, +1,2208,22,1,186, +1,2500,2209,17,2210, +15,2195,1,-1,1, +5,2211,20,2212,4, +14,69,0,118,0, +101,0,110,0,116, +0,95,0,54,0, +1,349,1,3,1, +2,1,1,2213,22, +1,185,1,2501,2214, +17,2215,15,2195,1, +-1,1,5,2216,20, +2217,4,14,69,0, 118,0,101,0,110, 0,116,0,95,0, -57,0,1,296,1, +53,0,1,348,1, 3,1,2,1,1, -1905,22,1,157,1, -2497,1906,17,1907,15, -1717,1,-1,1,5, -1908,20,1909,4,14, +2218,22,1,184,1, +2502,2219,17,2220,15, +2195,1,-1,1,5, +2221,20,2222,4,14, 69,0,118,0,101, 0,110,0,116,0, -95,0,56,0,1, -295,1,3,1,2, -1,1,1910,22,1, -156,1,2498,1911,17, -1912,15,1717,1,-1, -1,5,1913,20,1914, +95,0,52,0,1, +347,1,3,1,2, +1,1,2223,22,1, +183,1,2503,2224,17, +2225,15,2195,1,-1, +1,5,2226,20,2227, 4,14,69,0,118, 0,101,0,110,0, -116,0,95,0,55, -0,1,294,1,3, -1,2,1,1,1915, -22,1,155,1,2499, -1916,17,1917,15,1717, -1,-1,1,5,1918, -20,1919,4,14,69, +116,0,95,0,51, +0,1,346,1,3, +1,2,1,1,2228, +22,1,182,1,2504, +2229,17,2230,15,2195, +1,-1,1,5,2231, +20,2232,4,14,69, 0,118,0,101,0, 110,0,116,0,95, -0,54,0,1,293, +0,50,0,1,345, 1,3,1,2,1, -1,1920,22,1,154, -1,2500,1921,17,1922, -15,1717,1,-1,1, -5,1923,20,1924,4, +1,2233,22,1,181, +1,2505,2234,17,2235, +15,2195,1,-1,1, +5,2236,20,2237,4, 14,69,0,118,0, 101,0,110,0,116, -0,95,0,53,0, -1,292,1,3,1, -2,1,1,1925,22, -1,153,1,2501,1926, -17,1927,15,1717,1, --1,1,5,1928,20, -1929,4,14,69,0, -118,0,101,0,110, -0,116,0,95,0, -52,0,1,291,1, -3,1,2,1,1, -1930,22,1,152,1, -2502,1931,17,1932,15, -1717,1,-1,1,5, -1933,20,1934,4,14, -69,0,118,0,101, -0,110,0,116,0, -95,0,51,0,1, -290,1,3,1,2, -1,1,1935,22,1, -151,1,2503,1936,17, -1937,15,1717,1,-1, -1,5,1938,20,1939, -4,14,69,0,118, -0,101,0,110,0, -116,0,95,0,50, -0,1,289,1,3, -1,2,1,1,1940, -22,1,150,1,2504, -1941,17,1942,15,1717, -1,-1,1,5,1943, -20,1944,4,14,69, -0,118,0,101,0, -110,0,116,0,95, -0,49,0,1,288, -1,3,1,2,1, -1,1945,22,1,149, -1,2505,1946,16,0, -433,1,217,1947,16, -0,187,1,1756,1948, -16,0,187,1,17, -1949,19,154,1,17, -1950,5,117,1,1, -1951,17,1952,15,1953, -4,18,37,0,84, -0,121,0,112,0, -101,0,110,0,97, -0,109,0,101,0, -1,-1,1,5,1954, -20,1955,4,20,84, -0,121,0,112,0, -101,0,110,0,97, -0,109,0,101,0, -95,0,55,0,1, -287,1,3,1,2, -1,1,1956,22,1, -148,1,2,1957,17, -1958,15,1953,1,-1, -1,5,1959,20,1960, -4,20,84,0,121, -0,112,0,101,0, -110,0,97,0,109, -0,101,0,95,0, -54,0,1,286,1, -3,1,2,1,1, -1961,22,1,147,1, -3,1962,17,1963,15, -1953,1,-1,1,5, -1964,20,1965,4,20, -84,0,121,0,112, +0,95,0,49,0, +1,344,1,3,1, +2,1,1,2238,22, +1,180,1,2506,2239, +16,0,482,1,217, +2240,16,0,203,1, +1756,2241,16,0,203, +1,17,2242,19,163, +1,17,2243,5,134, +1,1,2244,17,2245, +15,2246,4,18,37, +0,84,0,121,0, +112,0,101,0,110, +0,97,0,109,0, +101,0,1,-1,1, +5,2247,20,2248,4, +20,84,0,121,0, +112,0,101,0,110, +0,97,0,109,0, +101,0,95,0,55, +0,1,343,1,3, +1,2,1,1,2249, +22,1,179,1,2, +2250,17,2251,15,2246, +1,-1,1,5,2252, +20,2253,4,20,84, +0,121,0,112,0, +101,0,110,0,97, +0,109,0,101,0, +95,0,54,0,1, +342,1,3,1,2, +1,1,2254,22,1, +178,1,3,2255,17, +2256,15,2246,1,-1, +1,5,2257,20,2258, +4,20,84,0,121, +0,112,0,101,0, +110,0,97,0,109, +0,101,0,95,0, +53,0,1,341,1, +3,1,2,1,1, +2259,22,1,177,1, +4,2260,17,2261,15, +2246,1,-1,1,5, +2262,20,2263,4,20, +84,0,121,0,112, +0,101,0,110,0, +97,0,109,0,101, +0,95,0,52,0, +1,340,1,3,1, +2,1,1,2264,22, +1,176,1,5,2265, +17,2266,15,2246,1, +-1,1,5,2267,20, +2268,4,20,84,0, +121,0,112,0,101, +0,110,0,97,0, +109,0,101,0,95, +0,51,0,1,339, +1,3,1,2,1, +1,2269,22,1,175, +1,6,2270,17,2271, +15,2246,1,-1,1, +5,2272,20,2273,4, +20,84,0,121,0, +112,0,101,0,110, +0,97,0,109,0, +101,0,95,0,50, +0,1,338,1,3, +1,2,1,1,2274, +22,1,174,1,7, +2275,17,2276,15,2246, +1,-1,1,5,2277, +20,2278,4,20,84, +0,121,0,112,0, +101,0,110,0,97, +0,109,0,101,0, +95,0,49,0,1, +337,1,3,1,2, +1,1,2279,22,1, +173,1,2518,2280,16, +0,499,1,9,1238, +1,10,1893,1,262, +1244,1,1267,1250,1, +1521,1255,1,1773,2281, +16,0,261,1,2528, +1927,1,19,1272,1, +20,2282,16,0,161, +1,2532,2283,17,2284, +15,2285,4,66,37, +0,73,0,110,0, +116,0,86,0,101, +0,99,0,86,0, +101,0,99,0,65, +0,114,0,103,0, +117,0,109,0,101, +0,110,0,116,0, +68,0,101,0,99, +0,108,0,97,0, +114,0,97,0,116, +0,105,0,111,0, +110,0,76,0,105, +0,115,0,116,0, +1,-1,1,5,2286, +20,2287,4,68,73, +0,110,0,116,0, +86,0,101,0,99, +0,86,0,101,0, +99,0,65,0,114, +0,103,0,117,0, +109,0,101,0,110, +0,116,0,68,0, +101,0,99,0,108, +0,97,0,114,0, +97,0,116,0,105, +0,111,0,110,0, +76,0,105,0,115, +0,116,0,95,0, +49,0,1,211,1, +3,1,6,1,5, +2288,22,1,46,1, +2533,2289,16,0,518, +1,30,1901,1,283, +1299,1,2543,1906,1, +2547,2290,17,2291,15, +2292,4,66,37,0, +73,0,110,0,116, +0,82,0,111,0, +116,0,82,0,111, +0,116,0,65,0, +114,0,103,0,117, +0,109,0,101,0, +110,0,116,0,68, +0,101,0,99,0, +108,0,97,0,114, +0,97,0,116,0, +105,0,111,0,110, +0,76,0,105,0, +115,0,116,0,1, +-1,1,5,2293,20, +2294,4,68,73,0, +110,0,116,0,82, +0,111,0,116,0, +82,0,111,0,116, +0,65,0,114,0, +103,0,117,0,109, +0,101,0,110,0, +116,0,68,0,101, +0,99,0,108,0, +97,0,114,0,97, +0,116,0,105,0, +111,0,110,0,76, +0,105,0,115,0, +116,0,95,0,49, +0,1,210,1,3, +1,6,1,5,2295, +22,1,45,1,2548, +2296,16,0,650,1, +1010,2297,16,0,716, +1,40,1304,1,41, +1913,1,42,1917,1, +44,1310,1,2555,2298, +17,2299,15,2300,4, +60,37,0,86,0, +101,0,99,0,116, +0,111,0,114,0, +65,0,114,0,103, +0,117,0,109,0, +101,0,110,0,116, +0,68,0,101,0, +99,0,108,0,97, +0,114,0,97,0, +116,0,105,0,111, +0,110,0,76,0, +105,0,115,0,116, +0,1,-1,1,5, +2301,20,2302,4,62, +86,0,101,0,99, +0,116,0,111,0, +114,0,65,0,114, +0,103,0,117,0, +109,0,101,0,110, +0,116,0,68,0, +101,0,99,0,108, +0,97,0,114,0, +97,0,116,0,105, +0,111,0,110,0, +76,0,105,0,115, +0,116,0,95,0, +49,0,1,209,1, +3,1,2,1,1, +2303,22,1,44,1, +1260,1221,1,47,1311, +1,48,1317,1,49, +1323,1,50,1328,1, +51,1333,1,2563,2304, +17,2305,15,2306,4, +54,37,0,73,0, +110,0,116,0,65, +0,114,0,103,0, +117,0,109,0,101, +0,110,0,116,0, +68,0,101,0,99, +0,108,0,97,0, +114,0,97,0,116, +0,105,0,111,0, +110,0,76,0,105, +0,115,0,116,0, +1,-1,1,5,2307, +20,2308,4,56,73, +0,110,0,116,0, +65,0,114,0,103, +0,117,0,109,0, +101,0,110,0,116, +0,68,0,101,0, +99,0,108,0,97, +0,114,0,97,0, +116,0,105,0,111, +0,110,0,76,0, +105,0,115,0,116, +0,95,0,49,0, +1,208,1,3,1, +2,1,1,2309,22, +1,43,1,305,1338, +1,1514,1233,1,525, +1343,1,61,2310,16, +0,217,1,2572,2311, +16,0,689,1,63, +1349,1,66,1355,1, +67,1360,1,68,1365, +1,69,1370,1,70, +1375,1,2582,1936,1, +73,2312,16,0,227, +1,827,1457,1,1013, +1385,1,2335,2313,16, +0,263,1,1332,1390, +1,74,1380,1,2591, +2314,16,0,710,1, +82,1407,1,2513,1886, +1,1341,1424,1,2517, +2315,17,2316,15,2317, +4,66,37,0,75, +0,101,0,121,0, +73,0,110,0,116, +0,73,0,110,0, +116,0,65,0,114, +0,103,0,117,0, +109,0,101,0,110, +0,116,0,68,0, +101,0,99,0,108, +0,97,0,114,0, +97,0,116,0,105, +0,111,0,110,0, +76,0,105,0,115, +0,116,0,1,-1, +1,5,2318,20,2319, +4,68,75,0,101, +0,121,0,73,0, +110,0,116,0,73, +0,110,0,116,0, +65,0,114,0,103, +0,117,0,109,0, +101,0,110,0,116, +0,68,0,101,0, +99,0,108,0,97, +0,114,0,97,0, +116,0,105,0,111, +0,110,0,76,0, +105,0,115,0,116, +0,95,0,49,0, +1,212,1,3,1, +6,1,5,2320,22, +1,47,1,328,1429, +1,1303,1434,1,1096, +1439,1,93,1445,1, +1550,1450,1,2281,1279, +1,2770,1925,1,352, +1475,1,2779,2321,16, +0,797,1,107,1464, +1,1114,1469,1,1048, +1470,1,1871,2322,16, +0,353,1,1370,1578, +1,1478,1583,1,118, +1481,1,1123,1486,1, +371,1491,1,1377,1497, +1,375,1502,1,1882, +2323,16,0,373,1, +377,1507,1,2556,2324, +16,0,661,1,379, +1512,1,380,1517,1, +130,1540,1,2074,2325, +16,0,652,1,373, +1535,1,2564,2326,16, +0,554,1,1011,1227, +1,1012,2327,16,0, +718,1,1840,2328,16, +0,343,1,143,1545, +1,1152,1551,1,2577, +2329,16,0,696,1, +1406,1556,1,1159,1563, +1,157,1568,1,1413, +1573,1,883,1523,1, +1094,2330,16,0,787, +1,1296,1294,1,172, +1595,1,1665,1600,1, +1939,2331,16,0,494, +1,1188,1605,1,1442, +1610,1,188,1644,1, +942,1616,1,1195,1622, +1,1449,1627,1,1701, +1632,1,447,1637,1, +205,1649,1,2467,1942, +1,464,1948,1,2197, +2332,16,0,782,1, +1224,1654,1,223,1659, +1,1730,1664,1,2571, +2333,17,2334,15,2335, +4,54,37,0,75, +0,101,0,121,0, +65,0,114,0,103, +0,117,0,109,0, +101,0,110,0,116, +0,68,0,101,0, +99,0,108,0,97, +0,114,0,97,0, +116,0,105,0,111, +0,110,0,76,0, +105,0,115,0,116, +0,1,-1,1,5, +2336,20,2337,4,56, +75,0,101,0,121, +0,65,0,114,0, +103,0,117,0,109, 0,101,0,110,0, -97,0,109,0,101, -0,95,0,53,0, -1,285,1,3,1, -2,1,1,1966,22, -1,146,1,4,1967, -17,1968,15,1953,1, --1,1,5,1969,20, -1970,4,20,84,0, -121,0,112,0,101, -0,110,0,97,0, -109,0,101,0,95, -0,52,0,1,284, -1,3,1,2,1, -1,1971,22,1,145, -1,5,1972,17,1973, -15,1953,1,-1,1, -5,1974,20,1975,4, -20,84,0,121,0, -112,0,101,0,110, -0,97,0,109,0, -101,0,95,0,51, -0,1,283,1,3, -1,2,1,1,1976, -22,1,144,1,6, -1977,17,1978,15,1953, -1,-1,1,5,1979, -20,1980,4,20,84, -0,121,0,112,0, -101,0,110,0,97, -0,109,0,101,0, -95,0,50,0,1, -282,1,3,1,2, -1,1,1981,22,1, -143,1,7,1982,17, -1983,15,1953,1,-1, -1,5,1984,20,1985, -4,20,84,0,121, -0,112,0,101,0, -110,0,97,0,109, -0,101,0,95,0, -49,0,1,281,1, -3,1,2,1,1, -1986,22,1,142,1, -1514,1108,1,9,1113, -1,10,1642,1,262, -1119,1,1267,1125,1, -481,1646,1,1521,1130, -1,1773,1987,16,0, -234,1,19,1147,1, -20,1988,16,0,152, -1,2281,1154,1,525, -1216,1,30,1654,1, -283,1172,1,1010,1989, -16,0,593,1,40, -1177,1,41,1659,1, -42,1662,1,44,1183, -1,1260,1096,1,47, -1184,1,1303,1307,1, -49,1196,1,50,1201, -1,48,1190,1,305, -1211,1,51,1206,1, -61,1990,16,0,194, -1,63,1222,1,66, -1228,1,67,1233,1, -1478,1458,1,69,1243, -1,70,1248,1,68, -1238,1,73,1991,16, -0,204,1,74,1253, -1,1013,1258,1,2335, -1992,16,0,239,1, -328,1302,1,1048,1344, -1,82,1280,1,1840, -1993,16,0,303,1, -2515,1994,16,0,436, -1,1341,1297,1,1094, -1995,16,0,666,1, -1096,1312,1,93,1318, -1,1550,1323,1,352, -1349,1,1011,1102,1, -107,1338,1,1114,1343, -1,1871,1996,16,0, -313,1,1370,1453,1, -118,1355,1,1123,1360, -1,1332,1263,1,1377, -1371,1,375,1376,1, -1882,1997,16,0,327, -1,377,1381,1,827, -1331,1,380,1391,1, -130,1414,1,2074,1998, -16,0,554,1,371, -1365,1,373,1409,1, -1012,1999,16,0,595, -1,379,1386,1,143, -1419,1,1152,1426,1, -1406,1431,1,1159,1438, -1,157,1443,1,1413, -1448,1,883,1397,1, -1296,1167,1,172,1469, -1,1665,1474,1,1939, -2000,16,0,435,1, -1188,1479,1,1442,1484, -1,188,1518,1,942, -1490,1,1195,1496,1, -1449,1501,1,1701,1506, -1,447,1511,1,205, -1523,1,2467,1677,1, -464,1683,1,2642,1669, -1,2197,2001,16,0, -662,1,1224,1528,1, -223,1533,1,1730,1538, -1,2651,2002,16,0, -570,1,477,1549,1, -1231,1554,1,479,1559, -1,480,1564,1,1485, -1570,1,459,1688,1, -476,1543,1,242,1578, -1,478,1583,1,2506, -1690,1,1001,1588,1, -1002,1593,1,18,2003, -19,490,1,18,2004, -5,84,1,1011,1102, -1,1012,2005,16,0, -488,1,1013,1258,1, -262,1119,1,1267,2006, -16,0,488,1,515, -2007,16,0,488,1, -1521,2008,16,0,488, -1,525,1216,1,283, -1172,1,2299,2009,16, -0,488,1,42,2010, -16,0,488,1,40, -1177,1,44,1183,1, -47,1184,1,1303,2011, -16,0,488,1,1555, -2012,16,0,488,1, -50,1201,1,48,1190, -1,49,1196,1,51, -1206,1,63,1222,1, -305,1211,1,66,1228, -1,67,1233,1,68, -1238,1,69,1243,1, -70,1248,1,73,2013, -16,0,488,1,74, -1253,1,328,1302,1, -1048,2014,16,0,488, -1,82,2015,16,0, -488,1,1840,2016,16, -0,488,1,1591,2017, -16,0,488,1,1341, -2018,16,0,488,1, -1096,1312,1,93,1318, -1,352,1349,1,107, -2019,16,0,488,1, -1114,1343,1,118,2020, -16,0,488,1,1123, -2021,16,0,488,1, -371,1365,1,1628,2022, -16,0,488,1,375, -1376,1,1882,2023,16, -0,488,1,377,1381, -1,379,1386,1,380, -1391,1,883,2024,16, -0,488,1,373,1409, -1,130,2025,16,0, -488,1,143,2026,16, -0,488,1,387,2027, -16,0,488,1,2664, -2028,16,0,488,1, -1159,2029,16,0,488, -1,157,2030,16,0, -488,1,1413,2031,16, -0,488,1,1665,2032, -16,0,488,1,412, -2033,16,0,488,1, -1377,2034,16,0,488, -1,172,2035,16,0, -488,1,1939,2036,16, -0,488,1,437,2037, -16,0,488,1,188, -2038,16,0,488,1, -942,2039,16,0,488, -1,1195,2040,16,0, -488,1,1449,2041,16, -0,488,1,1701,2042, -16,0,488,1,447, -1511,1,205,2043,16, -0,488,1,827,2044, -16,0,488,1,223, -2045,16,0,488,1, -476,1543,1,477,1549, -1,1231,2046,16,0, -488,1,479,1559,1, -480,1564,1,1485,2047, -16,0,488,1,1737, -2048,16,0,488,1, -242,2049,16,0,488, -1,478,1583,1,1001, -1588,1,1002,1593,1, -19,2050,19,225,1, -19,2051,5,176,1, -256,2052,16,0,223, -1,1261,2053,16,0, -223,1,1011,1102,1, -1012,2054,16,0,455, -1,2458,876,1,262, -1119,1,1267,2055,16, -0,455,1,2021,718, -1,1521,2056,16,0, -455,1,1775,2057,16, -0,223,1,2029,725, -1,2030,731,1,2031, -736,1,2032,741,1, -2033,746,1,277,2058, -16,0,223,1,2035, -752,1,2037,757,1, -2039,762,1,32,2059, -16,0,223,1,2464, -899,1,2293,2060,16, -0,223,1,2043,774, -1,2045,779,1,2299, -2061,16,0,455,1, -41,2062,16,0,223, -1,42,2063,16,0, -455,1,40,1177,1, -44,1183,1,43,2064, -16,0,223,1,1804, -2065,16,0,223,1, -48,1190,1,49,1196, -1,47,1184,1,51, -1206,1,52,2066,16, -0,223,1,50,1201, -1,305,1211,1,1096, -1312,1,1515,2067,16, -0,223,1,2318,2068, -16,0,223,1,283, -1172,1,63,1222,1, -66,1228,1,67,1233, -1,68,1238,1,69, -1243,1,70,1248,1, -71,2069,16,0,223, -1,73,2070,16,0, -455,1,74,1253,1, -1013,1258,1,76,2071, -16,0,223,1,1834, -2072,16,0,223,1, -2337,2073,16,0,223, -1,79,2074,16,0, -223,1,1335,2075,16, -0,223,1,299,2076, -16,0,223,1,82, -2077,16,0,455,1, -1840,2078,16,0,455, -1,1297,2079,16,0, -223,1,85,2080,16, -0,223,1,1341,2081, -16,0,455,1,89, -2082,16,0,223,1, -1303,2083,16,0,455, -1,509,2084,16,0, -223,1,93,1318,1, -322,2085,16,0,223, -1,97,2086,16,0, -223,1,2041,768,1, -1555,2087,16,0,455, -1,827,2088,16,0, -455,1,102,2089,16, -0,223,1,1860,821, -1,1803,787,1,2364, -827,1,107,2090,16, -0,455,1,1114,1343, -1,112,2091,16,0, -223,1,1117,2092,16, -0,223,1,352,1349, -1,1873,835,1,118, -2093,16,0,455,1, -1123,2094,16,0,455, -1,371,1365,1,515, -2095,16,0,455,1, -1377,2096,16,0,455, -1,124,2097,16,0, -223,1,1882,2098,16, -0,455,1,377,1381, -1,379,1386,1,380, -1391,1,130,2099,16, -0,455,1,346,2100, -16,0,223,1,2075, -2101,16,0,223,1, -373,1409,1,387,2102, -16,0,455,1,137, -2103,16,0,223,1, -143,2104,16,0,455, -1,1901,2105,16,0, -223,1,1048,2106,16, -0,455,1,2658,2107, -16,0,223,1,1153, -2108,16,0,223,1, -375,1376,1,151,2109, -16,0,223,1,1407, -2110,16,0,223,1, -1659,2111,16,0,223, -1,2413,2112,16,0, -223,1,1159,2113,16, -0,455,1,381,2114, -16,0,223,1,157, -2115,16,0,455,1, -1413,2116,16,0,455, -1,883,2117,16,0, -455,1,1371,2118,16, -0,223,1,328,1302, -1,2105,814,1,2106, -2119,16,0,223,1, -166,2120,16,0,223, -1,525,2121,16,0, -223,1,1622,2122,16, -0,223,1,406,2123, -16,0,223,1,1574, -799,1,172,2124,16, -0,455,1,1931,861, -1,412,2125,16,0, -455,1,1933,2126,16, -0,223,1,1876,2127, -16,0,223,1,431, -2128,16,0,223,1, -1585,2129,16,0,223, -1,182,2130,16,0, -223,1,1628,2131,16, -0,455,1,1189,2132, -16,0,223,1,437, -2133,16,0,455,1, -1591,2134,16,0,455, -1,188,2135,16,0, -455,1,1695,2136,16, -0,223,1,2198,2137, -16,0,223,1,1195, -2138,16,0,455,1, -1449,2139,16,0,455, -1,1701,2140,16,0, -455,1,447,2141,16, -0,223,1,199,2142, -16,0,223,1,2459, -882,1,1958,2143,16, -0,223,1,2462,889, -1,1657,894,1,205, -2144,16,0,455,1, -459,2145,16,0,223, -1,462,2146,16,0, -223,1,1665,2147,16, -0,455,1,217,2148, -16,0,223,1,2227, -908,1,942,2149,16, -0,455,1,1225,2150, -16,0,223,1,223, -2151,16,0,455,1, -1479,2152,16,0,223, -1,1731,2153,16,0, -223,1,477,1549,1, -1231,2154,16,0,455, -1,479,1559,1,480, -1564,1,1485,2155,16, -0,455,1,1737,2156, -16,0,455,1,1989, -916,1,1990,2157,16, -0,223,1,1443,2158, -16,0,223,1,236, -2159,16,0,223,1, -2136,842,1,2664,2160, -16,0,455,1,476, -1543,1,242,2161,16, -0,455,1,478,1583, -1,1939,2162,16,0, -455,1,1001,1588,1, -1002,1593,1,1756,2163, -16,0,223,1,20, -2164,19,442,1,20, -2165,5,84,1,1011, -1102,1,1012,2166,16, -0,440,1,1013,1258, -1,262,1119,1,1267, -2167,16,0,440,1, -515,2168,16,0,440, -1,1521,2169,16,0, -440,1,525,1216,1, -283,1172,1,2299,2170, -16,0,440,1,42, -2171,16,0,440,1, -40,1177,1,44,1183, -1,47,1184,1,1303, -2172,16,0,440,1, -1555,2173,16,0,440, -1,50,1201,1,48, -1190,1,49,1196,1, -51,1206,1,63,1222, -1,305,1211,1,66, -1228,1,67,1233,1, -68,1238,1,69,1243, -1,70,1248,1,73, -2174,16,0,440,1, -74,1253,1,328,2175, -16,0,440,1,1048, -2176,16,0,440,1, -82,2177,16,0,440, -1,1840,2178,16,0, -440,1,1591,2179,16, -0,440,1,1341,2180, -16,0,440,1,1096, -1312,1,93,1318,1, -352,2181,16,0,440, -1,107,2182,16,0, -440,1,1114,1343,1, -118,2183,16,0,440, -1,1123,2184,16,0, -440,1,371,1365,1, -1628,2185,16,0,440, -1,375,1376,1,1882, -2186,16,0,440,1, -377,1381,1,379,1386, -1,380,1391,1,883, -2187,16,0,440,1, -373,1409,1,130,2188, -16,0,440,1,143, -2189,16,0,440,1, -387,2190,16,0,440, -1,2664,2191,16,0, -440,1,1159,2192,16, -0,440,1,157,2193, -16,0,440,1,1413, -2194,16,0,440,1, -1665,2195,16,0,440, -1,412,2196,16,0, -440,1,1377,2197,16, -0,440,1,172,2198, -16,0,440,1,1939, -2199,16,0,440,1, -437,2200,16,0,440, -1,188,2201,16,0, -440,1,942,2202,16, -0,440,1,1195,2203, -16,0,440,1,1449, -2204,16,0,440,1, -1701,2205,16,0,440, -1,447,1511,1,205, -2206,16,0,440,1, -827,2207,16,0,440, -1,223,2208,16,0, -440,1,476,1543,1, -477,1549,1,1231,2209, -16,0,440,1,479, -1559,1,480,1564,1, -1485,2210,16,0,440, -1,1737,2211,16,0, -440,1,242,2212,16, -0,440,1,478,1583, -1,1001,1588,1,1002, -1593,1,21,2213,19, -432,1,21,2214,5, -84,1,1011,1102,1, -1012,2215,16,0,430, -1,1013,1258,1,262, -1119,1,1267,2216,16, -0,430,1,515,2217, -16,0,430,1,1521, -2218,16,0,430,1, -525,1216,1,283,1172, -1,2299,2219,16,0, -430,1,42,2220,16, -0,430,1,40,1177, -1,44,1183,1,47, -1184,1,1303,2221,16, -0,430,1,1555,2222, -16,0,430,1,50, -1201,1,48,1190,1, -49,1196,1,51,1206, -1,63,1222,1,305, -1211,1,66,1228,1, -67,1233,1,68,1238, -1,69,1243,1,70, -1248,1,73,2223,16, -0,430,1,74,1253, -1,328,2224,16,0, -430,1,1048,2225,16, -0,430,1,82,2226, -16,0,430,1,1840, -2227,16,0,430,1, -1591,2228,16,0,430, -1,1341,2229,16,0, -430,1,1096,1312,1, -93,1318,1,352,2230, -16,0,430,1,107, -2231,16,0,430,1, -1114,1343,1,118,2232, -16,0,430,1,1123, -2233,16,0,430,1, -371,1365,1,1628,2234, -16,0,430,1,375, -1376,1,1882,2235,16, -0,430,1,377,1381, -1,379,1386,1,380, -1391,1,883,2236,16, -0,430,1,373,1409, -1,130,2237,16,0, -430,1,143,2238,16, -0,430,1,387,2239, -16,0,430,1,2664, -2240,16,0,430,1, -1159,2241,16,0,430, -1,157,2242,16,0, -430,1,1413,2243,16, -0,430,1,1665,2244, -16,0,430,1,412, -2245,16,0,430,1, -1377,2246,16,0,430, -1,172,2247,16,0, -430,1,1939,2248,16, -0,430,1,437,2249, -16,0,430,1,188, -2250,16,0,430,1, -942,2251,16,0,430, -1,1195,2252,16,0, -430,1,1449,2253,16, -0,430,1,1701,2254, -16,0,430,1,447, -1511,1,205,2255,16, -0,430,1,827,2256, -16,0,430,1,223, -2257,16,0,430,1, -476,1543,1,477,1549, -1,1231,2258,16,0, -430,1,479,1559,1, -480,1564,1,1485,2259, -16,0,430,1,1737, -2260,16,0,430,1, -242,2261,16,0,430, -1,478,1583,1,1001, -1588,1,1002,1593,1, -22,2262,19,383,1, -22,2263,5,84,1, -1011,1102,1,1012,2264, -16,0,381,1,1013, -1258,1,262,1119,1, -1267,2265,16,0,381, -1,515,2266,16,0, -381,1,1521,2267,16, -0,381,1,525,1216, -1,283,1172,1,2299, -2268,16,0,381,1, -42,2269,16,0,381, -1,40,1177,1,44, -1183,1,47,1184,1, -1303,2270,16,0,381, -1,1555,2271,16,0, -381,1,50,1201,1, -48,1190,1,49,1196, -1,51,1206,1,63, -1222,1,305,1211,1, -66,1228,1,67,1233, -1,68,1238,1,69, -1243,1,70,1248,1, -73,2272,16,0,381, -1,74,1253,1,328, -2273,16,0,381,1, -1048,2274,16,0,381, -1,82,2275,16,0, -381,1,1840,2276,16, -0,381,1,1591,2277, -16,0,381,1,1341, -2278,16,0,381,1, -1096,1312,1,93,1318, -1,352,2279,16,0, -381,1,107,2280,16, -0,381,1,1114,1343, -1,118,2281,16,0, -381,1,1123,2282,16, -0,381,1,371,1365, -1,1628,2283,16,0, -381,1,375,1376,1, -1882,2284,16,0,381, -1,377,1381,1,379, -1386,1,380,1391,1, -883,2285,16,0,381, -1,373,1409,1,130, -2286,16,0,381,1, -143,2287,16,0,381, -1,387,2288,16,0, -381,1,2664,2289,16, -0,381,1,1159,2290, -16,0,381,1,157, -2291,16,0,381,1, -1413,2292,16,0,381, -1,1665,2293,16,0, -381,1,412,2294,16, -0,381,1,1377,2295, -16,0,381,1,172, -2296,16,0,381,1, -1939,2297,16,0,381, -1,437,2298,16,0, -381,1,188,2299,16, -0,381,1,942,2300, -16,0,381,1,1195, -2301,16,0,381,1, -1449,2302,16,0,381, -1,1701,2303,16,0, -381,1,447,1511,1, -205,2304,16,0,381, -1,827,2305,16,0, -381,1,223,2306,16, -0,381,1,476,1543, -1,477,1549,1,1231, -2307,16,0,381,1, -479,1559,1,480,1564, -1,1485,2308,16,0, -381,1,1737,2309,16, -0,381,1,242,2310, -16,0,381,1,478, -1583,1,1001,1588,1, -1002,1593,1,23,2311, -19,504,1,23,2312, -5,38,1,1901,2313, -16,0,502,1,2075, -2314,16,0,502,1, -1860,821,1,1803,787, -1,1804,2315,16,0, -502,1,2413,2316,16, -0,502,1,2198,2317, -16,0,502,1,1873, -835,1,1657,894,1, -1989,916,1,1990,2318, -16,0,502,1,1775, -2319,16,0,502,1, -32,2320,16,0,502, -1,2105,814,1,2106, -2321,16,0,502,1, -2364,827,1,2227,908, -1,2337,2322,16,0, -502,1,2021,718,1, -2458,876,1,2459,882, -1,2462,889,1,2136, -842,1,2464,899,1, -2029,725,1,2030,731, -1,2031,736,1,2032, -741,1,2033,746,1, -2035,752,1,2037,757, -1,2039,762,1,1931, -861,1,2041,768,1, -2043,774,1,2045,779, -1,1574,799,1,1958, -2323,16,0,502,1, -24,2324,19,177,1, -24,2325,5,5,1, -44,2326,16,0,175, -1,377,2327,16,0, -540,1,40,2328,16, -0,674,1,63,2329, -16,0,196,1,373, -2330,16,0,536,1, -25,2331,19,291,1, -25,2332,5,177,1, -256,2333,16,0,545, -1,1261,2334,16,0, -545,1,1011,1102,1, -1012,2335,16,0,289, -1,2458,876,1,262, -1119,1,1267,2336,16, -0,289,1,2021,718, -1,1521,2337,16,0, -289,1,1775,2338,16, -0,545,1,2029,725, -1,2030,731,1,2031, -736,1,2032,741,1, -2033,746,1,277,2339, -16,0,545,1,2035, -752,1,2037,757,1, -2039,762,1,32,2340, -16,0,545,1,2464, -899,1,2293,2341,16, -0,545,1,2043,774, -1,2045,779,1,2299, -2342,16,0,289,1, -41,2343,16,0,545, -1,42,2344,16,0, -289,1,40,1177,1, -44,1183,1,43,2345, -16,0,545,1,1804, -2346,16,0,545,1, -48,1190,1,49,1196, -1,47,1184,1,51, -1206,1,52,2347,16, -0,545,1,50,1201, -1,305,1211,1,1096, -1312,1,1515,2348,16, -0,545,1,2318,2349, -16,0,545,1,62, -2350,16,0,545,1, -63,1222,1,66,1228, -1,67,1233,1,68, -1238,1,69,1243,1, -70,1248,1,71,2351, -16,0,545,1,283, -1172,1,73,2352,16, -0,289,1,74,1253, -1,1013,1258,1,76, -2353,16,0,545,1, -1834,2354,16,0,545, -1,2337,2355,16,0, -545,1,79,2356,16, -0,545,1,1335,2357, -16,0,545,1,299, -2358,16,0,545,1, -82,2359,16,0,289, -1,1840,2360,16,0, -289,1,1297,2361,16, -0,545,1,85,2362, -16,0,545,1,1341, -2363,16,0,289,1, -89,2364,16,0,545, -1,1303,2365,16,0, -289,1,509,2366,16, -0,545,1,93,1318, -1,322,2367,16,0, -545,1,97,2368,16, -0,545,1,2041,768, -1,1555,2369,16,0, -289,1,827,2370,16, -0,289,1,102,2371, -16,0,545,1,1860, -821,1,1803,787,1, -2364,827,1,107,2372, -16,0,289,1,1114, -1343,1,112,2373,16, -0,545,1,1117,2374, -16,0,545,1,352, -1349,1,1873,835,1, -118,1355,1,1123,2375, -16,0,289,1,371, -1365,1,515,2376,16, -0,289,1,1377,2377, -16,0,289,1,124, -2378,16,0,545,1, -1882,2379,16,0,289, -1,377,1381,1,379, -1386,1,380,1391,1, -130,1414,1,346,2380, -16,0,545,1,2075, -2381,16,0,545,1, -373,1409,1,387,2382, -16,0,289,1,137, -2383,16,0,545,1, -143,2384,16,0,289, -1,1901,2385,16,0, -545,1,1048,1344,1, -2658,2386,16,0,545, -1,1153,2387,16,0, -545,1,375,1376,1, -151,2388,16,0,545, -1,1407,2389,16,0, -545,1,1659,2390,16, -0,545,1,2413,2391, -16,0,545,1,1159, -2392,16,0,289,1, -381,2393,16,0,545, -1,157,2394,16,0, -289,1,1413,2395,16, -0,289,1,883,2396, -16,0,289,1,1371, -2397,16,0,545,1, -328,1302,1,2105,814, -1,2106,2398,16,0, -545,1,166,2399,16, -0,545,1,525,2400, -16,0,545,1,1622, -2401,16,0,545,1, -406,2402,16,0,545, -1,1574,799,1,172, -1469,1,1931,861,1, -412,2403,16,0,289, -1,1933,2404,16,0, -545,1,1876,2405,16, -0,545,1,431,2406, -16,0,545,1,1585, -2407,16,0,545,1, -182,2408,16,0,545, -1,1628,2409,16,0, -289,1,1189,2410,16, -0,545,1,437,2411, -16,0,289,1,1591, -2412,16,0,289,1, -188,1518,1,1695,2413, -16,0,545,1,2198, -2414,16,0,545,1, -1195,2415,16,0,289, -1,1449,2416,16,0, -289,1,1701,2417,16, -0,289,1,447,2418, -16,0,545,1,199, -2419,16,0,545,1, -2459,882,1,1958,2420, -16,0,545,1,2462, -889,1,1657,894,1, -205,2421,16,0,289, -1,459,2422,16,0, -545,1,462,2423,16, -0,545,1,1665,2424, -16,0,289,1,217, -2425,16,0,545,1, -2227,908,1,942,1490, -1,1225,2426,16,0, -545,1,223,2427,16, -0,289,1,1479,2428, -16,0,545,1,1731, -2429,16,0,545,1, -477,1549,1,1231,2430, -16,0,289,1,479, -1559,1,480,1564,1, -1485,2431,16,0,289, -1,1737,2432,16,0, -289,1,1989,916,1, -1990,2433,16,0,545, -1,1443,2434,16,0, -545,1,236,2435,16, -0,545,1,2136,842, -1,2664,2436,16,0, -289,1,476,1543,1, -242,2437,16,0,289, -1,478,1583,1,1939, -2438,16,0,289,1, -1001,1588,1,1002,1593, -1,1756,2439,16,0, -545,1,26,2440,19, -308,1,26,2441,5, -84,1,1011,1102,1, -1012,2442,16,0,306, -1,1013,1258,1,262, -1119,1,1267,2443,16, -0,306,1,515,2444, -16,0,660,1,1521, -2445,16,0,306,1, -525,1216,1,283,1172, -1,2299,2446,16,0, -306,1,42,2447,16, -0,306,1,40,1177, -1,44,1183,1,47, -1184,1,1303,2448,16, -0,306,1,1555,2449, -16,0,306,1,50, -1201,1,48,1190,1, -49,1196,1,51,1206, -1,63,1222,1,305, -1211,1,66,1228,1, -67,1233,1,68,1238, -1,69,1243,1,70, -1248,1,73,2450,16, -0,306,1,74,1253, -1,328,1302,1,1048, -1344,1,82,2451,16, -0,306,1,1840,2452, -16,0,306,1,1591, -2453,16,0,306,1, -1341,2454,16,0,306, -1,1096,1312,1,93, -1318,1,352,1349,1, -107,2455,16,0,306, -1,1114,1343,1,118, -1355,1,1123,2456,16, -0,306,1,371,1365, -1,1628,2457,16,0, -306,1,375,1376,1, -1882,2458,16,0,306, -1,377,1381,1,379, -1386,1,380,1391,1, -883,2459,16,0,306, -1,373,1409,1,130, -1414,1,143,2460,16, -0,306,1,387,2461, -16,0,306,1,2664, -2462,16,0,306,1, -1159,2463,16,0,306, -1,157,2464,16,0, -306,1,1413,2465,16, -0,306,1,1665,2466, -16,0,306,1,412, -2467,16,0,306,1, -1377,2468,16,0,306, -1,172,1469,1,1939, -2469,16,0,306,1, -437,2470,16,0,588, -1,188,1518,1,942, -1490,1,1195,2471,16, -0,306,1,1449,2472, -16,0,306,1,1701, -2473,16,0,306,1, -447,1511,1,205,2474, -16,0,306,1,827, -2475,16,0,306,1, -223,2476,16,0,306, -1,476,1543,1,477, -1549,1,1231,2477,16, -0,306,1,479,1559, -1,480,1564,1,1485, -2478,16,0,306,1, -1737,2479,16,0,306, -1,242,2480,16,0, -306,1,478,1583,1, -1001,1588,1,1002,1593, -1,27,2481,19,598, -1,27,2482,5,95, -1,256,2483,16,0, -596,1,1261,2484,16, -0,596,1,509,2485, -16,0,596,1,1515, -2486,16,0,596,1, -2021,718,1,1775,2487, -16,0,596,1,2029, -725,1,2030,731,1, -2031,736,1,2032,741, -1,2033,746,1,277, -2488,16,0,596,1, -2035,752,1,2037,757, -1,2039,762,1,32, -2489,16,0,596,1, -2041,768,1,2293,2490, -16,0,596,1,2043, -774,1,2045,779,1, -41,2491,16,0,596, -1,1297,2492,16,0, -596,1,43,2493,16, -0,596,1,1803,787, -1,1804,2494,16,0, -596,1,299,2495,16, -0,596,1,52,2496, -16,0,596,1,2318, -2497,16,0,596,1, -62,2498,16,0,596, -1,2075,2499,16,0, -596,1,1574,799,1, -71,2500,16,0,596, -1,76,2501,16,0, -596,1,1834,2502,16, -0,596,1,2337,2503, -16,0,596,1,79, -2504,16,0,596,1, -1335,2505,16,0,596, -1,322,2506,16,0, -596,1,85,2507,16, -0,596,1,89,2508, -16,0,596,1,346, -2509,16,0,596,1, -2105,814,1,2106,2510, -16,0,596,1,97, -2511,16,0,596,1, -1860,821,1,2364,827, -1,102,2512,16,0, -596,1,112,2513,16, -0,596,1,1117,2514, -16,0,596,1,1873, -835,1,1876,2515,16, -0,596,1,124,2516, -16,0,596,1,2136, -842,1,381,2517,16, -0,596,1,525,2518, -16,0,596,1,137, -2519,16,0,596,1, -1901,2520,16,0,596, -1,2658,2521,16,0, -596,1,1153,2522,16, -0,596,1,151,2523, -16,0,596,1,1407, -2524,16,0,596,1, -1659,2525,16,0,596, -1,2413,2526,16,0, -596,1,406,2527,16, -0,596,1,1371,2528, -16,0,596,1,166, -2529,16,0,596,1, -1622,2530,16,0,596, -1,1931,861,1,1933, -2531,16,0,596,1, -431,2532,16,0,596, -1,1585,2533,16,0, -596,1,182,2534,16, -0,596,1,1189,2535, -16,0,596,1,1443, -2536,16,0,596,1, -1695,2537,16,0,596, -1,2198,2538,16,0, -596,1,447,2539,16, -0,596,1,2458,876, -1,2459,882,1,1958, -2540,16,0,596,1, -2462,889,1,1657,894, -1,2464,899,1,199, -2541,16,0,596,1, -459,2542,16,0,596, -1,462,2543,16,0, -596,1,217,2544,16, -0,596,1,2227,908, -1,1225,2545,16,0, -596,1,1479,2546,16, -0,596,1,1731,2547, -16,0,596,1,1989, -916,1,1990,2548,16, -0,596,1,236,2549, -16,0,596,1,1756, -2550,16,0,596,1, -28,2551,19,629,1, -28,2552,5,60,1, -328,1302,1,223,1533, -1,1096,1312,1,118, -1355,1,883,1397,1, -525,1216,1,1001,1588, -1,130,1414,1,459, -1688,1,1114,1343,1, -352,1349,1,447,1511, -1,464,1683,1,1011, -1102,1,1013,1258,1, -242,1578,1,143,1419, -1,40,1177,1,41, -1659,1,42,1662,1, -479,1559,1,44,1183, -1,481,1646,1,373, -1409,1,47,1184,1, -157,1443,1,49,1196, -1,50,1201,1,48, -1190,1,379,1386,1, -380,1391,1,51,1206, -1,476,1543,1,371, -1365,1,478,1583,1, -1048,1344,1,375,1376, -1,172,1469,1,262, -1119,1,283,1172,1, -63,1222,1,67,1233, -1,68,1238,1,69, -1243,1,66,1228,1, -461,2553,16,0,627, -1,74,1253,1,377, -1381,1,1002,1593,1, -70,1248,1,188,1518, -1,82,1280,1,305, -1211,1,477,1549,1, -827,1331,1,93,1318, -1,480,1564,1,205, -1523,1,942,1490,1, -107,1338,1,29,2554, -19,280,1,29,2555, -5,84,1,1011,1102, -1,1012,2556,16,0, -278,1,1013,1258,1, -262,1119,1,1267,2557, -16,0,278,1,515, -2558,16,0,278,1, -1521,2559,16,0,278, -1,525,1216,1,283, -1172,1,2299,2560,16, -0,278,1,42,2561, -16,0,278,1,40, -1177,1,44,1183,1, -47,1184,1,1303,2562, -16,0,278,1,1555, -2563,16,0,278,1, -50,1201,1,48,1190, -1,49,1196,1,51, -1206,1,63,1222,1, -305,1211,1,66,1228, -1,67,1233,1,68, -1238,1,69,1243,1, -70,1248,1,73,2564, -16,0,278,1,74, -1253,1,328,1302,1, -1048,1344,1,82,2565, -16,0,278,1,1840, -2566,16,0,278,1, -1591,2567,16,0,278, -1,1341,2568,16,0, -278,1,1096,1312,1, -93,1318,1,352,1349, -1,107,2569,16,0, -278,1,1114,1343,1, -118,1355,1,1123,2570, -16,0,278,1,371, -1365,1,1628,2571,16, -0,278,1,375,1376, -1,1882,2572,16,0, -278,1,377,1381,1, -379,1386,1,380,1391, -1,883,2573,16,0, -278,1,373,1409,1, -130,1414,1,143,1419, -1,387,2574,16,0, -278,1,2664,2575,16, -0,278,1,1159,2576, -16,0,278,1,157, -1443,1,1413,2577,16, -0,278,1,1665,2578, -16,0,278,1,412, -2579,16,0,278,1, -1377,2580,16,0,278, -1,172,1469,1,1939, -2581,16,0,278,1, -437,2582,16,0,278, -1,188,1518,1,942, -1490,1,1195,2583,16, -0,278,1,1449,2584, -16,0,278,1,1701, -2585,16,0,278,1, -447,1511,1,205,2586, -16,0,278,1,827, -2587,16,0,278,1, -223,2588,16,0,278, -1,476,1543,1,477, -1549,1,1231,2589,16, -0,278,1,479,1559, -1,480,1564,1,1485, -2590,16,0,278,1, -1737,2591,16,0,278, -1,242,2592,16,0, -278,1,478,1583,1, -1001,1588,1,1002,1593, -1,30,2593,19,268, -1,30,2594,5,84, -1,1011,1102,1,1012, -2595,16,0,266,1, -1013,1258,1,262,1119, -1,1267,2596,16,0, -266,1,515,2597,16, -0,266,1,1521,2598, -16,0,266,1,525, -1216,1,283,1172,1, -2299,2599,16,0,266, -1,42,2600,16,0, -266,1,40,1177,1, -44,1183,1,47,1184, -1,1303,2601,16,0, -266,1,1555,2602,16, -0,266,1,50,1201, -1,48,1190,1,49, -1196,1,51,1206,1, -63,1222,1,305,1211, -1,66,1228,1,67, -1233,1,68,1238,1, -69,1243,1,70,1248, -1,73,2603,16,0, -266,1,74,1253,1, -328,1302,1,1048,1344, -1,82,2604,16,0, -266,1,1840,2605,16, -0,266,1,1591,2606, -16,0,266,1,1341, -2607,16,0,266,1, -1096,1312,1,93,1318, -1,352,1349,1,107, -2608,16,0,266,1, -1114,1343,1,118,1355, -1,1123,2609,16,0, -266,1,371,1365,1, -1628,2610,16,0,266, -1,375,1376,1,1882, -2611,16,0,266,1, -377,1381,1,379,1386, -1,380,1391,1,883, -2612,16,0,266,1, -373,1409,1,130,1414, -1,143,1419,1,387, -2613,16,0,266,1, -2664,2614,16,0,266, -1,1159,2615,16,0, -266,1,157,1443,1, -1413,2616,16,0,266, -1,1665,2617,16,0, -266,1,412,2618,16, -0,266,1,1377,2619, -16,0,266,1,172, -1469,1,1939,2620,16, -0,266,1,437,2621, -16,0,266,1,188, -1518,1,942,1490,1, -1195,2622,16,0,266, -1,1449,2623,16,0, -266,1,1701,2624,16, -0,266,1,447,1511, -1,205,2625,16,0, -266,1,827,2626,16, -0,266,1,223,2627, -16,0,266,1,476, -1543,1,477,1549,1, -1231,2628,16,0,266, -1,479,1559,1,480, -1564,1,1485,2629,16, -0,266,1,1737,2630, -16,0,266,1,242, -2631,16,0,266,1, -478,1583,1,1001,1588, -1,1002,1593,1,31, -2632,19,253,1,31, -2633,5,84,1,1011, -1102,1,1012,2634,16, -0,251,1,1013,1258, -1,262,1119,1,1267, -2635,16,0,251,1, -515,2636,16,0,251, -1,1521,2637,16,0, -251,1,525,1216,1, -283,1172,1,2299,2638, -16,0,251,1,42, -2639,16,0,251,1, -40,1177,1,44,1183, -1,47,1184,1,1303, -2640,16,0,251,1, -1555,2641,16,0,251, -1,50,1201,1,48, -1190,1,49,1196,1, -51,1206,1,63,1222, -1,305,1211,1,66, -1228,1,67,1233,1, -68,1238,1,69,1243, -1,70,1248,1,73, -2642,16,0,251,1, -74,1253,1,328,1302, -1,1048,1344,1,82, -2643,16,0,251,1, -1840,2644,16,0,251, -1,1591,2645,16,0, -251,1,1341,2646,16, -0,251,1,1096,1312, -1,93,1318,1,352, -1349,1,107,2647,16, -0,251,1,1114,1343, -1,118,1355,1,1123, -2648,16,0,251,1, -371,1365,1,1628,2649, -16,0,251,1,375, -1376,1,1882,2650,16, -0,251,1,377,1381, -1,379,1386,1,380, -1391,1,883,2651,16, -0,251,1,373,1409, -1,130,1414,1,143, -2652,16,0,251,1, -387,2653,16,0,251, -1,2664,2654,16,0, -251,1,1159,2655,16, -0,251,1,157,2656, -16,0,251,1,1413, -2657,16,0,251,1, -1665,2658,16,0,251, -1,412,2659,16,0, -251,1,1377,2660,16, -0,251,1,172,1469, -1,1939,2661,16,0, -251,1,437,2662,16, -0,251,1,188,1518, -1,942,1490,1,1195, -2663,16,0,251,1, -1449,2664,16,0,251, -1,1701,2665,16,0, -251,1,447,1511,1, -205,2666,16,0,251, -1,827,2667,16,0, -251,1,223,2668,16, -0,251,1,476,1543, -1,477,1549,1,1231, -2669,16,0,251,1, -479,1559,1,480,1564, -1,1485,2670,16,0, -251,1,1737,2671,16, -0,251,1,242,2672, -16,0,251,1,478, -1583,1,1001,1588,1, -1002,1593,1,32,2673, -19,246,1,32,2674, -5,84,1,1011,1102, -1,1012,2675,16,0, -244,1,1013,1258,1, -262,1119,1,1267,2676, -16,0,244,1,515, -2677,16,0,244,1, -1521,2678,16,0,244, -1,525,1216,1,283, -1172,1,2299,2679,16, -0,244,1,42,2680, -16,0,244,1,40, -1177,1,44,1183,1, -47,1184,1,1303,2681, -16,0,244,1,1555, -2682,16,0,244,1, -50,1201,1,48,1190, -1,49,1196,1,51, -1206,1,63,1222,1, -305,1211,1,66,1228, -1,67,1233,1,68, -1238,1,69,1243,1, -70,1248,1,73,2683, -16,0,244,1,74, -1253,1,328,1302,1, -1048,1344,1,82,2684, -16,0,244,1,1840, -2685,16,0,244,1, -1591,2686,16,0,244, -1,1341,2687,16,0, -244,1,1096,1312,1, -93,1318,1,352,1349, -1,107,2688,16,0, -244,1,1114,1343,1, -118,1355,1,1123,2689, -16,0,244,1,371, -1365,1,1628,2690,16, -0,244,1,375,1376, -1,1882,2691,16,0, -244,1,377,1381,1, -379,1386,1,380,1391, -1,883,2692,16,0, -244,1,373,1409,1, -130,1414,1,143,2693, -16,0,244,1,387, -2694,16,0,244,1, -2664,2695,16,0,244, -1,1159,2696,16,0, -244,1,157,2697,16, -0,244,1,1413,2698, -16,0,244,1,1665, -2699,16,0,244,1, -412,2700,16,0,244, -1,1377,2701,16,0, -244,1,172,1469,1, -1939,2702,16,0,244, -1,437,2703,16,0, -244,1,188,1518,1, -942,1490,1,1195,2704, -16,0,244,1,1449, -2705,16,0,244,1, -1701,2706,16,0,244, -1,447,1511,1,205, -2707,16,0,244,1, -827,2708,16,0,244, -1,223,2709,16,0, -244,1,476,1543,1, -477,1549,1,1231,2710, -16,0,244,1,479, -1559,1,480,1564,1, -1485,2711,16,0,244, -1,1737,2712,16,0, -244,1,242,2713,16, -0,244,1,478,1583, -1,1001,1588,1,1002, -1593,1,33,2714,19, -332,1,33,2715,5, -84,1,1011,1102,1, -1012,2716,16,0,330, -1,1013,1258,1,262, -1119,1,1267,2717,16, -0,330,1,515,2718, -16,0,330,1,1521, -2719,16,0,330,1, -525,1216,1,283,1172, -1,2299,2720,16,0, -330,1,42,2721,16, -0,330,1,40,1177, -1,44,1183,1,47, -1184,1,1303,2722,16, -0,330,1,1555,2723, -16,0,330,1,50, -1201,1,48,1190,1, -49,1196,1,51,1206, -1,63,1222,1,305, -1211,1,66,1228,1, -67,1233,1,68,1238, -1,69,1243,1,70, -1248,1,73,2724,16, -0,330,1,74,1253, -1,328,1302,1,1048, -1344,1,82,2725,16, -0,330,1,1840,2726, -16,0,330,1,1591, -2727,16,0,330,1, -1341,2728,16,0,330, -1,1096,1312,1,93, -1318,1,352,1349,1, -107,2729,16,0,330, -1,1114,1343,1,118, -1355,1,1123,2730,16, -0,330,1,371,1365, -1,1628,2731,16,0, -330,1,375,1376,1, -1882,2732,16,0,330, -1,377,1381,1,379, -1386,1,380,1391,1, -883,2733,16,0,330, -1,373,1409,1,130, -1414,1,143,1419,1, -387,2734,16,0,330, -1,2664,2735,16,0, -330,1,1159,2736,16, -0,330,1,157,1443, -1,1413,2737,16,0, -330,1,1665,2738,16, -0,330,1,412,2739, -16,0,330,1,1377, -2740,16,0,330,1, -172,1469,1,1939,2741, -16,0,330,1,437, -2742,16,0,330,1, -188,1518,1,942,1490, -1,1195,2743,16,0, -330,1,1449,2744,16, -0,330,1,1701,2745, -16,0,330,1,447, -1511,1,205,2746,16, -0,330,1,827,2747, -16,0,330,1,223, -2748,16,0,330,1, -476,1543,1,477,1549, -1,1231,2749,16,0, -330,1,479,1559,1, -480,1564,1,1485,2750, -16,0,330,1,1737, -2751,16,0,330,1, -242,1578,1,478,1583, -1,1001,1588,1,1002, -1593,1,34,2752,19, -322,1,34,2753,5, -84,1,1011,1102,1, -1012,2754,16,0,320, -1,1013,1258,1,262, -1119,1,1267,2755,16, -0,320,1,515,2756, -16,0,320,1,1521, -2757,16,0,320,1, -525,1216,1,283,1172, -1,2299,2758,16,0, -320,1,42,2759,16, -0,320,1,40,1177, -1,44,1183,1,47, -1184,1,1303,2760,16, -0,320,1,1555,2761, -16,0,320,1,50, -1201,1,48,1190,1, -49,1196,1,51,1206, -1,63,1222,1,305, -1211,1,66,1228,1, -67,1233,1,68,1238, -1,69,1243,1,70, -1248,1,73,2762,16, -0,320,1,74,1253, -1,328,1302,1,1048, -1344,1,82,2763,16, -0,320,1,1840,2764, -16,0,320,1,1591, -2765,16,0,320,1, -1341,2766,16,0,320, -1,1096,1312,1,93, -1318,1,352,1349,1, -107,2767,16,0,320, -1,1114,1343,1,118, -1355,1,1123,2768,16, -0,320,1,371,1365, -1,1628,2769,16,0, -320,1,375,1376,1, -1882,2770,16,0,320, -1,377,1381,1,379, -1386,1,380,1391,1, -883,2771,16,0,320, -1,373,1409,1,130, -1414,1,143,1419,1, -387,2772,16,0,320, -1,2664,2773,16,0, -320,1,1159,2774,16, -0,320,1,157,1443, -1,1413,2775,16,0, -320,1,1665,2776,16, -0,320,1,412,2777, -16,0,320,1,1377, -2778,16,0,320,1, -172,1469,1,1939,2779, -16,0,320,1,437, -2780,16,0,320,1, -188,1518,1,942,1490, -1,1195,2781,16,0, -320,1,1449,2782,16, -0,320,1,1701,2783, -16,0,320,1,447, -1511,1,205,1523,1, -827,2784,16,0,320, -1,223,1533,1,476, -1543,1,477,1549,1, -1231,2785,16,0,320, -1,479,1559,1,480, -1564,1,1485,2786,16, -0,320,1,1737,2787, -16,0,320,1,242, -1578,1,478,1583,1, -1001,1588,1,1002,1593, -1,35,2788,19,311, -1,35,2789,5,84, -1,1011,1102,1,1012, -2790,16,0,309,1, -1013,1258,1,262,1119, -1,1267,2791,16,0, -309,1,515,2792,16, -0,309,1,1521,2793, -16,0,309,1,525, -1216,1,283,1172,1, -2299,2794,16,0,309, -1,42,2795,16,0, -309,1,40,1177,1, -44,1183,1,47,1184, -1,1303,2796,16,0, -309,1,1555,2797,16, -0,309,1,50,1201, -1,48,1190,1,49, -1196,1,51,1206,1, -63,1222,1,305,1211, -1,66,1228,1,67, -1233,1,68,1238,1, -69,1243,1,70,1248, -1,73,2798,16,0, -309,1,74,1253,1, -328,1302,1,1048,1344, -1,82,2799,16,0, -309,1,1840,2800,16, -0,309,1,1591,2801, -16,0,309,1,1341, -2802,16,0,309,1, -1096,1312,1,93,1318, -1,352,1349,1,107, -2803,16,0,309,1, -1114,1343,1,118,1355, -1,1123,2804,16,0, -309,1,371,1365,1, -1628,2805,16,0,309, -1,375,1376,1,1882, -2806,16,0,309,1, -377,1381,1,379,1386, -1,380,1391,1,883, -2807,16,0,309,1, -373,1409,1,130,1414, -1,143,1419,1,387, -2808,16,0,309,1, -2664,2809,16,0,309, -1,1159,2810,16,0, -309,1,157,1443,1, -1413,2811,16,0,309, -1,1665,2812,16,0, -309,1,412,2813,16, -0,309,1,1377,2814, -16,0,309,1,172, -1469,1,1939,2815,16, -0,309,1,437,2816, -16,0,309,1,188, -1518,1,942,1490,1, -1195,2817,16,0,309, -1,1449,2818,16,0, -309,1,1701,2819,16, -0,309,1,447,1511, -1,205,1523,1,827, -2820,16,0,309,1, -223,2821,16,0,309, -1,476,1543,1,477, -1549,1,1231,2822,16, -0,309,1,479,1559, -1,480,1564,1,1485, -2823,16,0,309,1, -1737,2824,16,0,309, -1,242,1578,1,478, -1583,1,1001,1588,1, -1002,1593,1,36,2825, -19,216,1,36,2826, -5,94,1,256,2827, -16,0,214,1,1261, -2828,16,0,214,1, -509,2829,16,0,214, -1,1515,2830,16,0, -214,1,2021,718,1, -1775,2831,16,0,214, -1,2029,725,1,2030, -731,1,2031,736,1, -2032,741,1,2033,746, -1,277,2832,16,0, -214,1,2035,752,1, -2037,757,1,2039,762, -1,32,2833,16,0, -214,1,2041,768,1, -2293,2834,16,0,214, -1,2043,774,1,2045, -779,1,41,2835,16, -0,214,1,1297,2836, -16,0,214,1,43, -2837,16,0,214,1, -1803,787,1,1804,2838, -16,0,214,1,299, -2839,16,0,214,1, -52,2840,16,0,214, -1,2318,2841,16,0, -214,1,2075,2842,16, -0,214,1,1574,799, -1,71,2843,16,0, -214,1,76,2844,16, -0,214,1,1834,2845, -16,0,214,1,2337, -2846,16,0,214,1, -79,2847,16,0,214, -1,1335,2848,16,0, -214,1,322,2849,16, -0,214,1,85,2850, -16,0,214,1,89, -2851,16,0,214,1, -346,2852,16,0,214, -1,2105,814,1,2106, -2853,16,0,214,1, -97,2854,16,0,214, -1,1860,821,1,2364, -827,1,102,2855,16, -0,214,1,112,2856, -16,0,214,1,1117, -2857,16,0,214,1, -1873,835,1,1876,2858, -16,0,214,1,124, -2859,16,0,214,1, -2136,842,1,381,2860, -16,0,214,1,525, -2861,16,0,214,1, -137,2862,16,0,214, -1,1901,2863,16,0, -214,1,2658,2864,16, -0,214,1,1153,2865, -16,0,214,1,151, -2866,16,0,214,1, -1407,2867,16,0,214, -1,1659,2868,16,0, -214,1,2413,2869,16, -0,214,1,406,2870, -16,0,214,1,1371, -2871,16,0,214,1, -166,2872,16,0,214, -1,1622,2873,16,0, -214,1,1931,861,1, -1933,2874,16,0,214, -1,431,2875,16,0, -214,1,1585,2876,16, -0,214,1,182,2877, -16,0,214,1,1189, -2878,16,0,214,1, -1443,2879,16,0,214, -1,1695,2880,16,0, -214,1,2198,2881,16, -0,214,1,447,2882, -16,0,214,1,2458, -876,1,2459,882,1, -1958,2883,16,0,214, -1,2462,889,1,1657, -894,1,2464,899,1, -199,2884,16,0,214, -1,459,2885,16,0, -214,1,462,2886,16, -0,214,1,217,2887, -16,0,214,1,2227, -908,1,1225,2888,16, -0,214,1,1479,2889, -16,0,214,1,1731, -2890,16,0,214,1, -1989,916,1,1990,2891, -16,0,214,1,236, -2892,16,0,214,1, -1756,2893,16,0,214, -1,37,2894,19,233, -1,37,2895,5,94, -1,256,2896,16,0, -231,1,1261,2897,16, -0,231,1,509,2898, -16,0,231,1,1515, -2899,16,0,231,1, -2021,718,1,1775,2900, -16,0,231,1,2029, -725,1,2030,731,1, -2031,736,1,2032,741, -1,2033,746,1,277, -2901,16,0,231,1, -2035,752,1,2037,757, -1,2039,762,1,32, -2902,16,0,231,1, -2041,768,1,2293,2903, -16,0,231,1,2043, -774,1,2045,779,1, -41,2904,16,0,231, -1,1297,2905,16,0, -231,1,43,2906,16, -0,231,1,1803,787, -1,1804,2907,16,0, -231,1,299,2908,16, -0,231,1,52,2909, -16,0,231,1,2318, -2910,16,0,231,1, -2075,2911,16,0,231, -1,1574,799,1,71, -2912,16,0,231,1, -76,2913,16,0,231, -1,1834,2914,16,0, -231,1,2337,2915,16, -0,231,1,79,2916, -16,0,231,1,1335, -2917,16,0,231,1, -322,2918,16,0,231, -1,85,2919,16,0, -231,1,89,2920,16, -0,231,1,346,2921, -16,0,231,1,2105, -814,1,2106,2922,16, -0,231,1,97,2923, -16,0,231,1,1860, -821,1,2364,827,1, -102,2924,16,0,231, -1,112,2925,16,0, -231,1,1117,2926,16, -0,231,1,1873,835, -1,1876,2927,16,0, -231,1,124,2928,16, -0,231,1,2136,842, -1,381,2929,16,0, -231,1,525,2930,16, -0,231,1,137,2931, -16,0,231,1,1901, -2932,16,0,231,1, -2658,2933,16,0,231, -1,1153,2934,16,0, -231,1,151,2935,16, -0,231,1,1407,2936, -16,0,231,1,1659, -2937,16,0,231,1, -2413,2938,16,0,231, -1,406,2939,16,0, -231,1,1371,2940,16, -0,231,1,166,2941, -16,0,231,1,1622, -2942,16,0,231,1, -1931,861,1,1933,2943, -16,0,231,1,431, -2944,16,0,231,1, -1585,2945,16,0,231, -1,182,2946,16,0, -231,1,1189,2947,16, -0,231,1,1443,2948, -16,0,231,1,1695, -2949,16,0,231,1, -2198,2950,16,0,231, -1,447,2951,16,0, -231,1,2458,876,1, -2459,882,1,1958,2952, -16,0,231,1,2462, -889,1,1657,894,1, -2464,899,1,199,2953, -16,0,231,1,459, -2954,16,0,231,1, -462,2955,16,0,231, -1,217,2956,16,0, -231,1,2227,908,1, -1225,2957,16,0,231, -1,1479,2958,16,0, -231,1,1731,2959,16, -0,231,1,1989,916, -1,1990,2960,16,0, -231,1,236,2961,16, -0,231,1,1756,2962, -16,0,231,1,38, -2963,19,230,1,38, -2964,5,84,1,1011, -1102,1,1012,2965,16, -0,228,1,1013,1258, -1,262,1119,1,1267, -2966,16,0,228,1, -515,2967,16,0,228, -1,1521,2968,16,0, -228,1,525,1216,1, -283,1172,1,2299,2969, -16,0,228,1,42, -2970,16,0,228,1, -40,1177,1,44,1183, -1,47,1184,1,1303, -2971,16,0,228,1, -1555,2972,16,0,228, -1,50,1201,1,48, -1190,1,49,1196,1, -51,1206,1,63,1222, -1,305,1211,1,66, -1228,1,67,1233,1, -68,1238,1,69,1243, -1,70,1248,1,73, -2973,16,0,228,1, -74,1253,1,328,1302, -1,1048,1344,1,82, -2974,16,0,228,1, -1840,2975,16,0,228, -1,1591,2976,16,0, -228,1,1341,2977,16, -0,228,1,1096,1312, -1,93,1318,1,352, -1349,1,107,2978,16, -0,228,1,1114,1343, -1,118,1355,1,1123, -2979,16,0,228,1, -371,1365,1,1628,2980, -16,0,228,1,375, -1376,1,1882,2981,16, -0,228,1,377,1381, -1,379,1386,1,380, -1391,1,883,1397,1, -373,1409,1,130,1414, -1,143,1419,1,387, -2982,16,0,228,1, -2664,2983,16,0,228, -1,1159,2984,16,0, -228,1,157,1443,1, -1413,2985,16,0,228, -1,1665,2986,16,0, -228,1,412,2987,16, -0,228,1,1377,2988, -16,0,228,1,172, -1469,1,1939,2989,16, -0,228,1,437,2990, -16,0,228,1,188, -1518,1,942,1490,1, -1195,2991,16,0,228, -1,1449,2992,16,0, -228,1,1701,2993,16, -0,228,1,447,1511, -1,205,1523,1,827, -1331,1,223,1533,1, -476,1543,1,477,1549, -1,1231,2994,16,0, -228,1,479,1559,1, -480,1564,1,1485,2995, -16,0,228,1,1737, -2996,16,0,228,1, -242,1578,1,478,1583, -1,1001,1588,1,1002, -1593,1,39,2997,19, -222,1,39,2998,5, -84,1,1011,1102,1, -1012,2999,16,0,220, -1,1013,1258,1,262, -1119,1,1267,3000,16, -0,220,1,515,3001, -16,0,220,1,1521, -3002,16,0,220,1, -525,1216,1,283,1172, -1,2299,3003,16,0, -220,1,42,3004,16, -0,220,1,40,1177, -1,44,1183,1,47, -1184,1,1303,3005,16, -0,220,1,1555,3006, -16,0,220,1,50, -1201,1,48,1190,1, -49,1196,1,51,1206, -1,63,1222,1,305, -1211,1,66,1228,1, -67,1233,1,68,1238, -1,69,1243,1,70, -1248,1,73,3007,16, -0,220,1,74,1253, -1,328,1302,1,1048, -1344,1,82,3008,16, -0,220,1,1840,3009, -16,0,220,1,1591, -3010,16,0,220,1, -1341,3011,16,0,220, -1,1096,1312,1,93, -1318,1,352,1349,1, -107,3012,16,0,220, -1,1114,1343,1,118, -1355,1,1123,3013,16, -0,220,1,371,1365, -1,1628,3014,16,0, -220,1,375,1376,1, -1882,3015,16,0,220, -1,377,1381,1,379, -1386,1,380,1391,1, -883,1397,1,373,1409, -1,130,1414,1,143, -1419,1,387,3016,16, -0,220,1,2664,3017, -16,0,220,1,1159, -3018,16,0,220,1, -157,1443,1,1413,3019, -16,0,220,1,1665, -3020,16,0,220,1, -412,3021,16,0,220, -1,1377,3022,16,0, -220,1,172,1469,1, -1939,3023,16,0,220, -1,437,3024,16,0, -220,1,188,1518,1, -942,1490,1,1195,3025, -16,0,220,1,1449, -3026,16,0,220,1, -1701,3027,16,0,220, -1,447,1511,1,205, -1523,1,827,1331,1, -223,1533,1,476,1543, -1,477,1549,1,1231, -3028,16,0,220,1, -479,1559,1,480,1564, -1,1485,3029,16,0, -220,1,1737,3030,16, -0,220,1,242,1578, -1,478,1583,1,1001, -1588,1,1002,1593,1, -40,3031,19,210,1, -40,3032,5,84,1, -1011,1102,1,1012,3033, -16,0,208,1,1013, -1258,1,262,1119,1, -1267,3034,16,0,208, -1,515,3035,16,0, -208,1,1521,3036,16, -0,208,1,525,1216, -1,283,1172,1,2299, -3037,16,0,208,1, -42,3038,16,0,208, -1,40,1177,1,44, -1183,1,47,1184,1, -1303,3039,16,0,208, -1,1555,3040,16,0, -208,1,50,1201,1, -48,1190,1,49,1196, -1,51,1206,1,63, -1222,1,305,1211,1, -66,1228,1,67,1233, -1,68,1238,1,69, -1243,1,70,1248,1, -73,3041,16,0,208, -1,74,1253,1,328, -1302,1,1048,1344,1, -82,3042,16,0,208, -1,1840,3043,16,0, -208,1,1591,3044,16, -0,208,1,1341,3045, -16,0,208,1,1096, -1312,1,93,1318,1, -352,1349,1,107,3046, -16,0,208,1,1114, -1343,1,118,3047,16, -0,208,1,1123,3048, -16,0,208,1,371, -1365,1,1628,3049,16, -0,208,1,375,1376, -1,1882,3050,16,0, -208,1,377,1381,1, -379,1386,1,380,1391, -1,883,3051,16,0, -208,1,373,1409,1, -130,3052,16,0,208, -1,143,3053,16,0, -208,1,387,3054,16, -0,208,1,2664,3055, -16,0,208,1,1159, -3056,16,0,208,1, -157,3057,16,0,208, -1,1413,3058,16,0, -208,1,1665,3059,16, -0,208,1,412,3060, -16,0,208,1,1377, -3061,16,0,208,1, -172,3062,16,0,208, -1,1939,3063,16,0, -208,1,437,3064,16, -0,208,1,188,3065, -16,0,208,1,942, -1490,1,1195,3066,16, -0,208,1,1449,3067, -16,0,208,1,1701, -3068,16,0,208,1, -447,1511,1,205,3069, -16,0,208,1,827, -3070,16,0,208,1, -223,3071,16,0,208, -1,476,1543,1,477, -1549,1,1231,3072,16, -0,208,1,479,1559, -1,480,1564,1,1485, -3073,16,0,208,1, -1737,3074,16,0,208, -1,242,3075,16,0, -208,1,478,1583,1, -1001,1588,1,1002,1593, -1,41,3076,19,172, -1,41,3077,5,84, -1,1011,1102,1,1012, -3078,16,0,170,1, -1013,1258,1,262,1119, -1,1267,3079,16,0, -170,1,515,3080,16, -0,170,1,1521,3081, -16,0,170,1,525, -1216,1,283,1172,1, -2299,3082,16,0,170, -1,42,3083,16,0, -170,1,40,1177,1, -44,1183,1,47,1184, -1,1303,3084,16,0, -170,1,1555,3085,16, -0,170,1,50,1201, -1,48,1190,1,49, -1196,1,51,1206,1, -63,1222,1,305,1211, -1,66,1228,1,67, -1233,1,68,1238,1, -69,1243,1,70,1248, -1,73,3086,16,0, -170,1,74,1253,1, -328,1302,1,1048,1344, -1,82,3087,16,0, -170,1,1840,3088,16, -0,170,1,1591,3089, -16,0,170,1,1341, -3090,16,0,170,1, -1096,1312,1,93,1318, -1,352,1349,1,107, -3091,16,0,170,1, -1114,1343,1,118,3092, -16,0,170,1,1123, -3093,16,0,170,1, -371,1365,1,1628,3094, -16,0,170,1,375, -1376,1,1882,3095,16, -0,170,1,377,1381, -1,379,1386,1,380, -1391,1,883,3096,16, -0,170,1,373,1409, -1,130,3097,16,0, -170,1,143,3098,16, -0,170,1,387,3099, -16,0,170,1,2664, -3100,16,0,170,1, -1159,3101,16,0,170, -1,157,3102,16,0, -170,1,1413,3103,16, -0,170,1,1665,3104, -16,0,170,1,412, -3105,16,0,170,1, -1377,3106,16,0,170, -1,172,3107,16,0, -170,1,1939,3108,16, -0,170,1,437,3109, -16,0,170,1,188, -3110,16,0,170,1, -942,1490,1,1195,3111, -16,0,170,1,1449, -3112,16,0,170,1, -1701,3113,16,0,170, -1,447,1511,1,205, -3114,16,0,170,1, -827,3115,16,0,170, -1,223,3116,16,0, -170,1,476,1543,1, -477,1549,1,1231,3117, -16,0,170,1,479, -1559,1,480,1564,1, -1485,3118,16,0,170, -1,1737,3119,16,0, -170,1,242,3120,16, -0,170,1,478,1583, -1,1001,1588,1,1002, -1593,1,42,3121,19, -394,1,42,3122,5, -38,1,1901,3123,16, -0,392,1,2075,3124, -16,0,392,1,1860, -821,1,1803,787,1, -1804,3125,16,0,392, -1,2413,3126,16,0, -392,1,2198,3127,16, -0,392,1,1873,835, -1,1657,894,1,1989, -916,1,1990,3128,16, -0,392,1,1775,3129, -16,0,392,1,32, -3130,16,0,392,1, -2105,814,1,2106,3131, -16,0,392,1,2364, -827,1,2227,908,1, -2337,3132,16,0,392, -1,2021,718,1,2458, -876,1,2459,882,1, -2462,889,1,2136,842, -1,2464,899,1,2029, -725,1,2030,731,1, -2031,736,1,2032,741, -1,2033,746,1,2035, -752,1,2037,757,1, -2039,762,1,1931,861, -1,2041,768,1,2043, -774,1,2045,779,1, -1574,799,1,1958,3133, -16,0,392,1,43, -3134,19,453,1,43, -3135,5,25,1,2035, -752,1,2037,757,1, -2039,762,1,2041,768, -1,2227,908,1,2043, -774,1,1657,894,1, -1860,821,1,2136,842, -1,2021,718,1,2459, -882,1,1574,799,1, -2105,3136,16,0,578, -1,1931,861,1,1873, -835,1,2031,736,1, -1803,787,1,1989,3137, -16,0,451,1,2464, -899,1,2029,725,1, -2030,731,1,2364,827, -1,2032,741,1,2033, -746,1,2045,779,1, -44,3138,19,264,1, -44,3139,5,38,1, -1901,3140,16,0,262, -1,2075,3141,16,0, -262,1,1860,821,1, -1803,787,1,1804,3142, -16,0,262,1,2413, -3143,16,0,262,1, -2198,3144,16,0,262, -1,1873,835,1,1657, -894,1,1989,916,1, -1990,3145,16,0,262, -1,1775,3146,16,0, -262,1,32,3147,16, -0,262,1,2105,814, -1,2106,3148,16,0, -262,1,2364,827,1, -2227,908,1,2337,3149, -16,0,262,1,2021, -718,1,2458,876,1, -2459,882,1,2462,889, -1,2136,842,1,2464, -899,1,2029,725,1, -2030,731,1,2031,736, -1,2032,741,1,2033, -746,1,2035,752,1, -2037,757,1,2039,762, -1,1931,861,1,2041, -768,1,2043,774,1, -2045,779,1,1574,799, -1,1958,3150,16,0, -262,1,45,3151,19, -287,1,45,3152,5, -39,1,1901,3153,16, -0,315,1,2075,3154, -16,0,315,1,1860, -821,1,1803,787,1, -1804,3155,16,0,315, -1,2413,3156,16,0, -315,1,2198,3157,16, -0,315,1,1873,835, -1,1657,894,1,1989, -916,1,1990,3158,16, -0,315,1,1775,3159, -16,0,315,1,32, -3160,16,0,315,1, -2105,814,1,2106,3161, -16,0,315,1,2364, -827,1,2227,908,1, -2337,3162,16,0,315, -1,2021,718,1,2458, -876,1,2459,882,1, -2462,889,1,2136,842, -1,2464,899,1,2029, -725,1,2030,731,1, -2031,736,1,2032,741, -1,2033,746,1,2035, -752,1,2037,757,1, -2039,762,1,1931,861, -1,2041,768,1,2043, -774,1,2045,779,1, -1832,3163,16,0,285, -1,1574,799,1,1958, -3164,16,0,315,1, -46,3165,19,671,1, -46,3166,5,38,1, -1901,3167,16,0,669, -1,2075,3168,16,0, -669,1,1860,821,1, -1803,787,1,1804,3169, -16,0,669,1,2413, -3170,16,0,669,1, -2198,3171,16,0,669, -1,1873,835,1,1657, -894,1,1989,916,1, -1990,3172,16,0,669, -1,1775,3173,16,0, -669,1,32,3174,16, -0,669,1,2105,814, -1,2106,3175,16,0, -669,1,2364,827,1, -2227,908,1,2337,3176, -16,0,669,1,2021, -718,1,2458,876,1, -2459,882,1,2462,889, -1,2136,842,1,2464, -899,1,2029,725,1, -2030,731,1,2031,736, -1,2032,741,1,2033, -746,1,2035,752,1, -2037,757,1,2039,762, -1,1931,861,1,2041, -768,1,2043,774,1, -2045,779,1,1574,799, -1,1958,3177,16,0, -669,1,47,3178,19, -466,1,47,3179,5, -19,1,0,3180,16, -0,464,1,2706,3181, -16,0,464,1,2634, -691,1,2636,3182,16, -0,464,1,2639,707, -1,2714,3183,17,3184, -15,3185,4,36,37, -0,71,0,108,0, -111,0,98,0,97, -0,108,0,68,0, +116,0,68,0,101, +0,99,0,108,0, +97,0,114,0,97, +0,116,0,105,0, +111,0,110,0,76, +0,105,0,115,0, +116,0,95,0,49, +0,1,207,1,3, +1,2,1,1,2338, +22,1,42,1,477, +1675,1,1231,1680,1, +479,1685,1,480,1690, +1,1485,1696,1,459, +1953,1,476,1669,1, +242,1703,1,478,1708, +1,481,1955,1,1001, +1713,1,1002,1718,1, +2509,1960,1,18,2339, +19,574,1,18,2340, +5,84,1,1011,1227, +1,1012,2341,16,0, +572,1,1013,1385,1, +262,1244,1,1267,2342, +16,0,572,1,515, +2343,16,0,572,1, +1521,2344,16,0,572, +1,525,1343,1,2792, +2345,16,0,572,1, +283,1299,1,2299,2346, +16,0,572,1,42, +2347,16,0,572,1, +40,1304,1,44,1310, +1,47,1311,1,1303, +2348,16,0,572,1, +1555,2349,16,0,572, +1,50,1328,1,48, +1317,1,49,1323,1, +51,1333,1,63,1349, +1,305,1338,1,66, +1355,1,67,1360,1, +68,1365,1,69,1370, +1,70,1375,1,73, +2350,16,0,572,1, +74,1380,1,328,1429, +1,1048,2351,16,0, +572,1,82,2352,16, +0,572,1,1840,2353, +16,0,572,1,1591, +2354,16,0,572,1, +1341,2355,16,0,572, +1,1096,1439,1,93, +1445,1,352,1475,1, +107,2356,16,0,572, +1,1114,1469,1,118, +2357,16,0,572,1, +1123,2358,16,0,572, +1,371,1491,1,1628, +2359,16,0,572,1, +375,1502,1,1882,2360, +16,0,572,1,377, +1507,1,379,1512,1, +380,1517,1,883,2361, +16,0,572,1,373, +1535,1,130,2362,16, +0,572,1,143,2363, +16,0,572,1,387, +2364,16,0,572,1, +1159,2365,16,0,572, +1,157,2366,16,0, +572,1,1413,2367,16, +0,572,1,1665,2368, +16,0,572,1,412, +2369,16,0,572,1, +1377,2370,16,0,572, +1,172,2371,16,0, +572,1,1939,2372,16, +0,572,1,437,2373, +16,0,572,1,188, +2374,16,0,572,1, +942,2375,16,0,572, +1,1195,2376,16,0, +572,1,1449,2377,16, +0,572,1,1701,2378, +16,0,572,1,447, +1637,1,205,2379,16, +0,572,1,827,2380, +16,0,572,1,223, +2381,16,0,572,1, +476,1669,1,477,1675, +1,1231,2382,16,0, +572,1,479,1685,1, +480,1690,1,1485,2383, +16,0,572,1,1737, +2384,16,0,572,1, +242,2385,16,0,572, +1,478,1708,1,1001, +1713,1,1002,1718,1, +19,2386,19,251,1, +19,2387,5,176,1, +942,2388,16,0,537, +1,256,2389,16,0, +249,1,1261,2390,16, +0,249,1,1011,1227, +1,1012,2391,16,0, +537,1,2458,1001,1, +262,1244,1,1267,2392, +16,0,537,1,2021, +843,1,1521,2393,16, +0,537,1,1775,2394, +16,0,249,1,2029, +850,1,2030,856,1, +2031,861,1,2032,866, +1,2786,2395,16,0, +249,1,277,2396,16, +0,249,1,2035,877, +1,2037,882,1,2792, +2397,16,0,537,1, +32,2398,16,0,249, +1,2464,1024,1,2293, +2399,16,0,249,1, +2043,899,1,2045,904, +1,2299,2400,16,0, +537,1,41,2401,16, +0,249,1,42,2402, +16,0,537,1,40, +1304,1,44,1310,1, +43,2403,16,0,249, +1,1804,2404,16,0, +249,1,48,1317,1, +49,1323,1,47,1311, +1,51,1333,1,52, +2405,16,0,249,1, +50,1328,1,305,1338, +1,1096,1439,1,1515, +2406,16,0,249,1, +2318,2407,16,0,249, +1,283,1299,1,63, +1349,1,66,1355,1, +67,1360,1,68,1365, +1,69,1370,1,70, +1375,1,71,2408,16, +0,249,1,73,2409, +16,0,537,1,74, +1380,1,1013,1385,1, +76,2410,16,0,249, +1,1834,2411,16,0, +249,1,2337,2412,16, +0,249,1,79,2413, +16,0,249,1,1335, +2414,16,0,249,1, +299,2415,16,0,249, +1,82,2416,16,0, +537,1,1840,2417,16, +0,537,1,1297,2418, +16,0,249,1,85, +2419,16,0,249,1, +1341,2420,16,0,537, +1,89,2421,16,0, +249,1,1303,2422,16, +0,537,1,509,2423, +16,0,249,1,93, +1445,1,322,2424,16, +0,249,1,2039,887, +1,97,2425,16,0, +249,1,2041,893,1, +1555,2426,16,0,537, +1,827,2427,16,0, +537,1,102,2428,16, +0,249,1,1860,946, +1,1803,912,1,2364, +952,1,107,2429,16, +0,537,1,1114,1469, +1,112,2430,16,0, +249,1,1117,2431,16, +0,249,1,352,1475, +1,1873,961,1,118, +2432,16,0,537,1, +1123,2433,16,0,537, +1,371,1491,1,515, +2434,16,0,537,1, +1377,2435,16,0,537, +1,124,2436,16,0, +249,1,1882,2437,16, +0,537,1,377,1507, +1,379,1512,1,380, +1517,1,130,2438,16, +0,537,1,346,2439, +16,0,249,1,2075, +2440,16,0,249,1, +373,1535,1,387,2441, +16,0,537,1,137, +2442,16,0,249,1, +143,2443,16,0,537, +1,1901,2444,16,0, +249,1,1048,2445,16, +0,537,1,1153,2446, +16,0,249,1,375, +1502,1,151,2447,16, +0,249,1,1407,2448, +16,0,249,1,1659, +2449,16,0,249,1, +2413,2450,16,0,249, +1,1159,2451,16,0, +537,1,381,2452,16, +0,249,1,157,2453, +16,0,537,1,1413, +2454,16,0,537,1, +883,2455,16,0,537, +1,1371,2456,16,0, +249,1,328,1429,1, +2105,939,1,2106,2457, +16,0,249,1,166, +2458,16,0,249,1, +525,2459,16,0,249, +1,1622,2460,16,0, +249,1,406,2461,16, +0,249,1,1574,924, +1,172,2462,16,0, +537,1,1931,986,1, +412,2463,16,0,537, +1,1933,2464,16,0, +249,1,1876,2465,16, +0,249,1,431,2466, +16,0,249,1,1585, +2467,16,0,249,1, +182,2468,16,0,249, +1,1628,2469,16,0, +537,1,1189,2470,16, +0,249,1,437,2471, +16,0,537,1,1591, +2472,16,0,537,1, +188,2473,16,0,537, +1,1695,2474,16,0, +249,1,2198,2475,16, +0,249,1,1195,2476, +16,0,537,1,1449, +2477,16,0,537,1, +1701,2478,16,0,537, +1,447,2479,16,0, +249,1,199,2480,16, +0,249,1,2459,1007, +1,1958,2481,16,0, +249,1,2462,1014,1, +1657,1019,1,205,2482, +16,0,537,1,459, +2483,16,0,249,1, +462,2484,16,0,249, +1,1665,2485,16,0, +537,1,217,2486,16, +0,249,1,2227,1033, +1,2033,871,1,1225, +2487,16,0,249,1, +223,2488,16,0,537, +1,1479,2489,16,0, +249,1,1731,2490,16, +0,249,1,477,1675, +1,1231,2491,16,0, +537,1,479,1685,1, +480,1690,1,1485,2492, +16,0,537,1,1737, +2493,16,0,537,1, +1989,1041,1,1990,2494, +16,0,249,1,1443, +2495,16,0,249,1, +236,2496,16,0,249, +1,2136,968,1,476, +1669,1,242,2497,16, +0,537,1,478,1708, +1,1939,2498,16,0, +537,1,1001,1713,1, +1002,1718,1,1756,2499, +16,0,249,1,20, +2500,19,510,1,20, +2501,5,84,1,1011, +1227,1,1012,2502,16, +0,508,1,1013,1385, +1,262,1244,1,1267, +2503,16,0,508,1, +515,2504,16,0,508, +1,1521,2505,16,0, +508,1,525,1343,1, +2792,2506,16,0,508, +1,283,1299,1,2299, +2507,16,0,508,1, +42,2508,16,0,508, +1,40,1304,1,44, +1310,1,47,1311,1, +1303,2509,16,0,508, +1,1555,2510,16,0, +508,1,50,1328,1, +48,1317,1,49,1323, +1,51,1333,1,63, +1349,1,305,1338,1, +66,1355,1,67,1360, +1,68,1365,1,69, +1370,1,70,1375,1, +73,2511,16,0,508, +1,74,1380,1,328, +2512,16,0,508,1, +1048,2513,16,0,508, +1,82,2514,16,0, +508,1,1840,2515,16, +0,508,1,1591,2516, +16,0,508,1,1341, +2517,16,0,508,1, +1096,1439,1,93,1445, +1,352,2518,16,0, +508,1,107,2519,16, +0,508,1,1114,1469, +1,118,2520,16,0, +508,1,1123,2521,16, +0,508,1,371,1491, +1,1628,2522,16,0, +508,1,375,1502,1, +1882,2523,16,0,508, +1,377,1507,1,379, +1512,1,380,1517,1, +883,2524,16,0,508, +1,373,1535,1,130, +2525,16,0,508,1, +143,2526,16,0,508, +1,387,2527,16,0, +508,1,1159,2528,16, +0,508,1,157,2529, +16,0,508,1,1413, +2530,16,0,508,1, +1665,2531,16,0,508, +1,412,2532,16,0, +508,1,1377,2533,16, +0,508,1,172,2534, +16,0,508,1,1939, +2535,16,0,508,1, +437,2536,16,0,508, +1,188,2537,16,0, +508,1,942,2538,16, +0,508,1,1195,2539, +16,0,508,1,1449, +2540,16,0,508,1, +1701,2541,16,0,508, +1,447,1637,1,205, +2542,16,0,508,1, +827,2543,16,0,508, +1,223,2544,16,0, +508,1,476,1669,1, +477,1675,1,1231,2545, +16,0,508,1,479, +1685,1,480,1690,1, +1485,2546,16,0,508, +1,1737,2547,16,0, +508,1,242,2548,16, +0,508,1,478,1708, +1,1001,1713,1,1002, +1718,1,21,2549,19, +478,1,21,2550,5, +84,1,1011,1227,1, +1012,2551,16,0,476, +1,1013,1385,1,262, +1244,1,1267,2552,16, +0,476,1,515,2553, +16,0,476,1,1521, +2554,16,0,476,1, +525,1343,1,2792,2555, +16,0,476,1,283, +1299,1,2299,2556,16, +0,476,1,42,2557, +16,0,476,1,40, +1304,1,44,1310,1, +47,1311,1,1303,2558, +16,0,476,1,1555, +2559,16,0,476,1, +50,1328,1,48,1317, +1,49,1323,1,51, +1333,1,63,1349,1, +305,1338,1,66,1355, +1,67,1360,1,68, +1365,1,69,1370,1, +70,1375,1,73,2560, +16,0,476,1,74, +1380,1,328,2561,16, +0,476,1,1048,2562, +16,0,476,1,82, +2563,16,0,476,1, +1840,2564,16,0,476, +1,1591,2565,16,0, +476,1,1341,2566,16, +0,476,1,1096,1439, +1,93,1445,1,352, +2567,16,0,476,1, +107,2568,16,0,476, +1,1114,1469,1,118, +2569,16,0,476,1, +1123,2570,16,0,476, +1,371,1491,1,1628, +2571,16,0,476,1, +375,1502,1,1882,2572, +16,0,476,1,377, +1507,1,379,1512,1, +380,1517,1,883,2573, +16,0,476,1,373, +1535,1,130,2574,16, +0,476,1,143,2575, +16,0,476,1,387, +2576,16,0,476,1, +1159,2577,16,0,476, +1,157,2578,16,0, +476,1,1413,2579,16, +0,476,1,1665,2580, +16,0,476,1,412, +2581,16,0,476,1, +1377,2582,16,0,476, +1,172,2583,16,0, +476,1,1939,2584,16, +0,476,1,437,2585, +16,0,476,1,188, +2586,16,0,476,1, +942,2587,16,0,476, +1,1195,2588,16,0, +476,1,1449,2589,16, +0,476,1,1701,2590, +16,0,476,1,447, +1637,1,205,2591,16, +0,476,1,827,2592, +16,0,476,1,223, +2593,16,0,476,1, +476,1669,1,477,1675, +1,1231,2594,16,0, +476,1,479,1685,1, +480,1690,1,1485,2595, +16,0,476,1,1737, +2596,16,0,476,1, +242,2597,16,0,476, +1,478,1708,1,1001, +1713,1,1002,1718,1, +22,2598,19,429,1, +22,2599,5,84,1, +1011,1227,1,1012,2600, +16,0,427,1,1013, +1385,1,262,1244,1, +1267,2601,16,0,427, +1,515,2602,16,0, +427,1,1521,2603,16, +0,427,1,525,1343, +1,2792,2604,16,0, +427,1,283,1299,1, +2299,2605,16,0,427, +1,42,2606,16,0, +427,1,40,1304,1, +44,1310,1,47,1311, +1,1303,2607,16,0, +427,1,1555,2608,16, +0,427,1,50,1328, +1,48,1317,1,49, +1323,1,51,1333,1, +63,1349,1,305,1338, +1,66,1355,1,67, +1360,1,68,1365,1, +69,1370,1,70,1375, +1,73,2609,16,0, +427,1,74,1380,1, +328,2610,16,0,427, +1,1048,2611,16,0, +427,1,82,2612,16, +0,427,1,1840,2613, +16,0,427,1,1591, +2614,16,0,427,1, +1341,2615,16,0,427, +1,1096,1439,1,93, +1445,1,352,2616,16, +0,427,1,107,2617, +16,0,427,1,1114, +1469,1,118,2618,16, +0,427,1,1123,2619, +16,0,427,1,371, +1491,1,1628,2620,16, +0,427,1,375,1502, +1,1882,2621,16,0, +427,1,377,1507,1, +379,1512,1,380,1517, +1,883,2622,16,0, +427,1,373,1535,1, +130,2623,16,0,427, +1,143,2624,16,0, +427,1,387,2625,16, +0,427,1,1159,2626, +16,0,427,1,157, +2627,16,0,427,1, +1413,2628,16,0,427, +1,1665,2629,16,0, +427,1,412,2630,16, +0,427,1,1377,2631, +16,0,427,1,172, +2632,16,0,427,1, +1939,2633,16,0,427, +1,437,2634,16,0, +427,1,188,2635,16, +0,427,1,942,2636, +16,0,427,1,1195, +2637,16,0,427,1, +1449,2638,16,0,427, +1,1701,2639,16,0, +427,1,447,1637,1, +205,2640,16,0,427, +1,827,2641,16,0, +427,1,223,2642,16, +0,427,1,476,1669, +1,477,1675,1,1231, +2643,16,0,427,1, +479,1685,1,480,1690, +1,1485,2644,16,0, +427,1,1737,2645,16, +0,427,1,242,2646, +16,0,427,1,478, +1708,1,1001,1713,1, +1002,1718,1,23,2647, +19,590,1,23,2648, +5,38,1,1901,2649, +16,0,588,1,2075, +2650,16,0,588,1, +1860,946,1,1803,912, +1,1804,2651,16,0, +588,1,2413,2652,16, +0,588,1,2198,2653, +16,0,588,1,1873, +961,1,1657,1019,1, +1989,1041,1,1990,2654, +16,0,588,1,1775, +2655,16,0,588,1, +32,2656,16,0,588, +1,2105,939,1,2106, +2657,16,0,588,1, +2364,952,1,2227,1033, +1,2337,2658,16,0, +588,1,2021,843,1, +2458,1001,1,2459,1007, +1,2462,1014,1,2136, +968,1,2464,1024,1, +2029,850,1,2030,856, +1,2031,861,1,2032, +866,1,2033,871,1, +2035,877,1,2037,882, +1,2039,887,1,1931, +986,1,2041,893,1, +2043,899,1,2045,904, +1,1574,924,1,1958, +2659,16,0,588,1, +24,2660,19,193,1, +24,2661,5,5,1, +44,2662,16,0,191, +1,377,2663,16,0, +626,1,40,2664,16, +0,799,1,63,2665, +16,0,219,1,373, +2666,16,0,622,1, +25,2667,19,329,1, +25,2668,5,177,1, +942,1616,1,256,2669, +16,0,631,1,1261, +2670,16,0,631,1, +1011,1227,1,1012,2671, +16,0,327,1,2458, +1001,1,262,1244,1, +1267,2672,16,0,327, +1,2021,843,1,1521, +2673,16,0,327,1, +1775,2674,16,0,631, +1,2029,850,1,2030, +856,1,2031,861,1, +2032,866,1,2786,2675, +16,0,631,1,277, +2676,16,0,631,1, +2035,877,1,2037,882, +1,2792,2677,16,0, +327,1,32,2678,16, +0,631,1,2464,1024, +1,2293,2679,16,0, +631,1,2043,899,1, +2045,904,1,2299,2680, +16,0,327,1,41, +2681,16,0,631,1, +42,2682,16,0,327, +1,40,1304,1,44, +1310,1,43,2683,16, +0,631,1,1804,2684, +16,0,631,1,48, +1317,1,49,1323,1, +47,1311,1,51,1333, +1,52,2685,16,0, +631,1,50,1328,1, +305,1338,1,1096,1439, +1,1515,2686,16,0, +631,1,2318,2687,16, +0,631,1,62,2688, +16,0,631,1,63, +1349,1,66,1355,1, +67,1360,1,68,1365, +1,69,1370,1,70, +1375,1,71,2689,16, +0,631,1,283,1299, +1,73,2690,16,0, +327,1,74,1380,1, +1013,1385,1,76,2691, +16,0,631,1,1834, +2692,16,0,631,1, +2337,2693,16,0,631, +1,79,2694,16,0, +631,1,1335,2695,16, +0,631,1,299,2696, +16,0,631,1,82, +2697,16,0,327,1, +1840,2698,16,0,327, +1,1297,2699,16,0, +631,1,85,2700,16, +0,631,1,1341,2701, +16,0,327,1,89, +2702,16,0,631,1, +1303,2703,16,0,327, +1,509,2704,16,0, +631,1,93,1445,1, +322,2705,16,0,631, +1,2039,887,1,97, +2706,16,0,631,1, +2041,893,1,1555,2707, +16,0,327,1,827, +2708,16,0,327,1, +102,2709,16,0,631, +1,1860,946,1,1803, +912,1,2364,952,1, +107,2710,16,0,327, +1,1114,1469,1,112, +2711,16,0,631,1, +1117,2712,16,0,631, +1,352,1475,1,1873, +961,1,118,1481,1, +1123,2713,16,0,327, +1,371,1491,1,515, +2714,16,0,327,1, +1377,2715,16,0,327, +1,124,2716,16,0, +631,1,1882,2717,16, +0,327,1,377,1507, +1,379,1512,1,380, +1517,1,130,1540,1, +346,2718,16,0,631, +1,2075,2719,16,0, +631,1,373,1535,1, +387,2720,16,0,327, +1,137,2721,16,0, +631,1,143,2722,16, +0,327,1,1901,2723, +16,0,631,1,1048, +1470,1,1153,2724,16, +0,631,1,375,1502, +1,151,2725,16,0, +631,1,1407,2726,16, +0,631,1,1659,2727, +16,0,631,1,2413, +2728,16,0,631,1, +1159,2729,16,0,327, +1,381,2730,16,0, +631,1,157,2731,16, +0,327,1,1413,2732, +16,0,327,1,883, +2733,16,0,327,1, +1371,2734,16,0,631, +1,328,1429,1,2105, +939,1,2106,2735,16, +0,631,1,166,2736, +16,0,631,1,525, +2737,16,0,631,1, +1622,2738,16,0,631, +1,406,2739,16,0, +631,1,1574,924,1, +172,1595,1,1931,986, +1,412,2740,16,0, +327,1,1933,2741,16, +0,631,1,1876,2742, +16,0,631,1,431, +2743,16,0,631,1, +1585,2744,16,0,631, +1,182,2745,16,0, +631,1,1628,2746,16, +0,327,1,1189,2747, +16,0,631,1,437, +2748,16,0,327,1, +1591,2749,16,0,327, +1,188,1644,1,1695, +2750,16,0,631,1, +2198,2751,16,0,631, +1,1195,2752,16,0, +327,1,1449,2753,16, +0,327,1,1701,2754, +16,0,327,1,447, +2755,16,0,631,1, +199,2756,16,0,631, +1,2459,1007,1,1958, +2757,16,0,631,1, +2462,1014,1,1657,1019, +1,205,2758,16,0, +327,1,459,2759,16, +0,631,1,462,2760, +16,0,631,1,1665, +2761,16,0,327,1, +217,2762,16,0,631, +1,2227,1033,1,2033, +871,1,1225,2763,16, +0,631,1,223,2764, +16,0,327,1,1479, +2765,16,0,631,1, +1731,2766,16,0,631, +1,477,1675,1,1231, +2767,16,0,327,1, +479,1685,1,480,1690, +1,1485,2768,16,0, +327,1,1737,2769,16, +0,327,1,1989,1041, +1,1990,2770,16,0, +631,1,1443,2771,16, +0,631,1,236,2772, +16,0,631,1,2136, +968,1,476,1669,1, +242,2773,16,0,327, +1,478,1708,1,1939, +2774,16,0,327,1, +1001,1713,1,1002,1718, +1,1756,2775,16,0, +631,1,26,2776,19, +348,1,26,2777,5, +84,1,1011,1227,1, +1012,2778,16,0,346, +1,1013,1385,1,262, +1244,1,1267,2779,16, +0,346,1,515,2780, +16,0,780,1,1521, +2781,16,0,346,1, +525,1343,1,2792,2782, +16,0,346,1,283, +1299,1,2299,2783,16, +0,346,1,42,2784, +16,0,346,1,40, +1304,1,44,1310,1, +47,1311,1,1303,2785, +16,0,346,1,1555, +2786,16,0,346,1, +50,1328,1,48,1317, +1,49,1323,1,51, +1333,1,63,1349,1, +305,1338,1,66,1355, +1,67,1360,1,68, +1365,1,69,1370,1, +70,1375,1,73,2787, +16,0,346,1,74, +1380,1,328,1429,1, +1048,1470,1,82,2788, +16,0,346,1,1840, +2789,16,0,346,1, +1591,2790,16,0,346, +1,1341,2791,16,0, +346,1,1096,1439,1, +93,1445,1,352,1475, +1,107,2792,16,0, +346,1,1114,1469,1, +118,1481,1,1123,2793, +16,0,346,1,371, +1491,1,1628,2794,16, +0,346,1,375,1502, +1,1882,2795,16,0, +346,1,377,1507,1, +379,1512,1,380,1517, +1,883,2796,16,0, +346,1,373,1535,1, +130,1540,1,143,2797, +16,0,346,1,387, +2798,16,0,346,1, +1159,2799,16,0,346, +1,157,2800,16,0, +346,1,1413,2801,16, +0,346,1,1665,2802, +16,0,346,1,412, +2803,16,0,346,1, +1377,2804,16,0,346, +1,172,1595,1,1939, +2805,16,0,346,1, +437,2806,16,0,709, +1,188,1644,1,942, +1616,1,1195,2807,16, +0,346,1,1449,2808, +16,0,346,1,1701, +2809,16,0,346,1, +447,1637,1,205,2810, +16,0,346,1,827, +2811,16,0,346,1, +223,2812,16,0,346, +1,476,1669,1,477, +1675,1,1231,2813,16, +0,346,1,479,1685, +1,480,1690,1,1485, +2814,16,0,346,1, +1737,2815,16,0,346, +1,242,2816,16,0, +346,1,478,1708,1, +1001,1713,1,1002,1718, +1,27,2817,19,721, +1,27,2818,5,95, +1,256,2819,16,0, +719,1,1261,2820,16, +0,719,1,509,2821, +16,0,719,1,1515, +2822,16,0,719,1, +2021,843,1,1775,2823, +16,0,719,1,2029, +850,1,2030,856,1, +2031,861,1,2032,866, +1,2033,871,1,277, +2824,16,0,719,1, +2035,877,1,2037,882, +1,2039,887,1,32, +2825,16,0,719,1, +2041,893,1,2293,2826, +16,0,719,1,2043, +899,1,2045,904,1, +41,2827,16,0,719, +1,1297,2828,16,0, +719,1,43,2829,16, +0,719,1,1803,912, +1,1804,2830,16,0, +719,1,299,2831,16, +0,719,1,52,2832, +16,0,719,1,2318, +2833,16,0,719,1, +62,2834,16,0,719, +1,2075,2835,16,0, +719,1,1574,924,1, +71,2836,16,0,719, +1,76,2837,16,0, +719,1,1834,2838,16, +0,719,1,2337,2839, +16,0,719,1,79, +2840,16,0,719,1, +1335,2841,16,0,719, +1,322,2842,16,0, +719,1,85,2843,16, +0,719,1,89,2844, +16,0,719,1,346, +2845,16,0,719,1, +2105,939,1,2106,2846, +16,0,719,1,97, +2847,16,0,719,1, +1860,946,1,2364,952, +1,102,2848,16,0, +719,1,112,2849,16, +0,719,1,1117,2850, +16,0,719,1,2786, +2851,16,0,719,1, +1873,961,1,1876,2852, +16,0,719,1,124, +2853,16,0,719,1, +2136,968,1,381,2854, +16,0,719,1,525, +2855,16,0,719,1, +137,2856,16,0,719, +1,1901,2857,16,0, +719,1,1153,2858,16, +0,719,1,151,2859, +16,0,719,1,1407, +2860,16,0,719,1, +1659,2861,16,0,719, +1,2413,2862,16,0, +719,1,406,2863,16, +0,719,1,1371,2864, +16,0,719,1,166, +2865,16,0,719,1, +1622,2866,16,0,719, +1,1931,986,1,1933, +2867,16,0,719,1, +431,2868,16,0,719, +1,1585,2869,16,0, +719,1,182,2870,16, +0,719,1,1189,2871, +16,0,719,1,1443, +2872,16,0,719,1, +1695,2873,16,0,719, +1,2198,2874,16,0, +719,1,447,2875,16, +0,719,1,2458,1001, +1,2459,1007,1,1958, +2876,16,0,719,1, +2462,1014,1,1657,1019, +1,2464,1024,1,199, +2877,16,0,719,1, +459,2878,16,0,719, +1,462,2879,16,0, +719,1,217,2880,16, +0,719,1,2227,1033, +1,1225,2881,16,0, +719,1,1479,2882,16, +0,719,1,1731,2883, +16,0,719,1,1989, +1041,1,1990,2884,16, +0,719,1,236,2885, +16,0,719,1,1756, +2886,16,0,719,1, +28,2887,19,749,1, +28,2888,5,60,1, +328,1429,1,223,1659, +1,1096,1439,1,118, +1481,1,883,1523,1, +525,1343,1,1001,1713, +1,130,1540,1,459, +1953,1,1114,1469,1, +352,1475,1,447,1637, +1,464,1948,1,1011, +1227,1,1013,1385,1, +242,1703,1,143,1545, +1,40,1304,1,41, +1913,1,42,1917,1, +479,1685,1,44,1310, +1,481,1955,1,373, +1535,1,47,1311,1, +157,1568,1,49,1323, +1,50,1328,1,48, +1317,1,379,1512,1, +380,1517,1,51,1333, +1,476,1669,1,371, +1491,1,478,1708,1, +1048,1470,1,375,1502, +1,172,1595,1,262, +1244,1,283,1299,1, +63,1349,1,67,1360, +1,68,1365,1,69, +1370,1,66,1355,1, +461,2889,16,0,747, +1,74,1380,1,377, +1507,1,1002,1718,1, +70,1375,1,188,1644, +1,82,1407,1,305, +1338,1,477,1675,1, +827,1457,1,93,1445, +1,480,1690,1,205, +1649,1,942,1616,1, +107,1464,1,29,2890, +19,315,1,29,2891, +5,84,1,1011,1227, +1,1012,2892,16,0, +313,1,1013,1385,1, +262,1244,1,1267,2893, +16,0,313,1,515, +2894,16,0,313,1, +1521,2895,16,0,313, +1,525,1343,1,2792, +2896,16,0,313,1, +283,1299,1,2299,2897, +16,0,313,1,42, +2898,16,0,313,1, +40,1304,1,44,1310, +1,47,1311,1,1303, +2899,16,0,313,1, +1555,2900,16,0,313, +1,50,1328,1,48, +1317,1,49,1323,1, +51,1333,1,63,1349, +1,305,1338,1,66, +1355,1,67,1360,1, +68,1365,1,69,1370, +1,70,1375,1,73, +2901,16,0,313,1, +74,1380,1,328,1429, +1,1048,1470,1,82, +2902,16,0,313,1, +1840,2903,16,0,313, +1,1591,2904,16,0, +313,1,1341,2905,16, +0,313,1,1096,1439, +1,93,1445,1,352, +1475,1,107,2906,16, +0,313,1,1114,1469, +1,118,1481,1,1123, +2907,16,0,313,1, +371,1491,1,1628,2908, +16,0,313,1,375, +1502,1,1882,2909,16, +0,313,1,377,1507, +1,379,1512,1,380, +1517,1,883,2910,16, +0,313,1,373,1535, +1,130,1540,1,143, +1545,1,387,2911,16, +0,313,1,1159,2912, +16,0,313,1,157, +1568,1,1413,2913,16, +0,313,1,1665,2914, +16,0,313,1,412, +2915,16,0,313,1, +1377,2916,16,0,313, +1,172,1595,1,1939, +2917,16,0,313,1, +437,2918,16,0,313, +1,188,1644,1,942, +1616,1,1195,2919,16, +0,313,1,1449,2920, +16,0,313,1,1701, +2921,16,0,313,1, +447,1637,1,205,2922, +16,0,313,1,827, +2923,16,0,313,1, +223,2924,16,0,313, +1,476,1669,1,477, +1675,1,1231,2925,16, +0,313,1,479,1685, +1,480,1690,1,1485, +2926,16,0,313,1, +1737,2927,16,0,313, +1,242,2928,16,0, +313,1,478,1708,1, +1001,1713,1,1002,1718, +1,30,2929,19,297, +1,30,2930,5,84, +1,1011,1227,1,1012, +2931,16,0,295,1, +1013,1385,1,262,1244, +1,1267,2932,16,0, +295,1,515,2933,16, +0,295,1,1521,2934, +16,0,295,1,525, +1343,1,2792,2935,16, +0,295,1,283,1299, +1,2299,2936,16,0, +295,1,42,2937,16, +0,295,1,40,1304, +1,44,1310,1,47, +1311,1,1303,2938,16, +0,295,1,1555,2939, +16,0,295,1,50, +1328,1,48,1317,1, +49,1323,1,51,1333, +1,63,1349,1,305, +1338,1,66,1355,1, +67,1360,1,68,1365, +1,69,1370,1,70, +1375,1,73,2940,16, +0,295,1,74,1380, +1,328,1429,1,1048, +1470,1,82,2941,16, +0,295,1,1840,2942, +16,0,295,1,1591, +2943,16,0,295,1, +1341,2944,16,0,295, +1,1096,1439,1,93, +1445,1,352,1475,1, +107,2945,16,0,295, +1,1114,1469,1,118, +1481,1,1123,2946,16, +0,295,1,371,1491, +1,1628,2947,16,0, +295,1,375,1502,1, +1882,2948,16,0,295, +1,377,1507,1,379, +1512,1,380,1517,1, +883,2949,16,0,295, +1,373,1535,1,130, +1540,1,143,1545,1, +387,2950,16,0,295, +1,1159,2951,16,0, +295,1,157,1568,1, +1413,2952,16,0,295, +1,1665,2953,16,0, +295,1,412,2954,16, +0,295,1,1377,2955, +16,0,295,1,172, +1595,1,1939,2956,16, +0,295,1,437,2957, +16,0,295,1,188, +1644,1,942,1616,1, +1195,2958,16,0,295, +1,1449,2959,16,0, +295,1,1701,2960,16, +0,295,1,447,1637, +1,205,2961,16,0, +295,1,827,2962,16, +0,295,1,223,2963, +16,0,295,1,476, +1669,1,477,1675,1, +1231,2964,16,0,295, +1,479,1685,1,480, +1690,1,1485,2965,16, +0,295,1,1737,2966, +16,0,295,1,242, +2967,16,0,295,1, +478,1708,1,1001,1713, +1,1002,1718,1,31, +2968,19,277,1,31, +2969,5,84,1,1011, +1227,1,1012,2970,16, +0,275,1,1013,1385, +1,262,1244,1,1267, +2971,16,0,275,1, +515,2972,16,0,275, +1,1521,2973,16,0, +275,1,525,1343,1, +2792,2974,16,0,275, +1,283,1299,1,2299, +2975,16,0,275,1, +42,2976,16,0,275, +1,40,1304,1,44, +1310,1,47,1311,1, +1303,2977,16,0,275, +1,1555,2978,16,0, +275,1,50,1328,1, +48,1317,1,49,1323, +1,51,1333,1,63, +1349,1,305,1338,1, +66,1355,1,67,1360, +1,68,1365,1,69, +1370,1,70,1375,1, +73,2979,16,0,275, +1,74,1380,1,328, +1429,1,1048,1470,1, +82,2980,16,0,275, +1,1840,2981,16,0, +275,1,1591,2982,16, +0,275,1,1341,2983, +16,0,275,1,1096, +1439,1,93,1445,1, +352,1475,1,107,2984, +16,0,275,1,1114, +1469,1,118,1481,1, +1123,2985,16,0,275, +1,371,1491,1,1628, +2986,16,0,275,1, +375,1502,1,1882,2987, +16,0,275,1,377, +1507,1,379,1512,1, +380,1517,1,883,2988, +16,0,275,1,373, +1535,1,130,1540,1, +143,2989,16,0,275, +1,387,2990,16,0, +275,1,1159,2991,16, +0,275,1,157,2992, +16,0,275,1,1413, +2993,16,0,275,1, +1665,2994,16,0,275, +1,412,2995,16,0, +275,1,1377,2996,16, +0,275,1,172,1595, +1,1939,2997,16,0, +275,1,437,2998,16, +0,275,1,188,1644, +1,942,1616,1,1195, +2999,16,0,275,1, +1449,3000,16,0,275, +1,1701,3001,16,0, +275,1,447,1637,1, +205,3002,16,0,275, +1,827,3003,16,0, +275,1,223,3004,16, +0,275,1,476,1669, +1,477,1675,1,1231, +3005,16,0,275,1, +479,1685,1,480,1690, +1,1485,3006,16,0, +275,1,1737,3007,16, +0,275,1,242,3008, +16,0,275,1,478, +1708,1,1001,1713,1, +1002,1718,1,32,3009, +19,270,1,32,3010, +5,84,1,1011,1227, +1,1012,3011,16,0, +268,1,1013,1385,1, +262,1244,1,1267,3012, +16,0,268,1,515, +3013,16,0,268,1, +1521,3014,16,0,268, +1,525,1343,1,2792, +3015,16,0,268,1, +283,1299,1,2299,3016, +16,0,268,1,42, +3017,16,0,268,1, +40,1304,1,44,1310, +1,47,1311,1,1303, +3018,16,0,268,1, +1555,3019,16,0,268, +1,50,1328,1,48, +1317,1,49,1323,1, +51,1333,1,63,1349, +1,305,1338,1,66, +1355,1,67,1360,1, +68,1365,1,69,1370, +1,70,1375,1,73, +3020,16,0,268,1, +74,1380,1,328,1429, +1,1048,1470,1,82, +3021,16,0,268,1, +1840,3022,16,0,268, +1,1591,3023,16,0, +268,1,1341,3024,16, +0,268,1,1096,1439, +1,93,1445,1,352, +1475,1,107,3025,16, +0,268,1,1114,1469, +1,118,1481,1,1123, +3026,16,0,268,1, +371,1491,1,1628,3027, +16,0,268,1,375, +1502,1,1882,3028,16, +0,268,1,377,1507, +1,379,1512,1,380, +1517,1,883,3029,16, +0,268,1,373,1535, +1,130,1540,1,143, +3030,16,0,268,1, +387,3031,16,0,268, +1,1159,3032,16,0, +268,1,157,3033,16, +0,268,1,1413,3034, +16,0,268,1,1665, +3035,16,0,268,1, +412,3036,16,0,268, +1,1377,3037,16,0, +268,1,172,1595,1, +1939,3038,16,0,268, +1,437,3039,16,0, +268,1,188,1644,1, +942,1616,1,1195,3040, +16,0,268,1,1449, +3041,16,0,268,1, +1701,3042,16,0,268, +1,447,1637,1,205, +3043,16,0,268,1, +827,3044,16,0,268, +1,223,3045,16,0, +268,1,476,1669,1, +477,1675,1,1231,3046, +16,0,268,1,479, +1685,1,480,1690,1, +1485,3047,16,0,268, +1,1737,3048,16,0, +268,1,242,3049,16, +0,268,1,478,1708, +1,1001,1713,1,1002, +1718,1,33,3050,19, +378,1,33,3051,5, +84,1,1011,1227,1, +1012,3052,16,0,376, +1,1013,1385,1,262, +1244,1,1267,3053,16, +0,376,1,515,3054, +16,0,376,1,1521, +3055,16,0,376,1, +525,1343,1,2792,3056, +16,0,376,1,283, +1299,1,2299,3057,16, +0,376,1,42,3058, +16,0,376,1,40, +1304,1,44,1310,1, +47,1311,1,1303,3059, +16,0,376,1,1555, +3060,16,0,376,1, +50,1328,1,48,1317, +1,49,1323,1,51, +1333,1,63,1349,1, +305,1338,1,66,1355, +1,67,1360,1,68, +1365,1,69,1370,1, +70,1375,1,73,3061, +16,0,376,1,74, +1380,1,328,1429,1, +1048,1470,1,82,3062, +16,0,376,1,1840, +3063,16,0,376,1, +1591,3064,16,0,376, +1,1341,3065,16,0, +376,1,1096,1439,1, +93,1445,1,352,1475, +1,107,3066,16,0, +376,1,1114,1469,1, +118,1481,1,1123,3067, +16,0,376,1,371, +1491,1,1628,3068,16, +0,376,1,375,1502, +1,1882,3069,16,0, +376,1,377,1507,1, +379,1512,1,380,1517, +1,883,3070,16,0, +376,1,373,1535,1, +130,1540,1,143,1545, +1,387,3071,16,0, +376,1,1159,3072,16, +0,376,1,157,1568, +1,1413,3073,16,0, +376,1,1665,3074,16, +0,376,1,412,3075, +16,0,376,1,1377, +3076,16,0,376,1, +172,1595,1,1939,3077, +16,0,376,1,437, +3078,16,0,376,1, +188,1644,1,942,1616, +1,1195,3079,16,0, +376,1,1449,3080,16, +0,376,1,1701,3081, +16,0,376,1,447, +1637,1,205,3082,16, +0,376,1,827,3083, +16,0,376,1,223, +3084,16,0,376,1, +476,1669,1,477,1675, +1,1231,3085,16,0, +376,1,479,1685,1, +480,1690,1,1485,3086, +16,0,376,1,1737, +3087,16,0,376,1, +242,1703,1,478,1708, +1,1001,1713,1,1002, +1718,1,34,3088,19, +365,1,34,3089,5, +84,1,1011,1227,1, +1012,3090,16,0,363, +1,1013,1385,1,262, +1244,1,1267,3091,16, +0,363,1,515,3092, +16,0,363,1,1521, +3093,16,0,363,1, +525,1343,1,2792,3094, +16,0,363,1,283, +1299,1,2299,3095,16, +0,363,1,42,3096, +16,0,363,1,40, +1304,1,44,1310,1, +47,1311,1,1303,3097, +16,0,363,1,1555, +3098,16,0,363,1, +50,1328,1,48,1317, +1,49,1323,1,51, +1333,1,63,1349,1, +305,1338,1,66,1355, +1,67,1360,1,68, +1365,1,69,1370,1, +70,1375,1,73,3099, +16,0,363,1,74, +1380,1,328,1429,1, +1048,1470,1,82,3100, +16,0,363,1,1840, +3101,16,0,363,1, +1591,3102,16,0,363, +1,1341,3103,16,0, +363,1,1096,1439,1, +93,1445,1,352,1475, +1,107,3104,16,0, +363,1,1114,1469,1, +118,1481,1,1123,3105, +16,0,363,1,371, +1491,1,1628,3106,16, +0,363,1,375,1502, +1,1882,3107,16,0, +363,1,377,1507,1, +379,1512,1,380,1517, +1,883,3108,16,0, +363,1,373,1535,1, +130,1540,1,143,1545, +1,387,3109,16,0, +363,1,1159,3110,16, +0,363,1,157,1568, +1,1413,3111,16,0, +363,1,1665,3112,16, +0,363,1,412,3113, +16,0,363,1,1377, +3114,16,0,363,1, +172,1595,1,1939,3115, +16,0,363,1,437, +3116,16,0,363,1, +188,1644,1,942,1616, +1,1195,3117,16,0, +363,1,1449,3118,16, +0,363,1,1701,3119, +16,0,363,1,447, +1637,1,205,1649,1, +827,3120,16,0,363, +1,223,1659,1,476, +1669,1,477,1675,1, +1231,3121,16,0,363, +1,479,1685,1,480, +1690,1,1485,3122,16, +0,363,1,1737,3123, +16,0,363,1,242, +1703,1,478,1708,1, +1001,1713,1,1002,1718, +1,35,3124,19,351, +1,35,3125,5,84, +1,1011,1227,1,1012, +3126,16,0,349,1, +1013,1385,1,262,1244, +1,1267,3127,16,0, +349,1,515,3128,16, +0,349,1,1521,3129, +16,0,349,1,525, +1343,1,2792,3130,16, +0,349,1,283,1299, +1,2299,3131,16,0, +349,1,42,3132,16, +0,349,1,40,1304, +1,44,1310,1,47, +1311,1,1303,3133,16, +0,349,1,1555,3134, +16,0,349,1,50, +1328,1,48,1317,1, +49,1323,1,51,1333, +1,63,1349,1,305, +1338,1,66,1355,1, +67,1360,1,68,1365, +1,69,1370,1,70, +1375,1,73,3135,16, +0,349,1,74,1380, +1,328,1429,1,1048, +1470,1,82,3136,16, +0,349,1,1840,3137, +16,0,349,1,1591, +3138,16,0,349,1, +1341,3139,16,0,349, +1,1096,1439,1,93, +1445,1,352,1475,1, +107,3140,16,0,349, +1,1114,1469,1,118, +1481,1,1123,3141,16, +0,349,1,371,1491, +1,1628,3142,16,0, +349,1,375,1502,1, +1882,3143,16,0,349, +1,377,1507,1,379, +1512,1,380,1517,1, +883,3144,16,0,349, +1,373,1535,1,130, +1540,1,143,1545,1, +387,3145,16,0,349, +1,1159,3146,16,0, +349,1,157,1568,1, +1413,3147,16,0,349, +1,1665,3148,16,0, +349,1,412,3149,16, +0,349,1,1377,3150, +16,0,349,1,172, +1595,1,1939,3151,16, +0,349,1,437,3152, +16,0,349,1,188, +1644,1,942,1616,1, +1195,3153,16,0,349, +1,1449,3154,16,0, +349,1,1701,3155,16, +0,349,1,447,1637, +1,205,1649,1,827, +3156,16,0,349,1, +223,3157,16,0,349, +1,476,1669,1,477, +1675,1,1231,3158,16, +0,349,1,479,1685, +1,480,1690,1,1485, +3159,16,0,349,1, +1737,3160,16,0,349, +1,242,1703,1,478, +1708,1,1001,1713,1, +1002,1718,1,36,3161, +19,239,1,36,3162, +5,94,1,256,3163, +16,0,237,1,1261, +3164,16,0,237,1, +509,3165,16,0,237, +1,1515,3166,16,0, +237,1,2021,843,1, +1775,3167,16,0,237, +1,2029,850,1,2030, +856,1,2031,861,1, +2032,866,1,2033,871, +1,277,3168,16,0, +237,1,2035,877,1, +2037,882,1,2039,887, +1,32,3169,16,0, +237,1,2041,893,1, +2293,3170,16,0,237, +1,2043,899,1,2045, +904,1,41,3171,16, +0,237,1,1297,3172, +16,0,237,1,43, +3173,16,0,237,1, +1803,912,1,1804,3174, +16,0,237,1,299, +3175,16,0,237,1, +52,3176,16,0,237, +1,2318,3177,16,0, +237,1,2075,3178,16, +0,237,1,1574,924, +1,71,3179,16,0, +237,1,76,3180,16, +0,237,1,1834,3181, +16,0,237,1,2337, +3182,16,0,237,1, +79,3183,16,0,237, +1,1335,3184,16,0, +237,1,322,3185,16, +0,237,1,85,3186, +16,0,237,1,89, +3187,16,0,237,1, +346,3188,16,0,237, +1,2105,939,1,2106, +3189,16,0,237,1, +97,3190,16,0,237, +1,1860,946,1,2364, +952,1,102,3191,16, +0,237,1,112,3192, +16,0,237,1,1117, +3193,16,0,237,1, +2786,3194,16,0,237, +1,1873,961,1,1876, +3195,16,0,237,1, +124,3196,16,0,237, +1,2136,968,1,381, +3197,16,0,237,1, +525,3198,16,0,237, +1,137,3199,16,0, +237,1,1901,3200,16, +0,237,1,1153,3201, +16,0,237,1,151, +3202,16,0,237,1, +1407,3203,16,0,237, +1,1659,3204,16,0, +237,1,2413,3205,16, +0,237,1,406,3206, +16,0,237,1,1371, +3207,16,0,237,1, +166,3208,16,0,237, +1,1622,3209,16,0, +237,1,1931,986,1, +1933,3210,16,0,237, +1,431,3211,16,0, +237,1,1585,3212,16, +0,237,1,182,3213, +16,0,237,1,1189, +3214,16,0,237,1, +1443,3215,16,0,237, +1,1695,3216,16,0, +237,1,2198,3217,16, +0,237,1,447,3218, +16,0,237,1,2458, +1001,1,2459,1007,1, +1958,3219,16,0,237, +1,2462,1014,1,1657, +1019,1,2464,1024,1, +199,3220,16,0,237, +1,459,3221,16,0, +237,1,462,3222,16, +0,237,1,217,3223, +16,0,237,1,2227, +1033,1,1225,3224,16, +0,237,1,1479,3225, +16,0,237,1,1731, +3226,16,0,237,1, +1989,1041,1,1990,3227, +16,0,237,1,236, +3228,16,0,237,1, +1756,3229,16,0,237, +1,37,3230,19,260, +1,37,3231,5,94, +1,256,3232,16,0, +258,1,1261,3233,16, +0,258,1,509,3234, +16,0,258,1,1515, +3235,16,0,258,1, +2021,843,1,1775,3236, +16,0,258,1,2029, +850,1,2030,856,1, +2031,861,1,2032,866, +1,2033,871,1,277, +3237,16,0,258,1, +2035,877,1,2037,882, +1,2039,887,1,32, +3238,16,0,258,1, +2041,893,1,2293,3239, +16,0,258,1,2043, +899,1,2045,904,1, +41,3240,16,0,258, +1,1297,3241,16,0, +258,1,43,3242,16, +0,258,1,1803,912, +1,1804,3243,16,0, +258,1,299,3244,16, +0,258,1,52,3245, +16,0,258,1,2318, +3246,16,0,258,1, +2075,3247,16,0,258, +1,1574,924,1,71, +3248,16,0,258,1, +76,3249,16,0,258, +1,1834,3250,16,0, +258,1,2337,3251,16, +0,258,1,79,3252, +16,0,258,1,1335, +3253,16,0,258,1, +322,3254,16,0,258, +1,85,3255,16,0, +258,1,89,3256,16, +0,258,1,346,3257, +16,0,258,1,2105, +939,1,2106,3258,16, +0,258,1,97,3259, +16,0,258,1,1860, +946,1,2364,952,1, +102,3260,16,0,258, +1,112,3261,16,0, +258,1,1117,3262,16, +0,258,1,2786,3263, +16,0,258,1,1873, +961,1,1876,3264,16, +0,258,1,124,3265, +16,0,258,1,2136, +968,1,381,3266,16, +0,258,1,525,3267, +16,0,258,1,137, +3268,16,0,258,1, +1901,3269,16,0,258, +1,1153,3270,16,0, +258,1,151,3271,16, +0,258,1,1407,3272, +16,0,258,1,1659, +3273,16,0,258,1, +2413,3274,16,0,258, +1,406,3275,16,0, +258,1,1371,3276,16, +0,258,1,166,3277, +16,0,258,1,1622, +3278,16,0,258,1, +1931,986,1,1933,3279, +16,0,258,1,431, +3280,16,0,258,1, +1585,3281,16,0,258, +1,182,3282,16,0, +258,1,1189,3283,16, +0,258,1,1443,3284, +16,0,258,1,1695, +3285,16,0,258,1, +2198,3286,16,0,258, +1,447,3287,16,0, +258,1,2458,1001,1, +2459,1007,1,1958,3288, +16,0,258,1,2462, +1014,1,1657,1019,1, +2464,1024,1,199,3289, +16,0,258,1,459, +3290,16,0,258,1, +462,3291,16,0,258, +1,217,3292,16,0, +258,1,2227,1033,1, +1225,3293,16,0,258, +1,1479,3294,16,0, +258,1,1731,3295,16, +0,258,1,1989,1041, +1,1990,3296,16,0, +258,1,236,3297,16, +0,258,1,1756,3298, +16,0,258,1,38, +3299,19,257,1,38, +3300,5,84,1,1011, +1227,1,1012,3301,16, +0,255,1,1013,1385, +1,262,1244,1,1267, +3302,16,0,255,1, +515,3303,16,0,255, +1,1521,3304,16,0, +255,1,525,1343,1, +2792,3305,16,0,255, +1,283,1299,1,2299, +3306,16,0,255,1, +42,3307,16,0,255, +1,40,1304,1,44, +1310,1,47,1311,1, +1303,3308,16,0,255, +1,1555,3309,16,0, +255,1,50,1328,1, +48,1317,1,49,1323, +1,51,1333,1,63, +1349,1,305,1338,1, +66,1355,1,67,1360, +1,68,1365,1,69, +1370,1,70,1375,1, +73,3310,16,0,255, +1,74,1380,1,328, +1429,1,1048,1470,1, +82,3311,16,0,255, +1,1840,3312,16,0, +255,1,1591,3313,16, +0,255,1,1341,3314, +16,0,255,1,1096, +1439,1,93,1445,1, +352,1475,1,107,3315, +16,0,255,1,1114, +1469,1,118,1481,1, +1123,3316,16,0,255, +1,371,1491,1,1628, +3317,16,0,255,1, +375,1502,1,1882,3318, +16,0,255,1,377, +1507,1,379,1512,1, +380,1517,1,883,1523, +1,373,1535,1,130, +1540,1,143,1545,1, +387,3319,16,0,255, +1,1159,3320,16,0, +255,1,157,1568,1, +1413,3321,16,0,255, +1,1665,3322,16,0, +255,1,412,3323,16, +0,255,1,1377,3324, +16,0,255,1,172, +1595,1,1939,3325,16, +0,255,1,437,3326, +16,0,255,1,188, +1644,1,942,1616,1, +1195,3327,16,0,255, +1,1449,3328,16,0, +255,1,1701,3329,16, +0,255,1,447,1637, +1,205,1649,1,827, +1457,1,223,1659,1, +476,1669,1,477,1675, +1,1231,3330,16,0, +255,1,479,1685,1, +480,1690,1,1485,3331, +16,0,255,1,1737, +3332,16,0,255,1, +242,1703,1,478,1708, +1,1001,1713,1,1002, +1718,1,39,3333,19, +245,1,39,3334,5, +84,1,1011,1227,1, +1012,3335,16,0,243, +1,1013,1385,1,262, +1244,1,1267,3336,16, +0,243,1,515,3337, +16,0,243,1,1521, +3338,16,0,243,1, +525,1343,1,2792,3339, +16,0,243,1,283, +1299,1,2299,3340,16, +0,243,1,42,3341, +16,0,243,1,40, +1304,1,44,1310,1, +47,1311,1,1303,3342, +16,0,243,1,1555, +3343,16,0,243,1, +50,1328,1,48,1317, +1,49,1323,1,51, +1333,1,63,1349,1, +305,1338,1,66,1355, +1,67,1360,1,68, +1365,1,69,1370,1, +70,1375,1,73,3344, +16,0,243,1,74, +1380,1,328,1429,1, +1048,1470,1,82,3345, +16,0,243,1,1840, +3346,16,0,243,1, +1591,3347,16,0,243, +1,1341,3348,16,0, +243,1,1096,1439,1, +93,1445,1,352,1475, +1,107,3349,16,0, +243,1,1114,1469,1, +118,1481,1,1123,3350, +16,0,243,1,371, +1491,1,1628,3351,16, +0,243,1,375,1502, +1,1882,3352,16,0, +243,1,377,1507,1, +379,1512,1,380,1517, +1,883,1523,1,373, +1535,1,130,1540,1, +143,1545,1,387,3353, +16,0,243,1,1159, +3354,16,0,243,1, +157,1568,1,1413,3355, +16,0,243,1,1665, +3356,16,0,243,1, +412,3357,16,0,243, +1,1377,3358,16,0, +243,1,172,1595,1, +1939,3359,16,0,243, +1,437,3360,16,0, +243,1,188,1644,1, +942,1616,1,1195,3361, +16,0,243,1,1449, +3362,16,0,243,1, +1701,3363,16,0,243, +1,447,1637,1,205, +1649,1,827,1457,1, +223,1659,1,476,1669, +1,477,1675,1,1231, +3364,16,0,243,1, +479,1685,1,480,1690, +1,1485,3365,16,0, +243,1,1737,3366,16, +0,243,1,242,1703, +1,478,1708,1,1001, +1713,1,1002,1718,1, +40,3367,19,233,1, +40,3368,5,84,1, +1011,1227,1,1012,3369, +16,0,231,1,1013, +1385,1,262,1244,1, +1267,3370,16,0,231, +1,515,3371,16,0, +231,1,1521,3372,16, +0,231,1,525,1343, +1,2792,3373,16,0, +231,1,283,1299,1, +2299,3374,16,0,231, +1,42,3375,16,0, +231,1,40,1304,1, +44,1310,1,47,1311, +1,1303,3376,16,0, +231,1,1555,3377,16, +0,231,1,50,1328, +1,48,1317,1,49, +1323,1,51,1333,1, +63,1349,1,305,1338, +1,66,1355,1,67, +1360,1,68,1365,1, +69,1370,1,70,1375, +1,73,3378,16,0, +231,1,74,1380,1, +328,1429,1,1048,1470, +1,82,3379,16,0, +231,1,1840,3380,16, +0,231,1,1591,3381, +16,0,231,1,1341, +3382,16,0,231,1, +1096,1439,1,93,1445, +1,352,1475,1,107, +3383,16,0,231,1, +1114,1469,1,118,3384, +16,0,231,1,1123, +3385,16,0,231,1, +371,1491,1,1628,3386, +16,0,231,1,375, +1502,1,1882,3387,16, +0,231,1,377,1507, +1,379,1512,1,380, +1517,1,883,3388,16, +0,231,1,373,1535, +1,130,3389,16,0, +231,1,143,3390,16, +0,231,1,387,3391, +16,0,231,1,1159, +3392,16,0,231,1, +157,3393,16,0,231, +1,1413,3394,16,0, +231,1,1665,3395,16, +0,231,1,412,3396, +16,0,231,1,1377, +3397,16,0,231,1, +172,3398,16,0,231, +1,1939,3399,16,0, +231,1,437,3400,16, +0,231,1,188,3401, +16,0,231,1,942, +1616,1,1195,3402,16, +0,231,1,1449,3403, +16,0,231,1,1701, +3404,16,0,231,1, +447,1637,1,205,3405, +16,0,231,1,827, +3406,16,0,231,1, +223,3407,16,0,231, +1,476,1669,1,477, +1675,1,1231,3408,16, +0,231,1,479,1685, +1,480,1690,1,1485, +3409,16,0,231,1, +1737,3410,16,0,231, +1,242,3411,16,0, +231,1,478,1708,1, +1001,1713,1,1002,1718, +1,41,3412,19,188, +1,41,3413,5,84, +1,1011,1227,1,1012, +3414,16,0,186,1, +1013,1385,1,262,1244, +1,1267,3415,16,0, +186,1,515,3416,16, +0,186,1,1521,3417, +16,0,186,1,525, +1343,1,2792,3418,16, +0,186,1,283,1299, +1,2299,3419,16,0, +186,1,42,3420,16, +0,186,1,40,1304, +1,44,1310,1,47, +1311,1,1303,3421,16, +0,186,1,1555,3422, +16,0,186,1,50, +1328,1,48,1317,1, +49,1323,1,51,1333, +1,63,1349,1,305, +1338,1,66,1355,1, +67,1360,1,68,1365, +1,69,1370,1,70, +1375,1,73,3423,16, +0,186,1,74,1380, +1,328,1429,1,1048, +1470,1,82,3424,16, +0,186,1,1840,3425, +16,0,186,1,1591, +3426,16,0,186,1, +1341,3427,16,0,186, +1,1096,1439,1,93, +1445,1,352,1475,1, +107,3428,16,0,186, +1,1114,1469,1,118, +3429,16,0,186,1, +1123,3430,16,0,186, +1,371,1491,1,1628, +3431,16,0,186,1, +375,1502,1,1882,3432, +16,0,186,1,377, +1507,1,379,1512,1, +380,1517,1,883,3433, +16,0,186,1,373, +1535,1,130,3434,16, +0,186,1,143,3435, +16,0,186,1,387, +3436,16,0,186,1, +1159,3437,16,0,186, +1,157,3438,16,0, +186,1,1413,3439,16, +0,186,1,1665,3440, +16,0,186,1,412, +3441,16,0,186,1, +1377,3442,16,0,186, +1,172,3443,16,0, +186,1,1939,3444,16, +0,186,1,437,3445, +16,0,186,1,188, +3446,16,0,186,1, +942,1616,1,1195,3447, +16,0,186,1,1449, +3448,16,0,186,1, +1701,3449,16,0,186, +1,447,1637,1,205, +3450,16,0,186,1, +827,3451,16,0,186, +1,223,3452,16,0, +186,1,476,1669,1, +477,1675,1,1231,3453, +16,0,186,1,479, +1685,1,480,1690,1, +1485,3454,16,0,186, +1,1737,3455,16,0, +186,1,242,3456,16, +0,186,1,478,1708, +1,1001,1713,1,1002, +1718,1,42,3457,19, +440,1,42,3458,5, +38,1,1901,3459,16, +0,438,1,2075,3460, +16,0,438,1,1860, +946,1,1803,912,1, +1804,3461,16,0,438, +1,2413,3462,16,0, +438,1,2198,3463,16, +0,438,1,1873,961, +1,1657,1019,1,1989, +1041,1,1990,3464,16, +0,438,1,1775,3465, +16,0,438,1,32, +3466,16,0,438,1, +2105,939,1,2106,3467, +16,0,438,1,2364, +952,1,2227,1033,1, +2337,3468,16,0,438, +1,2021,843,1,2458, +1001,1,2459,1007,1, +2462,1014,1,2136,968, +1,2464,1024,1,2029, +850,1,2030,856,1, +2031,861,1,2032,866, +1,2033,871,1,2035, +877,1,2037,882,1, +2039,887,1,1931,986, +1,2041,893,1,2043, +899,1,2045,904,1, +1574,924,1,1958,3469, +16,0,438,1,43, +3470,19,532,1,43, +3471,5,25,1,2035, +877,1,2037,882,1, +2039,887,1,2041,893, +1,2227,1033,1,2043, +899,1,1657,1019,1, +1860,946,1,2136,968, +1,2021,843,1,2459, +1007,1,1574,924,1, +2105,3472,16,0,698, +1,1931,986,1,1873, +961,1,2031,861,1, +1803,912,1,1989,3473, +16,0,530,1,2464, +1024,1,2029,850,1, +2030,856,1,2364,952, +1,2032,866,1,2033, +871,1,2045,904,1, +44,3474,19,292,1, +44,3475,5,38,1, +1901,3476,16,0,290, +1,2075,3477,16,0, +290,1,1860,946,1, +1803,912,1,1804,3478, +16,0,290,1,2413, +3479,16,0,290,1, +2198,3480,16,0,290, +1,1873,961,1,1657, +1019,1,1989,1041,1, +1990,3481,16,0,290, +1,1775,3482,16,0, +290,1,32,3483,16, +0,290,1,2105,939, +1,2106,3484,16,0, +290,1,2364,952,1, +2227,1033,1,2337,3485, +16,0,290,1,2021, +843,1,2458,1001,1, +2459,1007,1,2462,1014, +1,2136,968,1,2464, +1024,1,2029,850,1, +2030,856,1,2031,861, +1,2032,866,1,2033, +871,1,2035,877,1, +2037,882,1,2039,887, +1,1931,986,1,2041, +893,1,2043,899,1, +2045,904,1,1574,924, +1,1958,3486,16,0, +290,1,45,3487,19, +325,1,45,3488,5, +39,1,1901,3489,16, +0,355,1,2075,3490, +16,0,355,1,1860, +946,1,1803,912,1, +1804,3491,16,0,355, +1,2413,3492,16,0, +355,1,2198,3493,16, +0,355,1,1873,961, +1,1657,1019,1,1989, +1041,1,1990,3494,16, +0,355,1,1775,3495, +16,0,355,1,32, +3496,16,0,355,1, +2105,939,1,2106,3497, +16,0,355,1,2364, +952,1,2227,1033,1, +2337,3498,16,0,355, +1,2021,843,1,2458, +1001,1,2459,1007,1, +2462,1014,1,2136,968, +1,2464,1024,1,2029, +850,1,2030,856,1, +2031,861,1,2032,866, +1,2033,871,1,2035, +877,1,2037,882,1, +2039,887,1,1931,986, +1,2041,893,1,2043, +899,1,2045,904,1, +1832,3499,16,0,323, +1,1574,924,1,1958, +3500,16,0,355,1, +46,3501,19,794,1, +46,3502,5,38,1, +1901,3503,16,0,792, +1,2075,3504,16,0, +792,1,1860,946,1, +1803,912,1,1804,3505, +16,0,792,1,2413, +3506,16,0,792,1, +2198,3507,16,0,792, +1,1873,961,1,1657, +1019,1,1989,1041,1, +1990,3508,16,0,792, +1,1775,3509,16,0, +792,1,32,3510,16, +0,792,1,2105,939, +1,2106,3511,16,0, +792,1,2364,952,1, +2227,1033,1,2337,3512, +16,0,792,1,2021, +843,1,2458,1001,1, +2459,1007,1,2462,1014, +1,2136,968,1,2464, +1024,1,2029,850,1, +2030,856,1,2031,861, +1,2032,866,1,2033, +871,1,2035,877,1, +2037,882,1,2039,887, +1,1931,986,1,2041, +893,1,2043,899,1, +2045,904,1,1574,924, +1,1958,3513,16,0, +792,1,47,3514,19, +283,1,47,3515,5, +19,1,0,3516,16, +0,281,1,2783,3517, +17,3518,15,3519,4, +50,37,0,71,0, +108,0,111,0,98, +0,97,0,108,0, +70,0,117,0,110, +0,99,0,116,0, +105,0,111,0,110, +0,68,0,101,0, +102,0,105,0,110, +0,105,0,116,0, +105,0,111,0,110, +0,1,-1,1,5, +3520,20,3521,4,52, +71,0,108,0,111, +0,98,0,97,0, +108,0,70,0,117, +0,110,0,99,0, +116,0,105,0,111, +0,110,0,68,0, 101,0,102,0,105, 0,110,0,105,0, 116,0,105,0,111, -0,110,0,115,0, -1,-1,1,5,3186, -20,3187,4,38,71, +0,110,0,95,0, +49,0,1,175,1, +3,1,6,1,5, +3522,22,1,9,1, +2464,1024,1,2767,822, +1,2768,810,1,2822, +3523,17,3524,15,3525, +4,52,37,0,71, 0,108,0,111,0, 98,0,97,0,108, -0,68,0,101,0, -102,0,105,0,110, -0,105,0,116,0, -105,0,111,0,110, -0,115,0,95,0, -50,0,1,145,1, -3,1,3,1,2, -3188,22,1,4,1, -2558,697,1,2716,3189, -17,3190,15,3185,1, --1,1,5,3191,20, -3192,4,38,71,0, -108,0,111,0,98, -0,97,0,108,0, -68,0,101,0,102, -0,105,0,110,0, -105,0,116,0,105, -0,111,0,110,0, -115,0,95,0,49, -0,1,144,1,3, -1,2,1,1,3193, -22,1,3,1,2022, -3194,16,0,567,1, -2459,882,1,2715,3195, -17,3196,15,3185,1, --1,1,5,3197,20, -3198,4,38,71,0, +0,86,0,97,0, +114,0,105,0,97, +0,98,0,108,0, +101,0,68,0,101, +0,99,0,108,0, +97,0,114,0,97, +0,116,0,105,0, +111,0,110,0,1, +-1,1,5,3526,20, +3527,4,54,71,0, 108,0,111,0,98, 0,97,0,108,0, -68,0,101,0,102, -0,105,0,110,0, -105,0,116,0,105, -0,111,0,110,0, -115,0,95,0,51, -0,1,146,1,3, -1,2,1,1,3199, -22,1,5,1,2464, -899,1,2466,3200,17, -3201,15,3202,4,50, -37,0,71,0,108, -0,111,0,98,0, -97,0,108,0,70, -0,117,0,110,0, -99,0,116,0,105, -0,111,0,110,0, -68,0,101,0,102, -0,105,0,110,0, -105,0,116,0,105, -0,111,0,110,0, -1,-1,1,5,3203, -20,3204,4,52,71, +86,0,97,0,114, +0,105,0,97,0, +98,0,108,0,101, +0,68,0,101,0, +99,0,108,0,97, +0,114,0,97,0, +116,0,105,0,111, +0,110,0,95,0, +49,0,1,173,1, +3,1,3,1,2, +3528,22,1,7,1, +2823,3529,16,0,281, +1,2022,3530,16,0, +673,1,2755,816,1, +2834,3531,16,0,281, +1,2459,1007,1,2466, +3532,17,3533,15,3519, +1,-1,1,5,3534, +20,3535,4,52,71, 0,108,0,111,0, 98,0,97,0,108, 0,70,0,117,0, @@ -8477,70 +9979,74 @@ public yyLSLSyntax 110,0,105,0,116, 0,105,0,111,0, 110,0,95,0,50, -0,1,151,1,3, -1,7,1,6,3205, -22,1,10,1,2640, -685,1,2713,3206,17, -3207,15,3185,1,-1, -1,5,3208,20,3209, -4,38,71,0,108, -0,111,0,98,0, -97,0,108,0,68, -0,101,0,102,0, -105,0,110,0,105, -0,116,0,105,0, -111,0,110,0,115, -0,95,0,52,0, -1,147,1,3,1, -3,1,2,3210,22, -1,6,1,2655,3211, -17,3212,15,3202,1, --1,1,5,3213,20, -3214,4,52,71,0, +0,1,176,1,3, +1,7,1,6,3536, +22,1,10,1,2764, +3537,16,0,281,1, +2841,3538,17,3539,15, +3540,4,36,37,0, +71,0,108,0,111, +0,98,0,97,0, +108,0,68,0,101, +0,102,0,105,0, +110,0,105,0,116, +0,105,0,111,0, +110,0,115,0,1, +-1,1,5,3541,20, +3542,4,38,71,0, 108,0,111,0,98, 0,97,0,108,0, -70,0,117,0,110, -0,99,0,116,0, -105,0,111,0,110, +68,0,101,0,102, +0,105,0,110,0, +105,0,116,0,105, +0,111,0,110,0, +115,0,95,0,52, +0,1,172,1,3, +1,3,1,2,3543, +22,1,6,1,2842, +3544,17,3545,15,3540, +1,-1,1,5,3546, +20,3547,4,38,71, +0,108,0,111,0, +98,0,97,0,108, 0,68,0,101,0, 102,0,105,0,110, 0,105,0,116,0, 105,0,111,0,110, -0,95,0,49,0, -1,150,1,3,1, -6,1,5,3215,22, -1,9,1,2694,3216, -17,3217,15,3218,4, -52,37,0,71,0, -108,0,111,0,98, -0,97,0,108,0, -86,0,97,0,114, -0,105,0,97,0, -98,0,108,0,101, -0,68,0,101,0, -99,0,108,0,97, -0,114,0,97,0, -116,0,105,0,111, -0,110,0,1,-1, -1,5,3219,20,3220, -4,54,71,0,108, -0,111,0,98,0, -97,0,108,0,86, -0,97,0,114,0, -105,0,97,0,98, -0,108,0,101,0, -68,0,101,0,99, -0,108,0,97,0, -114,0,97,0,116, +0,115,0,95,0, +50,0,1,170,1, +3,1,3,1,2, +3548,22,1,4,1, +2843,3549,17,3550,15, +3540,1,-1,1,5, +3551,20,3552,4,38, +71,0,108,0,111, +0,98,0,97,0, +108,0,68,0,101, +0,102,0,105,0, +110,0,105,0,116, 0,105,0,111,0, -110,0,95,0,49, -0,1,148,1,3, -1,3,1,2,3221, -22,1,7,1,2695, -3222,16,0,464,1, -2683,3223,17,3224,15, -3218,1,-1,1,5, -3225,20,3226,4,54, +110,0,115,0,95, +0,51,0,1,171, +1,3,1,2,1, +1,3553,22,1,5, +1,2844,3554,17,3555, +15,3540,1,-1,1, +5,3556,20,3557,4, +38,71,0,108,0, +111,0,98,0,97, +0,108,0,68,0, +101,0,102,0,105, +0,110,0,105,0, +116,0,105,0,111, +0,110,0,115,0, +95,0,49,0,1, +169,1,3,1,2, +1,1,3558,22,1, +3,1,2649,832,1, +2811,3559,17,3560,15, +3525,1,-1,1,5, +3561,20,3562,4,54, 71,0,108,0,111, 0,98,0,97,0, 108,0,86,0,97, @@ -8552,2203 +10058,2877 @@ public yyLSLSyntax 97,0,116,0,105, 0,111,0,110,0, 95,0,50,0,1, -149,1,3,1,5, -1,4,3227,22,1, -8,1,48,3228,19, -339,1,48,3229,5, -54,1,0,3230,16, -0,337,1,2075,3231, -16,0,495,1,1860, -821,1,1803,787,1, -1804,3232,16,0,495, -1,2413,3233,16,0, -495,1,2634,691,1, -1873,835,1,1657,894, -1,2639,707,1,2640, -685,1,1989,916,1, -1990,3234,16,0,495, -1,2459,882,1,1775, -3235,16,0,495,1, -32,3236,16,0,495, -1,2105,814,1,2106, -3237,16,0,495,1, -2466,3200,1,2655,3211, -1,2683,3223,1,2227, -908,1,2337,3238,16, -0,495,1,2558,697, -1,2694,3216,1,2695, -3239,16,0,337,1, -2021,718,1,2458,876, -1,1901,3240,16,0, -495,1,2462,889,1, -2136,842,1,2464,899, -1,2029,725,1,2030, -731,1,2031,736,1, -2032,741,1,2033,746, -1,2035,752,1,2364, -827,1,2715,3195,1, -2039,762,1,1931,861, -1,2041,768,1,2043, -774,1,2045,779,1, -2198,3241,16,0,495, -1,2706,3242,16,0, -337,1,2037,757,1, -2713,3206,1,2714,3183, -1,1574,799,1,2716, -3189,1,2636,3243,16, -0,337,1,1958,3244, -16,0,495,1,49, -3245,19,500,1,49, -3246,5,38,1,1901, -3247,16,0,498,1, -2075,3248,16,0,498, -1,1860,821,1,1803, -787,1,1804,3249,16, -0,498,1,2413,3250, -16,0,498,1,2198, -3251,16,0,498,1, -1873,835,1,1657,894, -1,1989,916,1,1990, -3252,16,0,498,1, -1775,3253,16,0,498, -1,32,3254,16,0, -498,1,2105,814,1, -2106,3255,16,0,498, -1,2364,827,1,2227, -908,1,2337,3256,16, -0,498,1,2021,718, -1,2458,876,1,2459, -882,1,2462,889,1, -2136,842,1,2464,899, -1,2029,725,1,2030, -731,1,2031,736,1, -2032,741,1,2033,746, -1,2035,752,1,2037, -757,1,2039,762,1, -1931,861,1,2041,768, -1,2043,774,1,2045, -779,1,1574,799,1, -1958,3257,16,0,498, -1,50,3258,19,614, -1,50,3259,5,38, -1,1901,3260,16,0, -612,1,2075,3261,16, -0,612,1,1860,821, -1,1803,787,1,1804, -3262,16,0,612,1, -2413,3263,16,0,612, -1,2198,3264,16,0, -612,1,1873,835,1, -1657,894,1,1989,916, -1,1990,3265,16,0, -612,1,1775,3266,16, -0,612,1,32,3267, -16,0,612,1,2105, -814,1,2106,3268,16, -0,612,1,2364,827, -1,2227,908,1,2337, -3269,16,0,612,1, -2021,718,1,2458,876, -1,2459,882,1,2462, -889,1,2136,842,1, -2464,899,1,2029,725, -1,2030,731,1,2031, -736,1,2032,741,1, -2033,746,1,2035,752, -1,2037,757,1,2039, -762,1,1931,861,1, -2041,768,1,2043,774, -1,2045,779,1,1574, -799,1,1958,3270,16, -0,612,1,51,3271, -19,127,1,51,3272, -5,53,1,0,3273, -16,0,125,1,2075, -3274,16,0,125,1, -1860,821,1,1803,787, -1,1804,3275,16,0, -125,1,10,3276,16, -0,125,1,2413,3277, -16,0,125,1,2198, -3278,16,0,125,1, -1873,835,1,21,3279, -16,0,125,1,1657, -894,1,2030,731,1, -2642,3280,16,0,125, -1,1989,916,1,1990, -3281,16,0,125,1, -2459,882,1,1775,3282, -16,0,125,1,32, -3283,16,0,125,1, -2105,814,1,2106,3284, -16,0,125,1,2655, -3211,1,2683,3223,1, -2227,908,1,2337,3285, -16,0,125,1,52, -3286,16,0,125,1, -2694,3216,1,2695,3287, -16,0,125,1,2021, -718,1,2458,876,1, -1901,3288,16,0,125, -1,2462,889,1,2136, -842,1,2464,899,1, -2029,725,1,2466,3200, -1,2031,736,1,2032, -741,1,2033,746,1, -2035,752,1,2364,827, -1,2715,3195,1,2039, -762,1,1931,861,1, -2041,768,1,2043,774, -1,2045,779,1,2037, -757,1,2713,3206,1, -2714,3183,1,1574,799, -1,2716,3189,1,1958, -3289,16,0,125,1, -2506,3290,16,0,125, -1,52,3291,19,124, -1,52,3292,5,53, -1,0,3293,16,0, -122,1,2075,3294,16, -0,122,1,1860,821, -1,1803,787,1,1804, -3295,16,0,122,1, -10,3296,16,0,122, -1,2413,3297,16,0, -122,1,2198,3298,16, -0,122,1,1873,835, -1,21,3299,16,0, -122,1,1657,894,1, -2030,731,1,2642,3300, -16,0,122,1,1989, -916,1,1990,3301,16, -0,122,1,2459,882, -1,1775,3302,16,0, -122,1,32,3303,16, -0,122,1,2105,814, -1,2106,3304,16,0, -122,1,2655,3211,1, -2683,3223,1,2227,908, -1,2337,3305,16,0, -122,1,52,3306,16, -0,122,1,2694,3216, -1,2695,3307,16,0, -122,1,2021,718,1, -2458,876,1,1901,3308, -16,0,122,1,2462, -889,1,2136,842,1, -2464,899,1,2029,725, -1,2466,3200,1,2031, -736,1,2032,741,1, -2033,746,1,2035,752, -1,2364,827,1,2715, -3195,1,2039,762,1, -1931,861,1,2041,768, -1,2043,774,1,2045, -779,1,2037,757,1, -2713,3206,1,2714,3183, -1,1574,799,1,2716, -3189,1,1958,3309,16, -0,122,1,2506,3310, +174,1,3,1,5, +1,4,3563,22,1, +8,1,48,3564,19, +385,1,48,3565,5, +54,1,0,3566,16, +0,383,1,2075,3567, +16,0,581,1,1860, +946,1,2842,3544,1, +1804,3568,16,0,581, +1,2844,3554,1,2413, +3569,16,0,581,1, +2198,3570,16,0,581, +1,1873,961,1,1657, +1019,1,2030,856,1, +1989,1041,1,1990,3571, +16,0,581,1,2755, +816,1,1775,3572,16, +0,581,1,32,3573, +16,0,581,1,2649, +832,1,2105,939,1, +2106,3574,16,0,581, +1,2764,3575,16,0, +383,1,2841,3538,1, +1574,924,1,2767,822, +1,2768,810,1,2227, +1033,1,2337,3576,16, +0,581,1,2783,3517, +1,1803,912,1,2458, +1001,1,1901,3577,16, +0,581,1,2462,1014, +1,2136,968,1,2464, +1024,1,2029,850,1, +2466,3532,1,2031,861, +1,2032,866,1,2033, +871,1,2035,877,1, +2364,952,1,2039,887, +1,1931,986,1,2041, +893,1,2021,843,1, +2043,899,1,2045,904, +1,2811,3559,1,2834, +3578,16,0,383,1, +2037,882,1,2822,3523, +1,2823,3579,16,0, +383,1,2843,3549,1, +1958,3580,16,0,581, +1,2459,1007,1,49, +3581,19,586,1,49, +3582,5,38,1,1901, +3583,16,0,584,1, +2075,3584,16,0,584, +1,1860,946,1,1803, +912,1,1804,3585,16, +0,584,1,2413,3586, +16,0,584,1,2198, +3587,16,0,584,1, +1873,961,1,1657,1019, +1,1989,1041,1,1990, +3588,16,0,584,1, +1775,3589,16,0,584, +1,32,3590,16,0, +584,1,2105,939,1, +2106,3591,16,0,584, +1,2364,952,1,2227, +1033,1,2337,3592,16, +0,584,1,2021,843, +1,2458,1001,1,2459, +1007,1,2462,1014,1, +2136,968,1,2464,1024, +1,2029,850,1,2030, +856,1,2031,861,1, +2032,866,1,2033,871, +1,2035,877,1,2037, +882,1,2039,887,1, +1931,986,1,2041,893, +1,2043,899,1,2045, +904,1,1574,924,1, +1958,3593,16,0,584, +1,50,3594,19,733, +1,50,3595,5,38, +1,1901,3596,16,0, +731,1,2075,3597,16, +0,731,1,1860,946, +1,1803,912,1,1804, +3598,16,0,731,1, +2413,3599,16,0,731, +1,2198,3600,16,0, +731,1,1873,961,1, +1657,1019,1,1989,1041, +1,1990,3601,16,0, +731,1,1775,3602,16, +0,731,1,32,3603, +16,0,731,1,2105, +939,1,2106,3604,16, +0,731,1,2364,952, +1,2227,1033,1,2337, +3605,16,0,731,1, +2021,843,1,2458,1001, +1,2459,1007,1,2462, +1014,1,2136,968,1, +2464,1024,1,2029,850, +1,2030,856,1,2031, +861,1,2032,866,1, +2033,871,1,2035,877, +1,2037,882,1,2039, +887,1,1931,986,1, +2041,893,1,2043,899, +1,2045,904,1,1574, +924,1,1958,3606,16, +0,731,1,51,3607, +19,127,1,51,3608, +5,58,1,0,3609, +16,0,125,1,2538, +3610,16,0,489,1, +2075,3611,16,0,125, +1,2841,3538,1,2515, +3612,16,0,489,1, +2843,3549,1,10,3613, +16,0,125,1,2413, +3614,16,0,125,1, +2523,3615,16,0,489, +1,2198,3616,16,0, +125,1,1873,961,1, +21,3617,16,0,125, +1,1657,1019,1,2029, +850,1,2030,856,1, +1989,1041,1,1990,3618, +16,0,125,1,2458, +1001,1,2459,1007,1, +1775,3619,16,0,125, +1,32,3620,16,0, +125,1,2105,939,1, +2106,3621,16,0,125, +1,2823,3622,16,0, +125,1,2770,3623,16, +0,125,1,2227,1033, +1,2337,3624,16,0, +125,1,52,3625,16, +0,125,1,2561,3626, +16,0,489,1,2783, +3517,1,1803,912,1, +1804,3627,16,0,125, +1,1901,3628,16,0, +125,1,2462,1014,1, +2136,968,1,2464,1024, +1,1860,946,1,2466, +3532,1,2031,861,1, +2032,866,1,2033,871, +1,2035,877,1,2364, +952,1,2039,887,1, +1931,986,1,2041,893, +1,2021,843,1,2043, +899,1,2045,904,1, +2511,3629,16,0,489, +1,2811,3559,1,2037, +882,1,2822,3523,1, +2842,3544,1,1574,924, +1,2844,3554,1,2582, +3630,16,0,125,1, +1958,3631,16,0,125, +1,52,3632,19,124, +1,52,3633,5,53, +1,0,3634,16,0, +122,1,2075,3635,16, +0,122,1,2841,3538, +1,2842,3544,1,1804, +3636,16,0,122,1, +10,3637,16,0,122, +1,2413,3638,16,0, +122,1,2198,3639,16, +0,122,1,1873,961, +1,21,3640,16,0, +122,1,1657,1019,1, +2029,850,1,2030,856, +1,1989,1041,1,1990, +3641,16,0,122,1, +2459,1007,1,1775,3642, +16,0,122,1,32, +3643,16,0,122,1, +2105,939,1,2106,3644, +16,0,122,1,1574, +924,1,2770,3645,16, +0,122,1,2227,1033, +1,2337,3646,16,0, +122,1,52,3647,16, +0,122,1,2783,3517, +1,1803,912,1,2458, +1001,1,1901,3648,16, +0,122,1,2462,1014, +1,2136,968,1,2464, +1024,1,1860,946,1, +2466,3532,1,2031,861, +1,2032,866,1,2033, +871,1,2035,877,1, +2364,952,1,2039,887, +1,1931,986,1,2041, +893,1,2021,843,1, +2043,899,1,2045,904, +1,2811,3559,1,2037, +882,1,2822,3523,1, +2823,3649,16,0,122, +1,2843,3549,1,2844, +3554,1,2582,3650,16, +0,122,1,1958,3651, 16,0,122,1,53, -3311,19,121,1,53, -3312,5,53,1,0, -3313,16,0,119,1, -2075,3314,16,0,119, -1,1860,821,1,1803, -787,1,1804,3315,16, -0,119,1,10,3316, +3652,19,121,1,53, +3653,5,53,1,0, +3654,16,0,119,1, +2075,3655,16,0,119, +1,2841,3538,1,2842, +3544,1,1804,3656,16, +0,119,1,10,3657, 16,0,119,1,2413, -3317,16,0,119,1, -2198,3318,16,0,119, -1,1873,835,1,21, -3319,16,0,119,1, -1657,894,1,2030,731, -1,2642,3320,16,0, -119,1,1989,916,1, -1990,3321,16,0,119, -1,2459,882,1,1775, -3322,16,0,119,1, -32,3323,16,0,119, -1,2105,814,1,2106, -3324,16,0,119,1, -2655,3211,1,2683,3223, -1,2227,908,1,2337, -3325,16,0,119,1, -52,3326,16,0,119, -1,2694,3216,1,2695, -3327,16,0,119,1, -2021,718,1,2458,876, -1,1901,3328,16,0, -119,1,2462,889,1, -2136,842,1,2464,899, -1,2029,725,1,2466, -3200,1,2031,736,1, -2032,741,1,2033,746, -1,2035,752,1,2364, -827,1,2715,3195,1, -2039,762,1,1931,861, -1,2041,768,1,2043, -774,1,2045,779,1, -2037,757,1,2713,3206, -1,2714,3183,1,1574, -799,1,2716,3189,1, -1958,3329,16,0,119, -1,2506,3330,16,0, -119,1,54,3331,19, -118,1,54,3332,5, -53,1,0,3333,16, -0,116,1,2075,3334, -16,0,116,1,1860, -821,1,1803,787,1, -1804,3335,16,0,116, -1,10,3336,16,0, -116,1,2413,3337,16, -0,116,1,2198,3338, +3658,16,0,119,1, +2198,3659,16,0,119, +1,1873,961,1,21, +3660,16,0,119,1, +1657,1019,1,2029,850, +1,2030,856,1,1989, +1041,1,1990,3661,16, +0,119,1,2459,1007, +1,1775,3662,16,0, +119,1,32,3663,16, +0,119,1,2105,939, +1,2106,3664,16,0, +119,1,1574,924,1, +2770,3665,16,0,119, +1,2227,1033,1,2337, +3666,16,0,119,1, +52,3667,16,0,119, +1,2783,3517,1,1803, +912,1,2458,1001,1, +1901,3668,16,0,119, +1,2462,1014,1,2136, +968,1,2464,1024,1, +1860,946,1,2466,3532, +1,2031,861,1,2032, +866,1,2033,871,1, +2035,877,1,2364,952, +1,2039,887,1,1931, +986,1,2041,893,1, +2021,843,1,2043,899, +1,2045,904,1,2811, +3559,1,2037,882,1, +2822,3523,1,2823,3669, +16,0,119,1,2843, +3549,1,2844,3554,1, +2582,3670,16,0,119, +1,1958,3671,16,0, +119,1,54,3672,19, +118,1,54,3673,5, +55,1,0,3674,16, +0,116,1,2075,3675, +16,0,116,1,2841, +3538,1,2842,3544,1, +1804,3676,16,0,116, +1,10,3677,16,0, +116,1,2413,3678,16, +0,116,1,2198,3679, 16,0,116,1,1873, -835,1,21,3339,16, -0,116,1,1657,894, -1,2030,731,1,2642, -3340,16,0,116,1, -1989,916,1,1990,3341, -16,0,116,1,2459, -882,1,1775,3342,16, -0,116,1,32,3343, -16,0,116,1,2105, -814,1,2106,3344,16, -0,116,1,2655,3211, -1,2683,3223,1,2227, -908,1,2337,3345,16, -0,116,1,52,3346, -16,0,116,1,2694, -3216,1,2695,3347,16, -0,116,1,2021,718, -1,2458,876,1,1901, -3348,16,0,116,1, -2462,889,1,2136,842, -1,2464,899,1,2029, -725,1,2466,3200,1, -2031,736,1,2032,741, -1,2033,746,1,2035, -752,1,2364,827,1, -2715,3195,1,2039,762, -1,1931,861,1,2041, -768,1,2043,774,1, -2045,779,1,2037,757, -1,2713,3206,1,2714, -3183,1,1574,799,1, -2716,3189,1,1958,3349, -16,0,116,1,2506, -3350,16,0,116,1, -55,3351,19,115,1, -55,3352,5,53,1, -0,3353,16,0,113, -1,2075,3354,16,0, -113,1,1860,821,1, -1803,787,1,1804,3355, -16,0,113,1,10, -3356,16,0,113,1, -2413,3357,16,0,113, -1,2198,3358,16,0, -113,1,1873,835,1, -21,3359,16,0,113, -1,1657,894,1,2030, -731,1,2642,3360,16, -0,113,1,1989,916, -1,1990,3361,16,0, -113,1,2459,882,1, -1775,3362,16,0,113, -1,32,3363,16,0, -113,1,2105,814,1, -2106,3364,16,0,113, -1,2655,3211,1,2683, -3223,1,2227,908,1, -2337,3365,16,0,113, -1,52,3366,16,0, -113,1,2694,3216,1, -2695,3367,16,0,113, -1,2021,718,1,2458, -876,1,1901,3368,16, -0,113,1,2462,889, -1,2136,842,1,2464, -899,1,2029,725,1, -2466,3200,1,2031,736, -1,2032,741,1,2033, -746,1,2035,752,1, -2364,827,1,2715,3195, -1,2039,762,1,1931, -861,1,2041,768,1, -2043,774,1,2045,779, -1,2037,757,1,2713, -3206,1,2714,3183,1, -1574,799,1,2716,3189, -1,1958,3369,16,0, -113,1,2506,3370,16, -0,113,1,56,3371, -19,112,1,56,3372, -5,53,1,0,3373, +961,1,21,3680,16, +0,116,1,1657,1019, +1,2029,850,1,2030, +856,1,1989,1041,1, +1990,3681,16,0,116, +1,2459,1007,1,1775, +3682,16,0,116,1, +32,3683,16,0,116, +1,2105,939,1,2106, +3684,16,0,116,1, +2021,843,1,1574,924, +1,2770,3685,16,0, +116,1,2227,1033,1, +2337,3686,16,0,116, +1,52,3687,16,0, +116,1,2783,3517,1, +1803,912,1,2458,1001, +1,1901,3688,16,0, +116,1,2569,3689,16, +0,483,1,2462,1014, +1,2136,968,1,2464, +1024,1,1860,946,1, +2466,3532,1,2031,861, +1,2032,866,1,2033, +871,1,2035,877,1, +2364,952,1,2039,887, +1,1931,986,1,2041, +893,1,2507,3690,16, +0,483,1,2043,899, +1,2045,904,1,2811, +3559,1,2037,882,1, +2822,3523,1,2823,3691, +16,0,116,1,2843, +3549,1,2844,3554,1, +2582,3692,16,0,116, +1,1958,3693,16,0, +116,1,55,3694,19, +115,1,55,3695,5, +56,1,0,3696,16, +0,113,1,2075,3697, +16,0,113,1,2841, +3538,1,2842,3544,1, +2843,3549,1,10,3698, +16,0,113,1,2413, +3699,16,0,113,1, +2198,3700,16,0,113, +1,2526,3701,16,0, +304,1,1873,961,1, +21,3702,16,0,113, +1,1657,1019,1,2530, +3703,16,0,304,1, +2030,856,1,1989,1041, +1,1990,3704,16,0, +113,1,2458,1001,1, +2459,1007,1,1775,3705, +16,0,113,1,32, +3706,16,0,113,1, +2105,939,1,2106,3707, +16,0,113,1,2770, +3708,16,0,113,1, +2553,3709,16,0,304, +1,2227,1033,1,2337, +3710,16,0,113,1, +52,3711,16,0,113, +1,2783,3517,1,1803, +912,1,1804,3712,16, +0,113,1,1901,3713, +16,0,113,1,2462, +1014,1,2136,968,1, +2464,1024,1,1860,946, +1,2466,3532,1,2031, +861,1,2032,866,1, +2033,871,1,2035,877, +1,2364,952,1,2039, +887,1,1931,986,1, +2041,893,1,2021,843, +1,2043,899,1,2045, +904,1,2811,3559,1, +2029,850,1,2037,882, +1,2822,3523,1,2823, +3714,16,0,113,1, +1574,924,1,2844,3554, +1,2582,3715,16,0, +113,1,1958,3716,16, +0,113,1,56,3717, +19,112,1,56,3718, +5,55,1,0,3719, 16,0,110,1,2075, -3374,16,0,110,1, -1860,821,1,1803,787, -1,1804,3375,16,0, -110,1,10,3376,16, -0,110,1,2413,3377, +3720,16,0,110,1, +2841,3538,1,2842,3544, +1,1804,3721,16,0, +110,1,10,3722,16, +0,110,1,2413,3723, 16,0,110,1,2198, -3378,16,0,110,1, -1873,835,1,21,3379, +3724,16,0,110,1, +1873,961,1,21,3725, 16,0,110,1,1657, -894,1,2030,731,1, -2642,3380,16,0,110, -1,1989,916,1,1990, -3381,16,0,110,1, -2459,882,1,1775,3382, -16,0,110,1,32, -3383,16,0,110,1, -2105,814,1,2106,3384, -16,0,110,1,2655, -3211,1,2683,3223,1, -2227,908,1,2337,3385, -16,0,110,1,52, -3386,16,0,110,1, -2694,3216,1,2695,3387, -16,0,110,1,2021, -718,1,2458,876,1, -1901,3388,16,0,110, -1,2462,889,1,2136, -842,1,2464,899,1, -2029,725,1,2466,3200, -1,2031,736,1,2032, -741,1,2033,746,1, -2035,752,1,2364,827, -1,2715,3195,1,2039, -762,1,1931,861,1, -2041,768,1,2043,774, -1,2045,779,1,2037, -757,1,2713,3206,1, -2714,3183,1,1574,799, -1,2716,3189,1,1958, -3389,16,0,110,1, -2506,3390,16,0,110, -1,57,3391,19,109, -1,57,3392,5,53, -1,0,3393,16,0, -107,1,2075,3394,16, -0,107,1,1860,821, -1,1803,787,1,1804, -3395,16,0,107,1, -10,3396,16,0,107, -1,2413,3397,16,0, -107,1,2198,3398,16, -0,107,1,1873,835, -1,21,3399,16,0, -107,1,1657,894,1, -2030,731,1,2642,3400, -16,0,107,1,1989, -916,1,1990,3401,16, -0,107,1,2459,882, -1,1775,3402,16,0, -107,1,32,3403,16, -0,107,1,2105,814, -1,2106,3404,16,0, -107,1,2655,3211,1, -2683,3223,1,2227,908, -1,2337,3405,16,0, -107,1,52,3406,16, -0,107,1,2694,3216, -1,2695,3407,16,0, -107,1,2021,718,1, -2458,876,1,1901,3408, -16,0,107,1,2462, -889,1,2136,842,1, -2464,899,1,2029,725, -1,2466,3200,1,2031, -736,1,2032,741,1, -2033,746,1,2035,752, -1,2364,827,1,2715, -3195,1,2039,762,1, -1931,861,1,2041,768, -1,2043,774,1,2045, -779,1,2037,757,1, -2713,3206,1,2714,3183, -1,1574,799,1,2716, -3189,1,1958,3409,16, -0,107,1,2506,3410, -16,0,107,1,58, -3411,19,429,1,58, -3412,5,9,1,2519, -1618,1,2557,1627,1, -2521,3413,16,0,427, -1,2559,1633,1,2597, -3414,16,0,427,1, -2561,3415,16,0,427, -1,2459,882,1,2464, -899,1,2470,3416,16, -0,427,1,59,3417, -19,426,1,59,3418, -5,9,1,2519,1618, -1,2557,1627,1,2521, -3419,16,0,424,1, -2559,1633,1,2597,3420, -16,0,424,1,2561, -3421,16,0,424,1, -2459,882,1,2464,899, -1,2470,3422,16,0, -424,1,60,3423,19, -423,1,60,3424,5, -9,1,2519,1618,1, -2557,1627,1,2521,3425, -16,0,421,1,2559, -1633,1,2597,3426,16, -0,421,1,2561,3427, -16,0,421,1,2459, -882,1,2464,899,1, -2470,3428,16,0,421, -1,61,3429,19,420, -1,61,3430,5,9, -1,2519,1618,1,2557, -1627,1,2521,3431,16, -0,418,1,2559,1633, -1,2597,3432,16,0, -418,1,2561,3433,16, -0,418,1,2459,882, -1,2464,899,1,2470, -3434,16,0,418,1, -62,3435,19,417,1, -62,3436,5,9,1, -2519,1618,1,2557,1627, -1,2521,3437,16,0, -415,1,2559,1633,1, -2597,3438,16,0,415, -1,2561,3439,16,0, -415,1,2459,882,1, -2464,899,1,2470,3440, -16,0,415,1,63, -3441,19,414,1,63, -3442,5,9,1,2519, -1618,1,2557,1627,1, -2521,3443,16,0,412, -1,2559,1633,1,2597, -3444,16,0,412,1, -2561,3445,16,0,412, -1,2459,882,1,2464, -899,1,2470,3446,16, -0,412,1,64,3447, -19,653,1,64,3448, -5,9,1,2519,1618, -1,2557,1627,1,2521, -3449,16,0,651,1, -2559,1633,1,2597,3450, -16,0,651,1,2561, -3451,16,0,651,1, -2459,882,1,2464,899, -1,2470,3452,16,0, -651,1,65,3453,19, -410,1,65,3454,5, -9,1,2519,1618,1, -2557,1627,1,2521,3455, -16,0,408,1,2559, -1633,1,2597,3456,16, -0,408,1,2561,3457, -16,0,408,1,2459, -882,1,2464,899,1, -2470,3458,16,0,408, -1,66,3459,19,493, -1,66,3460,5,9, -1,2519,1618,1,2557, -1627,1,2521,3461,16, -0,491,1,2559,1633, -1,2597,3462,16,0, -491,1,2561,3463,16, -0,491,1,2459,882, -1,2464,899,1,2470, -3464,16,0,491,1, -67,3465,19,406,1, -67,3466,5,9,1, -2519,1618,1,2557,1627, -1,2521,3467,16,0, -404,1,2559,1633,1, -2597,3468,16,0,404, -1,2561,3469,16,0, -404,1,2459,882,1, -2464,899,1,2470,3470, -16,0,404,1,68, -3471,19,403,1,68, -3472,5,9,1,2519, -1618,1,2557,1627,1, -2521,3473,16,0,401, -1,2559,1633,1,2597, -3474,16,0,401,1, -2561,3475,16,0,401, -1,2459,882,1,2464, -899,1,2470,3476,16, -0,401,1,69,3477, -19,486,1,69,3478, -5,9,1,2519,1618, -1,2557,1627,1,2521, -3479,16,0,484,1, -2559,1633,1,2597,3480, -16,0,484,1,2561, -3481,16,0,484,1, -2459,882,1,2464,899, -1,2470,3482,16,0, -484,1,70,3483,19, -399,1,70,3484,5, -9,1,2519,1618,1, -2557,1627,1,2521,3485, -16,0,397,1,2559, -1633,1,2597,3486,16, -0,397,1,2561,3487, -16,0,397,1,2459, -882,1,2464,899,1, -2470,3488,16,0,397, -1,71,3489,19,483, -1,71,3490,5,9, -1,2519,1618,1,2557, -1627,1,2521,3491,16, -0,481,1,2559,1633, -1,2597,3492,16,0, -481,1,2561,3493,16, -0,481,1,2459,882, -1,2464,899,1,2470, -3494,16,0,481,1, -72,3495,19,480,1, -72,3496,5,9,1, -2519,1618,1,2557,1627, -1,2521,3497,16,0, -478,1,2559,1633,1, -2597,3498,16,0,478, -1,2561,3499,16,0, -478,1,2459,882,1, -2464,899,1,2470,3500, -16,0,478,1,73, -3501,19,477,1,73, -3502,5,9,1,2519, -1618,1,2557,1627,1, -2521,3503,16,0,475, -1,2559,1633,1,2597, -3504,16,0,475,1, -2561,3505,16,0,475, -1,2459,882,1,2464, -899,1,2470,3506,16, -0,475,1,74,3507, -19,474,1,74,3508, -5,9,1,2519,1618, -1,2557,1627,1,2521, -3509,16,0,472,1, -2559,1633,1,2597,3510, -16,0,472,1,2561, -3511,16,0,472,1, -2459,882,1,2464,899, -1,2470,3512,16,0, -472,1,75,3513,19, -390,1,75,3514,5, -9,1,2519,1618,1, -2557,1627,1,2521,3515, -16,0,388,1,2559, -1633,1,2597,3516,16, -0,388,1,2561,3517, -16,0,388,1,2459, -882,1,2464,899,1, -2470,3518,16,0,388, -1,76,3519,19,387, -1,76,3520,5,9, -1,2519,1618,1,2557, -1627,1,2521,3521,16, -0,385,1,2559,1633, -1,2597,3522,16,0, -385,1,2561,3523,16, -0,385,1,2459,882, -1,2464,899,1,2470, -3524,16,0,385,1, -77,3525,19,471,1, -77,3526,5,9,1, -2519,1618,1,2557,1627, -1,2521,3527,16,0, -469,1,2559,1633,1, -2597,3528,16,0,469, -1,2561,3529,16,0, -469,1,2459,882,1, -2464,899,1,2470,3530, -16,0,469,1,78, -3531,19,566,1,78, -3532,5,9,1,2519, -1618,1,2557,1627,1, -2521,3533,16,0,564, -1,2559,1633,1,2597, -3534,16,0,564,1, -2561,3535,16,0,564, -1,2459,882,1,2464, -899,1,2470,3536,16, -0,564,1,79,3537, -19,380,1,79,3538, -5,9,1,2519,1618, -1,2557,1627,1,2521, -3539,16,0,378,1, -2559,1633,1,2597,3540, -16,0,378,1,2561, -3541,16,0,378,1, -2459,882,1,2464,899, -1,2470,3542,16,0, -378,1,80,3543,19, -377,1,80,3544,5, -9,1,2519,1618,1, -2557,1627,1,2521,3545, -16,0,375,1,2559, -1633,1,2597,3546,16, -0,375,1,2561,3547, -16,0,375,1,2459, -882,1,2464,899,1, -2470,3548,16,0,375, -1,81,3549,19,374, -1,81,3550,5,9, -1,2519,1618,1,2557, -1627,1,2521,3551,16, -0,372,1,2559,1633, -1,2597,3552,16,0, -372,1,2561,3553,16, -0,372,1,2459,882, -1,2464,899,1,2470, -3554,16,0,372,1, -82,3555,19,371,1, -82,3556,5,9,1, -2519,1618,1,2557,1627, -1,2521,3557,16,0, -369,1,2559,1633,1, -2597,3558,16,0,369, -1,2561,3559,16,0, -369,1,2459,882,1, -2464,899,1,2470,3560, -16,0,369,1,83, -3561,19,368,1,83, -3562,5,9,1,2519, -1618,1,2557,1627,1, -2521,3563,16,0,366, -1,2559,1633,1,2597, -3564,16,0,366,1, -2561,3565,16,0,366, -1,2459,882,1,2464, -899,1,2470,3566,16, -0,366,1,84,3567, -19,365,1,84,3568, -5,9,1,2519,1618, -1,2557,1627,1,2521, -3569,16,0,363,1, -2559,1633,1,2597,3570, -16,0,363,1,2561, -3571,16,0,363,1, -2459,882,1,2464,899, -1,2470,3572,16,0, -363,1,85,3573,19, -362,1,85,3574,5, -9,1,2519,1618,1, -2557,1627,1,2521,3575, -16,0,360,1,2559, -1633,1,2597,3576,16, -0,360,1,2561,3577, -16,0,360,1,2459, -882,1,2464,899,1, -2470,3578,16,0,360, -1,86,3579,19,359, -1,86,3580,5,9, -1,2519,1618,1,2557, -1627,1,2521,3581,16, -0,357,1,2559,1633, -1,2597,3582,16,0, -357,1,2561,3583,16, -0,357,1,2459,882, -1,2464,899,1,2470, -3584,16,0,357,1, -87,3585,19,356,1, -87,3586,5,9,1, -2519,1618,1,2557,1627, -1,2521,3587,16,0, -354,1,2559,1633,1, -2597,3588,16,0,354, -1,2561,3589,16,0, -354,1,2459,882,1, -2464,899,1,2470,3590, -16,0,354,1,88, -3591,19,353,1,88, -3592,5,9,1,2519, -1618,1,2557,1627,1, -2521,3593,16,0,351, -1,2559,1633,1,2597, -3594,16,0,351,1, -2561,3595,16,0,351, -1,2459,882,1,2464, -899,1,2470,3596,16, -0,351,1,89,3597, -19,347,1,89,3598, -5,9,1,2519,1618, -1,2557,1627,1,2521, -3599,16,0,345,1, -2559,1633,1,2597,3600, -16,0,345,1,2561, -3601,16,0,345,1, -2459,882,1,2464,899, -1,2470,3602,16,0, -345,1,90,3603,19, -350,1,90,3604,5, -9,1,2519,1618,1, -2557,1627,1,2521,3605, -16,0,348,1,2559, -1633,1,2597,3606,16, -0,348,1,2561,3607, -16,0,348,1,2459, -882,1,2464,899,1, -2470,3608,16,0,348, -1,91,3609,19,344, -1,91,3610,5,9, -1,2519,1618,1,2557, -1627,1,2521,3611,16, -0,342,1,2559,1633, -1,2597,3612,16,0, -342,1,2561,3613,16, -0,342,1,2459,882, -1,2464,899,1,2470, -3614,16,0,342,1, -92,3615,19,133,1, -92,3616,5,125,1, -0,3617,16,0,563, -1,1,1951,1,2, -1957,1,3,1962,1, -4,1967,1,5,1972, -1,6,1977,1,7, -1982,1,8,3618,16, -0,131,1,1515,3619, -16,0,165,1,2021, -718,1,2022,3620,16, -0,497,1,256,3621, -16,0,173,1,2025, -3622,16,0,501,1, -18,3623,16,0,138, -1,2027,3624,16,0, -505,1,2695,3625,16, -0,563,1,2029,725, -1,2030,731,1,2031, -736,1,2032,741,1, -2033,746,1,277,3626, -16,0,173,1,2035, -752,1,2037,757,1, -2039,762,1,32,3627, -16,0,165,1,2041, -768,1,2293,3628,16, -0,173,1,2043,774, -1,2045,779,1,2713, -3206,1,2715,3195,1, -41,3629,16,0,173, -1,1297,3630,16,0, -165,1,43,3631,16, -0,173,1,46,3632, -16,0,178,1,1804, -3633,16,0,165,1, -299,3634,16,0,173, -1,52,3635,16,0, -165,1,509,3636,16, -0,173,1,2318,3637, -16,0,165,1,62, -3638,16,0,195,1, -65,3639,16,0,197, -1,2075,3640,16,0, -165,1,1574,799,1, -71,3641,16,0,173, -1,1775,3642,16,0, -165,1,76,3643,16, -0,173,1,1834,3644, -16,0,165,1,2337, -3645,16,0,165,1, -79,3646,16,0,173, -1,1335,3647,16,0, -165,1,322,3648,16, -0,173,1,85,3649, -16,0,173,1,1261, -3650,16,0,165,1, -89,3651,16,0,173, -1,346,3652,16,0, -173,1,97,3653,16, -0,173,1,2106,3654, -16,0,165,1,102, -3655,16,0,173,1, -1860,821,1,1803,787, -1,2364,827,1,1113, -3656,16,0,158,1, -112,3657,16,0,173, -1,1117,3658,16,0, -165,1,1873,835,1, -1876,3659,16,0,165, -1,372,3660,16,0, -535,1,374,3661,16, -0,537,1,124,3662, -16,0,173,1,376, -3663,16,0,539,1, -378,3664,16,0,541, -1,2136,842,1,381, -3665,16,0,173,1, -525,3666,16,0,173, -1,137,3667,16,0, -173,1,1901,3668,16, -0,165,1,2655,3211, -1,2658,3669,16,0, -173,1,1153,3670,16, -0,165,1,151,3671, -16,0,173,1,1407, -3672,16,0,165,1, -1659,3673,16,0,165, -1,2413,3674,16,0, -165,1,406,3675,16, -0,173,1,1371,3676, -16,0,165,1,2105, -814,1,1657,894,1, -166,3677,16,0,173, -1,1622,3678,16,0, -173,1,2683,3223,1, -1931,861,1,1933,3679, -16,0,165,1,431, -3680,16,0,173,1, -1585,3681,16,0,173, -1,182,3682,16,0, -173,1,2694,3216,1, -1189,3683,16,0,165, -1,1443,3684,16,0, -165,1,1695,3685,16, -0,165,1,2198,3686, -16,0,165,1,447, -3687,16,0,173,1, -2458,876,1,2459,882, -1,1958,3688,16,0, -165,1,2462,889,1, -2714,3183,1,2464,899, -1,2716,3189,1,2466, -3200,1,459,3689,16, -0,173,1,2468,3690, -16,0,340,1,462, -3691,16,0,173,1, -199,3692,16,0,173, -1,217,3693,16,0, -173,1,2227,908,1, -1225,3694,16,0,165, -1,1479,3695,16,0, -165,1,1731,3696,16, -0,173,1,1989,916, -1,1990,3697,16,0, -165,1,236,3698,16, -0,173,1,1756,3699, -16,0,165,1,93, -3700,19,626,1,93, -3701,5,95,1,256, -3702,16,0,624,1, -1261,3703,16,0,624, -1,509,3704,16,0, -624,1,1515,3705,16, -0,624,1,2021,718, -1,1775,3706,16,0, -624,1,2029,725,1, -2030,731,1,2031,736, -1,2032,741,1,2033, -746,1,277,3707,16, -0,624,1,2035,752, -1,2037,757,1,2039, -762,1,32,3708,16, -0,624,1,2041,768, -1,2293,3709,16,0, -624,1,2043,774,1, -2045,779,1,41,3710, -16,0,624,1,1297, -3711,16,0,624,1, -43,3712,16,0,624, -1,1803,787,1,1804, -3713,16,0,624,1, -299,3714,16,0,624, -1,52,3715,16,0, -624,1,2318,3716,16, -0,624,1,62,3717, -16,0,624,1,2075, -3718,16,0,624,1, -1574,799,1,71,3719, -16,0,624,1,76, -3720,16,0,624,1, -1834,3721,16,0,624, -1,2337,3722,16,0, -624,1,79,3723,16, -0,624,1,1335,3724, -16,0,624,1,322, -3725,16,0,624,1, -85,3726,16,0,624, -1,89,3727,16,0, -624,1,346,3728,16, -0,624,1,2105,814, -1,2106,3729,16,0, -624,1,97,3730,16, -0,624,1,1860,821, -1,2364,827,1,102, -3731,16,0,624,1, -112,3732,16,0,624, -1,1117,3733,16,0, -624,1,1873,835,1, -1876,3734,16,0,624, -1,124,3735,16,0, -624,1,2136,842,1, -381,3736,16,0,624, -1,525,3737,16,0, -624,1,137,3738,16, -0,624,1,1901,3739, -16,0,624,1,2658, -3740,16,0,624,1, -1153,3741,16,0,624, -1,151,3742,16,0, -624,1,1407,3743,16, -0,624,1,1659,3744, -16,0,624,1,2413, -3745,16,0,624,1, -406,3746,16,0,624, -1,1371,3747,16,0, -624,1,166,3748,16, -0,624,1,1622,3749, -16,0,624,1,1931, -861,1,1933,3750,16, -0,624,1,431,3751, -16,0,624,1,1585, -3752,16,0,624,1, -182,3753,16,0,624, -1,1189,3754,16,0, -624,1,1443,3755,16, -0,624,1,1695,3756, -16,0,624,1,2198, -3757,16,0,624,1, -447,3758,16,0,624, -1,2458,876,1,2459, -882,1,1958,3759,16, -0,624,1,2462,889, -1,1657,894,1,2464, -899,1,199,3760,16, -0,624,1,459,3761, -16,0,624,1,462, -3762,16,0,624,1, -217,3763,16,0,624, -1,2227,908,1,1225, -3764,16,0,624,1, -1479,3765,16,0,624, -1,1731,3766,16,0, -624,1,1989,916,1, -1990,3767,16,0,624, -1,236,3768,16,0, -624,1,1756,3769,16, -0,624,1,94,3770, -19,623,1,94,3771, -5,95,1,256,3772, -16,0,621,1,1261, -3773,16,0,621,1, -509,3774,16,0,621, -1,1515,3775,16,0, -621,1,2021,718,1, -1775,3776,16,0,621, -1,2029,725,1,2030, -731,1,2031,736,1, -2032,741,1,2033,746, -1,277,3777,16,0, -621,1,2035,752,1, -2037,757,1,2039,762, -1,32,3778,16,0, -621,1,2041,768,1, -2293,3779,16,0,621, -1,2043,774,1,2045, -779,1,41,3780,16, -0,621,1,1297,3781, -16,0,621,1,43, -3782,16,0,621,1, -1803,787,1,1804,3783, -16,0,621,1,299, -3784,16,0,621,1, -52,3785,16,0,621, -1,2318,3786,16,0, -621,1,62,3787,16, -0,621,1,2075,3788, -16,0,621,1,1574, -799,1,71,3789,16, -0,621,1,76,3790, -16,0,621,1,1834, -3791,16,0,621,1, -2337,3792,16,0,621, -1,79,3793,16,0, -621,1,1335,3794,16, -0,621,1,322,3795, -16,0,621,1,85, -3796,16,0,621,1, -89,3797,16,0,621, -1,346,3798,16,0, -621,1,2105,814,1, -2106,3799,16,0,621, -1,97,3800,16,0, -621,1,1860,821,1, -2364,827,1,102,3801, -16,0,621,1,112, -3802,16,0,621,1, -1117,3803,16,0,621, -1,1873,835,1,1876, -3804,16,0,621,1, -124,3805,16,0,621, -1,2136,842,1,381, -3806,16,0,621,1, -525,3807,16,0,621, -1,137,3808,16,0, -621,1,1901,3809,16, -0,621,1,2658,3810, -16,0,621,1,1153, -3811,16,0,621,1, -151,3812,16,0,621, -1,1407,3813,16,0, -621,1,1659,3814,16, -0,621,1,2413,3815, -16,0,621,1,406, -3816,16,0,621,1, -1371,3817,16,0,621, -1,166,3818,16,0, -621,1,1622,3819,16, -0,621,1,1931,861, -1,1933,3820,16,0, -621,1,431,3821,16, -0,621,1,1585,3822, -16,0,621,1,182, -3823,16,0,621,1, -1189,3824,16,0,621, -1,1443,3825,16,0, -621,1,1695,3826,16, -0,621,1,2198,3827, -16,0,621,1,447, -3828,16,0,621,1, -2458,876,1,2459,882, -1,1958,3829,16,0, -621,1,2462,889,1, -1657,894,1,2464,899, -1,199,3830,16,0, -621,1,459,3831,16, -0,621,1,462,3832, -16,0,621,1,217, -3833,16,0,621,1, -2227,908,1,1225,3834, -16,0,621,1,1479, -3835,16,0,621,1, -1731,3836,16,0,621, -1,1989,916,1,1990, -3837,16,0,621,1, -236,3838,16,0,621, -1,1756,3839,16,0, -621,1,95,3840,19, -620,1,95,3841,5, -95,1,256,3842,16, -0,618,1,1261,3843, -16,0,618,1,509, -3844,16,0,618,1, -1515,3845,16,0,618, -1,2021,718,1,1775, -3846,16,0,618,1, -2029,725,1,2030,731, -1,2031,736,1,2032, -741,1,2033,746,1, -277,3847,16,0,618, -1,2035,752,1,2037, -757,1,2039,762,1, -32,3848,16,0,618, -1,2041,768,1,2293, -3849,16,0,618,1, -2043,774,1,2045,779, -1,41,3850,16,0, -618,1,1297,3851,16, -0,618,1,43,3852, -16,0,618,1,1803, -787,1,1804,3853,16, -0,618,1,299,3854, -16,0,618,1,52, -3855,16,0,618,1, -2318,3856,16,0,618, -1,62,3857,16,0, -618,1,2075,3858,16, -0,618,1,1574,799, -1,71,3859,16,0, -618,1,76,3860,16, -0,618,1,1834,3861, -16,0,618,1,2337, -3862,16,0,618,1, -79,3863,16,0,618, -1,1335,3864,16,0, -618,1,322,3865,16, -0,618,1,85,3866, -16,0,618,1,89, -3867,16,0,618,1, -346,3868,16,0,618, -1,2105,814,1,2106, -3869,16,0,618,1, -97,3870,16,0,618, -1,1860,821,1,2364, -827,1,102,3871,16, -0,618,1,112,3872, -16,0,618,1,1117, -3873,16,0,618,1, -1873,835,1,1876,3874, -16,0,618,1,124, -3875,16,0,618,1, -2136,842,1,381,3876, -16,0,618,1,525, -3877,16,0,618,1, -137,3878,16,0,618, -1,1901,3879,16,0, -618,1,2658,3880,16, -0,618,1,1153,3881, -16,0,618,1,151, -3882,16,0,618,1, -1407,3883,16,0,618, -1,1659,3884,16,0, -618,1,2413,3885,16, -0,618,1,406,3886, -16,0,618,1,1371, -3887,16,0,618,1, -166,3888,16,0,618, -1,1622,3889,16,0, -618,1,1931,861,1, -1933,3890,16,0,618, -1,431,3891,16,0, -618,1,1585,3892,16, -0,618,1,182,3893, -16,0,618,1,1189, -3894,16,0,618,1, -1443,3895,16,0,618, -1,1695,3896,16,0, -618,1,2198,3897,16, -0,618,1,447,3898, -16,0,618,1,2458, -876,1,2459,882,1, -1958,3899,16,0,618, -1,2462,889,1,1657, -894,1,2464,899,1, -199,3900,16,0,618, -1,459,3901,16,0, -618,1,462,3902,16, -0,618,1,217,3903, -16,0,618,1,2227, -908,1,1225,3904,16, -0,618,1,1479,3905, -16,0,618,1,1731, -3906,16,0,618,1, -1989,916,1,1990,3907, -16,0,618,1,236, -3908,16,0,618,1, -1756,3909,16,0,618, -1,96,3910,19,103, -1,96,3911,5,1, -1,0,3912,16,0, -104,1,97,3913,19, -611,1,97,3914,5, -1,1,0,3915,16, -0,609,1,98,3916, -19,636,1,98,3917, -5,2,1,0,3918, -16,0,638,1,2695, -3919,16,0,634,1, -99,3920,19,633,1, -99,3921,5,2,1, -0,3922,16,0,637, -1,2695,3923,16,0, -631,1,100,3924,19, -296,1,100,3925,5, -2,1,0,3926,16, -0,557,1,2695,3927, -16,0,294,1,101, -3928,19,561,1,101, -3929,5,4,1,0, -3930,16,0,641,1, -2695,3931,16,0,641, -1,2706,3932,16,0, -559,1,2636,3933,16, -0,559,1,102,3934, -19,591,1,102,3935, -5,2,1,2470,3936, -16,0,664,1,2561, -3937,16,0,589,1, -103,3938,19,463,1, -103,3939,5,4,1, -2597,3940,16,0,558, -1,2521,3941,16,0, -558,1,2470,3942,16, -0,461,1,2561,3943, -16,0,461,1,104, -3944,19,141,1,104, -3945,5,3,1,2642, -3946,16,0,569,1, -2506,3947,16,0,317, -1,10,3948,16,0, -139,1,105,3949,19, -151,1,105,3950,5, -17,1,0,3951,16, -0,254,1,2075,3952, -16,0,648,1,2337, -3953,16,0,648,1, -2413,3954,16,0,648, -1,10,3955,16,0, -336,1,2198,3956,16, -0,648,1,1901,3957, -16,0,648,1,2642, -3958,16,0,336,1, -21,3959,16,0,149, -1,2106,3960,16,0, -648,1,2506,3961,16, -0,336,1,1804,3962, -16,0,648,1,1990, -3963,16,0,648,1, -2695,3964,16,0,254, -1,32,3965,16,0, -648,1,1958,3966,16, -0,648,1,1775,3967, -16,0,648,1,106, -3968,19,130,1,106, -3969,5,18,1,0, -3970,16,0,128,1, -2642,3971,16,0,137, -1,2075,3972,16,0, -137,1,2337,3973,16, -0,137,1,2413,3974, -16,0,137,1,10, -3975,16,0,137,1, -2198,3976,16,0,137, -1,1901,3977,16,0, -137,1,52,3978,16, -0,193,1,21,3979, -16,0,137,1,2106, -3980,16,0,137,1, -2506,3981,16,0,137, -1,1804,3982,16,0, -137,1,1990,3983,16, -0,137,1,2695,3984, -16,0,128,1,32, -3985,16,0,137,1, -1958,3986,16,0,137, -1,1775,3987,16,0, -137,1,107,3988,19, -658,1,107,3989,5, -4,1,2597,3990,16, -0,656,1,2521,3991, -16,0,656,1,2470, -3992,16,0,656,1, -2561,3993,16,0,656, -1,108,3994,19,335, -1,108,3995,5,14, -1,2517,3996,16,0, -437,1,2075,3997,16, -0,506,1,2337,3998, -16,0,506,1,2413, -3999,16,0,506,1, -1901,4000,16,0,506, -1,2198,4001,16,0, -506,1,2106,4002,16, -0,506,1,2653,4003, -16,0,571,1,1804, -4004,16,0,506,1, -1990,4005,16,0,506, -1,31,4006,16,0, -333,1,32,4007,16, -0,506,1,1958,4008, -16,0,506,1,1775, -4009,16,0,506,1, -109,4010,19,302,1, -109,4011,5,1,1, -32,4012,16,0,300, -1,110,4013,19,261, -1,110,4014,5,11, -1,2075,4015,16,0, -577,1,2337,4016,16, -0,265,1,2413,4017, -16,0,445,1,1901, -4018,16,0,391,1, -2198,4019,16,0,319, -1,2106,4020,16,0, -607,1,1804,4021,16, -0,284,1,1990,4022, -16,0,494,1,32, -4023,16,0,329,1, -1958,4024,16,0,450, -1,1775,4025,16,0, -259,1,111,4026,19, -583,1,111,4027,5, -11,1,2075,4028,16, -0,581,1,2337,4029, -16,0,581,1,2413, -4030,16,0,581,1, -1901,4031,16,0,581, -1,2198,4032,16,0, -581,1,2106,4033,16, -0,581,1,1804,4034, -16,0,581,1,1990, -4035,16,0,581,1, -32,4036,16,0,581, -1,1958,4037,16,0, -581,1,1775,4038,16, -0,581,1,112,4039, -19,645,1,112,4040, -5,11,1,2075,4041, -16,0,643,1,2337, -4042,16,0,643,1, -2413,4043,16,0,643, -1,1901,4044,16,0, -643,1,2198,4045,16, -0,643,1,2106,4046, -16,0,643,1,1804, -4047,16,0,643,1, -1990,4048,16,0,643, -1,32,4049,16,0, -643,1,1958,4050,16, -0,643,1,1775,4051, -16,0,643,1,113, -4052,19,161,1,113, -4053,5,31,1,1901, -4054,16,0,647,1, -1479,4055,16,0,551, -1,2075,4056,16,0, -647,1,1695,4057,16, -0,189,1,1756,4058, -16,0,188,1,2413, -4059,16,0,647,1, -2198,4060,16,0,647, -1,1876,4061,16,0, -661,1,1659,4062,16, -0,188,1,1443,4063, -16,0,522,1,1117, -4064,16,0,159,1, -1990,4065,16,0,647, -1,1189,4066,16,0, -240,1,1775,4067,16, -0,647,1,32,4068, -16,0,647,1,2106, -4069,16,0,647,1, -1515,4070,16,0,579, -1,2337,4071,16,0, -647,1,52,4072,16, -0,592,1,1804,4073, -16,0,647,1,1261, -4074,16,0,298,1, -1153,4075,16,0,247, -1,1225,4076,16,0, -274,1,1335,4077,16, -0,443,1,1933,4078, -16,0,553,1,1834, -4079,16,0,312,1, -1297,4080,16,0,323, -1,1407,4081,16,0, -568,1,2318,4082,16, -0,188,1,1958,4083, -16,0,647,1,1371, -4084,16,0,438,1, -114,4085,19,531,1, -114,4086,5,11,1, -2075,4087,16,0,529, -1,2337,4088,16,0, -529,1,2413,4089,16, -0,529,1,1901,4090, -16,0,529,1,2198, -4091,16,0,529,1, -2106,4092,16,0,529, -1,1804,4093,16,0, -529,1,1990,4094,16, -0,529,1,32,4095, -16,0,529,1,1958, -4096,16,0,529,1, -1775,4097,16,0,529, -1,115,4098,19,527, -1,115,4099,5,11, -1,2075,4100,16,0, -525,1,2337,4101,16, -0,525,1,2413,4102, -16,0,525,1,1901, -4103,16,0,525,1, -2198,4104,16,0,525, -1,2106,4105,16,0, -525,1,1804,4106,16, -0,525,1,1990,4107, -16,0,525,1,32, -4108,16,0,525,1, -1958,4109,16,0,525, -1,1775,4110,16,0, -525,1,116,4111,19, -575,1,116,4112,5, -11,1,2075,4113,16, -0,573,1,2337,4114, -16,0,573,1,2413, -4115,16,0,573,1, -1901,4116,16,0,573, -1,2198,4117,16,0, -573,1,2106,4118,16, -0,573,1,1804,4119, -16,0,573,1,1990, -4120,16,0,573,1, -32,4121,16,0,573, -1,1958,4122,16,0, -573,1,1775,4123,16, -0,573,1,117,4124, -19,521,1,117,4125, -5,11,1,2075,4126, -16,0,519,1,2337, -4127,16,0,519,1, -2413,4128,16,0,519, -1,1901,4129,16,0, -519,1,2198,4130,16, -0,519,1,2106,4131, -16,0,519,1,1804, -4132,16,0,519,1, -1990,4133,16,0,519, -1,32,4134,16,0, -519,1,1958,4135,16, -0,519,1,1775,4136, -16,0,519,1,118, -4137,19,518,1,118, -4138,5,11,1,2075, -4139,16,0,516,1, -2337,4140,16,0,516, -1,2413,4141,16,0, -516,1,1901,4142,16, -0,516,1,2198,4143, -16,0,516,1,2106, -4144,16,0,516,1, -1804,4145,16,0,516, -1,1990,4146,16,0, -516,1,32,4147,16, -0,516,1,1958,4148, -16,0,516,1,1775, -4149,16,0,516,1, -119,4150,19,515,1, -119,4151,5,11,1, -2075,4152,16,0,513, -1,2337,4153,16,0, -513,1,2413,4154,16, -0,513,1,1901,4155, -16,0,513,1,2198, -4156,16,0,513,1, -2106,4157,16,0,513, -1,1804,4158,16,0, -513,1,1990,4159,16, -0,513,1,32,4160, -16,0,513,1,1958, -4161,16,0,513,1, -1775,4162,16,0,513, -1,120,4163,19,512, -1,120,4164,5,11, -1,2075,4165,16,0, -510,1,2337,4166,16, -0,510,1,2413,4167, -16,0,510,1,1901, -4168,16,0,510,1, -2198,4169,16,0,510, -1,2106,4170,16,0, -510,1,1804,4171,16, -0,510,1,1990,4172, -16,0,510,1,32, -4173,16,0,510,1, -1958,4174,16,0,510, -1,1775,4175,16,0, -510,1,121,4176,19, -509,1,121,4177,5, -11,1,2075,4178,16, -0,507,1,2337,4179, -16,0,507,1,2413, -4180,16,0,507,1, -1901,4181,16,0,507, -1,2198,4182,16,0, -507,1,2106,4183,16, -0,507,1,1804,4184, -16,0,507,1,1990, -4185,16,0,507,1, -32,4186,16,0,507, +1019,1,2029,850,1, +2030,856,1,1989,1041, +1,1990,3726,16,0, +110,1,2459,1007,1, +1775,3727,16,0,110, +1,32,3728,16,0, +110,1,2541,3729,16, +0,525,1,2106,3730, +16,0,110,1,2545, +3731,16,0,525,1, +1574,924,1,2770,3732, +16,0,110,1,2227, +1033,1,2337,3733,16, +0,110,1,52,3734, +16,0,110,1,2783, +3517,1,1803,912,1, +2458,1001,1,1901,3735, +16,0,110,1,2462, +1014,1,2136,968,1, +2464,1024,1,1860,946, +1,2466,3532,1,2031, +861,1,2032,866,1, +2033,871,1,2035,877, +1,2364,952,1,2039, +887,1,1931,986,1, +2041,893,1,2021,843, +1,2043,899,1,2045, +904,1,2811,3559,1, +2037,882,1,2822,3523, +1,2823,3736,16,0, +110,1,2843,3549,1, +2844,3554,1,2105,939, +1,2582,3737,16,0, +110,1,1958,3738,16, +0,110,1,57,3739, +19,109,1,57,3740, +5,53,1,0,3741, +16,0,107,1,2075, +3742,16,0,107,1, +2841,3538,1,2842,3544, +1,1804,3743,16,0, +107,1,10,3744,16, +0,107,1,2413,3745, +16,0,107,1,2198, +3746,16,0,107,1, +1873,961,1,21,3747, +16,0,107,1,1657, +1019,1,2029,850,1, +2030,856,1,1989,1041, +1,1990,3748,16,0, +107,1,2459,1007,1, +1775,3749,16,0,107, +1,32,3750,16,0, +107,1,2105,939,1, +2106,3751,16,0,107, +1,1574,924,1,2770, +3752,16,0,107,1, +2227,1033,1,2337,3753, +16,0,107,1,52, +3754,16,0,107,1, +2783,3517,1,1803,912, +1,2458,1001,1,1901, +3755,16,0,107,1, +2462,1014,1,2136,968, +1,2464,1024,1,1860, +946,1,2466,3532,1, +2031,861,1,2032,866, +1,2033,871,1,2035, +877,1,2364,952,1, +2039,887,1,1931,986, +1,2041,893,1,2021, +843,1,2043,899,1, +2045,904,1,2811,3559, +1,2037,882,1,2822, +3523,1,2823,3756,16, +0,107,1,2843,3549, +1,2844,3554,1,2582, +3757,16,0,107,1, +1958,3758,16,0,107, +1,58,3759,19,396, +1,58,3760,5,30, +1,2536,1750,1,2521, +1767,1,2641,1779,1, +2642,1784,1,2643,1756, +1,2644,1789,1,2645, +1794,1,2646,1799,1, +2647,1762,1,2648,1878, +1,2650,1811,1,2651, +1816,1,2652,1821,1, +2653,1826,1,2654,1831, +1,2655,1836,1,2656, +1841,1,2657,1774,1, +2659,3761,16,0,394, +1,2551,1852,1,2559, +1864,1,2567,1805,1, +2459,1007,1,2464,1024, +1,2575,1846,1,2470, +3762,16,0,394,1, +2580,1858,1,2703,3763, +16,0,394,1,2595, +1871,1,2597,3764,16, +0,394,1,59,3765, +19,393,1,59,3766, +5,30,1,2536,1750, +1,2521,1767,1,2641, +1779,1,2642,1784,1, +2643,1756,1,2644,1789, +1,2645,1794,1,2646, +1799,1,2647,1762,1, +2648,1878,1,2650,1811, +1,2651,1816,1,2652, +1821,1,2653,1826,1, +2654,1831,1,2655,1836, +1,2656,1841,1,2657, +1774,1,2659,3767,16, +0,391,1,2551,1852, +1,2559,1864,1,2567, +1805,1,2459,1007,1, +2464,1024,1,2575,1846, +1,2470,3768,16,0, +391,1,2580,1858,1, +2703,3769,16,0,391, +1,2595,1871,1,2597, +3770,16,0,391,1, +60,3771,19,557,1, +60,3772,5,30,1, +2536,1750,1,2521,1767, +1,2641,1779,1,2642, +1784,1,2643,1756,1, +2644,1789,1,2645,1794, +1,2646,1799,1,2647, +1762,1,2648,1878,1, +2650,1811,1,2651,1816, +1,2652,1821,1,2653, +1826,1,2654,1831,1, +2655,1836,1,2656,1841, +1,2657,1774,1,2659, +3773,16,0,555,1, +2551,1852,1,2559,1864, +1,2567,1805,1,2459, +1007,1,2464,1024,1, +2575,1846,1,2470,3774, +16,0,555,1,2580, +1858,1,2703,3775,16, +0,555,1,2595,1871, +1,2597,3776,16,0, +555,1,61,3777,19, +433,1,61,3778,5, +30,1,2536,1750,1, +2521,1767,1,2641,1779, +1,2642,1784,1,2643, +1756,1,2644,1789,1, +2645,1794,1,2646,1799, +1,2647,1762,1,2648, +1878,1,2650,1811,1, +2651,1816,1,2652,1821, +1,2653,1826,1,2654, +1831,1,2655,1836,1, +2656,1841,1,2657,1774, +1,2659,3779,16,0, +431,1,2551,1852,1, +2559,1864,1,2567,1805, +1,2459,1007,1,2464, +1024,1,2575,1846,1, +2470,3780,16,0,431, +1,2580,1858,1,2703, +3781,16,0,431,1, +2595,1871,1,2597,3782, +16,0,431,1,62, +3783,19,553,1,62, +3784,5,30,1,2536, +1750,1,2521,1767,1, +2641,1779,1,2642,1784, +1,2643,1756,1,2644, +1789,1,2645,1794,1, +2646,1799,1,2647,1762, +1,2648,1878,1,2650, +1811,1,2651,1816,1, +2652,1821,1,2653,1826, +1,2654,1831,1,2655, +1836,1,2656,1841,1, +2657,1774,1,2659,3785, +16,0,551,1,2551, +1852,1,2559,1864,1, +2567,1805,1,2459,1007, +1,2464,1024,1,2575, +1846,1,2470,3786,16, +0,551,1,2580,1858, +1,2703,3787,16,0, +551,1,2595,1871,1, +2597,3788,16,0,551, +1,63,3789,19,666, +1,63,3790,5,30, +1,2536,1750,1,2521, +1767,1,2641,1779,1, +2642,1784,1,2643,1756, +1,2644,1789,1,2645, +1794,1,2646,1799,1, +2647,1762,1,2648,1878, +1,2650,1811,1,2651, +1816,1,2652,1821,1, +2653,1826,1,2654,1831, +1,2655,1836,1,2656, +1841,1,2657,1774,1, +2659,3791,16,0,664, +1,2551,1852,1,2559, +1864,1,2567,1805,1, +2459,1007,1,2464,1024, +1,2575,1846,1,2470, +3792,16,0,664,1, +2580,1858,1,2703,3793, +16,0,664,1,2595, +1871,1,2597,3794,16, +0,664,1,64,3795, +19,426,1,64,3796, +5,30,1,2536,1750, +1,2521,1767,1,2641, +1779,1,2642,1784,1, +2643,1756,1,2644,1789, +1,2645,1794,1,2646, +1799,1,2647,1762,1, +2648,1878,1,2650,1811, +1,2651,1816,1,2652, +1821,1,2653,1826,1, +2654,1831,1,2655,1836, +1,2656,1841,1,2657, +1774,1,2659,3797,16, +0,424,1,2551,1852, +1,2559,1864,1,2567, +1805,1,2459,1007,1, +2464,1024,1,2575,1846, +1,2470,3798,16,0, +424,1,2580,1858,1, +2703,3799,16,0,424, +1,2595,1871,1,2597, +3800,16,0,424,1, +65,3801,19,390,1, +65,3802,5,30,1, +2536,1750,1,2521,1767, +1,2641,1779,1,2642, +1784,1,2643,1756,1, +2644,1789,1,2645,1794, +1,2646,1799,1,2647, +1762,1,2648,1878,1, +2650,1811,1,2651,1816, +1,2652,1821,1,2653, +1826,1,2654,1831,1, +2655,1836,1,2656,1841, +1,2657,1774,1,2659, +3803,16,0,388,1, +2551,1852,1,2559,1864, +1,2567,1805,1,2459, +1007,1,2464,1024,1, +2575,1846,1,2470,3804, +16,0,388,1,2580, +1858,1,2703,3805,16, +0,388,1,2595,1871, +1,2597,3806,16,0, +388,1,66,3807,19, +778,1,66,3808,5, +30,1,2536,1750,1, +2521,1767,1,2641,1779, +1,2642,1784,1,2643, +1756,1,2644,1789,1, +2645,1794,1,2646,1799, +1,2647,1762,1,2648, +1878,1,2650,1811,1, +2651,1816,1,2652,1821, +1,2653,1826,1,2654, +1831,1,2655,1836,1, +2656,1841,1,2657,1774, +1,2659,3809,16,0, +776,1,2551,1852,1, +2559,1864,1,2567,1805, +1,2459,1007,1,2464, +1024,1,2575,1846,1, +2470,3810,16,0,776, +1,2580,1858,1,2703, +3811,16,0,776,1, +2595,1871,1,2597,3812, +16,0,776,1,67, +3813,19,475,1,67, +3814,5,30,1,2536, +1750,1,2521,1767,1, +2641,1779,1,2642,1784, +1,2643,1756,1,2644, +1789,1,2645,1794,1, +2646,1799,1,2647,1762, +1,2648,1878,1,2650, +1811,1,2651,1816,1, +2652,1821,1,2653,1826, +1,2654,1831,1,2655, +1836,1,2656,1841,1, +2657,1774,1,2659,3815, +16,0,473,1,2551, +1852,1,2559,1864,1, +2567,1805,1,2459,1007, +1,2464,1024,1,2575, +1846,1,2470,3816,16, +0,473,1,2580,1858, +1,2703,3817,16,0, +473,1,2595,1871,1, +2597,3818,16,0,473, +1,68,3819,19,472, +1,68,3820,5,30, +1,2536,1750,1,2521, +1767,1,2641,1779,1, +2642,1784,1,2643,1756, +1,2644,1789,1,2645, +1794,1,2646,1799,1, +2647,1762,1,2648,1878, +1,2650,1811,1,2651, +1816,1,2652,1821,1, +2653,1826,1,2654,1831, +1,2655,1836,1,2656, +1841,1,2657,1774,1, +2659,3821,16,0,470, +1,2551,1852,1,2559, +1864,1,2567,1805,1, +2459,1007,1,2464,1024, +1,2575,1846,1,2470, +3822,16,0,470,1, +2580,1858,1,2703,3823, +16,0,470,1,2595, +1871,1,2597,3824,16, +0,470,1,69,3825, +19,405,1,69,3826, +5,30,1,2536,1750, +1,2521,1767,1,2641, +1779,1,2642,1784,1, +2643,1756,1,2644,1789, +1,2645,1794,1,2646, +1799,1,2647,1762,1, +2648,1878,1,2650,1811, +1,2651,1816,1,2652, +1821,1,2653,1826,1, +2654,1831,1,2655,1836, +1,2656,1841,1,2657, +1774,1,2659,3827,16, +0,403,1,2551,1852, +1,2559,1864,1,2567, +1805,1,2459,1007,1, +2464,1024,1,2575,1846, +1,2470,3828,16,0, +403,1,2580,1858,1, +2703,3829,16,0,403, +1,2595,1871,1,2597, +3830,16,0,403,1, +70,3831,19,402,1, +70,3832,5,30,1, +2536,1750,1,2521,1767, +1,2641,1779,1,2642, +1784,1,2643,1756,1, +2644,1789,1,2645,1794, +1,2646,1799,1,2647, +1762,1,2648,1878,1, +2650,1811,1,2651,1816, +1,2652,1821,1,2653, +1826,1,2654,1831,1, +2655,1836,1,2656,1841, +1,2657,1774,1,2659, +3833,16,0,400,1, +2551,1852,1,2559,1864, +1,2567,1805,1,2459, +1007,1,2464,1024,1, +2575,1846,1,2470,3834, +16,0,400,1,2580, +1858,1,2703,3835,16, +0,400,1,2595,1871, +1,2597,3836,16,0, +400,1,71,3837,19, +399,1,71,3838,5, +30,1,2536,1750,1, +2521,1767,1,2641,1779, +1,2642,1784,1,2643, +1756,1,2644,1789,1, +2645,1794,1,2646,1799, +1,2647,1762,1,2648, +1878,1,2650,1811,1, +2651,1816,1,2652,1821, +1,2653,1826,1,2654, +1831,1,2655,1836,1, +2656,1841,1,2657,1774, +1,2659,3839,16,0, +397,1,2551,1852,1, +2559,1864,1,2567,1805, +1,2459,1007,1,2464, +1024,1,2575,1846,1, +2470,3840,16,0,397, +1,2580,1858,1,2703, +3841,16,0,397,1, +2595,1871,1,2597,3842, +16,0,397,1,72, +3843,19,469,1,72, +3844,5,30,1,2536, +1750,1,2521,1767,1, +2641,1779,1,2642,1784, +1,2643,1756,1,2644, +1789,1,2645,1794,1, +2646,1799,1,2647,1762, +1,2648,1878,1,2650, +1811,1,2651,1816,1, +2652,1821,1,2653,1826, +1,2654,1831,1,2655, +1836,1,2656,1841,1, +2657,1774,1,2659,3845, +16,0,467,1,2551, +1852,1,2559,1864,1, +2567,1805,1,2459,1007, +1,2464,1024,1,2575, +1846,1,2470,3846,16, +0,467,1,2580,1858, +1,2703,3847,16,0, +467,1,2595,1871,1, +2597,3848,16,0,467, +1,73,3849,19,466, +1,73,3850,5,30, +1,2536,1750,1,2521, +1767,1,2641,1779,1, +2642,1784,1,2643,1756, +1,2644,1789,1,2645, +1794,1,2646,1799,1, +2647,1762,1,2648,1878, +1,2650,1811,1,2651, +1816,1,2652,1821,1, +2653,1826,1,2654,1831, +1,2655,1836,1,2656, +1841,1,2657,1774,1, +2659,3851,16,0,464, +1,2551,1852,1,2559, +1864,1,2567,1805,1, +2459,1007,1,2464,1024, +1,2575,1846,1,2470, +3852,16,0,464,1, +2580,1858,1,2703,3853, +16,0,464,1,2595, +1871,1,2597,3854,16, +0,464,1,74,3855, +19,463,1,74,3856, +5,30,1,2536,1750, +1,2521,1767,1,2641, +1779,1,2642,1784,1, +2643,1756,1,2644,1789, +1,2645,1794,1,2646, +1799,1,2647,1762,1, +2648,1878,1,2650,1811, +1,2651,1816,1,2652, +1821,1,2653,1826,1, +2654,1831,1,2655,1836, +1,2656,1841,1,2657, +1774,1,2659,3857,16, +0,461,1,2551,1852, +1,2559,1864,1,2567, +1805,1,2459,1007,1, +2464,1024,1,2575,1846, +1,2470,3858,16,0, +461,1,2580,1858,1, +2703,3859,16,0,461, +1,2595,1871,1,2597, +3860,16,0,461,1, +75,3861,19,449,1, +75,3862,5,30,1, +2536,1750,1,2521,1767, +1,2641,1779,1,2642, +1784,1,2643,1756,1, +2644,1789,1,2645,1794, +1,2646,1799,1,2647, +1762,1,2648,1878,1, +2650,1811,1,2651,1816, +1,2652,1821,1,2653, +1826,1,2654,1831,1, +2655,1836,1,2656,1841, +1,2657,1774,1,2659, +3863,16,0,447,1, +2551,1852,1,2559,1864, +1,2567,1805,1,2459, +1007,1,2464,1024,1, +2575,1846,1,2470,3864, +16,0,447,1,2580, +1858,1,2703,3865,16, +0,447,1,2595,1871, +1,2597,3866,16,0, +447,1,76,3867,19, +570,1,76,3868,5, +30,1,2536,1750,1, +2521,1767,1,2641,1779, +1,2642,1784,1,2643, +1756,1,2644,1789,1, +2645,1794,1,2646,1799, +1,2647,1762,1,2648, +1878,1,2650,1811,1, +2651,1816,1,2652,1821, +1,2653,1826,1,2654, +1831,1,2655,1836,1, +2656,1841,1,2657,1774, +1,2659,3869,16,0, +568,1,2551,1852,1, +2559,1864,1,2567,1805, +1,2459,1007,1,2464, +1024,1,2575,1846,1, +2470,3870,16,0,568, +1,2580,1858,1,2703, +3871,16,0,568,1, +2595,1871,1,2597,3872, +16,0,568,1,77, +3873,19,445,1,77, +3874,5,30,1,2536, +1750,1,2521,1767,1, +2641,1779,1,2642,1784, +1,2643,1756,1,2644, +1789,1,2645,1794,1, +2646,1799,1,2647,1762, +1,2648,1878,1,2650, +1811,1,2651,1816,1, +2652,1821,1,2653,1826, +1,2654,1831,1,2655, +1836,1,2656,1841,1, +2657,1774,1,2659,3875, +16,0,443,1,2551, +1852,1,2559,1864,1, +2567,1805,1,2459,1007, +1,2464,1024,1,2575, +1846,1,2470,3876,16, +0,443,1,2580,1858, +1,2703,3877,16,0, +443,1,2595,1871,1, +2597,3878,16,0,443, +1,78,3879,19,566, +1,78,3880,5,30, +1,2536,1750,1,2521, +1767,1,2641,1779,1, +2642,1784,1,2643,1756, +1,2644,1789,1,2645, +1794,1,2646,1799,1, +2647,1762,1,2648,1878, +1,2650,1811,1,2651, +1816,1,2652,1821,1, +2653,1826,1,2654,1831, +1,2655,1836,1,2656, +1841,1,2657,1774,1, +2659,3881,16,0,564, +1,2551,1852,1,2559, +1864,1,2567,1805,1, +2459,1007,1,2464,1024, +1,2575,1846,1,2470, +3882,16,0,564,1, +2580,1858,1,2703,3883, +16,0,564,1,2595, +1871,1,2597,3884,16, +0,564,1,79,3885, +19,563,1,79,3886, +5,30,1,2536,1750, +1,2521,1767,1,2641, +1779,1,2642,1784,1, +2643,1756,1,2644,1789, +1,2645,1794,1,2646, +1799,1,2647,1762,1, +2648,1878,1,2650,1811, +1,2651,1816,1,2652, +1821,1,2653,1826,1, +2654,1831,1,2655,1836, +1,2656,1841,1,2657, +1774,1,2659,3887,16, +0,561,1,2551,1852, +1,2559,1864,1,2567, +1805,1,2459,1007,1, +2464,1024,1,2575,1846, +1,2470,3888,16,0, +561,1,2580,1858,1, +2703,3889,16,0,561, +1,2595,1871,1,2597, +3890,16,0,561,1, +80,3891,19,436,1, +80,3892,5,30,1, +2536,1750,1,2521,1767, +1,2641,1779,1,2642, +1784,1,2643,1756,1, +2644,1789,1,2645,1794, +1,2646,1799,1,2647, +1762,1,2648,1878,1, +2650,1811,1,2651,1816, +1,2652,1821,1,2653, +1826,1,2654,1831,1, +2655,1836,1,2656,1841, +1,2657,1774,1,2659, +3893,16,0,434,1, +2551,1852,1,2559,1864, +1,2567,1805,1,2459, +1007,1,2464,1024,1, +2575,1846,1,2470,3894, +16,0,434,1,2580, +1858,1,2703,3895,16, +0,434,1,2595,1871, +1,2597,3896,16,0, +434,1,81,3897,19, +423,1,81,3898,5, +30,1,2536,1750,1, +2521,1767,1,2641,1779, +1,2642,1784,1,2643, +1756,1,2644,1789,1, +2645,1794,1,2646,1799, +1,2647,1762,1,2648, +1878,1,2650,1811,1, +2651,1816,1,2652,1821, +1,2653,1826,1,2654, +1831,1,2655,1836,1, +2656,1841,1,2657,1774, +1,2659,3899,16,0, +421,1,2551,1852,1, +2559,1864,1,2567,1805, +1,2459,1007,1,2464, +1024,1,2575,1846,1, +2470,3900,16,0,421, +1,2580,1858,1,2703, +3901,16,0,421,1, +2595,1871,1,2597,3902, +16,0,421,1,82, +3903,19,460,1,82, +3904,5,30,1,2536, +1750,1,2521,1767,1, +2641,1779,1,2642,1784, +1,2643,1756,1,2644, +1789,1,2645,1794,1, +2646,1799,1,2647,1762, +1,2648,1878,1,2650, +1811,1,2651,1816,1, +2652,1821,1,2653,1826, +1,2654,1831,1,2655, +1836,1,2656,1841,1, +2657,1774,1,2659,3905, +16,0,458,1,2551, +1852,1,2559,1864,1, +2567,1805,1,2459,1007, +1,2464,1024,1,2575, +1846,1,2470,3906,16, +0,458,1,2580,1858, +1,2703,3907,16,0, +458,1,2595,1871,1, +2597,3908,16,0,458, +1,83,3909,19,420, +1,83,3910,5,30, +1,2536,1750,1,2521, +1767,1,2641,1779,1, +2642,1784,1,2643,1756, +1,2644,1789,1,2645, +1794,1,2646,1799,1, +2647,1762,1,2648,1878, +1,2650,1811,1,2651, +1816,1,2652,1821,1, +2653,1826,1,2654,1831, +1,2655,1836,1,2656, +1841,1,2657,1774,1, +2659,3911,16,0,418, +1,2551,1852,1,2559, +1864,1,2567,1805,1, +2459,1007,1,2464,1024, +1,2575,1846,1,2470, +3912,16,0,418,1, +2580,1858,1,2703,3913, +16,0,418,1,2595, +1871,1,2597,3914,16, +0,418,1,84,3915, +19,417,1,84,3916, +5,30,1,2536,1750, +1,2521,1767,1,2641, +1779,1,2642,1784,1, +2643,1756,1,2644,1789, +1,2645,1794,1,2646, +1799,1,2647,1762,1, +2648,1878,1,2650,1811, +1,2651,1816,1,2652, +1821,1,2653,1826,1, +2654,1831,1,2655,1836, +1,2656,1841,1,2657, +1774,1,2659,3917,16, +0,415,1,2551,1852, +1,2559,1864,1,2567, +1805,1,2459,1007,1, +2464,1024,1,2575,1846, +1,2470,3918,16,0, +415,1,2580,1858,1, +2703,3919,16,0,415, +1,2595,1871,1,2597, +3920,16,0,415,1, +85,3921,19,578,1, +85,3922,5,30,1, +2536,1750,1,2521,1767, +1,2641,1779,1,2642, +1784,1,2643,1756,1, +2644,1789,1,2645,1794, +1,2646,1799,1,2647, +1762,1,2648,1878,1, +2650,1811,1,2651,1816, +1,2652,1821,1,2653, +1826,1,2654,1831,1, +2655,1836,1,2656,1841, +1,2657,1774,1,2659, +3923,16,0,576,1, +2551,1852,1,2559,1864, +1,2567,1805,1,2459, +1007,1,2464,1024,1, +2575,1846,1,2470,3924, +16,0,576,1,2580, +1858,1,2703,3925,16, +0,576,1,2595,1871, +1,2597,3926,16,0, +576,1,86,3927,19, +452,1,86,3928,5, +30,1,2536,1750,1, +2521,1767,1,2641,1779, +1,2642,1784,1,2643, +1756,1,2644,1789,1, +2645,1794,1,2646,1799, +1,2647,1762,1,2648, +1878,1,2650,1811,1, +2651,1816,1,2652,1821, +1,2653,1826,1,2654, +1831,1,2655,1836,1, +2656,1841,1,2657,1774, +1,2659,3929,16,0, +450,1,2551,1852,1, +2559,1864,1,2567,1805, +1,2459,1007,1,2464, +1024,1,2575,1846,1, +2470,3930,16,0,450, +1,2580,1858,1,2703, +3931,16,0,450,1, +2595,1871,1,2597,3932, +16,0,450,1,87, +3933,19,560,1,87, +3934,5,30,1,2536, +1750,1,2521,1767,1, +2641,1779,1,2642,1784, +1,2643,1756,1,2644, +1789,1,2645,1794,1, +2646,1799,1,2647,1762, +1,2648,1878,1,2650, +1811,1,2651,1816,1, +2652,1821,1,2653,1826, +1,2654,1831,1,2655, +1836,1,2656,1841,1, +2657,1774,1,2659,3935, +16,0,558,1,2551, +1852,1,2559,1864,1, +2567,1805,1,2459,1007, +1,2464,1024,1,2575, +1846,1,2470,3936,16, +0,558,1,2580,1858, +1,2703,3937,16,0, +558,1,2595,1871,1, +2597,3938,16,0,558, +1,88,3939,19,414, +1,88,3940,5,30, +1,2536,1750,1,2521, +1767,1,2641,1779,1, +2642,1784,1,2643,1756, +1,2644,1789,1,2645, +1794,1,2646,1799,1, +2647,1762,1,2648,1878, +1,2650,1811,1,2651, +1816,1,2652,1821,1, +2653,1826,1,2654,1831, +1,2655,1836,1,2656, +1841,1,2657,1774,1, +2659,3941,16,0,412, +1,2551,1852,1,2559, +1864,1,2567,1805,1, +2459,1007,1,2464,1024, +1,2575,1846,1,2470, +3942,16,0,412,1, +2580,1858,1,2703,3943, +16,0,412,1,2595, +1871,1,2597,3944,16, +0,412,1,89,3945, +19,408,1,89,3946, +5,30,1,2536,1750, +1,2521,1767,1,2641, +1779,1,2642,1784,1, +2643,1756,1,2644,1789, +1,2645,1794,1,2646, +1799,1,2647,1762,1, +2648,1878,1,2650,1811, +1,2651,1816,1,2652, +1821,1,2653,1826,1, +2654,1831,1,2655,1836, +1,2656,1841,1,2657, +1774,1,2659,3947,16, +0,406,1,2551,1852, +1,2559,1864,1,2567, +1805,1,2459,1007,1, +2464,1024,1,2575,1846, +1,2470,3948,16,0, +406,1,2580,1858,1, +2703,3949,16,0,406, +1,2595,1871,1,2597, +3950,16,0,406,1, +90,3951,19,411,1, +90,3952,5,30,1, +2536,1750,1,2521,1767, +1,2641,1779,1,2642, +1784,1,2643,1756,1, +2644,1789,1,2645,1794, +1,2646,1799,1,2647, +1762,1,2648,1878,1, +2650,1811,1,2651,1816, +1,2652,1821,1,2653, +1826,1,2654,1831,1, +2655,1836,1,2656,1841, +1,2657,1774,1,2659, +3953,16,0,409,1, +2551,1852,1,2559,1864, +1,2567,1805,1,2459, +1007,1,2464,1024,1, +2575,1846,1,2470,3954, +16,0,409,1,2580, +1858,1,2703,3955,16, +0,409,1,2595,1871, +1,2597,3956,16,0, +409,1,91,3957,19, +768,1,91,3958,5, +30,1,2536,1750,1, +2521,1767,1,2641,1779, +1,2642,1784,1,2643, +1756,1,2644,1789,1, +2645,1794,1,2646,1799, +1,2647,1762,1,2648, +1878,1,2650,1811,1, +2651,1816,1,2652,1821, +1,2653,1826,1,2654, +1831,1,2655,1836,1, +2656,1841,1,2657,1774, +1,2659,3959,16,0, +766,1,2551,1852,1, +2559,1864,1,2567,1805, +1,2459,1007,1,2464, +1024,1,2575,1846,1, +2470,3960,16,0,766, +1,2580,1858,1,2703, +3961,16,0,766,1, +2595,1871,1,2597,3962, +16,0,766,1,92, +3963,19,456,1,92, +3964,5,30,1,2536, +1750,1,2521,1767,1, +2641,1779,1,2642,1784, +1,2643,1756,1,2644, +1789,1,2645,1794,1, +2646,1799,1,2647,1762, +1,2648,1878,1,2650, +1811,1,2651,1816,1, +2652,1821,1,2653,1826, +1,2654,1831,1,2655, +1836,1,2656,1841,1, +2657,1774,1,2659,3965, +16,0,454,1,2551, +1852,1,2559,1864,1, +2567,1805,1,2459,1007, +1,2464,1024,1,2575, +1846,1,2470,3966,16, +0,454,1,2580,1858, +1,2703,3967,16,0, +454,1,2595,1871,1, +2597,3968,16,0,454, +1,93,3969,19,133, +1,93,3970,5,129, +1,0,3971,16,0, +789,1,1,2244,1, +2,2250,1,3,2255, +1,4,2260,1,5, +2265,1,6,2270,1, +7,2275,1,8,3972, +16,0,131,1,1515, +3973,16,0,181,1, +2021,843,1,2022,3974, +16,0,583,1,256, +3975,16,0,189,1, +2527,3976,16,0,311, +1,18,3977,16,0, +138,1,2027,3978,16, +0,591,1,2029,850, +1,2030,856,1,2031, +861,1,2032,866,1, +2786,3979,16,0,189, +1,277,3980,16,0, +189,1,2035,877,1, +2037,882,1,2039,887, +1,32,3981,16,0, +181,1,2041,893,1, +2293,3982,16,0,189, +1,2043,899,1,2045, +904,1,41,3983,16, +0,189,1,1297,3984, +16,0,181,1,43, +3985,16,0,189,1, +46,3986,16,0,194, +1,1804,3987,16,0, +181,1,299,3988,16, +0,189,1,2811,3559, +1,52,3989,16,0, +181,1,509,3990,16, +0,189,1,2318,3991, +16,0,181,1,2822, +3523,1,62,3992,16, +0,218,1,65,3993, +16,0,220,1,2075, +3994,16,0,181,1, +1574,924,1,71,3995, +16,0,189,1,1775, +3996,16,0,181,1, +76,3997,16,0,189, +1,1834,3998,16,0, +181,1,2337,3999,16, +0,181,1,79,4000, +16,0,189,1,1335, +4001,16,0,181,1, +2842,3544,1,2843,3549, +1,2844,3554,1,85, +4002,16,0,189,1, +1261,4003,16,0,181, +1,89,4004,16,0, +189,1,2033,871,1, +322,4005,16,0,189, +1,97,4006,16,0, +189,1,2106,4007,16, +0,181,1,102,4008, +16,0,189,1,1860, +946,1,1803,912,1, +2364,952,1,346,4009, +16,0,189,1,1113, +4010,16,0,173,1, +2783,3517,1,112,4011, +16,0,189,1,1117, +4012,16,0,181,1, +1371,4013,16,0,181, +1,1876,4014,16,0, +181,1,372,4015,16, +0,621,1,374,4016, +16,0,623,1,124, +4017,16,0,189,1, +376,4018,16,0,625, +1,378,4019,16,0, +627,1,2136,968,1, +381,4020,16,0,189, +1,525,4021,16,0, +189,1,137,4022,16, +0,189,1,1901,4023, +16,0,181,1,2025, +4024,16,0,587,1, +1153,4025,16,0,181, +1,151,4026,16,0, +189,1,1407,4027,16, +0,181,1,1659,4028, +16,0,181,1,2413, +4029,16,0,181,1, +406,4030,16,0,189, +1,2512,4031,16,0, +490,1,2105,939,1, +166,4032,16,0,189, +1,1622,4033,16,0, +189,1,2841,3538,1, +1931,986,1,1873,961, +1,431,4034,16,0, +189,1,1585,4035,16, +0,189,1,182,4036, +16,0,189,1,1189, +4037,16,0,181,1, +1443,4038,16,0,181, +1,1695,4039,16,0, +181,1,2198,4040,16, +0,181,1,2542,4041, +16,0,644,1,447, +4042,16,0,189,1, +2458,1001,1,2459,1007, +1,1958,4043,16,0, +181,1,2462,1014,1, +1657,1019,1,2464,1024, +1,2466,3532,1,459, +4044,16,0,189,1, +2468,4045,16,0,386, +1,462,4046,16,0, +189,1,199,4047,16, +0,189,1,217,4048, +16,0,189,1,2227, +1033,1,1225,4049,16, +0,181,1,1479,4050, +16,0,181,1,1731, +4051,16,0,189,1, +1989,1041,1,1990,4052, +16,0,181,1,236, +4053,16,0,189,1, +1933,4054,16,0,181, +1,2823,4055,16,0, +789,1,2508,4056,16, +0,484,1,1756,4057, +16,0,181,1,94, +4058,19,746,1,94, +4059,5,95,1,256, +4060,16,0,744,1, +1261,4061,16,0,744, +1,509,4062,16,0, +744,1,1515,4063,16, +0,744,1,2021,843, +1,1775,4064,16,0, +744,1,2029,850,1, +2030,856,1,2031,861, +1,2032,866,1,2033, +871,1,277,4065,16, +0,744,1,2035,877, +1,2037,882,1,2039, +887,1,32,4066,16, +0,744,1,2041,893, +1,2293,4067,16,0, +744,1,2043,899,1, +2045,904,1,41,4068, +16,0,744,1,1297, +4069,16,0,744,1, +43,4070,16,0,744, +1,1803,912,1,1804, +4071,16,0,744,1, +299,4072,16,0,744, +1,52,4073,16,0, +744,1,2318,4074,16, +0,744,1,62,4075, +16,0,744,1,2075, +4076,16,0,744,1, +1574,924,1,71,4077, +16,0,744,1,76, +4078,16,0,744,1, +1834,4079,16,0,744, +1,2337,4080,16,0, +744,1,79,4081,16, +0,744,1,1335,4082, +16,0,744,1,322, +4083,16,0,744,1, +85,4084,16,0,744, +1,89,4085,16,0, +744,1,346,4086,16, +0,744,1,2105,939, +1,2106,4087,16,0, +744,1,97,4088,16, +0,744,1,1860,946, +1,2364,952,1,102, +4089,16,0,744,1, +112,4090,16,0,744, +1,1117,4091,16,0, +744,1,2786,4092,16, +0,744,1,1873,961, +1,1876,4093,16,0, +744,1,124,4094,16, +0,744,1,2136,968, +1,381,4095,16,0, +744,1,525,4096,16, +0,744,1,137,4097, +16,0,744,1,1901, +4098,16,0,744,1, +1153,4099,16,0,744, +1,151,4100,16,0, +744,1,1407,4101,16, +0,744,1,1659,4102, +16,0,744,1,2413, +4103,16,0,744,1, +406,4104,16,0,744, +1,1371,4105,16,0, +744,1,166,4106,16, +0,744,1,1622,4107, +16,0,744,1,1931, +986,1,1933,4108,16, +0,744,1,431,4109, +16,0,744,1,1585, +4110,16,0,744,1, +182,4111,16,0,744, +1,1189,4112,16,0, +744,1,1443,4113,16, +0,744,1,1695,4114, +16,0,744,1,2198, +4115,16,0,744,1, +447,4116,16,0,744, +1,2458,1001,1,2459, +1007,1,1958,4117,16, +0,744,1,2462,1014, +1,1657,1019,1,2464, +1024,1,199,4118,16, +0,744,1,459,4119, +16,0,744,1,462, +4120,16,0,744,1, +217,4121,16,0,744, +1,2227,1033,1,1225, +4122,16,0,744,1, +1479,4123,16,0,744, +1,1731,4124,16,0, +744,1,1989,1041,1, +1990,4125,16,0,744, +1,236,4126,16,0, +744,1,1756,4127,16, +0,744,1,95,4128, +19,743,1,95,4129, +5,95,1,256,4130, +16,0,741,1,1261, +4131,16,0,741,1, +509,4132,16,0,741, +1,1515,4133,16,0, +741,1,2021,843,1, +1775,4134,16,0,741, +1,2029,850,1,2030, +856,1,2031,861,1, +2032,866,1,2033,871, +1,277,4135,16,0, +741,1,2035,877,1, +2037,882,1,2039,887, +1,32,4136,16,0, +741,1,2041,893,1, +2293,4137,16,0,741, +1,2043,899,1,2045, +904,1,41,4138,16, +0,741,1,1297,4139, +16,0,741,1,43, +4140,16,0,741,1, +1803,912,1,1804,4141, +16,0,741,1,299, +4142,16,0,741,1, +52,4143,16,0,741, +1,2318,4144,16,0, +741,1,62,4145,16, +0,741,1,2075,4146, +16,0,741,1,1574, +924,1,71,4147,16, +0,741,1,76,4148, +16,0,741,1,1834, +4149,16,0,741,1, +2337,4150,16,0,741, +1,79,4151,16,0, +741,1,1335,4152,16, +0,741,1,322,4153, +16,0,741,1,85, +4154,16,0,741,1, +89,4155,16,0,741, +1,346,4156,16,0, +741,1,2105,939,1, +2106,4157,16,0,741, +1,97,4158,16,0, +741,1,1860,946,1, +2364,952,1,102,4159, +16,0,741,1,112, +4160,16,0,741,1, +1117,4161,16,0,741, +1,2786,4162,16,0, +741,1,1873,961,1, +1876,4163,16,0,741, +1,124,4164,16,0, +741,1,2136,968,1, +381,4165,16,0,741, +1,525,4166,16,0, +741,1,137,4167,16, +0,741,1,1901,4168, +16,0,741,1,1153, +4169,16,0,741,1, +151,4170,16,0,741, +1,1407,4171,16,0, +741,1,1659,4172,16, +0,741,1,2413,4173, +16,0,741,1,406, +4174,16,0,741,1, +1371,4175,16,0,741, +1,166,4176,16,0, +741,1,1622,4177,16, +0,741,1,1931,986, +1,1933,4178,16,0, +741,1,431,4179,16, +0,741,1,1585,4180, +16,0,741,1,182, +4181,16,0,741,1, +1189,4182,16,0,741, +1,1443,4183,16,0, +741,1,1695,4184,16, +0,741,1,2198,4185, +16,0,741,1,447, +4186,16,0,741,1, +2458,1001,1,2459,1007, 1,1958,4187,16,0, -507,1,1775,4188,16, -0,507,1,122,4189, -19,147,1,122,4190, -5,3,1,1756,4191, -16,0,283,1,2318, -4192,16,0,297,1, -1659,4193,16,0,145, -1,123,4194,19,548, -1,123,4195,5,68, -1,1901,4196,16,0, -546,1,1479,4197,16, -0,546,1,112,4198, -16,0,546,1,2293, -4199,16,0,546,1, -1804,4200,16,0,546, -1,431,4201,16,0, -546,1,1443,4202,16, -0,546,1,1756,4203, -16,0,546,1,124, -4204,16,0,546,1, -525,4205,16,0,546, -1,236,4206,16,0, -546,1,346,4207,16, -0,546,1,1876,4208, -16,0,546,1,1659, -4209,16,0,546,1, -1225,4210,16,0,546, -1,1117,4211,16,0, -546,1,137,4212,16, -0,546,1,2318,4213, -16,0,546,1,1775, -4214,16,0,546,1, -32,4215,16,0,546, -1,1407,4216,16,0, -546,1,256,4217,16, -0,546,1,459,4218, -16,0,546,1,406, -4219,16,0,546,1, -41,4220,16,0,546, -1,2658,4221,16,0, -546,1,43,4222,16, -0,546,1,1585,4223, -16,0,546,1,1990, -4224,16,0,546,1, -2337,4225,16,0,546, -1,509,4226,16,0, -546,1,52,4227,16, -0,546,1,151,4228, -16,0,546,1,447, -4229,16,0,546,1, -166,4230,16,0,546, -1,462,4231,16,0, -546,1,277,4232,16, -0,546,1,1695,4233, -16,0,546,1,62, -4234,16,0,586,1, -1153,4235,16,0,546, -1,381,4236,16,0, -546,1,2106,4237,16, -0,546,1,1335,4238, -16,0,546,1,71, -4239,16,0,546,1, -182,4240,16,0,546, -1,76,4241,16,0, -546,1,79,4242,16, -0,546,1,1933,4243, -16,0,546,1,299, -4244,16,0,546,1, -85,4245,16,0,546, -1,1515,4246,16,0, -546,1,2198,4247,16, -0,546,1,89,4248, -16,0,546,1,1834, -4249,16,0,546,1, -1622,4250,16,0,546, -1,2413,4251,16,0, -546,1,2075,4252,16, -0,546,1,1731,4253, -16,0,546,1,97, -4254,16,0,546,1, -1297,4255,16,0,546, -1,1189,4256,16,0, -546,1,102,4257,16, -0,546,1,1261,4258, -16,0,546,1,322, -4259,16,0,546,1, -1958,4260,16,0,546, -1,199,4261,16,0, -546,1,1371,4262,16, -0,546,1,217,4263, -16,0,546,1,124, -4264,19,602,1,124, -4265,5,2,1,459, -4266,16,0,600,1, -41,4267,16,0,665, -1,125,4268,19,606, -1,125,4269,5,3, -1,462,4270,16,0, -604,1,459,4271,16, -0,630,1,41,4272, -16,0,630,1,126, -4273,19,4274,4,36, -69,0,120,0,112, -0,114,0,101,0, -115,0,115,0,105, +741,1,2462,1014,1, +1657,1019,1,2464,1024, +1,199,4188,16,0, +741,1,459,4189,16, +0,741,1,462,4190, +16,0,741,1,217, +4191,16,0,741,1, +2227,1033,1,1225,4192, +16,0,741,1,1479, +4193,16,0,741,1, +1731,4194,16,0,741, +1,1989,1041,1,1990, +4195,16,0,741,1, +236,4196,16,0,741, +1,1756,4197,16,0, +741,1,96,4198,19, +740,1,96,4199,5, +95,1,256,4200,16, +0,738,1,1261,4201, +16,0,738,1,509, +4202,16,0,738,1, +1515,4203,16,0,738, +1,2021,843,1,1775, +4204,16,0,738,1, +2029,850,1,2030,856, +1,2031,861,1,2032, +866,1,2033,871,1, +277,4205,16,0,738, +1,2035,877,1,2037, +882,1,2039,887,1, +32,4206,16,0,738, +1,2041,893,1,2293, +4207,16,0,738,1, +2043,899,1,2045,904, +1,41,4208,16,0, +738,1,1297,4209,16, +0,738,1,43,4210, +16,0,738,1,1803, +912,1,1804,4211,16, +0,738,1,299,4212, +16,0,738,1,52, +4213,16,0,738,1, +2318,4214,16,0,738, +1,62,4215,16,0, +738,1,2075,4216,16, +0,738,1,1574,924, +1,71,4217,16,0, +738,1,76,4218,16, +0,738,1,1834,4219, +16,0,738,1,2337, +4220,16,0,738,1, +79,4221,16,0,738, +1,1335,4222,16,0, +738,1,322,4223,16, +0,738,1,85,4224, +16,0,738,1,89, +4225,16,0,738,1, +346,4226,16,0,738, +1,2105,939,1,2106, +4227,16,0,738,1, +97,4228,16,0,738, +1,1860,946,1,2364, +952,1,102,4229,16, +0,738,1,112,4230, +16,0,738,1,1117, +4231,16,0,738,1, +2786,4232,16,0,738, +1,1873,961,1,1876, +4233,16,0,738,1, +124,4234,16,0,738, +1,2136,968,1,381, +4235,16,0,738,1, +525,4236,16,0,738, +1,137,4237,16,0, +738,1,1901,4238,16, +0,738,1,1153,4239, +16,0,738,1,151, +4240,16,0,738,1, +1407,4241,16,0,738, +1,1659,4242,16,0, +738,1,2413,4243,16, +0,738,1,406,4244, +16,0,738,1,1371, +4245,16,0,738,1, +166,4246,16,0,738, +1,1622,4247,16,0, +738,1,1931,986,1, +1933,4248,16,0,738, +1,431,4249,16,0, +738,1,1585,4250,16, +0,738,1,182,4251, +16,0,738,1,1189, +4252,16,0,738,1, +1443,4253,16,0,738, +1,1695,4254,16,0, +738,1,2198,4255,16, +0,738,1,447,4256, +16,0,738,1,2458, +1001,1,2459,1007,1, +1958,4257,16,0,738, +1,2462,1014,1,1657, +1019,1,2464,1024,1, +199,4258,16,0,738, +1,459,4259,16,0, +738,1,462,4260,16, +0,738,1,217,4261, +16,0,738,1,2227, +1033,1,1225,4262,16, +0,738,1,1479,4263, +16,0,738,1,1731, +4264,16,0,738,1, +1989,1041,1,1990,4265, +16,0,738,1,236, +4266,16,0,738,1, +1756,4267,16,0,738, +1,97,4268,19,103, +1,97,4269,5,1, +1,0,4270,16,0, +104,1,98,4271,19, +647,1,98,4272,5, +1,1,0,4273,16, +0,645,1,99,4274, +19,210,1,99,4275, +5,2,1,0,4276, +16,0,312,1,2823, +4277,16,0,208,1, +100,4278,19,207,1, +100,4279,5,2,1, +0,4280,16,0,286, +1,2823,4281,16,0, +205,1,101,4282,19, +301,1,101,4283,5, +2,1,0,4284,16, +0,785,1,2823,4285, +16,0,299,1,102, +4286,19,320,1,102, +4287,5,4,1,0, +4288,16,0,788,1, +2764,4289,16,0,318, +1,2823,4290,16,0, +788,1,2834,4291,16, +0,318,1,103,4292, +19,714,1,103,4293, +5,2,1,2470,4294, +16,0,712,1,2659, +4295,16,0,734,1, +104,4296,19,280,1, +104,4297,5,4,1, +2597,4298,16,0,680, +1,2703,4299,16,0, +680,1,2470,4300,16, +0,278,1,2659,4301, +16,0,278,1,105, +4302,19,679,1,105, +4303,5,4,1,2597, +4304,16,0,677,1, +2703,4305,16,0,677, +1,2470,4306,16,0, +690,1,2659,4307,16, +0,690,1,106,4308, +19,157,1,106,4309, +5,4,1,2597,4310, +16,0,155,1,2703, +4311,16,0,155,1, +2470,4312,16,0,769, +1,2659,4313,16,0, +769,1,107,4314,19, +154,1,107,4315,5, +4,1,2597,4316,16, +0,152,1,2703,4317, +16,0,152,1,2470, +4318,16,0,174,1, +2659,4319,16,0,174, +1,108,4320,19,672, +1,108,4321,5,4, +1,2597,4322,16,0, +670,1,2703,4323,16, +0,670,1,2470,4324, +16,0,685,1,2659, +4325,16,0,685,1, +109,4326,19,669,1, +109,4327,5,4,1, +2597,4328,16,0,667, +1,2703,4329,16,0, +667,1,2470,4330,16, +0,684,1,2659,4331, +16,0,684,1,110, +4332,19,172,1,110, +4333,5,4,1,2597, +4334,16,0,752,1, +2703,4335,16,0,752, +1,2470,4336,16,0, +170,1,2659,4337,16, +0,170,1,111,4338, +19,169,1,111,4339, +5,4,1,2597,4340, +16,0,663,1,2703, +4341,16,0,663,1, +2470,4342,16,0,167, +1,2659,4343,16,0, +167,1,112,4344,19, +141,1,112,4345,5, +3,1,2582,4346,16, +0,293,1,2770,4347, +16,0,331,1,10, +4348,16,0,139,1, +113,4349,19,688,1, +113,4350,5,1,1, +2569,4351,16,0,686, +1,114,4352,19,676, +1,114,4353,5,1, +1,2561,4354,16,0, +674,1,115,4355,19, +660,1,115,4356,5, +1,1,2553,4357,16, +0,658,1,116,4358, +19,535,1,116,4359, +5,1,1,2538,4360, +16,0,533,1,117, +4361,19,638,1,117, +4362,5,1,1,2523, +4363,16,0,636,1, +118,4364,19,498,1, +118,4365,5,1,1, +2507,4366,16,0,496, +1,119,4367,19,160, +1,119,4368,5,17, +1,0,4369,16,0, +333,1,2582,4370,16, +0,382,1,2075,4371, +16,0,763,1,2337, +4372,16,0,763,1, +2413,4373,16,0,763, +1,10,4374,16,0, +382,1,2823,4375,16, +0,333,1,1901,4376, +16,0,763,1,2198, +4377,16,0,763,1, +21,4378,16,0,158, +1,2106,4379,16,0, +763,1,2770,4380,16, +0,382,1,1804,4381, +16,0,763,1,1990, +4382,16,0,763,1, +32,4383,16,0,763, +1,1958,4384,16,0, +763,1,1775,4385,16, +0,763,1,120,4386, +19,487,1,120,4387, +5,2,1,2569,4388, +16,0,567,1,2507, +4389,16,0,485,1, +121,4390,19,493,1, +121,4391,5,5,1, +2511,4392,16,0,491, +1,2523,4393,16,0, +506,1,2515,4394,16, +0,495,1,2538,4395, +16,0,523,1,2561, +4396,16,0,753,1, +122,4397,19,514,1, +122,4398,5,3,1, +2530,4399,16,0,516, +1,2553,4400,16,0, +542,1,2526,4401,16, +0,512,1,123,4402, +19,248,1,123,4403, +5,2,1,2541,4404, +16,0,527,1,2545, +4405,16,0,246,1, +124,4406,19,130,1, +124,4407,5,18,1, +0,4408,16,0,128, +1,2582,4409,16,0, +137,1,2075,4410,16, +0,137,1,2337,4411, +16,0,137,1,2413, +4412,16,0,137,1, +10,4413,16,0,137, +1,2823,4414,16,0, +128,1,2198,4415,16, +0,137,1,1901,4416, +16,0,137,1,52, +4417,16,0,216,1, +21,4418,16,0,137, +1,2106,4419,16,0, +137,1,2770,4420,16, +0,137,1,1804,4421, +16,0,137,1,1990, +4422,16,0,137,1, +32,4423,16,0,137, +1,1958,4424,16,0, +137,1,1775,4425,16, +0,137,1,125,4426, +19,359,1,125,4427, +5,4,1,2597,4428, +16,0,357,1,2703, +4429,16,0,357,1, +2470,4430,16,0,357, +1,2659,4431,16,0, +357,1,126,4432,19, +772,1,126,4433,5, +4,1,2597,4434,16, +0,770,1,2703,4435, +16,0,770,1,2470, +4436,16,0,770,1, +2659,4437,16,0,770, +1,127,4438,19,760, +1,127,4439,5,4, +1,2597,4440,16,0, +758,1,2703,4441,16, +0,758,1,2470,4442, +16,0,758,1,2659, +4443,16,0,758,1, +128,4444,19,548,1, +128,4445,5,4,1, +2597,4446,16,0,546, +1,2703,4447,16,0, +546,1,2470,4448,16, +0,546,1,2659,4449, +16,0,546,1,129, +4450,19,655,1,129, +4451,5,4,1,2597, +4452,16,0,653,1, +2703,4453,16,0,653, +1,2470,4454,16,0, +653,1,2659,4455,16, +0,653,1,130,4456, +19,643,1,130,4457, +5,4,1,2597,4458, +16,0,641,1,2703, +4459,16,0,641,1, +2470,4460,16,0,641, +1,2659,4461,16,0, +641,1,131,4462,19, +504,1,131,4463,5, +4,1,2597,4464,16, +0,502,1,2703,4465, +16,0,502,1,2470, +4466,16,0,502,1, +2659,4467,16,0,502, +1,132,4468,19,481, +1,132,4469,5,4, +1,2597,4470,16,0, +479,1,2703,4471,16, +0,479,1,2470,4472, +16,0,479,1,2659, +4473,16,0,479,1, +133,4474,19,381,1, +133,4475,5,21,1, +2781,4476,16,0,798, +1,2519,4477,16,0, +784,1,2557,4478,16, +0,545,1,2337,4479, +16,0,592,1,2413, +4480,16,0,592,1, +2593,4481,16,0,711, +1,2565,4482,16,0, +681,1,1901,4483,16, +0,592,1,2198,4484, +16,0,592,1,2534, +4485,16,0,640,1, +2573,4486,16,0,575, +1,2106,4487,16,0, +592,1,2578,4488,16, +0,775,1,2075,4489, +16,0,592,1,1804, +4490,16,0,592,1, +1990,4491,16,0,592, +1,31,4492,16,0, +379,1,32,4493,16, +0,592,1,2549,4494, +16,0,538,1,1958, +4495,16,0,592,1, +1775,4496,16,0,592, +1,134,4497,19,342, +1,134,4498,5,1, +1,32,4499,16,0, +340,1,135,4500,19, +289,1,135,4501,5, +11,1,2075,4502,16, +0,697,1,2337,4503, +16,0,294,1,2413, +4504,16,0,520,1, +1901,4505,16,0,437, +1,2198,4506,16,0, +362,1,2106,4507,16, +0,730,1,1804,4508, +16,0,322,1,1990, +4509,16,0,580,1, +32,4510,16,0,375, +1,1958,4511,16,0, +529,1,1775,4512,16, +0,287,1,136,4513, +19,703,1,136,4514, +5,11,1,2075,4515, +16,0,701,1,2337, +4516,16,0,701,1, +2413,4517,16,0,701, +1,1901,4518,16,0, +701,1,2198,4519,16, +0,701,1,2106,4520, +16,0,701,1,1804, +4521,16,0,701,1, +1990,4522,16,0,701, +1,32,4523,16,0, +701,1,1958,4524,16, +0,701,1,1775,4525, +16,0,701,1,137, +4526,19,756,1,137, +4527,5,11,1,2075, +4528,16,0,754,1, +2337,4529,16,0,754, +1,2413,4530,16,0, +754,1,1901,4531,16, +0,754,1,2198,4532, +16,0,754,1,2106, +4533,16,0,754,1, +1804,4534,16,0,754, +1,1990,4535,16,0, +754,1,32,4536,16, +0,754,1,1958,4537, +16,0,754,1,1775, +4538,16,0,754,1, +138,4539,19,177,1, +138,4540,5,31,1, +1901,4541,16,0,762, +1,1479,4542,16,0, +648,1,2075,4543,16, +0,762,1,1695,4544, +16,0,214,1,1756, +4545,16,0,204,1, +2413,4546,16,0,762, +1,2198,4547,16,0, +762,1,1876,4548,16, +0,781,1,1659,4549, +16,0,204,1,1443, +4550,16,0,608,1, +1117,4551,16,0,175, +1,1990,4552,16,0, +762,1,1189,4553,16, +0,264,1,1775,4554, +16,0,762,1,32, +4555,16,0,762,1, +2106,4556,16,0,762, +1,1515,4557,16,0, +699,1,2337,4558,16, +0,762,1,52,4559, +16,0,715,1,1804, +4560,16,0,762,1, +1261,4561,16,0,338, +1,1153,4562,16,0, +271,1,1225,4563,16, +0,307,1,1335,4564, +16,0,511,1,1933, +4565,16,0,651,1, +1834,4566,16,0,352, +1,1297,4567,16,0, +366,1,1407,4568,16, +0,682,1,2318,4569, +16,0,204,1,1958, +4570,16,0,762,1, +1371,4571,16,0,500, +1,139,4572,19,617, +1,139,4573,5,11, +1,2075,4574,16,0, +615,1,2337,4575,16, +0,615,1,2413,4576, +16,0,615,1,1901, +4577,16,0,615,1, +2198,4578,16,0,615, +1,2106,4579,16,0, +615,1,1804,4580,16, +0,615,1,1990,4581, +16,0,615,1,32, +4582,16,0,615,1, +1958,4583,16,0,615, +1,1775,4584,16,0, +615,1,140,4585,19, +613,1,140,4586,5, +11,1,2075,4587,16, +0,611,1,2337,4588, +16,0,611,1,2413, +4589,16,0,611,1, +1901,4590,16,0,611, +1,2198,4591,16,0, +611,1,2106,4592,16, +0,611,1,1804,4593, +16,0,611,1,1990, +4594,16,0,611,1, +32,4595,16,0,611, +1,1958,4596,16,0, +611,1,1775,4597,16, +0,611,1,141,4598, +19,694,1,141,4599, +5,11,1,2075,4600, +16,0,692,1,2337, +4601,16,0,692,1, +2413,4602,16,0,692, +1,1901,4603,16,0, +692,1,2198,4604,16, +0,692,1,2106,4605, +16,0,692,1,1804, +4606,16,0,692,1, +1990,4607,16,0,692, +1,32,4608,16,0, +692,1,1958,4609,16, +0,692,1,1775,4610, +16,0,692,1,142, +4611,19,607,1,142, +4612,5,11,1,2075, +4613,16,0,605,1, +2337,4614,16,0,605, +1,2413,4615,16,0, +605,1,1901,4616,16, +0,605,1,2198,4617, +16,0,605,1,2106, +4618,16,0,605,1, +1804,4619,16,0,605, +1,1990,4620,16,0, +605,1,32,4621,16, +0,605,1,1958,4622, +16,0,605,1,1775, +4623,16,0,605,1, +143,4624,19,604,1, +143,4625,5,11,1, +2075,4626,16,0,602, +1,2337,4627,16,0, +602,1,2413,4628,16, +0,602,1,1901,4629, +16,0,602,1,2198, +4630,16,0,602,1, +2106,4631,16,0,602, +1,1804,4632,16,0, +602,1,1990,4633,16, +0,602,1,32,4634, +16,0,602,1,1958, +4635,16,0,602,1, +1775,4636,16,0,602, +1,144,4637,19,601, +1,144,4638,5,11, +1,2075,4639,16,0, +599,1,2337,4640,16, +0,599,1,2413,4641, +16,0,599,1,1901, +4642,16,0,599,1, +2198,4643,16,0,599, +1,2106,4644,16,0, +599,1,1804,4645,16, +0,599,1,1990,4646, +16,0,599,1,32, +4647,16,0,599,1, +1958,4648,16,0,599, +1,1775,4649,16,0, +599,1,145,4650,19, +598,1,145,4651,5, +11,1,2075,4652,16, +0,596,1,2337,4653, +16,0,596,1,2413, +4654,16,0,596,1, +1901,4655,16,0,596, +1,2198,4656,16,0, +596,1,2106,4657,16, +0,596,1,1804,4658, +16,0,596,1,1990, +4659,16,0,596,1, +32,4660,16,0,596, +1,1958,4661,16,0, +596,1,1775,4662,16, +0,596,1,146,4663, +19,595,1,146,4664, +5,11,1,2075,4665, +16,0,593,1,2337, +4666,16,0,593,1, +2413,4667,16,0,593, +1,1901,4668,16,0, +593,1,2198,4669,16, +0,593,1,2106,4670, +16,0,593,1,1804, +4671,16,0,593,1, +1990,4672,16,0,593, +1,32,4673,16,0, +593,1,1958,4674,16, +0,593,1,1775,4675, +16,0,593,1,147, +4676,19,147,1,147, +4677,5,3,1,1756, +4678,16,0,321,1, +2318,4679,16,0,337, +1,1659,4680,16,0, +145,1,148,4681,19, +634,1,148,4682,5, +68,1,1901,4683,16, +0,632,1,1479,4684, +16,0,632,1,112, +4685,16,0,632,1, +2293,4686,16,0,632, +1,1804,4687,16,0, +632,1,431,4688,16, +0,632,1,1443,4689, +16,0,632,1,1756, +4690,16,0,632,1, +124,4691,16,0,632, +1,525,4692,16,0, +632,1,236,4693,16, +0,632,1,346,4694, +16,0,632,1,1876, +4695,16,0,632,1, +1659,4696,16,0,632, +1,1225,4697,16,0, +632,1,1117,4698,16, +0,632,1,137,4699, +16,0,632,1,2318, +4700,16,0,632,1, +1775,4701,16,0,632, +1,32,4702,16,0, +632,1,1407,4703,16, +0,632,1,256,4704, +16,0,632,1,459, +4705,16,0,632,1, +406,4706,16,0,632, +1,41,4707,16,0, +632,1,151,4708,16, +0,632,1,43,4709, +16,0,632,1,1585, +4710,16,0,632,1, +1990,4711,16,0,632, +1,2337,4712,16,0, +632,1,509,4713,16, +0,632,1,52,4714, +16,0,632,1,381, +4715,16,0,632,1, +447,4716,16,0,632, +1,166,4717,16,0, +632,1,462,4718,16, +0,632,1,277,4719, +16,0,632,1,1695, +4720,16,0,632,1, +2786,4721,16,0,632, +1,62,4722,16,0, +707,1,1153,4723,16, +0,632,1,2106,4724, +16,0,632,1,1335, +4725,16,0,632,1, +71,4726,16,0,632, +1,182,4727,16,0, +632,1,76,4728,16, +0,632,1,79,4729, +16,0,632,1,1933, +4730,16,0,632,1, +299,4731,16,0,632, +1,85,4732,16,0, +632,1,1515,4733,16, +0,632,1,2198,4734, +16,0,632,1,89, +4735,16,0,632,1, +1834,4736,16,0,632, +1,1622,4737,16,0, +632,1,2413,4738,16, +0,632,1,2075,4739, +16,0,632,1,1731, +4740,16,0,632,1, +97,4741,16,0,632, +1,1297,4742,16,0, +632,1,1189,4743,16, +0,632,1,102,4744, +16,0,632,1,1261, +4745,16,0,632,1, +322,4746,16,0,632, +1,1958,4747,16,0, +632,1,199,4748,16, +0,632,1,1371,4749, +16,0,632,1,217, +4750,16,0,632,1, +149,4751,19,725,1, +149,4752,5,2,1, +459,4753,16,0,723, +1,41,4754,16,0, +786,1,150,4755,19, +729,1,150,4756,5, +3,1,462,4757,16, +0,727,1,459,4758, +16,0,750,1,41, +4759,16,0,750,1, +151,4760,19,4761,4, +36,69,0,120,0, +112,0,114,0,101, +0,115,0,115,0, +105,0,111,0,110, +0,65,0,114,0, +103,0,117,0,109, +0,101,0,110,0, +116,0,1,151,4756, +1,152,4762,19,630, +1,152,4763,5,68, +1,1901,4764,16,0, +628,1,1479,4765,16, +0,628,1,112,4766, +16,0,628,1,2293, +4767,16,0,628,1, +1804,4768,16,0,628, +1,431,4769,16,0, +628,1,1443,4770,16, +0,628,1,1756,4771, +16,0,628,1,124, +4772,16,0,628,1, +525,4773,16,0,628, +1,236,4774,16,0, +628,1,346,4775,16, +0,628,1,1876,4776, +16,0,628,1,1659, +4777,16,0,628,1, +1225,4778,16,0,628, +1,1117,4779,16,0, +628,1,137,4780,16, +0,628,1,2318,4781, +16,0,628,1,1775, +4782,16,0,628,1, +32,4783,16,0,628, +1,1407,4784,16,0, +628,1,256,4785,16, +0,628,1,459,4786, +16,0,628,1,406, +4787,16,0,628,1, +41,4788,16,0,628, +1,151,4789,16,0, +628,1,43,4790,16, +0,628,1,1585,4791, +16,0,628,1,1990, +4792,16,0,628,1, +2337,4793,16,0,628, +1,509,4794,16,0, +628,1,52,4795,16, +0,628,1,381,4796, +16,0,628,1,447, +4797,16,0,628,1, +166,4798,16,0,628, +1,462,4799,16,0, +628,1,277,4800,16, +0,628,1,1695,4801, +16,0,628,1,2786, +4802,16,0,628,1, +62,4803,16,0,708, +1,1153,4804,16,0, +628,1,2106,4805,16, +0,628,1,1335,4806, +16,0,628,1,71, +4807,16,0,628,1, +182,4808,16,0,628, +1,76,4809,16,0, +628,1,79,4810,16, +0,628,1,1933,4811, +16,0,628,1,299, +4812,16,0,628,1, +85,4813,16,0,628, +1,1515,4814,16,0, +628,1,2198,4815,16, +0,628,1,89,4816, +16,0,628,1,1834, +4817,16,0,628,1, +1622,4818,16,0,628, +1,2413,4819,16,0, +628,1,2075,4820,16, +0,628,1,1731,4821, +16,0,628,1,97, +4822,16,0,628,1, +1297,4823,16,0,628, +1,1189,4824,16,0, +628,1,102,4825,16, +0,628,1,1261,4826, +16,0,628,1,322, +4827,16,0,628,1, +1958,4828,16,0,628, +1,199,4829,16,0, +628,1,1371,4830,16, +0,628,1,217,4831, +16,0,628,1,153, +4832,19,4833,4,28, +86,0,101,0,99, +0,116,0,111,0, +114,0,67,0,111, +0,110,0,115,0, +116,0,97,0,110, +0,116,0,1,153, +4763,1,154,4834,19, +4835,4,32,82,0, +111,0,116,0,97, +0,116,0,105,0, +111,0,110,0,67, 0,111,0,110,0, -65,0,114,0,103, -0,117,0,109,0, -101,0,110,0,116, -0,1,126,4269,1, -127,4275,19,544,1, -127,4276,5,68,1, -1901,4277,16,0,542, -1,1479,4278,16,0, -542,1,112,4279,16, -0,542,1,2293,4280, -16,0,542,1,1804, -4281,16,0,542,1, -431,4282,16,0,542, -1,1443,4283,16,0, -542,1,1756,4284,16, -0,542,1,124,4285, -16,0,542,1,525, -4286,16,0,542,1, -236,4287,16,0,542, -1,346,4288,16,0, -542,1,1876,4289,16, -0,542,1,1659,4290, -16,0,542,1,1225, -4291,16,0,542,1, -1117,4292,16,0,542, -1,137,4293,16,0, -542,1,2318,4294,16, -0,542,1,1775,4295, -16,0,542,1,32, -4296,16,0,542,1, -1407,4297,16,0,542, -1,256,4298,16,0, -542,1,459,4299,16, -0,542,1,406,4300, -16,0,542,1,41, -4301,16,0,542,1, -2658,4302,16,0,542, -1,43,4303,16,0, -542,1,1585,4304,16, -0,542,1,1990,4305, -16,0,542,1,2337, -4306,16,0,542,1, -509,4307,16,0,542, -1,52,4308,16,0, -542,1,151,4309,16, -0,542,1,447,4310, -16,0,542,1,166, -4311,16,0,542,1, -462,4312,16,0,542, -1,277,4313,16,0, -542,1,1695,4314,16, -0,542,1,62,4315, -16,0,587,1,1153, -4316,16,0,542,1, -381,4317,16,0,542, -1,2106,4318,16,0, -542,1,1335,4319,16, -0,542,1,71,4320, -16,0,542,1,182, -4321,16,0,542,1, -76,4322,16,0,542, -1,79,4323,16,0, -542,1,1933,4324,16, -0,542,1,299,4325, -16,0,542,1,85, -4326,16,0,542,1, -1515,4327,16,0,542, -1,2198,4328,16,0, -542,1,89,4329,16, -0,542,1,1834,4330, -16,0,542,1,1622, -4331,16,0,542,1, -2413,4332,16,0,542, -1,2075,4333,16,0, -542,1,1731,4334,16, -0,542,1,97,4335, -16,0,542,1,1297, -4336,16,0,542,1, -1189,4337,16,0,542, -1,102,4338,16,0, -542,1,1261,4339,16, -0,542,1,322,4340, -16,0,542,1,1958, -4341,16,0,542,1, -199,4342,16,0,542, -1,1371,4343,16,0, -542,1,217,4344,16, -0,542,1,128,4345, -19,4346,4,28,86, -0,101,0,99,0, -116,0,111,0,114, -0,67,0,111,0, -110,0,115,0,116, -0,97,0,110,0, -116,0,1,128,4276, -1,129,4347,19,4348, -4,32,82,0,111, -0,116,0,97,0, -116,0,105,0,111, -0,110,0,67,0, +115,0,116,0,97, +0,110,0,116,0, +1,154,4763,1,155, +4836,19,4837,4,24, +76,0,105,0,115, +0,116,0,67,0, 111,0,110,0,115, 0,116,0,97,0, 110,0,116,0,1, -129,4276,1,130,4349, -19,4350,4,24,76, -0,105,0,115,0, -116,0,67,0,111, -0,110,0,115,0, -116,0,97,0,110, -0,116,0,1,130, -4276,1,131,4351,19, -169,1,131,4352,5, -67,1,1901,4353,16, -0,585,1,1479,4354, -16,0,533,1,112, -4355,16,0,249,1, -2293,4356,16,0,273, -1,1804,4357,16,0, -585,1,431,4358,16, -0,580,1,1443,4359, -16,0,468,1,1756, -4360,16,0,673,1, -124,4361,16,0,258, -1,525,4362,16,0, -305,1,236,4363,16, -0,341,1,346,4364, -16,0,496,1,1876, -4365,16,0,318,1, -1659,4366,16,0,673, -1,1225,4367,16,0, -248,1,1117,4368,16, -0,219,1,137,4369, -16,0,272,1,2318, -4370,16,0,673,1, -1775,4371,16,0,585, -1,32,4372,16,0, -585,1,1407,4373,16, -0,487,1,256,4374, -16,0,395,1,459, -4375,16,0,167,1, -406,4376,16,0,562, -1,41,4377,16,0, -167,1,2658,4378,16, -0,659,1,43,4379, -16,0,640,1,1990, -4380,16,0,585,1, -2337,4381,16,0,585, -1,509,4382,16,0, -655,1,52,4383,16, -0,594,1,151,4384, -16,0,282,1,447, -4385,16,0,305,1, -166,4386,16,0,293, -1,462,4387,16,0, -167,1,277,4388,16, -0,434,1,1695,4389, -16,0,270,1,1261, -4390,16,0,281,1, -1153,4391,16,0,174, -1,381,4392,16,0, -550,1,2106,4393,16, -0,585,1,1335,4394, -16,0,326,1,71, -4395,16,0,203,1, -182,4396,16,0,305, -1,76,4397,16,0, -549,1,79,4398,16, -0,218,1,1933,4399, -16,0,407,1,299, -4400,16,0,444,1, -85,4401,16,0,457, -1,1515,4402,16,0, -556,1,2198,4403,16, -0,585,1,89,4404, -16,0,227,1,1834, -4405,16,0,292,1, -1622,4406,16,0,654, -1,2413,4407,16,0, -585,1,2075,4408,16, -0,585,1,1731,4409, -16,0,250,1,97, -4410,16,0,411,1, -1297,4411,16,0,328, -1,1189,4412,16,0, -217,1,102,4413,16, -0,238,1,1585,4414, -16,0,663,1,322, -4415,16,0,458,1, -1958,4416,16,0,585, -1,199,4417,16,0, -316,1,1371,4418,16, -0,396,1,217,4419, -16,0,325,1,132, -4420,19,4421,4,36, -67,0,111,0,110, -0,115,0,116,0, -97,0,110,0,116, -0,69,0,120,0, -112,0,114,0,101, -0,115,0,115,0, -105,0,111,0,110, -0,1,132,4352,1, -133,4422,19,4423,4, -30,73,0,100,0, -101,0,110,0,116, -0,69,0,120,0, -112,0,114,0,101, -0,115,0,115,0, -105,0,111,0,110, -0,1,133,4352,1, -134,4424,19,4425,4, -36,73,0,100,0, -101,0,110,0,116, -0,68,0,111,0, +155,4763,1,156,4838, +19,185,1,156,4839, +5,67,1,1901,4840, +16,0,705,1,1479, +4841,16,0,619,1, +112,4842,16,0,273, +1,2293,4843,16,0, +306,1,1804,4844,16, +0,705,1,431,4845, +16,0,700,1,1443, +4846,16,0,550,1, +1756,4847,16,0,796, +1,124,4848,16,0, +285,1,525,4849,16, +0,345,1,236,4850, +16,0,387,1,346, +4851,16,0,582,1, +1876,4852,16,0,361, +1,1659,4853,16,0, +796,1,1225,4854,16, +0,272,1,1117,4855, +16,0,242,1,137, +4856,16,0,305,1, +2318,4857,16,0,796, +1,1775,4858,16,0, +705,1,32,4859,16, +0,705,1,1407,4860, +16,0,571,1,256, +4861,16,0,441,1, +459,4862,16,0,183, +1,406,4863,16,0, +662,1,41,4864,16, +0,183,1,151,4865, +16,0,317,1,43, +4866,16,0,751,1, +1990,4867,16,0,705, +1,2337,4868,16,0, +705,1,509,4869,16, +0,774,1,52,4870, +16,0,717,1,381, +4871,16,0,639,1, +447,4872,16,0,345, +1,166,4873,16,0, +332,1,462,4874,16, +0,183,1,277,4875, +16,0,488,1,1695, +4876,16,0,302,1, +2786,4877,16,0,254, +1,1261,4878,16,0, +316,1,1153,4879,16, +0,190,1,2106,4880, +16,0,705,1,1335, +4881,16,0,372,1, +71,4882,16,0,226, +1,182,4883,16,0, +345,1,76,4884,16, +0,635,1,79,4885, +16,0,241,1,1933, +4886,16,0,453,1, +299,4887,16,0,517, +1,85,4888,16,0, +541,1,1515,4889,16, +0,657,1,2198,4890, +16,0,705,1,89, +4891,16,0,253,1, +1834,4892,16,0,330, +1,1622,4893,16,0, +773,1,2413,4894,16, +0,705,1,2075,4895, +16,0,705,1,1731, +4896,16,0,274,1, +97,4897,16,0,457, +1,1297,4898,16,0, +374,1,1189,4899,16, +0,240,1,102,4900, +16,0,262,1,1585, +4901,16,0,783,1, +322,4902,16,0,543, +1,1958,4903,16,0, +705,1,199,4904,16, +0,356,1,1371,4905, +16,0,442,1,217, +4906,16,0,368,1, +157,4907,19,4908,4, +36,67,0,111,0, +110,0,115,0,116, +0,97,0,110,0, 116,0,69,0,120, 0,112,0,114,0, 101,0,115,0,115, 0,105,0,111,0, -110,0,1,134,4352, -1,135,4426,19,4427, -4,44,70,0,117, -0,110,0,99,0, -116,0,105,0,111, -0,110,0,67,0, -97,0,108,0,108, -0,69,0,120,0, -112,0,114,0,101, -0,115,0,115,0, -105,0,111,0,110, -0,1,135,4352,1, -136,4428,19,4429,4, -32,66,0,105,0, -110,0,97,0,114, -0,121,0,69,0, -120,0,112,0,114, -0,101,0,115,0, -115,0,105,0,111, -0,110,0,1,136, -4352,1,137,4430,19, -4431,4,30,85,0, -110,0,97,0,114, -0,121,0,69,0, +110,0,1,157,4839, +1,158,4909,19,4910, +4,30,73,0,100, +0,101,0,110,0, +116,0,69,0,120, +0,112,0,114,0, +101,0,115,0,115, +0,105,0,111,0, +110,0,1,158,4839, +1,159,4911,19,4912, +4,36,73,0,100, +0,101,0,110,0, +116,0,68,0,111, +0,116,0,69,0, 120,0,112,0,114, 0,101,0,115,0, 115,0,105,0,111, -0,110,0,1,137, -4352,1,138,4432,19, -4433,4,36,84,0, -121,0,112,0,101, -0,99,0,97,0, -115,0,116,0,69, +0,110,0,1,159, +4839,1,160,4913,19, +4914,4,44,70,0, +117,0,110,0,99, +0,116,0,105,0, +111,0,110,0,67, +0,97,0,108,0, +108,0,69,0,120, +0,112,0,114,0, +101,0,115,0,115, +0,105,0,111,0, +110,0,1,160,4839, +1,161,4915,19,4916, +4,32,66,0,105, +0,110,0,97,0, +114,0,121,0,69, 0,120,0,112,0, 114,0,101,0,115, 0,115,0,105,0, 111,0,110,0,1, -138,4352,1,139,4434, -19,4435,4,42,80, -0,97,0,114,0, -101,0,110,0,116, -0,104,0,101,0, -115,0,105,0,115, -0,69,0,120,0, -112,0,114,0,101, -0,115,0,115,0, -105,0,111,0,110, -0,1,139,4352,1, -140,4436,19,4437,4, -56,73,0,110,0, -99,0,114,0,101, -0,109,0,101,0, -110,0,116,0,68, -0,101,0,99,0, -114,0,101,0,109, +161,4839,1,162,4917, +19,4918,4,30,85, +0,110,0,97,0, +114,0,121,0,69, +0,120,0,112,0, +114,0,101,0,115, +0,115,0,105,0, +111,0,110,0,1, +162,4839,1,163,4919, +19,4920,4,36,84, +0,121,0,112,0, +101,0,99,0,97, +0,115,0,116,0, +69,0,120,0,112, +0,114,0,101,0, +115,0,115,0,105, +0,111,0,110,0, +1,163,4839,1,164, +4921,19,4922,4,42, +80,0,97,0,114, 0,101,0,110,0, -116,0,69,0,120, +116,0,104,0,101, +0,115,0,105,0, +115,0,69,0,120, 0,112,0,114,0, 101,0,115,0,115, 0,105,0,111,0, -110,0,1,140,4352, -1,142,4438,19,683, -1,142,3911,1,143, -4439,19,705,1,143, -3911,1,144,4440,19, -3192,1,144,3914,1, -145,4441,19,3187,1, -145,3914,1,146,4442, -19,3198,1,146,3914, -1,147,4443,19,3209, -1,147,3914,1,148, -4444,19,3220,1,148, -3917,1,149,4445,19, -3226,1,149,3917,1, -150,4446,19,3214,1, -150,3921,1,151,4447, -19,3204,1,151,3921, -1,152,4448,19,689, -1,152,3925,1,153, -4449,19,710,1,153, -3925,1,154,4450,19, -695,1,154,3929,1, -155,4451,19,700,1, -155,3929,1,156,4452, -19,1636,1,156,3935, -1,157,4453,19,1631, -1,157,3935,1,158, -4454,19,1622,1,158, -3939,1,159,4455,19, -1680,1,159,3945,1, -160,4456,19,1657,1, -160,3945,1,161,4457, -19,1117,1,161,3950, -1,162,4458,19,902, -1,162,3995,1,163, -4459,19,886,1,163, -3995,1,164,4460,19, -892,1,164,4011,1, -165,4461,19,880,1, -165,4011,1,166,4462, -19,1145,1,166,4027, -1,167,4463,19,782, -1,167,4014,1,168, -4464,19,897,1,168, -4014,1,169,4465,19, -777,1,169,4014,1, -170,4466,19,802,1, -170,4014,1,171,4467, -19,771,1,171,4014, -1,172,4468,19,765, -1,172,4014,1,173, -4469,19,760,1,173, -4014,1,174,4470,19, -755,1,174,4014,1, -175,4471,19,749,1, -175,4014,1,176,4472, -19,744,1,176,4014, -1,177,4473,19,739, -1,177,4014,1,178, -4474,19,734,1,178, -4014,1,179,4475,19, -729,1,179,4014,1, -180,4476,19,1152,1, -180,4099,1,181,4477, -19,1290,1,181,4112, -1,182,4478,19,1139, -1,182,4125,1,183, -4479,19,1278,1,183, -4125,1,184,4480,19, -919,1,184,4138,1, -185,4481,19,722,1, -185,4138,1,186,4482, -19,817,1,186,4138, -1,187,4483,19,845, -1,187,4138,1,188, -4484,19,865,1,188, -4151,1,189,4485,19, -911,1,189,4151,1, -190,4486,19,825,1, -190,4164,1,191,4487, -19,838,1,191,4164, -1,192,4488,19,791, -1,192,4177,1,193, -4489,19,830,1,193, -4177,1,194,4490,19, -1477,1,194,4190,1, -195,4491,19,1158,1, -195,4190,1,196,4492, -19,1509,1,196,4190, -1,197,4493,19,1541, -1,197,4190,1,198, -4494,19,1406,1,198, -4040,1,199,4495,19, -1466,1,199,4040,1, -200,4496,19,1133,1, -200,4053,1,201,4497, -19,1573,1,201,4053, -1,202,4498,19,1504, -1,202,4053,1,203, -4499,19,1451,1,203, -4053,1,204,4500,19, -1374,1,204,4053,1, -205,4501,19,1300,1, -205,4053,1,206,4502, -19,1310,1,206,4053, -1,207,4503,19,1128, -1,207,4053,1,208, -4504,19,1557,1,208, -4053,1,209,4505,19, -1499,1,209,4053,1, -210,4506,19,1441,1, -210,4053,1,211,4507, -19,1363,1,211,4053, -1,212,4508,19,1326, -1,212,4053,1,213, -4509,19,1111,1,213, -4053,1,214,4510,19, -1461,1,214,4053,1, -215,4511,19,1487,1, -215,4053,1,216,4512, -19,1434,1,216,4053, -1,217,4513,19,1456, -1,217,4053,1,218, -4514,19,1266,1,218, -4053,1,219,4515,19, -1170,1,219,4053,1, -220,4516,19,1100,1, -220,4053,1,221,4517, -19,1531,1,221,4053, -1,222,4518,19,1482, -1,222,4053,1,223, -4519,19,1429,1,223, -4053,1,224,4520,19, -1295,1,224,4086,1, -225,4521,19,1273,1, -225,4086,1,226,4522, -19,1562,1,226,4276, -1,227,4523,19,1586, -1,227,4276,1,228, -4524,19,1552,1,228, -4276,1,229,4525,19, -1547,1,229,4276,1, -230,4526,19,1568,1, -230,4276,1,231,4527, -19,1515,1,231,4276, -1,232,4528,19,1220, -1,232,4276,1,233, -4529,19,1395,1,233, -4352,1,234,4530,19, -1181,1,234,4352,1, -235,4531,19,1188,1, -235,4352,1,236,4532, -19,1209,1,236,4352, -1,237,4533,19,1204, -1,237,4352,1,238, -4534,19,1199,1,238, -4352,1,239,4535,19, -1194,1,239,4352,1, -240,4536,19,1384,1, -240,4352,1,241,4537, -19,1412,1,241,4352, -1,242,4538,19,1389, -1,242,4352,1,243, -4539,19,1379,1,243, -4352,1,244,4540,19, -1369,1,244,4352,1, -245,4541,19,1352,1, -245,4352,1,246,4542, -19,1305,1,246,4352, -1,247,4543,19,1214, -1,247,4352,1,248, -4544,19,1175,1,248, -4352,1,249,4545,19, -1123,1,249,4352,1, -250,4546,19,1581,1, -250,4352,1,251,4547, -19,1536,1,251,4352, -1,252,4548,19,1526, -1,252,4352,1,253, -4549,19,1521,1,253, -4352,1,254,4550,19, -1472,1,254,4352,1, -255,4551,19,1446,1, -255,4352,1,256,4552, -19,1422,1,256,4352, -1,257,4553,19,1417, -1,257,4352,1,258, -4554,19,1358,1,258, -4352,1,259,4555,19, -1334,1,259,4352,1, -260,4556,19,1400,1, -260,4352,1,261,4557, -19,1493,1,261,4352, -1,262,4558,19,1347, -1,262,4352,1,263, -4559,19,1341,1,263, -4352,1,264,4560,19, -1321,1,264,4352,1, -265,4561,19,1284,1, -265,4352,1,266,4562, -19,1261,1,266,4352, -1,267,4563,19,1106, -1,267,4352,1,268, -4564,19,1596,1,268, -4352,1,269,4565,19, -1226,1,269,4352,1, -270,4566,19,1231,1, -270,4352,1,271,4567, -19,1251,1,271,4352, -1,272,4568,19,1241, -1,272,4352,1,273, -4569,19,1246,1,273, -4352,1,274,4570,19, -1236,1,274,4352,1, -275,4571,19,1591,1, -275,4352,1,276,4572, -19,1256,1,276,4352, -1,277,4573,19,1316, -1,277,4195,1,278, -4574,19,1650,1,278, -4265,1,279,4575,19, -1686,1,279,4265,1, -280,4576,19,1666,1, -280,4269,1,281,4577, -19,1985,1,281,3969, -1,282,4578,19,1980, -1,282,3969,1,283, -4579,19,1975,1,283, -3969,1,284,4580,19, -1970,1,284,3969,1, -285,4581,19,1965,1, -285,3969,1,286,4582, -19,1960,1,286,3969, -1,287,4583,19,1955, -1,287,3969,1,288, -4584,19,1944,1,288, -3989,1,289,4585,19, -1939,1,289,3989,1, -290,4586,19,1934,1, -290,3989,1,291,4587, -19,1929,1,291,3989, -1,292,4588,19,1924, -1,292,3989,1,293, -4589,19,1919,1,293, -3989,1,294,4590,19, -1914,1,294,3989,1, -295,4591,19,1909,1, -295,3989,1,296,4592, -19,1904,1,296,3989, -1,297,4593,19,1739, -1,297,3989,1,298, -4594,19,1898,1,298, -3989,1,299,4595,19, -1893,1,299,3989,1, -300,4596,19,1888,1, -300,3989,1,301,4597, -19,1732,1,301,3989, -1,302,4598,19,1883, -1,302,3989,1,303, -4599,19,1878,1,303, -3989,1,304,4600,19, -1873,1,304,3989,1, -305,4601,19,1868,1, -305,3989,1,306,4602, -19,1863,1,306,3989, -1,307,4603,19,1858, -1,307,3989,1,308, -4604,19,1725,1,308, -3989,1,309,4605,19, -1852,1,309,3989,1, -310,4606,19,1847,1, -310,3989,1,311,4607, -19,1842,1,311,3989, -1,312,4608,19,1719, -1,312,3989,1,313, -4609,19,1836,1,313, -3989,1,314,4610,19, -1767,1,314,3989,1, -315,4611,19,1831,1, -315,3989,1,316,4612, -19,1826,1,316,3989, -1,317,4613,19,1821, -1,317,3989,1,318, -4614,19,1816,1,318, -3989,1,319,4615,19, -1811,1,319,3989,1, -320,4616,19,1806,1, -320,3989,1,321,4617, -19,1801,1,321,3989, -1,322,4618,19,4619, -4,50,65,0,114, -0,103,0,117,0, +110,0,1,164,4839, +1,165,4923,19,4924, +4,56,73,0,110, +0,99,0,114,0, +101,0,109,0,101, +0,110,0,116,0, +68,0,101,0,99, +0,114,0,101,0, 109,0,101,0,110, -0,116,0,68,0, -101,0,99,0,108, -0,97,0,114,0, -97,0,116,0,105, -0,111,0,110,0, +0,116,0,69,0, +120,0,112,0,114, +0,101,0,115,0, +115,0,105,0,111, +0,110,0,1,165, +4839,1,167,4925,19, +830,1,167,4269,1, +168,4926,19,808,1, +168,4269,1,169,4927, +19,3557,1,169,4272, +1,170,4928,19,3547, +1,170,4272,1,171, +4929,19,3552,1,171, +4272,1,172,4930,19, +3542,1,172,4272,1, +173,4931,19,3527,1, +173,4275,1,174,4932, +19,3562,1,174,4275, +1,175,4933,19,3521, +1,175,4279,1,176, +4934,19,3535,1,176, +4279,1,177,4935,19, +814,1,177,4283,1, +178,4936,19,825,1, +178,4283,1,179,4937, +19,820,1,179,4287, +1,180,4938,19,835, +1,180,4287,1,181, +4939,19,1777,1,181, +4293,1,182,4940,19, +1881,1,182,4293,1, +183,4941,19,1844,1, +183,4293,1,184,4942, +19,1765,1,184,4293, +1,185,4943,19,1839, +1,185,4293,1,186, +4944,19,1802,1,186, +4293,1,187,4945,19, +1834,1,187,4293,1, +188,4946,19,1797,1, +188,4293,1,189,4947, +19,1829,1,189,4293, +1,190,4948,19,1792, +1,190,4293,1,191, +4949,19,1824,1,191, +4293,1,192,4950,19, +1760,1,192,4293,1, +193,4951,19,1819,1, +193,4293,1,194,4952, +19,1787,1,194,4293, +1,195,4953,19,1814, +1,195,4293,1,196, +4954,19,1782,1,196, +4293,1,197,4955,19, +1875,1,197,4297,1, +198,4956,19,1862,1, +198,4303,1,199,4957, +19,1850,1,199,4309, +1,200,4958,19,1809, +1,200,4315,1,201, +4959,19,1868,1,201, +4321,1,202,4960,19, +1856,1,202,4327,1, +203,4961,19,1754,1, +203,4333,1,204,4962, +19,1771,1,204,4339, +1,205,4963,19,1945, +1,205,4345,1,206, +4964,19,1904,1,206, +4345,1,207,4965,19, +2337,1,207,4350,1, +208,4966,19,2308,1, +208,4353,1,209,4967, +19,2302,1,209,4356, +1,210,4968,19,2294, +1,210,4359,1,211, +4969,19,2287,1,211, +4362,1,212,4970,19, +2319,1,212,4365,1, +213,4971,19,1242,1, +213,4368,1,214,4972, +19,1964,1,214,4387, +1,215,4973,19,1890, +1,215,4391,1,216, +4974,19,1931,1,216, +4398,1,217,4975,19, +1910,1,217,4403,1, +218,4976,19,1027,1, +218,4475,1,219,4977, +19,1011,1,219,4475, +1,220,4978,19,1017, +1,220,4498,1,221, +4979,19,1005,1,221, +4498,1,222,4980,19, +1270,1,222,4514,1, +223,4981,19,907,1, +223,4501,1,224,4982, +19,1022,1,224,4501, +1,225,4983,19,902, +1,225,4501,1,226, +4984,19,927,1,226, +4501,1,227,4985,19, +896,1,227,4501,1, +228,4986,19,890,1, +228,4501,1,229,4987, +19,885,1,229,4501, +1,230,4988,19,880, +1,230,4501,1,231, +4989,19,874,1,231, +4501,1,232,4990,19, +869,1,232,4501,1, +233,4991,19,864,1, +233,4501,1,234,4992, +19,859,1,234,4501, +1,235,4993,19,854, +1,235,4501,1,236, +4994,19,1277,1,236, +4586,1,237,4995,19, +1417,1,237,4599,1, +238,4996,19,1264,1, +238,4612,1,239,4997, +19,1405,1,239,4612, +1,240,4998,19,1044, +1,240,4625,1,241, +4999,19,847,1,241, +4625,1,242,5000,19, +942,1,242,4625,1, +243,5001,19,971,1, +243,4625,1,244,5002, +19,990,1,244,4638, +1,245,5003,19,1036, +1,245,4638,1,246, +5004,19,950,1,246, +4651,1,247,5005,19, +964,1,247,4651,1, +248,5006,19,916,1, +248,4664,1,249,5007, +19,955,1,249,4664, +1,250,5008,19,1603, +1,250,4677,1,251, +5009,19,1283,1,251, +4677,1,252,5010,19, +1635,1,252,4677,1, +253,5011,19,1667,1, +253,4677,1,254,5012, +19,1532,1,254,4527, +1,255,5013,19,1592, +1,255,4527,1,256, +5014,19,1258,1,256, +4540,1,257,5015,19, +1699,1,257,4540,1, +258,5016,19,1630,1, +258,4540,1,259,5017, +19,1576,1,259,4540, +1,260,5018,19,1500, +1,260,4540,1,261, +5019,19,1427,1,261, +4540,1,262,5020,19, +1437,1,262,4540,1, +263,5021,19,1253,1, +263,4540,1,264,5022, +19,1683,1,264,4540, +1,265,5023,19,1625, +1,265,4540,1,266, +5024,19,1566,1,266, +4540,1,267,5025,19, +1489,1,267,4540,1, +268,5026,19,1453,1, +268,4540,1,269,5027, +19,1236,1,269,4540, +1,270,5028,19,1586, +1,270,4540,1,271, +5029,19,1613,1,271, +4540,1,272,5030,19, +1559,1,272,4540,1, +273,5031,19,1581,1, +273,4540,1,274,5032, +19,1393,1,274,4540, +1,275,5033,19,1297, +1,275,4540,1,276, +5034,19,1225,1,276, +4540,1,277,5035,19, +1657,1,277,4540,1, +278,5036,19,1608,1, +278,4540,1,279,5037, +19,1554,1,279,4540, +1,280,5038,19,1422, +1,280,4573,1,281, +5039,19,1400,1,281, +4573,1,282,5040,19, +1688,1,282,4763,1, +283,5041,19,1711,1, +283,4763,1,284,5042, +19,1678,1,284,4763, +1,285,5043,19,1673, +1,285,4763,1,286, +5044,19,1694,1,286, +4763,1,287,5045,19, +1641,1,287,4763,1, +288,5046,19,1347,1, +288,4763,1,289,5047, +19,1521,1,289,4839, +1,290,5048,19,1308, +1,290,4839,1,291, +5049,19,1315,1,291, +4839,1,292,5050,19, +1336,1,292,4839,1, +293,5051,19,1331,1, +293,4839,1,294,5052, +19,1326,1,294,4839, +1,295,5053,19,1321, +1,295,4839,1,296, +5054,19,1510,1,296, +4839,1,297,5055,19, +1538,1,297,4839,1, +298,5056,19,1515,1, +298,4839,1,299,5057, +19,1505,1,299,4839, +1,300,5058,19,1495, +1,300,4839,1,301, +5059,19,1478,1,301, +4839,1,302,5060,19, +1432,1,302,4839,1, +303,5061,19,1341,1, +303,4839,1,304,5062, +19,1302,1,304,4839, +1,305,5063,19,1248, +1,305,4839,1,306, +5064,19,1706,1,306, +4839,1,307,5065,19, +1662,1,307,4839,1, +308,5066,19,1652,1, +308,4839,1,309,5067, +19,1647,1,309,4839, +1,310,5068,19,1598, +1,310,4839,1,311, +5069,19,1571,1,311, +4839,1,312,5070,19, +1548,1,312,4839,1, +313,5071,19,1543,1, +313,4839,1,314,5072, +19,1484,1,314,4839, +1,315,5073,19,1460, +1,315,4839,1,316, +5074,19,1526,1,316, +4839,1,317,5075,19, +1619,1,317,4839,1, +318,5076,19,1473,1, +318,4839,1,319,5077, +19,1467,1,319,4839, +1,320,5078,19,1448, +1,320,4839,1,321, +5079,19,1411,1,321, +4839,1,322,5080,19, +1388,1,322,4839,1, +323,5081,19,1231,1, +323,4839,1,324,5082, +19,1721,1,324,4839, +1,325,5083,19,1353, +1,325,4839,1,326, +5084,19,1358,1,326, +4839,1,327,5085,19, +1378,1,327,4839,1, +328,5086,19,1368,1, +328,4839,1,329,5087, +19,1373,1,329,4839, +1,330,5088,19,1363, +1,330,4839,1,331, +5089,19,1716,1,331, +4839,1,332,5090,19, +1383,1,332,4839,1, +333,5091,19,1443,1, +333,4682,1,334,5092, +19,1958,1,334,4752, +1,335,5093,19,1951, +1,335,4752,1,336, +5094,19,1921,1,336, +4756,1,337,5095,19, +2278,1,337,4407,1, +338,5096,19,2273,1, +338,4407,1,339,5097, +19,2268,1,339,4407, +1,340,5098,19,2263, +1,340,4407,1,341, +5099,19,2258,1,341, +4407,1,342,5100,19, +2253,1,342,4407,1, +343,5101,19,2248,1, +343,4407,1,344,5102, +19,2237,1,344,4427, +1,345,5103,19,2232, +1,345,4427,1,346, +5104,19,2227,1,346, +4427,1,347,5105,19, +2222,1,347,4427,1, +348,5106,19,2217,1, +348,4427,1,349,5107, +19,2212,1,349,4427, +1,350,5108,19,2207, +1,350,4427,1,351, +5109,19,2202,1,351, +4427,1,352,5110,19, +2197,1,352,4427,1, +353,5111,19,2191,1, +353,4433,1,354,5112, +19,2019,1,354,4433, +1,355,5113,19,2185, +1,355,4433,1,356, +5114,19,2180,1,356, +4433,1,357,5115,19, +2175,1,357,4433,1, +358,5116,19,2012,1, +358,4433,1,359,5117, +19,2170,1,359,4433, +1,360,5118,19,2165, +1,360,4433,1,361, +5119,19,2160,1,361, +4439,1,362,5120,19, +2155,1,362,4439,1, +363,5121,19,2149,1, +363,4445,1,364,5122, +19,2144,1,364,4445, +1,365,5123,19,2004, +1,365,4445,1,366, +5124,19,2138,1,366, +4445,1,367,5125,19, +2133,1,367,4445,1, +368,5126,19,2128,1, +368,4445,1,369,5127, +19,1997,1,369,4445, +1,370,5128,19,2122, +1,370,4445,1,371, +5129,19,2049,1,371, +4445,1,372,5130,19, +2117,1,372,4445,1, +373,5131,19,2112,1, +373,4451,1,374,5132, +19,2107,1,374,4451, +1,375,5133,19,2102, +1,375,4451,1,376, +5134,19,2096,1,376, +4457,1,377,5135,19, +2090,1,377,4463,1, +378,5136,19,2084,1, +378,4469,1,379,5137, +19,5138,4,50,65, +0,114,0,103,0, +117,0,109,0,101, +0,110,0,116,0, +68,0,101,0,99, +0,108,0,97,0, +114,0,97,0,116, +0,105,0,111,0, +110,0,76,0,105, +0,115,0,116,0, +95,0,51,0,1, +379,4345,1,380,5139, +19,5140,4,28,65, +0,114,0,103,0, +117,0,109,0,101, +0,110,0,116,0, 76,0,105,0,115, 0,116,0,95,0, -51,0,1,322,3945, -1,323,4620,19,4621, +51,0,1,380,4752, +1,381,5141,19,5142, 4,28,65,0,114, 0,103,0,117,0, 109,0,101,0,110, 0,116,0,76,0, 105,0,115,0,116, -0,95,0,51,0, -1,323,4265,1,324, -4622,19,4623,4,50, +0,95,0,52,0, +1,381,4752,1,382, +5143,19,5144,4,50, 65,0,114,0,103, 0,117,0,109,0, 101,0,110,0,116, @@ -10759,32 +12939,29 @@ public yyLSLSyntax 0,110,0,76,0, 105,0,115,0,116, 0,95,0,52,0, -1,324,3945,1,325, -4624,19,4625,4,28, +1,382,4345,1,383, +5145,19,5146,4,50, 65,0,114,0,103, 0,117,0,109,0, 101,0,110,0,116, -0,76,0,105,0, -115,0,116,0,95, -0,52,0,1,325, -4265,1,326,4626,19, -4627,4,50,65,0, -114,0,103,0,117, -0,109,0,101,0, -110,0,116,0,68, -0,101,0,99,0, -108,0,97,0,114, -0,97,0,116,0, -105,0,111,0,110, -0,76,0,105,0, -115,0,116,0,95, -0,53,0,1,326, -3945,2,0,0}; +0,68,0,101,0, +99,0,108,0,97, +0,114,0,97,0, +116,0,105,0,111, +0,110,0,76,0, +105,0,115,0,116, +0,95,0,53,0, +1,383,4345,2,0,0}; new Sfactory(this,"ExpressionArgument_1",new SCreator(ExpressionArgument_1_factory)); -new Sfactory(this,"SimpleAssignment_8",new SCreator(SimpleAssignment_8_factory)); +new Sfactory(this,"VectorArgStateEvent",new SCreator(VectorArgStateEvent_factory)); +new Sfactory(this,"IntVecVecArgStateEvent",new SCreator(IntVecVecArgStateEvent_factory)); +new Sfactory(this,"IntArgStateEvent_1",new SCreator(IntArgStateEvent_1_factory)); +new Sfactory(this,"SimpleAssignment_9",new SCreator(SimpleAssignment_9_factory)); new Sfactory(this,"StatementList_1",new SCreator(StatementList_1_factory)); +new Sfactory(this,"RotDeclaration_1",new SCreator(RotDeclaration_1_factory)); +new Sfactory(this,"IntRotRotArgEvent_1",new SCreator(IntRotRotArgEvent_1_factory)); new Sfactory(this,"StateChange_1",new SCreator(StateChange_1_factory)); -new Sfactory(this,"StateChange_2",new SCreator(StateChange_2_factory)); +new Sfactory(this,"EmptyStatement",new SCreator(EmptyStatement_factory)); new Sfactory(this,"Declaration",new SCreator(Declaration_factory)); new Sfactory(this,"IdentExpression",new SCreator(IdentExpression_factory)); new Sfactory(this,"error",new SCreator(error_factory)); @@ -10797,20 +12974,25 @@ new Sfactory(this,"SimpleAssignment_19",new SCreator(SimpleAssignment_19_factory new Sfactory(this,"BinaryExpression_9",new SCreator(BinaryExpression_9_factory)); new Sfactory(this,"VectorConstant_1",new SCreator(VectorConstant_1_factory)); new Sfactory(this,"ParenthesisExpression",new SCreator(ParenthesisExpression_factory)); +new Sfactory(this,"StatementList",new SCreator(StatementList_factory)); +new Sfactory(this,"IntRotRotArgEvent",new SCreator(IntRotRotArgEvent_factory)); new Sfactory(this,"UnaryExpression",new SCreator(UnaryExpression_factory)); new Sfactory(this,"IdentDotExpression_1",new SCreator(IdentDotExpression_1_factory)); new Sfactory(this,"ArgumentList_4",new SCreator(ArgumentList_4_factory)); new Sfactory(this,"Typename",new SCreator(Typename_factory)); new Sfactory(this,"IfStatement_1",new SCreator(IfStatement_1_factory)); +new Sfactory(this,"RotationConstant_1",new SCreator(RotationConstant_1_factory)); new Sfactory(this,"Assignment",new SCreator(Assignment_factory)); +new Sfactory(this,"IfStatement_4",new SCreator(IfStatement_4_factory)); new Sfactory(this,"CompoundStatement_1",new SCreator(CompoundStatement_1_factory)); new Sfactory(this,"CompoundStatement_2",new SCreator(CompoundStatement_2_factory)); +new Sfactory(this,"KeyIntIntArgumentDeclarationList_1",new SCreator(KeyIntIntArgumentDeclarationList_1_factory)); new Sfactory(this,"BinaryExpression_8",new SCreator(BinaryExpression_8_factory)); +new Sfactory(this,"VectorArgEvent",new SCreator(VectorArgEvent_factory)); new Sfactory(this,"ReturnStatement_1",new SCreator(ReturnStatement_1_factory)); new Sfactory(this,"IdentDotExpression",new SCreator(IdentDotExpression_factory)); new Sfactory(this,"Argument",new SCreator(Argument_factory)); new Sfactory(this,"State_2",new SCreator(State_2_factory)); -new Sfactory(this,"WhileStatement_1",new SCreator(WhileStatement_1_factory)); new Sfactory(this,"GlobalDefinitions_3",new SCreator(GlobalDefinitions_3_factory)); new Sfactory(this,"GlobalDefinitions_4",new SCreator(GlobalDefinitions_4_factory)); new Sfactory(this,"Event_1",new SCreator(Event_1_factory)); @@ -10820,9 +13002,9 @@ new Sfactory(this,"Event_4",new SCreator(Event_4_factory)); new Sfactory(this,"Event_5",new SCreator(Event_5_factory)); new Sfactory(this,"SimpleAssignment_5",new SCreator(SimpleAssignment_5_factory)); new Sfactory(this,"Typename_1",new SCreator(Typename_1_factory)); -new Sfactory(this,"Typename_2",new SCreator(Typename_2_factory)); +new Sfactory(this,"VoidArgStateEvent_1",new SCreator(VoidArgStateEvent_1_factory)); new Sfactory(this,"Typename_3",new SCreator(Typename_3_factory)); -new Sfactory(this,"Typename_4",new SCreator(Typename_4_factory)); +new Sfactory(this,"IntRotRotArgStateEvent",new SCreator(IntRotRotArgStateEvent_factory)); new Sfactory(this,"Typename_5",new SCreator(Typename_5_factory)); new Sfactory(this,"Typename_6",new SCreator(Typename_6_factory)); new Sfactory(this,"Typename_7",new SCreator(Typename_7_factory)); @@ -10830,10 +13012,16 @@ new Sfactory(this,"ArgumentDeclarationList",new SCreator(ArgumentDeclarationList new Sfactory(this,"ConstantExpression",new SCreator(ConstantExpression_factory)); new Sfactory(this,"LSLProgramRoot_1",new SCreator(LSLProgramRoot_1_factory)); new Sfactory(this,"LSLProgramRoot_2",new SCreator(LSLProgramRoot_2_factory)); +new Sfactory(this,"KeyIntIntArgEvent_1",new SCreator(KeyIntIntArgEvent_1_factory)); new Sfactory(this,"States_1",new SCreator(States_1_factory)); new Sfactory(this,"States_2",new SCreator(States_2_factory)); new Sfactory(this,"FunctionCallExpression_1",new SCreator(FunctionCallExpression_1_factory)); +new Sfactory(this,"KeyArgEvent_1",new SCreator(KeyArgEvent_1_factory)); new Sfactory(this,"ForLoopStatement",new SCreator(ForLoopStatement_factory)); +new Sfactory(this,"IntArgStateEvent",new SCreator(IntArgStateEvent_factory)); +new Sfactory(this,"StateBody_15",new SCreator(StateBody_15_factory)); +new Sfactory(this,"IntRotRotArgumentDeclarationList_1",new SCreator(IntRotRotArgumentDeclarationList_1_factory)); +new Sfactory(this,"IntArgEvent_9",new SCreator(IntArgEvent_9_factory)); new Sfactory(this,"DoWhileStatement_1",new SCreator(DoWhileStatement_1_factory)); new Sfactory(this,"DoWhileStatement_2",new SCreator(DoWhileStatement_2_factory)); new Sfactory(this,"ForLoopStatement_4",new SCreator(ForLoopStatement_4_factory)); @@ -10842,74 +13030,93 @@ new Sfactory(this,"SimpleAssignment_12",new SCreator(SimpleAssignment_12_factory new Sfactory(this,"SimpleAssignment_13",new SCreator(SimpleAssignment_13_factory)); new Sfactory(this,"JumpLabel",new SCreator(JumpLabel_factory)); new Sfactory(this,"SimpleAssignment_15",new SCreator(SimpleAssignment_15_factory)); -new Sfactory(this,"SimpleAssignment_17",new SCreator(SimpleAssignment_17_factory)); -new Sfactory(this,"SimpleAssignment_18",new SCreator(SimpleAssignment_18_factory)); -new Sfactory(this,"JumpStatement_1",new SCreator(JumpStatement_1_factory)); +new Sfactory(this,"IntVecVecArgEvent",new SCreator(IntVecVecArgEvent_factory)); +new Sfactory(this,"VecDeclaration",new SCreator(VecDeclaration_factory)); +new Sfactory(this,"StateBody_14",new SCreator(StateBody_14_factory)); new Sfactory(this,"GlobalDefinitions",new SCreator(GlobalDefinitions_factory)); +new Sfactory(this,"StateBody_16",new SCreator(StateBody_16_factory)); +new Sfactory(this,"KeyIntIntArgumentDeclarationList",new SCreator(KeyIntIntArgumentDeclarationList_factory)); +new Sfactory(this,"ConstantExpression_1",new SCreator(ConstantExpression_1_factory)); +new Sfactory(this,"VoidArgEvent_4",new SCreator(VoidArgEvent_4_factory)); new Sfactory(this,"FunctionCall_1",new SCreator(FunctionCall_1_factory)); -new Sfactory(this,"ArgumentList_3",new SCreator(ArgumentList_3_factory)); +new Sfactory(this,"Assignment_1",new SCreator(Assignment_1_factory)); new Sfactory(this,"Assignment_2",new SCreator(Assignment_2_factory)); +new Sfactory(this,"IntVecVecArgEvent_1",new SCreator(IntVecVecArgEvent_1_factory)); new Sfactory(this,"TypecastExpression_1",new SCreator(TypecastExpression_1_factory)); new Sfactory(this,"SimpleAssignment_21",new SCreator(SimpleAssignment_21_factory)); new Sfactory(this,"SimpleAssignment_22",new SCreator(SimpleAssignment_22_factory)); -new Sfactory(this,"SimpleAssignment_23",new SCreator(SimpleAssignment_23_factory)); +new Sfactory(this,"KeyIntIntArgStateEvent",new SCreator(KeyIntIntArgStateEvent_factory)); new Sfactory(this,"TypecastExpression_9",new SCreator(TypecastExpression_9_factory)); +new Sfactory(this,"VoidArgEvent_2",new SCreator(VoidArgEvent_2_factory)); +new Sfactory(this,"Event_9",new SCreator(Event_9_factory)); new Sfactory(this,"ArgumentDeclarationList_1",new SCreator(ArgumentDeclarationList_1_factory)); new Sfactory(this,"ArgumentDeclarationList_2",new SCreator(ArgumentDeclarationList_2_factory)); -new Sfactory(this,"ArgumentDeclarationList_3",new SCreator(ArgumentDeclarationList_3_factory)); new Sfactory(this,"GlobalDefinitions_1",new SCreator(GlobalDefinitions_1_factory)); new Sfactory(this,"GlobalDefinitions_2",new SCreator(GlobalDefinitions_2_factory)); new Sfactory(this,"IncrementDecrementExpression",new SCreator(IncrementDecrementExpression_factory)); new Sfactory(this,"GlobalVariableDeclaration",new SCreator(GlobalVariableDeclaration_factory)); -new Sfactory(this,"Event_11",new SCreator(Event_11_factory)); +new Sfactory(this,"IntArgumentDeclarationList_1",new SCreator(IntArgumentDeclarationList_1_factory)); +new Sfactory(this,"IntDeclaration_1",new SCreator(IntDeclaration_1_factory)); +new Sfactory(this,"ArgumentDeclarationList_5",new SCreator(ArgumentDeclarationList_5_factory)); +new Sfactory(this,"IntVecVecArgumentDeclarationList",new SCreator(IntVecVecArgumentDeclarationList_factory)); +new Sfactory(this,"VectorArgumentDeclarationList_1",new SCreator(VectorArgumentDeclarationList_1_factory)); +new Sfactory(this,"KeyArgumentDeclarationList",new SCreator(KeyArgumentDeclarationList_factory)); new Sfactory(this,"TypecastExpression_2",new SCreator(TypecastExpression_2_factory)); -new Sfactory(this,"TypecastExpression_3",new SCreator(TypecastExpression_3_factory)); +new Sfactory(this,"KeyArgStateEvent",new SCreator(KeyArgStateEvent_factory)); new Sfactory(this,"TypecastExpression_5",new SCreator(TypecastExpression_5_factory)); new Sfactory(this,"TypecastExpression_8",new SCreator(TypecastExpression_8_factory)); new Sfactory(this,"Constant_1",new SCreator(Constant_1_factory)); new Sfactory(this,"Expression",new SCreator(Expression_factory)); new Sfactory(this,"Constant_3",new SCreator(Constant_3_factory)); new Sfactory(this,"Constant_4",new SCreator(Constant_4_factory)); +new Sfactory(this,"IntArgEvent_5",new SCreator(IntArgEvent_5_factory)); new Sfactory(this,"BinaryExpression_1",new SCreator(BinaryExpression_1_factory)); new Sfactory(this,"IfStatement_2",new SCreator(IfStatement_2_factory)); new Sfactory(this,"IfStatement_3",new SCreator(IfStatement_3_factory)); -new Sfactory(this,"IfStatement_4",new SCreator(IfStatement_4_factory)); -new Sfactory(this,"ReturnStatement",new SCreator(ReturnStatement_factory)); +new Sfactory(this,"KeyArgEvent",new SCreator(KeyArgEvent_factory)); new Sfactory(this,"Event_2",new SCreator(Event_2_factory)); +new Sfactory(this,"JumpLabel_1",new SCreator(JumpLabel_1_factory)); new Sfactory(this,"RotationConstant",new SCreator(RotationConstant_factory)); new Sfactory(this,"Statement_12",new SCreator(Statement_12_factory)); +new Sfactory(this,"Statement_13",new SCreator(Statement_13_factory)); new Sfactory(this,"UnaryExpression_1",new SCreator(UnaryExpression_1_factory)); new Sfactory(this,"UnaryExpression_2",new SCreator(UnaryExpression_2_factory)); new Sfactory(this,"UnaryExpression_3",new SCreator(UnaryExpression_3_factory)); new Sfactory(this,"ArgumentList_1",new SCreator(ArgumentList_1_factory)); -new Sfactory(this,"ArgumentList_2",new SCreator(ArgumentList_2_factory)); +new Sfactory(this,"KeyIntIntArgEvent",new SCreator(KeyIntIntArgEvent_factory)); +new Sfactory(this,"ArgumentList_3",new SCreator(ArgumentList_3_factory)); new Sfactory(this,"Constant",new SCreator(Constant_factory)); new Sfactory(this,"State",new SCreator(State_factory)); -new Sfactory(this,"Event_13",new SCreator(Event_13_factory)); +new Sfactory(this,"StateBody_13",new SCreator(StateBody_13_factory)); +new Sfactory(this,"KeyArgStateEvent_1",new SCreator(KeyArgStateEvent_1_factory)); +new Sfactory(this,"SimpleAssignment_8",new SCreator(SimpleAssignment_8_factory)); new Sfactory(this,"LSLProgramRoot",new SCreator(LSLProgramRoot_factory)); new Sfactory(this,"StateChange",new SCreator(StateChange_factory)); -new Sfactory(this,"IncrementDecrementExpression_2",new SCreator(IncrementDecrementExpression_2_factory)); +new Sfactory(this,"VecDeclaration_1",new SCreator(VecDeclaration_1_factory)); new Sfactory(this,"GlobalVariableDeclaration_1",new SCreator(GlobalVariableDeclaration_1_factory)); new Sfactory(this,"GlobalVariableDeclaration_2",new SCreator(GlobalVariableDeclaration_2_factory)); new Sfactory(this,"IncrementDecrementExpression_5",new SCreator(IncrementDecrementExpression_5_factory)); -new Sfactory(this,"GlobalFunctionDefinition_2",new SCreator(GlobalFunctionDefinition_2_factory)); -new Sfactory(this,"IncrementDecrementExpression_7",new SCreator(IncrementDecrementExpression_7_factory)); -new Sfactory(this,"IncrementDecrementExpression_8",new SCreator(IncrementDecrementExpression_8_factory)); -new Sfactory(this,"Assignment_1",new SCreator(Assignment_1_factory)); -new Sfactory(this,"Event_21",new SCreator(Event_21_factory)); -new Sfactory(this,"Event_22",new SCreator(Event_22_factory)); +new Sfactory(this,"ReturnStatement",new SCreator(ReturnStatement_factory)); +new Sfactory(this,"StateBody_10",new SCreator(StateBody_10_factory)); +new Sfactory(this,"StateBody_11",new SCreator(StateBody_11_factory)); +new Sfactory(this,"StateBody_12",new SCreator(StateBody_12_factory)); +new Sfactory(this,"IntVecVecArgStateEvent_1",new SCreator(IntVecVecArgStateEvent_1_factory)); +new Sfactory(this,"KeyDeclaration",new SCreator(KeyDeclaration_factory)); +new Sfactory(this,"IntArgEvent_6",new SCreator(IntArgEvent_6_factory)); +new Sfactory(this,"ArgumentDeclarationList_3",new SCreator(ArgumentDeclarationList_3_factory)); +new Sfactory(this,"ArgumentList_2",new SCreator(ArgumentList_2_factory)); +new Sfactory(this,"IntArgEvent_10",new SCreator(IntArgEvent_10_factory)); new Sfactory(this,"CompoundStatement",new SCreator(CompoundStatement_factory)); -new Sfactory(this,"RotationConstant_1",new SCreator(RotationConstant_1_factory)); -new Sfactory(this,"TypecastExpression",new SCreator(TypecastExpression_factory)); +new Sfactory(this,"TypecastExpression_3",new SCreator(TypecastExpression_3_factory)); +new Sfactory(this,"IntArgumentDeclarationList",new SCreator(IntArgumentDeclarationList_factory)); +new Sfactory(this,"ArgumentDeclarationList_4",new SCreator(ArgumentDeclarationList_4_factory)); new Sfactory(this,"SimpleAssignment_3",new SCreator(SimpleAssignment_3_factory)); new Sfactory(this,"SimpleAssignment_4",new SCreator(SimpleAssignment_4_factory)); new Sfactory(this,"Statement_1",new SCreator(Statement_1_factory)); new Sfactory(this,"Statement_2",new SCreator(Statement_2_factory)); -new Sfactory(this,"Statement_3",new SCreator(Statement_3_factory)); new Sfactory(this,"Statement_4",new SCreator(Statement_4_factory)); new Sfactory(this,"Statement_5",new SCreator(Statement_5_factory)); new Sfactory(this,"Statement_6",new SCreator(Statement_6_factory)); -new Sfactory(this,"Statement_7",new SCreator(Statement_7_factory)); new Sfactory(this,"Statement_8",new SCreator(Statement_8_factory)); new Sfactory(this,"Statement_9",new SCreator(Statement_9_factory)); new Sfactory(this,"ExpressionArgument",new SCreator(ExpressionArgument_factory)); @@ -10922,27 +13129,35 @@ new Sfactory(this,"StateBody",new SCreator(StateBody_factory)); new Sfactory(this,"Event_7",new SCreator(Event_7_factory)); new Sfactory(this,"Event_8",new SCreator(Event_8_factory)); new Sfactory(this,"IncrementDecrementExpression_1",new SCreator(IncrementDecrementExpression_1_factory)); -new Sfactory(this,"IncrementDecrementExpression_3",new SCreator(IncrementDecrementExpression_3_factory)); +new Sfactory(this,"IncrementDecrementExpression_2",new SCreator(IncrementDecrementExpression_2_factory)); +new Sfactory(this,"IntVecVecArgumentDeclarationList_1",new SCreator(IntVecVecArgumentDeclarationList_1_factory)); new Sfactory(this,"IncrementDecrementExpression_4",new SCreator(IncrementDecrementExpression_4_factory)); new Sfactory(this,"IncrementDecrementExpression_6",new SCreator(IncrementDecrementExpression_6_factory)); +new Sfactory(this,"IncrementDecrementExpression_7",new SCreator(IncrementDecrementExpression_7_factory)); new Sfactory(this,"StateEvent",new SCreator(StateEvent_factory)); -new Sfactory(this,"Event_20",new SCreator(Event_20_factory)); -new Sfactory(this,"Event_23",new SCreator(Event_23_factory)); -new Sfactory(this,"Event_24",new SCreator(Event_24_factory)); -new Sfactory(this,"Event_26",new SCreator(Event_26_factory)); +new Sfactory(this,"IntArgEvent_3",new SCreator(IntArgEvent_3_factory)); +new Sfactory(this,"IntArgEvent_4",new SCreator(IntArgEvent_4_factory)); +new Sfactory(this,"KeyDeclaration_1",new SCreator(KeyDeclaration_1_factory)); +new Sfactory(this,"Statement_3",new SCreator(Statement_3_factory)); +new Sfactory(this,"IntArgEvent_7",new SCreator(IntArgEvent_7_factory)); +new Sfactory(this,"IntArgEvent_8",new SCreator(IntArgEvent_8_factory)); new Sfactory(this,"SimpleAssignment_10",new SCreator(SimpleAssignment_10_factory)); +new Sfactory(this,"StatementList_2",new SCreator(StatementList_2_factory)); +new Sfactory(this,"IntRotRotArgStateEvent_1",new SCreator(IntRotRotArgStateEvent_1_factory)); +new Sfactory(this,"VectorArgEvent_2",new SCreator(VectorArgEvent_2_factory)); new Sfactory(this,"Event",new SCreator(Event_factory)); new Sfactory(this,"SimpleAssignment_14",new SCreator(SimpleAssignment_14_factory)); new Sfactory(this,"SimpleAssignment_16",new SCreator(SimpleAssignment_16_factory)); +new Sfactory(this,"SimpleAssignment_17",new SCreator(SimpleAssignment_17_factory)); +new Sfactory(this,"SimpleAssignment_18",new SCreator(SimpleAssignment_18_factory)); new Sfactory(this,"Statement_10",new SCreator(Statement_10_factory)); new Sfactory(this,"Statement_11",new SCreator(Statement_11_factory)); new Sfactory(this,"SimpleAssignment",new SCreator(SimpleAssignment_factory)); -new Sfactory(this,"Statement_13",new SCreator(Statement_13_factory)); -new Sfactory(this,"Event_15",new SCreator(Event_15_factory)); -new Sfactory(this,"Event_16",new SCreator(Event_16_factory)); -new Sfactory(this,"Event_32",new SCreator(Event_32_factory)); -new Sfactory(this,"Event_34",new SCreator(Event_34_factory)); +new Sfactory(this,"TypecastExpression",new SCreator(TypecastExpression_factory)); +new Sfactory(this,"JumpStatement_1",new SCreator(JumpStatement_1_factory)); new Sfactory(this,"SimpleAssignment_20",new SCreator(SimpleAssignment_20_factory)); +new Sfactory(this,"Statement_7",new SCreator(Statement_7_factory)); +new Sfactory(this,"SimpleAssignment_23",new SCreator(SimpleAssignment_23_factory)); new Sfactory(this,"SimpleAssignment_24",new SCreator(SimpleAssignment_24_factory)); new Sfactory(this,"SimpleAssignment_1",new SCreator(SimpleAssignment_1_factory)); new Sfactory(this,"SimpleAssignment_2",new SCreator(SimpleAssignment_2_factory)); @@ -10950,73 +13165,91 @@ new Sfactory(this,"BinaryExpression",new SCreator(BinaryExpression_factory)); new Sfactory(this,"FunctionCallExpression",new SCreator(FunctionCallExpression_factory)); new Sfactory(this,"SimpleAssignment_6",new SCreator(SimpleAssignment_6_factory)); new Sfactory(this,"StateBody_1",new SCreator(StateBody_1_factory)); -new Sfactory(this,"StatementList_2",new SCreator(StatementList_2_factory)); -new Sfactory(this,"SimpleAssignment_9",new SCreator(SimpleAssignment_9_factory)); -new Sfactory(this,"BinaryExpression_15",new SCreator(BinaryExpression_15_factory)); -new Sfactory(this,"BinaryExpression_16",new SCreator(BinaryExpression_16_factory)); -new Sfactory(this,"BinaryExpression_17",new SCreator(BinaryExpression_17_factory)); -new Sfactory(this,"BinaryExpression_18",new SCreator(BinaryExpression_18_factory)); -new Sfactory(this,"Event_25",new SCreator(Event_25_factory)); -new Sfactory(this,"Event_9",new SCreator(Event_9_factory)); +new Sfactory(this,"StateBody_2",new SCreator(StateBody_2_factory)); +new Sfactory(this,"StateBody_3",new SCreator(StateBody_3_factory)); +new Sfactory(this,"StateBody_4",new SCreator(StateBody_4_factory)); +new Sfactory(this,"StateBody_5",new SCreator(StateBody_5_factory)); +new Sfactory(this,"StateBody_6",new SCreator(StateBody_6_factory)); +new Sfactory(this,"StateBody_7",new SCreator(StateBody_7_factory)); +new Sfactory(this,"StateBody_8",new SCreator(StateBody_8_factory)); +new Sfactory(this,"StateBody_9",new SCreator(StateBody_9_factory)); new Sfactory(this,"Statement",new SCreator(Statement_factory)); +new Sfactory(this,"IncrementDecrementExpression_3",new SCreator(IncrementDecrementExpression_3_factory)); new Sfactory(this,"JumpStatement",new SCreator(JumpStatement_factory)); new Sfactory(this,"BinaryExpression_11",new SCreator(BinaryExpression_11_factory)); -new Sfactory(this,"BinaryExpression_12",new SCreator(BinaryExpression_12_factory)); -new Sfactory(this,"BinaryExpression_13",new SCreator(BinaryExpression_13_factory)); +new Sfactory(this,"IntArgEvent",new SCreator(IntArgEvent_factory)); +new Sfactory(this,"IncrementDecrementExpression_8",new SCreator(IncrementDecrementExpression_8_factory)); new Sfactory(this,"BinaryExpression_14",new SCreator(BinaryExpression_14_factory)); +new Sfactory(this,"BinaryExpression_15",new SCreator(BinaryExpression_15_factory)); +new Sfactory(this,"BinaryExpression_16",new SCreator(BinaryExpression_16_factory)); new Sfactory(this,"BinaryExpression_6",new SCreator(BinaryExpression_6_factory)); new Sfactory(this,"BinaryExpression_7",new SCreator(BinaryExpression_7_factory)); +new Sfactory(this,"Typename_2",new SCreator(Typename_2_factory)); +new Sfactory(this,"Typename_4",new SCreator(Typename_4_factory)); new Sfactory(this,"ArgumentList",new SCreator(ArgumentList_factory)); -new Sfactory(this,"Event_10",new SCreator(Event_10_factory)); -new Sfactory(this,"ConstantExpression_1",new SCreator(ConstantExpression_1_factory)); -new Sfactory(this,"Event_12",new SCreator(Event_12_factory)); -new Sfactory(this,"Event_14",new SCreator(Event_14_factory)); -new Sfactory(this,"Event_17",new SCreator(Event_17_factory)); -new Sfactory(this,"Event_18",new SCreator(Event_18_factory)); -new Sfactory(this,"Event_19",new SCreator(Event_19_factory)); +new Sfactory(this,"BinaryExpression_12",new SCreator(BinaryExpression_12_factory)); +new Sfactory(this,"BinaryExpression_13",new SCreator(BinaryExpression_13_factory)); +new Sfactory(this,"GlobalFunctionDefinition_2",new SCreator(GlobalFunctionDefinition_2_factory)); +new Sfactory(this,"StateChange_2",new SCreator(StateChange_2_factory)); +new Sfactory(this,"VoidArgEvent_1",new SCreator(VoidArgEvent_1_factory)); +new Sfactory(this,"VoidArgEvent_3",new SCreator(VoidArgEvent_3_factory)); new Sfactory(this,"BinaryExpression_10",new SCreator(BinaryExpression_10_factory)); +new Sfactory(this,"VoidArgEvent_5",new SCreator(VoidArgEvent_5_factory)); +new Sfactory(this,"VoidArgEvent_6",new SCreator(VoidArgEvent_6_factory)); +new Sfactory(this,"VoidArgEvent_7",new SCreator(VoidArgEvent_7_factory)); +new Sfactory(this,"VoidArgEvent_8",new SCreator(VoidArgEvent_8_factory)); +new Sfactory(this,"BinaryExpression_17",new SCreator(BinaryExpression_17_factory)); new Sfactory(this,"StateEvent_1",new SCreator(StateEvent_1_factory)); new Sfactory(this,"VectorConstant",new SCreator(VectorConstant_factory)); -new Sfactory(this,"EmptyStatement_1",new SCreator(EmptyStatement_1_factory)); +new Sfactory(this,"VectorArgEvent_1",new SCreator(VectorArgEvent_1_factory)); +new Sfactory(this,"IntDeclaration",new SCreator(IntDeclaration_factory)); +new Sfactory(this,"VectorArgEvent_3",new SCreator(VectorArgEvent_3_factory)); new Sfactory(this,"TypecastExpression_4",new SCreator(TypecastExpression_4_factory)); new Sfactory(this,"TypecastExpression_6",new SCreator(TypecastExpression_6_factory)); new Sfactory(this,"TypecastExpression_7",new SCreator(TypecastExpression_7_factory)); new Sfactory(this,"FunctionCall",new SCreator(FunctionCall_factory)); -new Sfactory(this,"Event_27",new SCreator(Event_27_factory)); -new Sfactory(this,"Event_28",new SCreator(Event_28_factory)); -new Sfactory(this,"Event_29",new SCreator(Event_29_factory)); new Sfactory(this,"ListConstant_1",new SCreator(ListConstant_1_factory)); +new Sfactory(this,"BinaryExpression_18",new SCreator(BinaryExpression_18_factory)); new Sfactory(this,"Event_6",new SCreator(Event_6_factory)); +new Sfactory(this,"KeyArgEvent_2",new SCreator(KeyArgEvent_2_factory)); new Sfactory(this,"Declaration_1",new SCreator(Declaration_1_factory)); +new Sfactory(this,"EmptyStatement_1",new SCreator(EmptyStatement_1_factory)); new Sfactory(this,"SimpleAssignment_7",new SCreator(SimpleAssignment_7_factory)); new Sfactory(this,"ForLoop",new SCreator(ForLoop_factory)); new Sfactory(this,"ForLoop_2",new SCreator(ForLoop_2_factory)); -new Sfactory(this,"Event_30",new SCreator(Event_30_factory)); -new Sfactory(this,"Event_31",new SCreator(Event_31_factory)); -new Sfactory(this,"Event_33",new SCreator(Event_33_factory)); +new Sfactory(this,"KeyIntIntArgStateEvent_1",new SCreator(KeyIntIntArgStateEvent_1_factory)); +new Sfactory(this,"KeyArgumentDeclarationList_1",new SCreator(KeyArgumentDeclarationList_1_factory)); new Sfactory(this,"GlobalFunctionDefinition_1",new SCreator(GlobalFunctionDefinition_1_factory)); -new Sfactory(this,"JumpLabel_1",new SCreator(JumpLabel_1_factory)); new Sfactory(this,"IfStatement",new SCreator(IfStatement_factory)); new Sfactory(this,"ForLoopStatement_1",new SCreator(ForLoopStatement_1_factory)); new Sfactory(this,"ForLoopStatement_2",new SCreator(ForLoopStatement_2_factory)); new Sfactory(this,"ForLoopStatement_3",new SCreator(ForLoopStatement_3_factory)); -new Sfactory(this,"ArgumentDeclarationList_4",new SCreator(ArgumentDeclarationList_4_factory)); -new Sfactory(this,"ArgumentDeclarationList_5",new SCreator(ArgumentDeclarationList_5_factory)); -new Sfactory(this,"EmptyStatement",new SCreator(EmptyStatement_factory)); +new Sfactory(this,"IntRotRotArgumentDeclarationList",new SCreator(IntRotRotArgumentDeclarationList_factory)); +new Sfactory(this,"IntArgEvent_1",new SCreator(IntArgEvent_1_factory)); +new Sfactory(this,"IntArgEvent_2",new SCreator(IntArgEvent_2_factory)); new Sfactory(this,"WhileStatement",new SCreator(WhileStatement_factory)); new Sfactory(this,"ForLoop_1",new SCreator(ForLoop_1_factory)); new Sfactory(this,"Constant_2",new SCreator(Constant_2_factory)); -new Sfactory(this,"StatementList",new SCreator(StatementList_factory)); -new Sfactory(this,"StateBody_2",new SCreator(StateBody_2_factory)); +new Sfactory(this,"VoidArgEvent",new SCreator(VoidArgEvent_factory)); +new Sfactory(this,"RotDeclaration",new SCreator(RotDeclaration_factory)); +new Sfactory(this,"WhileStatement_1",new SCreator(WhileStatement_1_factory)); new Sfactory(this,"WhileStatement_2",new SCreator(WhileStatement_2_factory)); +new Sfactory(this,"VectorArgStateEvent_1",new SCreator(VectorArgStateEvent_1_factory)); new Sfactory(this,"IdentExpression_1",new SCreator(IdentExpression_1_factory)); +new Sfactory(this,"VectorArgumentDeclarationList",new SCreator(VectorArgumentDeclarationList_factory)); new Sfactory(this,"States",new SCreator(States_factory)); +new Sfactory(this,"VoidArgStateEvent",new SCreator(VoidArgStateEvent_factory)); } public static object ExpressionArgument_1_factory(Parser yyp) { return new ExpressionArgument_1(yyp); } -public static object SimpleAssignment_8_factory(Parser yyp) { return new SimpleAssignment_8(yyp); } +public static object VectorArgStateEvent_factory(Parser yyp) { return new VectorArgStateEvent(yyp); } +public static object IntVecVecArgStateEvent_factory(Parser yyp) { return new IntVecVecArgStateEvent(yyp); } +public static object IntArgStateEvent_1_factory(Parser yyp) { return new IntArgStateEvent_1(yyp); } +public static object SimpleAssignment_9_factory(Parser yyp) { return new SimpleAssignment_9(yyp); } public static object StatementList_1_factory(Parser yyp) { return new StatementList_1(yyp); } +public static object RotDeclaration_1_factory(Parser yyp) { return new RotDeclaration_1(yyp); } +public static object IntRotRotArgEvent_1_factory(Parser yyp) { return new IntRotRotArgEvent_1(yyp); } public static object StateChange_1_factory(Parser yyp) { return new StateChange_1(yyp); } -public static object StateChange_2_factory(Parser yyp) { return new StateChange_2(yyp); } +public static object EmptyStatement_factory(Parser yyp) { return new EmptyStatement(yyp); } public static object Declaration_factory(Parser yyp) { return new Declaration(yyp); } public static object IdentExpression_factory(Parser yyp) { return new IdentExpression(yyp); } public static object error_factory(Parser yyp) { return new error(yyp); } @@ -11029,20 +13262,25 @@ public static object SimpleAssignment_19_factory(Parser yyp) { return new Simple public static object BinaryExpression_9_factory(Parser yyp) { return new BinaryExpression_9(yyp); } public static object VectorConstant_1_factory(Parser yyp) { return new VectorConstant_1(yyp); } public static object ParenthesisExpression_factory(Parser yyp) { return new ParenthesisExpression(yyp); } +public static object StatementList_factory(Parser yyp) { return new StatementList(yyp); } +public static object IntRotRotArgEvent_factory(Parser yyp) { return new IntRotRotArgEvent(yyp); } public static object UnaryExpression_factory(Parser yyp) { return new UnaryExpression(yyp); } public static object IdentDotExpression_1_factory(Parser yyp) { return new IdentDotExpression_1(yyp); } public static object ArgumentList_4_factory(Parser yyp) { return new ArgumentList_4(yyp); } public static object Typename_factory(Parser yyp) { return new Typename(yyp); } public static object IfStatement_1_factory(Parser yyp) { return new IfStatement_1(yyp); } +public static object RotationConstant_1_factory(Parser yyp) { return new RotationConstant_1(yyp); } public static object Assignment_factory(Parser yyp) { return new Assignment(yyp); } +public static object IfStatement_4_factory(Parser yyp) { return new IfStatement_4(yyp); } public static object CompoundStatement_1_factory(Parser yyp) { return new CompoundStatement_1(yyp); } public static object CompoundStatement_2_factory(Parser yyp) { return new CompoundStatement_2(yyp); } +public static object KeyIntIntArgumentDeclarationList_1_factory(Parser yyp) { return new KeyIntIntArgumentDeclarationList_1(yyp); } public static object BinaryExpression_8_factory(Parser yyp) { return new BinaryExpression_8(yyp); } +public static object VectorArgEvent_factory(Parser yyp) { return new VectorArgEvent(yyp); } public static object ReturnStatement_1_factory(Parser yyp) { return new ReturnStatement_1(yyp); } public static object IdentDotExpression_factory(Parser yyp) { return new IdentDotExpression(yyp); } public static object Argument_factory(Parser yyp) { return new Argument(yyp); } public static object State_2_factory(Parser yyp) { return new State_2(yyp); } -public static object WhileStatement_1_factory(Parser yyp) { return new WhileStatement_1(yyp); } public static object GlobalDefinitions_3_factory(Parser yyp) { return new GlobalDefinitions_3(yyp); } public static object GlobalDefinitions_4_factory(Parser yyp) { return new GlobalDefinitions_4(yyp); } public static object Event_1_factory(Parser yyp) { return new Event_1(yyp); } @@ -11052,9 +13290,9 @@ public static object Event_4_factory(Parser yyp) { return new Event_4(yyp); } public static object Event_5_factory(Parser yyp) { return new Event_5(yyp); } public static object SimpleAssignment_5_factory(Parser yyp) { return new SimpleAssignment_5(yyp); } public static object Typename_1_factory(Parser yyp) { return new Typename_1(yyp); } -public static object Typename_2_factory(Parser yyp) { return new Typename_2(yyp); } +public static object VoidArgStateEvent_1_factory(Parser yyp) { return new VoidArgStateEvent_1(yyp); } public static object Typename_3_factory(Parser yyp) { return new Typename_3(yyp); } -public static object Typename_4_factory(Parser yyp) { return new Typename_4(yyp); } +public static object IntRotRotArgStateEvent_factory(Parser yyp) { return new IntRotRotArgStateEvent(yyp); } public static object Typename_5_factory(Parser yyp) { return new Typename_5(yyp); } public static object Typename_6_factory(Parser yyp) { return new Typename_6(yyp); } public static object Typename_7_factory(Parser yyp) { return new Typename_7(yyp); } @@ -11062,10 +13300,16 @@ public static object ArgumentDeclarationList_factory(Parser yyp) { return new Ar public static object ConstantExpression_factory(Parser yyp) { return new ConstantExpression(yyp); } public static object LSLProgramRoot_1_factory(Parser yyp) { return new LSLProgramRoot_1(yyp); } public static object LSLProgramRoot_2_factory(Parser yyp) { return new LSLProgramRoot_2(yyp); } +public static object KeyIntIntArgEvent_1_factory(Parser yyp) { return new KeyIntIntArgEvent_1(yyp); } public static object States_1_factory(Parser yyp) { return new States_1(yyp); } public static object States_2_factory(Parser yyp) { return new States_2(yyp); } public static object FunctionCallExpression_1_factory(Parser yyp) { return new FunctionCallExpression_1(yyp); } +public static object KeyArgEvent_1_factory(Parser yyp) { return new KeyArgEvent_1(yyp); } public static object ForLoopStatement_factory(Parser yyp) { return new ForLoopStatement(yyp); } +public static object IntArgStateEvent_factory(Parser yyp) { return new IntArgStateEvent(yyp); } +public static object StateBody_15_factory(Parser yyp) { return new StateBody_15(yyp); } +public static object IntRotRotArgumentDeclarationList_1_factory(Parser yyp) { return new IntRotRotArgumentDeclarationList_1(yyp); } +public static object IntArgEvent_9_factory(Parser yyp) { return new IntArgEvent_9(yyp); } public static object DoWhileStatement_1_factory(Parser yyp) { return new DoWhileStatement_1(yyp); } public static object DoWhileStatement_2_factory(Parser yyp) { return new DoWhileStatement_2(yyp); } public static object ForLoopStatement_4_factory(Parser yyp) { return new ForLoopStatement_4(yyp); } @@ -11074,74 +13318,93 @@ public static object SimpleAssignment_12_factory(Parser yyp) { return new Simple public static object SimpleAssignment_13_factory(Parser yyp) { return new SimpleAssignment_13(yyp); } public static object JumpLabel_factory(Parser yyp) { return new JumpLabel(yyp); } public static object SimpleAssignment_15_factory(Parser yyp) { return new SimpleAssignment_15(yyp); } -public static object SimpleAssignment_17_factory(Parser yyp) { return new SimpleAssignment_17(yyp); } -public static object SimpleAssignment_18_factory(Parser yyp) { return new SimpleAssignment_18(yyp); } -public static object JumpStatement_1_factory(Parser yyp) { return new JumpStatement_1(yyp); } +public static object IntVecVecArgEvent_factory(Parser yyp) { return new IntVecVecArgEvent(yyp); } +public static object VecDeclaration_factory(Parser yyp) { return new VecDeclaration(yyp); } +public static object StateBody_14_factory(Parser yyp) { return new StateBody_14(yyp); } public static object GlobalDefinitions_factory(Parser yyp) { return new GlobalDefinitions(yyp); } +public static object StateBody_16_factory(Parser yyp) { return new StateBody_16(yyp); } +public static object KeyIntIntArgumentDeclarationList_factory(Parser yyp) { return new KeyIntIntArgumentDeclarationList(yyp); } +public static object ConstantExpression_1_factory(Parser yyp) { return new ConstantExpression_1(yyp); } +public static object VoidArgEvent_4_factory(Parser yyp) { return new VoidArgEvent_4(yyp); } public static object FunctionCall_1_factory(Parser yyp) { return new FunctionCall_1(yyp); } -public static object ArgumentList_3_factory(Parser yyp) { return new ArgumentList_3(yyp); } +public static object Assignment_1_factory(Parser yyp) { return new Assignment_1(yyp); } public static object Assignment_2_factory(Parser yyp) { return new Assignment_2(yyp); } +public static object IntVecVecArgEvent_1_factory(Parser yyp) { return new IntVecVecArgEvent_1(yyp); } public static object TypecastExpression_1_factory(Parser yyp) { return new TypecastExpression_1(yyp); } public static object SimpleAssignment_21_factory(Parser yyp) { return new SimpleAssignment_21(yyp); } public static object SimpleAssignment_22_factory(Parser yyp) { return new SimpleAssignment_22(yyp); } -public static object SimpleAssignment_23_factory(Parser yyp) { return new SimpleAssignment_23(yyp); } +public static object KeyIntIntArgStateEvent_factory(Parser yyp) { return new KeyIntIntArgStateEvent(yyp); } public static object TypecastExpression_9_factory(Parser yyp) { return new TypecastExpression_9(yyp); } +public static object VoidArgEvent_2_factory(Parser yyp) { return new VoidArgEvent_2(yyp); } +public static object Event_9_factory(Parser yyp) { return new Event_9(yyp); } public static object ArgumentDeclarationList_1_factory(Parser yyp) { return new ArgumentDeclarationList_1(yyp); } public static object ArgumentDeclarationList_2_factory(Parser yyp) { return new ArgumentDeclarationList_2(yyp); } -public static object ArgumentDeclarationList_3_factory(Parser yyp) { return new ArgumentDeclarationList_3(yyp); } public static object GlobalDefinitions_1_factory(Parser yyp) { return new GlobalDefinitions_1(yyp); } public static object GlobalDefinitions_2_factory(Parser yyp) { return new GlobalDefinitions_2(yyp); } public static object IncrementDecrementExpression_factory(Parser yyp) { return new IncrementDecrementExpression(yyp); } public static object GlobalVariableDeclaration_factory(Parser yyp) { return new GlobalVariableDeclaration(yyp); } -public static object Event_11_factory(Parser yyp) { return new Event_11(yyp); } +public static object IntArgumentDeclarationList_1_factory(Parser yyp) { return new IntArgumentDeclarationList_1(yyp); } +public static object IntDeclaration_1_factory(Parser yyp) { return new IntDeclaration_1(yyp); } +public static object ArgumentDeclarationList_5_factory(Parser yyp) { return new ArgumentDeclarationList_5(yyp); } +public static object IntVecVecArgumentDeclarationList_factory(Parser yyp) { return new IntVecVecArgumentDeclarationList(yyp); } +public static object VectorArgumentDeclarationList_1_factory(Parser yyp) { return new VectorArgumentDeclarationList_1(yyp); } +public static object KeyArgumentDeclarationList_factory(Parser yyp) { return new KeyArgumentDeclarationList(yyp); } public static object TypecastExpression_2_factory(Parser yyp) { return new TypecastExpression_2(yyp); } -public static object TypecastExpression_3_factory(Parser yyp) { return new TypecastExpression_3(yyp); } +public static object KeyArgStateEvent_factory(Parser yyp) { return new KeyArgStateEvent(yyp); } public static object TypecastExpression_5_factory(Parser yyp) { return new TypecastExpression_5(yyp); } public static object TypecastExpression_8_factory(Parser yyp) { return new TypecastExpression_8(yyp); } public static object Constant_1_factory(Parser yyp) { return new Constant_1(yyp); } public static object Expression_factory(Parser yyp) { return new Expression(yyp); } public static object Constant_3_factory(Parser yyp) { return new Constant_3(yyp); } public static object Constant_4_factory(Parser yyp) { return new Constant_4(yyp); } +public static object IntArgEvent_5_factory(Parser yyp) { return new IntArgEvent_5(yyp); } public static object BinaryExpression_1_factory(Parser yyp) { return new BinaryExpression_1(yyp); } public static object IfStatement_2_factory(Parser yyp) { return new IfStatement_2(yyp); } public static object IfStatement_3_factory(Parser yyp) { return new IfStatement_3(yyp); } -public static object IfStatement_4_factory(Parser yyp) { return new IfStatement_4(yyp); } -public static object ReturnStatement_factory(Parser yyp) { return new ReturnStatement(yyp); } +public static object KeyArgEvent_factory(Parser yyp) { return new KeyArgEvent(yyp); } public static object Event_2_factory(Parser yyp) { return new Event_2(yyp); } +public static object JumpLabel_1_factory(Parser yyp) { return new JumpLabel_1(yyp); } public static object RotationConstant_factory(Parser yyp) { return new RotationConstant(yyp); } public static object Statement_12_factory(Parser yyp) { return new Statement_12(yyp); } +public static object Statement_13_factory(Parser yyp) { return new Statement_13(yyp); } public static object UnaryExpression_1_factory(Parser yyp) { return new UnaryExpression_1(yyp); } public static object UnaryExpression_2_factory(Parser yyp) { return new UnaryExpression_2(yyp); } public static object UnaryExpression_3_factory(Parser yyp) { return new UnaryExpression_3(yyp); } public static object ArgumentList_1_factory(Parser yyp) { return new ArgumentList_1(yyp); } -public static object ArgumentList_2_factory(Parser yyp) { return new ArgumentList_2(yyp); } +public static object KeyIntIntArgEvent_factory(Parser yyp) { return new KeyIntIntArgEvent(yyp); } +public static object ArgumentList_3_factory(Parser yyp) { return new ArgumentList_3(yyp); } public static object Constant_factory(Parser yyp) { return new Constant(yyp); } public static object State_factory(Parser yyp) { return new State(yyp); } -public static object Event_13_factory(Parser yyp) { return new Event_13(yyp); } +public static object StateBody_13_factory(Parser yyp) { return new StateBody_13(yyp); } +public static object KeyArgStateEvent_1_factory(Parser yyp) { return new KeyArgStateEvent_1(yyp); } +public static object SimpleAssignment_8_factory(Parser yyp) { return new SimpleAssignment_8(yyp); } public static object LSLProgramRoot_factory(Parser yyp) { return new LSLProgramRoot(yyp); } public static object StateChange_factory(Parser yyp) { return new StateChange(yyp); } -public static object IncrementDecrementExpression_2_factory(Parser yyp) { return new IncrementDecrementExpression_2(yyp); } +public static object VecDeclaration_1_factory(Parser yyp) { return new VecDeclaration_1(yyp); } public static object GlobalVariableDeclaration_1_factory(Parser yyp) { return new GlobalVariableDeclaration_1(yyp); } public static object GlobalVariableDeclaration_2_factory(Parser yyp) { return new GlobalVariableDeclaration_2(yyp); } public static object IncrementDecrementExpression_5_factory(Parser yyp) { return new IncrementDecrementExpression_5(yyp); } -public static object GlobalFunctionDefinition_2_factory(Parser yyp) { return new GlobalFunctionDefinition_2(yyp); } -public static object IncrementDecrementExpression_7_factory(Parser yyp) { return new IncrementDecrementExpression_7(yyp); } -public static object IncrementDecrementExpression_8_factory(Parser yyp) { return new IncrementDecrementExpression_8(yyp); } -public static object Assignment_1_factory(Parser yyp) { return new Assignment_1(yyp); } -public static object Event_21_factory(Parser yyp) { return new Event_21(yyp); } -public static object Event_22_factory(Parser yyp) { return new Event_22(yyp); } +public static object ReturnStatement_factory(Parser yyp) { return new ReturnStatement(yyp); } +public static object StateBody_10_factory(Parser yyp) { return new StateBody_10(yyp); } +public static object StateBody_11_factory(Parser yyp) { return new StateBody_11(yyp); } +public static object StateBody_12_factory(Parser yyp) { return new StateBody_12(yyp); } +public static object IntVecVecArgStateEvent_1_factory(Parser yyp) { return new IntVecVecArgStateEvent_1(yyp); } +public static object KeyDeclaration_factory(Parser yyp) { return new KeyDeclaration(yyp); } +public static object IntArgEvent_6_factory(Parser yyp) { return new IntArgEvent_6(yyp); } +public static object ArgumentDeclarationList_3_factory(Parser yyp) { return new ArgumentDeclarationList_3(yyp); } +public static object ArgumentList_2_factory(Parser yyp) { return new ArgumentList_2(yyp); } +public static object IntArgEvent_10_factory(Parser yyp) { return new IntArgEvent_10(yyp); } public static object CompoundStatement_factory(Parser yyp) { return new CompoundStatement(yyp); } -public static object RotationConstant_1_factory(Parser yyp) { return new RotationConstant_1(yyp); } -public static object TypecastExpression_factory(Parser yyp) { return new TypecastExpression(yyp); } +public static object TypecastExpression_3_factory(Parser yyp) { return new TypecastExpression_3(yyp); } +public static object IntArgumentDeclarationList_factory(Parser yyp) { return new IntArgumentDeclarationList(yyp); } +public static object ArgumentDeclarationList_4_factory(Parser yyp) { return new ArgumentDeclarationList_4(yyp); } public static object SimpleAssignment_3_factory(Parser yyp) { return new SimpleAssignment_3(yyp); } public static object SimpleAssignment_4_factory(Parser yyp) { return new SimpleAssignment_4(yyp); } public static object Statement_1_factory(Parser yyp) { return new Statement_1(yyp); } public static object Statement_2_factory(Parser yyp) { return new Statement_2(yyp); } -public static object Statement_3_factory(Parser yyp) { return new Statement_3(yyp); } public static object Statement_4_factory(Parser yyp) { return new Statement_4(yyp); } public static object Statement_5_factory(Parser yyp) { return new Statement_5(yyp); } public static object Statement_6_factory(Parser yyp) { return new Statement_6(yyp); } -public static object Statement_7_factory(Parser yyp) { return new Statement_7(yyp); } public static object Statement_8_factory(Parser yyp) { return new Statement_8(yyp); } public static object Statement_9_factory(Parser yyp) { return new Statement_9(yyp); } public static object ExpressionArgument_factory(Parser yyp) { return new ExpressionArgument(yyp); } @@ -11154,27 +13417,35 @@ public static object StateBody_factory(Parser yyp) { return new StateBody(yyp); public static object Event_7_factory(Parser yyp) { return new Event_7(yyp); } public static object Event_8_factory(Parser yyp) { return new Event_8(yyp); } public static object IncrementDecrementExpression_1_factory(Parser yyp) { return new IncrementDecrementExpression_1(yyp); } -public static object IncrementDecrementExpression_3_factory(Parser yyp) { return new IncrementDecrementExpression_3(yyp); } +public static object IncrementDecrementExpression_2_factory(Parser yyp) { return new IncrementDecrementExpression_2(yyp); } +public static object IntVecVecArgumentDeclarationList_1_factory(Parser yyp) { return new IntVecVecArgumentDeclarationList_1(yyp); } public static object IncrementDecrementExpression_4_factory(Parser yyp) { return new IncrementDecrementExpression_4(yyp); } public static object IncrementDecrementExpression_6_factory(Parser yyp) { return new IncrementDecrementExpression_6(yyp); } +public static object IncrementDecrementExpression_7_factory(Parser yyp) { return new IncrementDecrementExpression_7(yyp); } public static object StateEvent_factory(Parser yyp) { return new StateEvent(yyp); } -public static object Event_20_factory(Parser yyp) { return new Event_20(yyp); } -public static object Event_23_factory(Parser yyp) { return new Event_23(yyp); } -public static object Event_24_factory(Parser yyp) { return new Event_24(yyp); } -public static object Event_26_factory(Parser yyp) { return new Event_26(yyp); } +public static object IntArgEvent_3_factory(Parser yyp) { return new IntArgEvent_3(yyp); } +public static object IntArgEvent_4_factory(Parser yyp) { return new IntArgEvent_4(yyp); } +public static object KeyDeclaration_1_factory(Parser yyp) { return new KeyDeclaration_1(yyp); } +public static object Statement_3_factory(Parser yyp) { return new Statement_3(yyp); } +public static object IntArgEvent_7_factory(Parser yyp) { return new IntArgEvent_7(yyp); } +public static object IntArgEvent_8_factory(Parser yyp) { return new IntArgEvent_8(yyp); } public static object SimpleAssignment_10_factory(Parser yyp) { return new SimpleAssignment_10(yyp); } +public static object StatementList_2_factory(Parser yyp) { return new StatementList_2(yyp); } +public static object IntRotRotArgStateEvent_1_factory(Parser yyp) { return new IntRotRotArgStateEvent_1(yyp); } +public static object VectorArgEvent_2_factory(Parser yyp) { return new VectorArgEvent_2(yyp); } public static object Event_factory(Parser yyp) { return new Event(yyp); } public static object SimpleAssignment_14_factory(Parser yyp) { return new SimpleAssignment_14(yyp); } public static object SimpleAssignment_16_factory(Parser yyp) { return new SimpleAssignment_16(yyp); } +public static object SimpleAssignment_17_factory(Parser yyp) { return new SimpleAssignment_17(yyp); } +public static object SimpleAssignment_18_factory(Parser yyp) { return new SimpleAssignment_18(yyp); } public static object Statement_10_factory(Parser yyp) { return new Statement_10(yyp); } public static object Statement_11_factory(Parser yyp) { return new Statement_11(yyp); } public static object SimpleAssignment_factory(Parser yyp) { return new SimpleAssignment(yyp); } -public static object Statement_13_factory(Parser yyp) { return new Statement_13(yyp); } -public static object Event_15_factory(Parser yyp) { return new Event_15(yyp); } -public static object Event_16_factory(Parser yyp) { return new Event_16(yyp); } -public static object Event_32_factory(Parser yyp) { return new Event_32(yyp); } -public static object Event_34_factory(Parser yyp) { return new Event_34(yyp); } +public static object TypecastExpression_factory(Parser yyp) { return new TypecastExpression(yyp); } +public static object JumpStatement_1_factory(Parser yyp) { return new JumpStatement_1(yyp); } public static object SimpleAssignment_20_factory(Parser yyp) { return new SimpleAssignment_20(yyp); } +public static object Statement_7_factory(Parser yyp) { return new Statement_7(yyp); } +public static object SimpleAssignment_23_factory(Parser yyp) { return new SimpleAssignment_23(yyp); } public static object SimpleAssignment_24_factory(Parser yyp) { return new SimpleAssignment_24(yyp); } public static object SimpleAssignment_1_factory(Parser yyp) { return new SimpleAssignment_1(yyp); } public static object SimpleAssignment_2_factory(Parser yyp) { return new SimpleAssignment_2(yyp); } @@ -11182,67 +13453,80 @@ public static object BinaryExpression_factory(Parser yyp) { return new BinaryExp public static object FunctionCallExpression_factory(Parser yyp) { return new FunctionCallExpression(yyp); } public static object SimpleAssignment_6_factory(Parser yyp) { return new SimpleAssignment_6(yyp); } public static object StateBody_1_factory(Parser yyp) { return new StateBody_1(yyp); } -public static object StatementList_2_factory(Parser yyp) { return new StatementList_2(yyp); } -public static object SimpleAssignment_9_factory(Parser yyp) { return new SimpleAssignment_9(yyp); } -public static object BinaryExpression_15_factory(Parser yyp) { return new BinaryExpression_15(yyp); } -public static object BinaryExpression_16_factory(Parser yyp) { return new BinaryExpression_16(yyp); } -public static object BinaryExpression_17_factory(Parser yyp) { return new BinaryExpression_17(yyp); } -public static object BinaryExpression_18_factory(Parser yyp) { return new BinaryExpression_18(yyp); } -public static object Event_25_factory(Parser yyp) { return new Event_25(yyp); } -public static object Event_9_factory(Parser yyp) { return new Event_9(yyp); } +public static object StateBody_2_factory(Parser yyp) { return new StateBody_2(yyp); } +public static object StateBody_3_factory(Parser yyp) { return new StateBody_3(yyp); } +public static object StateBody_4_factory(Parser yyp) { return new StateBody_4(yyp); } +public static object StateBody_5_factory(Parser yyp) { return new StateBody_5(yyp); } +public static object StateBody_6_factory(Parser yyp) { return new StateBody_6(yyp); } +public static object StateBody_7_factory(Parser yyp) { return new StateBody_7(yyp); } +public static object StateBody_8_factory(Parser yyp) { return new StateBody_8(yyp); } +public static object StateBody_9_factory(Parser yyp) { return new StateBody_9(yyp); } public static object Statement_factory(Parser yyp) { return new Statement(yyp); } +public static object IncrementDecrementExpression_3_factory(Parser yyp) { return new IncrementDecrementExpression_3(yyp); } public static object JumpStatement_factory(Parser yyp) { return new JumpStatement(yyp); } public static object BinaryExpression_11_factory(Parser yyp) { return new BinaryExpression_11(yyp); } -public static object BinaryExpression_12_factory(Parser yyp) { return new BinaryExpression_12(yyp); } -public static object BinaryExpression_13_factory(Parser yyp) { return new BinaryExpression_13(yyp); } +public static object IntArgEvent_factory(Parser yyp) { return new IntArgEvent(yyp); } +public static object IncrementDecrementExpression_8_factory(Parser yyp) { return new IncrementDecrementExpression_8(yyp); } public static object BinaryExpression_14_factory(Parser yyp) { return new BinaryExpression_14(yyp); } +public static object BinaryExpression_15_factory(Parser yyp) { return new BinaryExpression_15(yyp); } +public static object BinaryExpression_16_factory(Parser yyp) { return new BinaryExpression_16(yyp); } public static object BinaryExpression_6_factory(Parser yyp) { return new BinaryExpression_6(yyp); } public static object BinaryExpression_7_factory(Parser yyp) { return new BinaryExpression_7(yyp); } +public static object Typename_2_factory(Parser yyp) { return new Typename_2(yyp); } +public static object Typename_4_factory(Parser yyp) { return new Typename_4(yyp); } public static object ArgumentList_factory(Parser yyp) { return new ArgumentList(yyp); } -public static object Event_10_factory(Parser yyp) { return new Event_10(yyp); } -public static object ConstantExpression_1_factory(Parser yyp) { return new ConstantExpression_1(yyp); } -public static object Event_12_factory(Parser yyp) { return new Event_12(yyp); } -public static object Event_14_factory(Parser yyp) { return new Event_14(yyp); } -public static object Event_17_factory(Parser yyp) { return new Event_17(yyp); } -public static object Event_18_factory(Parser yyp) { return new Event_18(yyp); } -public static object Event_19_factory(Parser yyp) { return new Event_19(yyp); } +public static object BinaryExpression_12_factory(Parser yyp) { return new BinaryExpression_12(yyp); } +public static object BinaryExpression_13_factory(Parser yyp) { return new BinaryExpression_13(yyp); } +public static object GlobalFunctionDefinition_2_factory(Parser yyp) { return new GlobalFunctionDefinition_2(yyp); } +public static object StateChange_2_factory(Parser yyp) { return new StateChange_2(yyp); } +public static object VoidArgEvent_1_factory(Parser yyp) { return new VoidArgEvent_1(yyp); } +public static object VoidArgEvent_3_factory(Parser yyp) { return new VoidArgEvent_3(yyp); } public static object BinaryExpression_10_factory(Parser yyp) { return new BinaryExpression_10(yyp); } +public static object VoidArgEvent_5_factory(Parser yyp) { return new VoidArgEvent_5(yyp); } +public static object VoidArgEvent_6_factory(Parser yyp) { return new VoidArgEvent_6(yyp); } +public static object VoidArgEvent_7_factory(Parser yyp) { return new VoidArgEvent_7(yyp); } +public static object VoidArgEvent_8_factory(Parser yyp) { return new VoidArgEvent_8(yyp); } +public static object BinaryExpression_17_factory(Parser yyp) { return new BinaryExpression_17(yyp); } public static object StateEvent_1_factory(Parser yyp) { return new StateEvent_1(yyp); } public static object VectorConstant_factory(Parser yyp) { return new VectorConstant(yyp); } -public static object EmptyStatement_1_factory(Parser yyp) { return new EmptyStatement_1(yyp); } +public static object VectorArgEvent_1_factory(Parser yyp) { return new VectorArgEvent_1(yyp); } +public static object IntDeclaration_factory(Parser yyp) { return new IntDeclaration(yyp); } +public static object VectorArgEvent_3_factory(Parser yyp) { return new VectorArgEvent_3(yyp); } public static object TypecastExpression_4_factory(Parser yyp) { return new TypecastExpression_4(yyp); } public static object TypecastExpression_6_factory(Parser yyp) { return new TypecastExpression_6(yyp); } public static object TypecastExpression_7_factory(Parser yyp) { return new TypecastExpression_7(yyp); } public static object FunctionCall_factory(Parser yyp) { return new FunctionCall(yyp); } -public static object Event_27_factory(Parser yyp) { return new Event_27(yyp); } -public static object Event_28_factory(Parser yyp) { return new Event_28(yyp); } -public static object Event_29_factory(Parser yyp) { return new Event_29(yyp); } public static object ListConstant_1_factory(Parser yyp) { return new ListConstant_1(yyp); } +public static object BinaryExpression_18_factory(Parser yyp) { return new BinaryExpression_18(yyp); } public static object Event_6_factory(Parser yyp) { return new Event_6(yyp); } +public static object KeyArgEvent_2_factory(Parser yyp) { return new KeyArgEvent_2(yyp); } public static object Declaration_1_factory(Parser yyp) { return new Declaration_1(yyp); } +public static object EmptyStatement_1_factory(Parser yyp) { return new EmptyStatement_1(yyp); } public static object SimpleAssignment_7_factory(Parser yyp) { return new SimpleAssignment_7(yyp); } public static object ForLoop_factory(Parser yyp) { return new ForLoop(yyp); } public static object ForLoop_2_factory(Parser yyp) { return new ForLoop_2(yyp); } -public static object Event_30_factory(Parser yyp) { return new Event_30(yyp); } -public static object Event_31_factory(Parser yyp) { return new Event_31(yyp); } -public static object Event_33_factory(Parser yyp) { return new Event_33(yyp); } +public static object KeyIntIntArgStateEvent_1_factory(Parser yyp) { return new KeyIntIntArgStateEvent_1(yyp); } +public static object KeyArgumentDeclarationList_1_factory(Parser yyp) { return new KeyArgumentDeclarationList_1(yyp); } public static object GlobalFunctionDefinition_1_factory(Parser yyp) { return new GlobalFunctionDefinition_1(yyp); } -public static object JumpLabel_1_factory(Parser yyp) { return new JumpLabel_1(yyp); } public static object IfStatement_factory(Parser yyp) { return new IfStatement(yyp); } public static object ForLoopStatement_1_factory(Parser yyp) { return new ForLoopStatement_1(yyp); } public static object ForLoopStatement_2_factory(Parser yyp) { return new ForLoopStatement_2(yyp); } public static object ForLoopStatement_3_factory(Parser yyp) { return new ForLoopStatement_3(yyp); } -public static object ArgumentDeclarationList_4_factory(Parser yyp) { return new ArgumentDeclarationList_4(yyp); } -public static object ArgumentDeclarationList_5_factory(Parser yyp) { return new ArgumentDeclarationList_5(yyp); } -public static object EmptyStatement_factory(Parser yyp) { return new EmptyStatement(yyp); } +public static object IntRotRotArgumentDeclarationList_factory(Parser yyp) { return new IntRotRotArgumentDeclarationList(yyp); } +public static object IntArgEvent_1_factory(Parser yyp) { return new IntArgEvent_1(yyp); } +public static object IntArgEvent_2_factory(Parser yyp) { return new IntArgEvent_2(yyp); } public static object WhileStatement_factory(Parser yyp) { return new WhileStatement(yyp); } public static object ForLoop_1_factory(Parser yyp) { return new ForLoop_1(yyp); } public static object Constant_2_factory(Parser yyp) { return new Constant_2(yyp); } -public static object StatementList_factory(Parser yyp) { return new StatementList(yyp); } -public static object StateBody_2_factory(Parser yyp) { return new StateBody_2(yyp); } +public static object VoidArgEvent_factory(Parser yyp) { return new VoidArgEvent(yyp); } +public static object RotDeclaration_factory(Parser yyp) { return new RotDeclaration(yyp); } +public static object WhileStatement_1_factory(Parser yyp) { return new WhileStatement_1(yyp); } public static object WhileStatement_2_factory(Parser yyp) { return new WhileStatement_2(yyp); } +public static object VectorArgStateEvent_1_factory(Parser yyp) { return new VectorArgStateEvent_1(yyp); } public static object IdentExpression_1_factory(Parser yyp) { return new IdentExpression_1(yyp); } +public static object VectorArgumentDeclarationList_factory(Parser yyp) { return new VectorArgumentDeclarationList(yyp); } public static object States_factory(Parser yyp) { return new States(yyp); } +public static object VoidArgStateEvent_factory(Parser yyp) { return new VoidArgStateEvent(yyp); } } public class LSLSyntax : Parser { diff --git a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs index 5a58f73..e02d35e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs @@ -81,6 +81,24 @@ namespace OpenSim.Region.ScriptEngine.Shared } } + /// + /// Used to signal when the script is stopping in co-operation with the script engine + /// (instead of through Thread.Abort()). + /// + [Serializable] + public class ScriptCoopStopException : Exception + { + public ScriptCoopStopException() + { + } + + protected ScriptCoopStopException( + SerializationInfo info, + StreamingContext context) + { + } + } + public class DetectParams { 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..b7c4bab 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; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 01a5e34..fa6e6fc 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -51,6 +51,7 @@ using OpenSim.Region.ScriptEngine.Shared.Api.Runtime; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Region.ScriptEngine.Shared.CodeTools; using OpenSim.Region.ScriptEngine.Interfaces; +using System.Diagnostics; namespace OpenSim.Region.ScriptEngine.Shared.Instance { @@ -58,6 +59,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public bool StatePersistedHere { get { return m_AttachedAvatar == UUID.Zero; } } + /// /// The current work item if an event for this script is running or waiting to run, /// @@ -71,14 +74,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance private bool m_TimerQueued; private DateTime m_EventStart; private bool m_InEvent; - private string m_Assembly; + private string m_assemblyPath; + private string m_dataPath; private string m_CurrentEvent = String.Empty; private bool m_InSelfDelete; private int m_MaxScriptQueue; - private bool m_SaveState = true; + private bool m_SaveState; private int m_ControlEventsInQueue; private int m_LastControlLevel; private bool m_CollisionInQueue; + private bool m_StateChangeInProgress; // The following is for setting a minimum delay between events private double m_minEventDelay; @@ -95,6 +100,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public int DebugLevel { get; set; } + public WaitHandle CoopWaitHandle { get; private set; } + public Stopwatch ExecutionTimer { get; private set; } + public Dictionary, KeyValuePair> LineMap { get; set; } private Dictionary m_Apis = new Dictionary(); @@ -121,7 +129,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } } - public bool Running { get; set; } + public bool Running + { + get { return m_running; } + + set + { + m_running = value; + if (m_running) + StayStopped = false; + } + } + private bool m_running; public bool Suspended { @@ -153,23 +172,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public string State { get; set; } + public bool StayStopped { get; set; } + public IScriptEngine Engine { get; private set; } public UUID AppDomain { get; set; } + public SceneObjectPart Part { get; private set; } + public string PrimName { get; private set; } public string ScriptName { get; private set; } public UUID ItemID { get; private set; } - public UUID ObjectID { get; private set; } + public UUID ObjectID { get { return Part.UUID; } } - public uint LocalID { get; private set; } + public uint LocalID { get { return Part.LocalId; } } - public UUID RootObjectID { get; private set; } + public UUID RootObjectID { get { return Part.ParentGroup.UUID; } } - public uint RootLocalID { get; private set; } + public uint RootLocalID { get { return Part.ParentGroup.LocalId; } } public UUID AssetID { get; private set; } @@ -192,83 +215,92 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public DateTime TimeStarted { get; private set; } - public long MeasurementPeriodTickStart { get; private set; } + public MetricsCollectorTime ExecutionTime { get; private set; } - public long MeasurementPeriodExecutionTime { get; private set; } + private static readonly int MeasurementWindow = 30 * 1000; // show the *recent* time used by the script, to find currently active scripts - public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute; + private bool m_coopTermination; + + private EventWaitHandle m_coopSleepHandle; public void ClearQueue() { m_TimerQueued = false; + m_StateChangeInProgress = false; EventQueue.Clear(); } - public ScriptInstance(IScriptEngine engine, SceneObjectPart part, - UUID itemID, UUID assetID, string assembly, - AppDomain dom, string primName, string scriptName, - int startParam, bool postOnRez, StateSource stateSource, - int maxScriptQueue) + public ScriptInstance( + IScriptEngine engine, SceneObjectPart part, TaskInventoryItem item, + int startParam, bool postOnRez, + int maxScriptQueue) { State = "default"; EventQueue = new Queue(32); + ExecutionTimer = new Stopwatch(); Engine = engine; - LocalID = part.LocalId; - ObjectID = part.UUID; - RootLocalID = part.ParentGroup.LocalId; - RootObjectID = part.ParentGroup.UUID; - ItemID = itemID; - AssetID = assetID; - PrimName = primName; - ScriptName = scriptName; - m_Assembly = assembly; + Part = part; + ScriptTask = item; + + // This is currently only here to allow regression tests to get away without specifying any inventory + // item when they are testing script logic that doesn't require an item. + if (ScriptTask != null) + { + ScriptName = ScriptTask.Name; + ItemID = ScriptTask.ItemID; + AssetID = ScriptTask.AssetID; + } + + PrimName = part.ParentGroup.Name; StartParam = startParam; m_MaxScriptQueue = maxScriptQueue; - m_stateSource = stateSource; m_postOnRez = postOnRez; - m_AttachedAvatar = part.ParentGroup.AttachedAvatar; - m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID; + m_AttachedAvatar = Part.ParentGroup.AttachedAvatar; + m_RegionID = Part.ParentGroup.Scene.RegionInfo.RegionID; - if (part != null) - { - lock (part.TaskInventory) - { - if (part.TaskInventory.ContainsKey(ItemID)) - { - ScriptTask = part.TaskInventory[ItemID]; - } - } - } + m_SaveState = StatePersistedHere; + + ExecutionTime = new MetricsCollectorTime(MeasurementWindow, 10); + +// m_log.DebugFormat( +// "[SCRIPT INSTANCE]: Instantiated script instance {0} (id {1}) in part {2} (id {3}) in object {4} attached avatar {5} in {6}", +// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, m_AttachedAvatar, Engine.World.Name); + } + + /// + /// Load the script from an assembly into an AppDomain. + /// + /// + /// + /// + /// Path for all script associated data (state, etc.). In a multi-region set up + /// with all scripts loading into the same AppDomain this may not be the same place as the DLL itself. + /// + /// + /// false if load failed, true if suceeded + public bool Load( + IScript script, EventWaitHandle coopSleepHandle, string assemblyPath, + string dataPath, StateSource stateSource, bool coopTermination) + { + m_Script = script; + m_coopSleepHandle = coopSleepHandle; + m_assemblyPath = assemblyPath; + m_dataPath = dataPath; + m_stateSource = stateSource; + m_coopTermination = coopTermination; + + if (m_coopTermination) + CoopWaitHandle = coopSleepHandle; + else + CoopWaitHandle = null; ApiManager am = new ApiManager(); foreach (string api in am.GetApis()) { m_Apis[api] = am.CreateApi(api); - m_Apis[api].Initialize(engine, part, ScriptTask); - } - - try - { - if (dom != System.AppDomain.CurrentDomain) - m_Script = (IScript)dom.CreateInstanceAndUnwrap( - Path.GetFileNameWithoutExtension(assembly), - "SecondLife.Script"); - else - m_Script = (IScript)Assembly.Load( - Path.GetFileNameWithoutExtension(assembly)).CreateInstance( - "SecondLife.Script"); - - //ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); - //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); -// lease.Register(this); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[SCRIPT INSTANCE]: Error loading assembly {0}. Exception {1}{2}", - assembly, e.Message, e.StackTrace); + m_Apis[api].Initialize(Engine, Part, ScriptTask); } try @@ -278,26 +310,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_Script.InitApi(kv.Key, kv.Value); } -// // m_log.Debug("[Script] Script instance created"); + // // m_log.Debug("[Script] Script instance created"); - part.SetScriptEvents(ItemID, - (int)m_Script.GetStateEventFlags(State)); + Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State)); } catch (Exception e) { m_log.ErrorFormat( - "[SCRIPT INSTANCE]: Error loading script instance from assembly {0}. Exception {1}{2}", - assembly, e.Message, e.StackTrace); + "[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}", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, e.Message, e.StackTrace); - return; + return false; } - m_SaveState = true; + // For attachments, XEngine saves the state into a .state file when XEngine.SetXMLState() is called. + string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state"); - string savedState = Path.Combine(Path.GetDirectoryName(assembly), - ItemID.ToString() + ".state"); if (File.Exists(savedState)) { + // m_log.DebugFormat( + // "[SCRIPT INSTANCE]: Found state for script {0} for {1} ({2}) at {3} in {4}", + // ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name); + string xml = String.Empty; try @@ -317,13 +351,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance ScriptSerializer.Deserialize(xml, this); AsyncCommandManager.CreateFromData(Engine, - LocalID, ItemID, ObjectID, - PluginData); + LocalID, ItemID, ObjectID, + PluginData); -// m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName); + // m_log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", PrimName, m_ScriptName); - part.SetScriptEvents(ItemID, - (int)m_Script.GetStateEventFlags(State)); + Part.SetScriptEvents(ItemID, + (int)m_Script.GetStateEventFlags(State)); if (!Running) m_startOnInit = false; @@ -338,29 +372,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_SaveState = false; m_startedFromSavedState = true; } + + // If this script is in an attachment then we no longer need the state file. + if (!StatePersistedHere) + RemoveState(); } - else - { - m_log.WarnFormat( - "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). Memory limit exceeded", - savedState, ScriptName, ItemID, PrimName, ObjectID, assembly); - } + // else + // { + // m_log.WarnFormat( + // "[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.", + // ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState); + // } } catch (Exception e) { - m_log.ErrorFormat( - "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). XML is {6}. Exception {7}{8}", - savedState, ScriptName, ItemID, PrimName, ObjectID, assembly, xml, e.Message, e.StackTrace); + m_log.ErrorFormat( + "[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}", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState, xml, e.Message, e.StackTrace); } } -// else -// { -// ScenePresence presence = Engine.World.GetScenePresence(part.OwnerID); + // else + // { + // m_log.DebugFormat( + // "[SCRIPT INSTANCE]: Did not find state for script {0} for {1} ({2}) at {3} in {4}", + // ItemID, savedState, Part.Name, Part.ParentGroup.Name, Part.ParentGroup.Scene.Name); + // } -// if (presence != null && (!postOnRez)) -// presence.ControllingClient.SendAgentAlertMessage("Compile successful", false); - -// } + return true; } public void Init() @@ -418,33 +456,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance PostEvent(new EventParams("attach", new object[] { new LSL_Types.LSLString(m_AttachedAvatar.ToString()) }, new DetectParams[0])); } - } } private void ReleaseControls() { - SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); - - if (part != null) + int permsMask; + UUID permsGranter; + lock (Part.TaskInventory) { - int permsMask; - UUID permsGranter; - lock (part.TaskInventory) - { - if (!part.TaskInventory.ContainsKey(ItemID)) - return; + if (!Part.TaskInventory.ContainsKey(ItemID)) + return; - permsGranter = part.TaskInventory[ItemID].PermsGranter; - permsMask = part.TaskInventory[ItemID].PermsMask; - } + permsGranter = Part.TaskInventory[ItemID].PermsGranter; + permsMask = Part.TaskInventory[ItemID].PermsMask; + } - if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0) - { - ScenePresence presence = Engine.World.GetScenePresence(permsGranter); - if (presence != null) - presence.UnRegisterControlEventsToScript(LocalID, ItemID); - } + if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0) + { + ScenePresence presence = Engine.World.GetScenePresence(permsGranter); + if (presence != null) + presence.UnRegisterControlEventsToScript(LocalID, ItemID); } } @@ -456,15 +488,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public void RemoveState() { - string savedState = Path.Combine(Path.GetDirectoryName(m_Assembly), - ItemID.ToString() + ".state"); + string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state"); + +// m_log.DebugFormat( +// "[SCRIPT INSTANCE]: Deleting state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}.", +// savedState, ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name); try { File.Delete(savedState); } - catch(Exception) + catch (Exception e) { + m_log.Warn( + string.Format( + "[SCRIPT INSTANCE]: Could not delete script state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}. Exception ", + savedState, ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name), + e); } } @@ -487,8 +527,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance Running = true; TimeStarted = DateTime.Now; - MeasurementPeriodTickStart = Util.EnvironmentTickCount(); - MeasurementPeriodExecutionTime = 0; + + // Note: we don't reset ExecutionTime. The reason is that runaway scripts are stopped and restarted + // automatically, and we *do* want to show that they had high CPU in that case. If we had reset + // ExecutionTime here then runaway scripts, paradoxically, would never show up in the "Top Scripts" dialog. if (EventQueue.Count > 0) { @@ -500,16 +542,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } } - public bool Stop(int timeout) + public bool Stop(int timeout, bool clearEventQueue = false) { -// m_log.DebugFormat( -// "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}", -// ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks); + if (DebugLevel >= 1) + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}", + ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks); IScriptWorkItem workItem; lock (EventQueue) { + if (clearEventQueue) + ClearQueue(); + if (!Running) return true; @@ -533,9 +579,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } // Wait for the current event to complete. - if (!m_InSelfDelete && workItem.Wait(new TimeSpan((long)timeout * 100000))) + if (!m_InSelfDelete) { - return true; + if (!m_coopTermination) + { + // If we're not co-operative terminating then try and wait for the event to complete before stopping + if (workItem.Wait(timeout)) + return true; + } + else + { + if (DebugLevel >= 1) + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Co-operatively stopping script {0} {1} in {2} {3}", + ScriptName, ItemID, PrimName, ObjectID); + + // This will terminate the event on next handle check by the script. + m_coopSleepHandle.Set(); + + // For now, we will wait forever since the event should always cleanly terminate once LSL loop + // checking is implemented. May want to allow a shorter timeout option later. + if (workItem.Wait(Timeout.Infinite)) + { + if (DebugLevel >= 1) + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}", + ScriptName, ItemID, PrimName, ObjectID); + + return true; + } + } } lock (EventQueue) @@ -548,6 +621,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // If the event still hasn't stopped and we the stop isn't the result of script or object removal, then // forcibly abort the work item (this aborts the underlying thread). + // Co-operative termination should never reach this point. if (!m_InSelfDelete) { m_log.DebugFormat( @@ -570,12 +644,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance if (state == State) return; - PostEvent(new EventParams("state_exit", new Object[0], - new DetectParams[0])); - PostEvent(new EventParams("state", new Object[] { state }, - new DetectParams[0])); - PostEvent(new EventParams("state_entry", new Object[0], - new DetectParams[0])); + EventParams lastTimerEv = null; + + lock (EventQueue) + { + // Remove all queued events, remembering the last timer event + while (EventQueue.Count > 0) + { + EventParams tempv = (EventParams)EventQueue.Dequeue(); + if (tempv.EventName == "timer") lastTimerEv = tempv; + } + + // Post events + PostEvent(new EventParams("state_exit", new Object[0], + new DetectParams[0])); + PostEvent(new EventParams("state", new Object[] { state }, + new DetectParams[0])); + PostEvent(new EventParams("state_entry", new Object[0], + new DetectParams[0])); + + // Requeue the timer event after the state changing events + if (lastTimerEv != null) EventQueue.Enqueue(lastTimerEv); + + // This will stop events from being queued and processed + // until the new state is started + m_StateChangeInProgress = true; + } throw new EventAbortException(); } @@ -607,6 +701,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance lock (EventQueue) { + // The only events that persist across state changes are timers + if (m_StateChangeInProgress && data.EventName != "timer") + return; + if (EventQueue.Count >= m_MaxScriptQueue) return; @@ -677,196 +775,222 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance if (Suspended) return 0; - EventParams data = null; + ExecutionTimer.Restart(); + + try + { + return EventProcessorInt(); + } + finally + { + ExecutionTimer.Stop(); + ExecutionTime.AddSample(ExecutionTimer); + Part.ParentGroup.Scene.AddScriptExecutionTime(ExecutionTimer.ElapsedTicks); + } + } + } + + private object EventProcessorInt() + { + EventParams data = null; - lock (EventQueue) + lock (EventQueue) + { + data = (EventParams)EventQueue.Dequeue(); + if (data == null) // Shouldn't happen { - data = (EventParams)EventQueue.Dequeue(); - if (data == null) // Shouldn't happen + if (EventQueue.Count > 0 && Running && !ShuttingDown) { - if (EventQueue.Count > 0 && Running && !ShuttingDown) - { - m_CurrentWorkItem = Engine.QueueEventHandler(this); - } - else - { - m_CurrentWorkItem = null; - } - return 0; + m_CurrentWorkItem = Engine.QueueEventHandler(this); } - - if (data.EventName == "timer") - m_TimerQueued = false; - if (data.EventName == "control") + else { - if (m_ControlEventsInQueue > 0) - m_ControlEventsInQueue--; + m_CurrentWorkItem = null; } - if (data.EventName == "collision") - m_CollisionInQueue = false; + return 0; } - SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); + if (data.EventName == "timer") + m_TimerQueued = false; + if (data.EventName == "control") + { + if (m_ControlEventsInQueue > 0) + m_ControlEventsInQueue--; + } + if (data.EventName == "collision") + m_CollisionInQueue = false; + } - if (DebugLevel >= 2) + if (DebugLevel >= 2) + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}", + data.EventName, + ScriptName, + Part.Name, + Part.LocalId, + Part.ParentGroup.Name, + Part.ParentGroup.UUID, + Part.AbsolutePosition, + Part.ParentGroup.Scene.Name); + + m_DetectParams = data.DetectParams; + + if (data.EventName == "state") // Hardcoded state change + { + State = data.Params[0].ToString(); + + if (DebugLevel >= 1) m_log.DebugFormat( - "[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}", - data.EventName, - ScriptName, - part.Name, - part.LocalId, - part.ParentGroup.Name, - part.ParentGroup.UUID, - part.AbsolutePosition, - part.ParentGroup.Scene.Name); - - m_DetectParams = data.DetectParams; - - if (data.EventName == "state") // Hardcoded state change + "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}", + State, + ScriptName, + Part.Name, + Part.LocalId, + Part.ParentGroup.Name, + Part.ParentGroup.UUID, + Part.AbsolutePosition, + Part.ParentGroup.Scene.Name); + + AsyncCommandManager.StateChange(Engine, + LocalID, ItemID); + // we are effectively in the new state now, so we can resume queueing + // and processing other non-timer events + m_StateChangeInProgress = false; + + Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State)); + } + else + { + if (Engine.World.PipeEventsForScript(LocalID) || + data.EventName == "control") // Don't freeze avies! { - State = data.Params[0].ToString(); + // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", + // PrimName, ScriptName, data.EventName, State); - if (DebugLevel >= 1) - m_log.DebugFormat( - "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}", - State, - ScriptName, - part.Name, - part.LocalId, - part.ParentGroup.Name, - part.ParentGroup.UUID, - part.AbsolutePosition, - part.ParentGroup.Scene.Name); - - AsyncCommandManager.RemoveScript(Engine, - LocalID, ItemID); - - if (part != null) + try { - part.SetScriptEvents(ItemID, - (int)m_Script.GetStateEventFlags(State)); - } - } - else - { - if (Engine.World.PipeEventsForScript(LocalID) || - data.EventName == "control") // Don't freeze avies! - { - // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", - // PrimName, ScriptName, data.EventName, State); + m_CurrentEvent = data.EventName; + m_EventStart = DateTime.Now; + m_InEvent = true; try { - m_CurrentEvent = data.EventName; - m_EventStart = DateTime.Now; - m_InEvent = true; - - int start = Util.EnvironmentTickCount(); - - // Reset the measurement period when we reach the end of the current one. - if (start - MeasurementPeriodTickStart > MaxMeasurementPeriod) - MeasurementPeriodTickStart = start; - m_Script.ExecuteEvent(State, data.EventName, data.Params); - - MeasurementPeriodExecutionTime += Util.EnvironmentTickCount() - start; - + } + finally + { m_InEvent = false; m_CurrentEvent = String.Empty; + } - if (m_SaveState) - { - // This will be the very first event we deliver - // (state_entry) in default state - // - SaveState(m_Assembly); + if (m_SaveState) + { + // This will be the very first event we deliver + // (state_entry) in default state + // + SaveState(); - m_SaveState = false; - } + m_SaveState = false; } - catch (Exception e) + } + catch (Exception e) + { + // m_log.DebugFormat( + // "[SCRIPT] Exception in script {0} {1}: {2}{3}", + // ScriptName, ItemID, e.Message, e.StackTrace); + + if ((!(e is TargetInvocationException) + || (!(e.InnerException is SelfDeleteException) + && !(e.InnerException is ScriptDeleteException) + && !(e.InnerException is ScriptCoopStopException))) + && !(e is ThreadAbortException)) { -// m_log.DebugFormat( -// "[SCRIPT] Exception in script {0} {1}: {2}{3}", -// ScriptName, ItemID, e.Message, e.StackTrace); - - m_InEvent = false; - m_CurrentEvent = String.Empty; - - if ((!(e is TargetInvocationException) || (!(e.InnerException is SelfDeleteException) && !(e.InnerException is ScriptDeleteException))) && !(e is ThreadAbortException)) + try { - try - { - // DISPLAY ERROR INWORLD - string text = FormatException(e); - - if (text.Length > 1000) - text = text.Substring(0, 1000); - Engine.World.SimChat(Utils.StringToBytes(text), - ChatTypeEnum.DebugChannel, 2147483647, - part.AbsolutePosition, - part.Name, part.UUID, false); - - - m_log.DebugFormat( - "[SCRIPT INSTANCE]: Runtime error in script {0}, part {1} {2} at {3} in {4}, displayed error {5}, actual exception {6}", - ScriptName, - PrimName, - part.UUID, - part.AbsolutePosition, - part.ParentGroup.Scene.Name, - text.Replace("\n", "\\n"), - e.InnerException); - } - catch (Exception) - { - } - // catch (Exception e2) // LEGIT: User Scripting - // { - // m_log.Error("[SCRIPT]: "+ - // "Error displaying error in-world: " + - // e2.ToString()); - // m_log.Error("[SCRIPT]: " + - // "Errormessage: Error compiling script:\r\n" + - // e.ToString()); - // } + // DISPLAY ERROR INWORLD + string text = FormatException(e); + + if (text.Length > 1000) + text = text.Substring(0, 1000); + Engine.World.SimChat(Utils.StringToBytes(text), + ChatTypeEnum.DebugChannel, 2147483647, + Part.AbsolutePosition, + Part.Name, Part.UUID, false); + + + m_log.Debug(string.Format( + "[SCRIPT INSTANCE]: Runtime error in script {0} (event {1}), part {2} {3} at {4} in {5} ", + ScriptName, + data.EventName, + PrimName, + Part.UUID, + Part.AbsolutePosition, + Part.ParentGroup.Scene.Name), + e); } - else if ((e is TargetInvocationException) && (e.InnerException is SelfDeleteException)) + catch (Exception) { - m_InSelfDelete = true; - if (part != null) - Engine.World.DeleteSceneObject(part.ParentGroup, false); - } - else if ((e is TargetInvocationException) && (e.InnerException is ScriptDeleteException)) - { - m_InSelfDelete = true; - if (part != null) - part.Inventory.RemoveInventoryItem(ItemID); } + // catch (Exception e2) // LEGIT: User Scripting + // { + // m_log.Error("[SCRIPT]: "+ + // "Error displaying error in-world: " + + // e2.ToString()); + // m_log.Error("[SCRIPT]: " + + // "Errormessage: Error compiling script:\r\n" + + // e.ToString()); + // } + } + else if ((e is TargetInvocationException) && (e.InnerException is SelfDeleteException)) + { + m_InSelfDelete = true; + Engine.World.DeleteSceneObject(Part.ParentGroup, false); + } + else if ((e is TargetInvocationException) && (e.InnerException is ScriptDeleteException)) + { + m_InSelfDelete = true; + Part.Inventory.RemoveInventoryItem(ItemID); + } + else if ((e is TargetInvocationException) && (e.InnerException is ScriptCoopStopException)) + { + if (DebugLevel >= 1) + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.", + PrimName, ScriptName, data.EventName, State); } } } + } - // If there are more events and we are currently running and not shutting down, then ask the - // script engine to run the next event. - lock (EventQueue) + // If there are more events and we are currently running and not shutting down, then ask the + // script engine to run the next event. + lock (EventQueue) + { + // Increase processed events counter and prevent wrap; + if (++EventsProcessed == 1000000) + EventsProcessed = 100000; + + if ((EventsProcessed % 100000) == 0 && DebugLevel > 0) { - EventsProcessed++; + m_log.DebugFormat("[SCRIPT INSTANCE]: Script \"{0}\" (Object \"{1}\" {2} @ {3}.{4}, Item ID {5}, Asset {6}) in event {7}: processed {8:n0} script events", + ScriptTask.Name, + Part.ParentGroup.Name, Part.ParentGroup.UUID, Part.ParentGroup.AbsolutePosition, Part.ParentGroup.Scene.Name, + ScriptTask.ItemID, ScriptTask.AssetID, data.EventName, EventsProcessed); + } - if (EventQueue.Count > 0 && Running && !ShuttingDown) - { - m_CurrentWorkItem = Engine.QueueEventHandler(this); - } - else - { - m_CurrentWorkItem = null; - } + if (EventQueue.Count > 0 && Running && !ShuttingDown) + { + m_CurrentWorkItem = Engine.QueueEventHandler(this); } + else + { + m_CurrentWorkItem = null; + } + } - m_DetectParams = null; + m_DetectParams = null; - return 0; - } + return 0; } public int EventTime() @@ -888,19 +1012,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance ReleaseControls(); Stop(timeout); - SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); - part.Inventory.GetInventoryItem(ItemID).PermsMask = 0; - part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero; + Part.Inventory.GetInventoryItem(ItemID).PermsMask = 0; + Part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero; AsyncCommandManager.RemoveScript(Engine, LocalID, ItemID); EventQueue.Clear(); m_Script.ResetVars(); + StartParam = 0; State = "default"; - part.SetScriptEvents(ItemID, + Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State)); if (running) Start(); - m_SaveState = true; + + m_SaveState = StatePersistedHere; + PostEvent(new EventParams("state_entry", new Object[0], new DetectParams[0])); } @@ -913,21 +1039,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance ReleaseControls(); m_Script.ResetVars(); - SceneObjectPart part = Engine.World.GetSceneObjectPart(LocalID); - part.Inventory.GetInventoryItem(ItemID).PermsMask = 0; - part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero; + Part.Inventory.GetInventoryItem(ItemID).PermsMask = 0; + Part.Inventory.GetInventoryItem(ItemID).PermsGranter = UUID.Zero; AsyncCommandManager.RemoveScript(Engine, LocalID, ItemID); EventQueue.Clear(); m_Script.ResetVars(); + string oldState = State; + StartParam = 0; State = "default"; - part.SetScriptEvents(ItemID, + Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State)); - if (m_CurrentEvent != "state_entry") + if (m_CurrentEvent != "state_entry" || oldState != "default") { - m_SaveState = true; + m_SaveState = StatePersistedHere; PostEvent(new EventParams("state_entry", new Object[0], new DetectParams[0])); throw new EventAbortException(); @@ -944,6 +1071,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public void SetVars(Dictionary vars) { +// foreach (KeyValuePair kvp in vars) +// m_log.DebugFormat("[SCRIPT INSTANCE]: Setting var {0}={1}", kvp.Key, kvp.Value); + m_Script.SetVars(vars); } @@ -967,42 +1097,63 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance return m_DetectParams[idx].Key; } - public void SaveState(string assembly) + public void SaveState() { - // If we're currently in an event, just tell it to save upon return - // - if (m_InEvent) - { - m_SaveState = true; + if (!Running && !StayStopped) return; - } + // We cannot call this inside the EventQueue lock since it will currently take AsyncCommandManager.staticLock. + // This may already be held by AsyncCommandManager.DoOneCmdHandlerPass() which in turn can take EventQueue + // lock via ScriptInstance.PostEvent(). PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID); - string xml = ScriptSerializer.Serialize(this); - - // Compare hash of the state we just just created with the state last written to disk - // If the state is different, update the disk file. - UUID hash = UUID.Parse(Utils.MD5String(xml)); - - if (hash != m_CurrentStateHash) + // We need to lock here to avoid any race with a thread that is removing this script. + lock (EventQueue) { - try + // Check again to avoid a race with a thread in Stop() + if (!Running && !StayStopped) + return; + + // If we're currently in an event, just tell it to save upon return + // + if (m_InEvent) { - FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")); - Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml); - fs.Write(buf, 0, buf.Length); - fs.Close(); + m_SaveState = true; + return; } - catch(Exception) + + // m_log.DebugFormat( + // "[SCRIPT INSTANCE]: Saving state for script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}", + // ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name); + + string xml = ScriptSerializer.Serialize(this); + + // Compare hash of the state we just just created with the state last written to disk + // If the state is different, update the disk file. + UUID hash = UUID.Parse(Utils.MD5String(xml)); + + if (hash != m_CurrentStateHash) { - // m_log.Error("Unable to save xml\n"+e.ToString()); + try + { + using (FileStream fs = File.Create(Path.Combine(m_dataPath, ItemID.ToString() + ".state"))) + { + Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml); + fs.Write(buf, 0, buf.Length); + } + } + catch(Exception) + { + // m_log.Error("Unable to save xml\n"+e.ToString()); + } + //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state"))) + //{ + // throw new Exception("Completed persistence save, but no file was created"); + //} + m_CurrentStateHash = hash; } - //if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state"))) - //{ - // throw new Exception("Completed persistence save, but no file was created"); - //} - m_CurrentStateHash = hash; + + StayStopped = false; } } @@ -1072,7 +1223,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public string GetAssemblyName() { - return m_Assembly; + return m_assemblyPath; } public string GetXMLState() @@ -1109,4 +1260,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance Suspended = false; } } + + /// + /// Xengine event wait handle. + /// + /// + /// This class exists becase XEngineScriptBase gets a reference to this wait handle. We need to make sure that + /// when scripts are running in different AppDomains the lease does not expire. + /// FIXME: Like LSL_Api, etc., this effectively leaks memory since the GC will never collect it. To avoid this, + /// proper remoting sponsorship needs to be implemented across the board. + /// + public class XEngineEventWaitHandle : EventWaitHandle + { + public XEngineEventWaitHandle(bool initialState, EventResetMode mode) : base(initialState, mode) {} + + public override Object InitializeLifetimeService() + { + return null; + } + } } 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..5b9794b --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Tests/CoopTerminationTests.cs @@ -0,0 +1,513 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Scripting.WorldComm; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.ScriptEngine.XEngine; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.Shared.Instance.Tests +{ + /// + /// Test that co-operative script thread termination is working correctly. + /// + [TestFixture] + public class CoopTerminationTests : OpenSimTestCase + { + private TestScene m_scene; + private OpenSim.Region.ScriptEngine.XEngine.XEngine m_xEngine; + + private AutoResetEvent m_chatEvent; + private AutoResetEvent m_stoppedEvent; + + private OSChatMessage m_osChatMessageReceived; + + /// + /// Number of chat messages received so far. Reset before each test. + /// + private int m_chatMessagesReceived; + + /// + /// Number of chat messages expected. m_chatEvent is not fired until this number is reached or exceeded. + /// + private int m_chatMessagesThreshold; + + [SetUp] + public void Init() + { + m_osChatMessageReceived = null; + m_chatMessagesReceived = 0; + m_chatMessagesThreshold = 0; + m_chatEvent = new AutoResetEvent(false); + m_stoppedEvent = new AutoResetEvent(false); + + //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin"); +// Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); + m_xEngine = new OpenSim.Region.ScriptEngine.XEngine.XEngine(); + m_xEngine.DebugLevel = 1; + + IniConfigSource configSource = new IniConfigSource(); + + IConfig startupConfig = configSource.AddConfig("Startup"); + startupConfig.Set("DefaultScriptEngine", "XEngine"); + + IConfig xEngineConfig = configSource.AddConfig("XEngine"); + xEngineConfig.Set("Enabled", "true"); + xEngineConfig.Set("StartDelay", "0"); + + // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call + // to AssemblyResolver.OnAssemblyResolve fails. + xEngineConfig.Set("AppDomainLoading", "false"); + + xEngineConfig.Set("ScriptStopStrategy", "co-op"); + + // Make sure loops aren't actually being terminated by a script delay wait. + xEngineConfig.Set("ScriptDelayFactor", 0); + + // This is really just set for debugging the test. + xEngineConfig.Set("WriteScriptSourceToDebugFile", true); + + // Set to false if we need to debug test so the old scripts don't get wiped before each separate test +// xEngineConfig.Set("DeleteScriptsOnStartup", false); + + // This is not currently used at all for co-op termination. Bumping up to demonstrate that co-op termination + // has an effect - without it tests will fail due to a 120 second wait for the event to finish. + xEngineConfig.Set("WaitForEventCompletionOnScriptStop", 120000); + + m_scene = new SceneHelpers().SetupScene("My Test", TestHelpers.ParseTail(0x9999), 1000, 1000, configSource); + SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine); + m_scene.StartScripts(); + } + + /// + /// Test co-operative termination on derez of an object containing a script with a long-running event. + /// + /// + /// TODO: Actually compiling the script is incidental to this test. Really want a way to compile test scripts + /// within the build itself. + /// + [Test] + public void TestStopOnLongSleep() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + llSay(0, ""Thin Lizzy""); + llSleep(60); + } +}"; + + TestStop(script); + } + + [Test] + public void TestNoStopOnSingleStatementForLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + for (i = 0; i <= 1; i++) llSay(0, ""Iter "" + (string)i); + } +}"; + + TestSingleStatementNoStop(script); + } + + [Test] + public void TestStopOnLongSingleStatementForLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + for (i = 0; i < 2147483647; i++) llSay(0, ""Iter "" + (string)i); + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnLongCompoundStatementForLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + for (i = 0; i < 2147483647; i++) + { + llSay(0, ""Iter "" + (string)i); + } + } +}"; + + TestStop(script); + } + + [Test] + public void TestNoStopOnSingleStatementWhileLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + while (i < 2) llSay(0, ""Iter "" + (string)i++); + } +}"; + + TestSingleStatementNoStop(script); + } + + [Test] + public void TestStopOnLongSingleStatementWhileLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + while (1 == 1) + llSay(0, ""Iter "" + (string)i++); + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnLongCompoundStatementWhileLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + while (1 == 1) + { + llSay(0, ""Iter "" + (string)i++); + } + } +}"; + + TestStop(script); + } + + [Test] + public void TestNoStopOnSingleStatementDoWhileLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + + do llSay(0, ""Iter "" + (string)i++); + while (i < 2); + } +}"; + + TestSingleStatementNoStop(script); + } + + [Test] + public void TestStopOnLongSingleStatementDoWhileLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + do llSay(0, ""Iter "" + (string)i++); + while (1 == 1); + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnLongCompoundStatementDoWhileLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + do + { + llSay(0, ""Iter "" + (string)i++); + } while (1 == 1); + } +}"; + + TestStop(script); + } + + [Test] + public void TestStopOnInfiniteJumpLoop() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + @p1; + llSay(0, ""Iter "" + (string)i++); + jump p1; + } +}"; + + TestStop(script); + } + + // Disabling for now as these are not particularly useful tests (since they fail due to stack overflow before + // termination can even be tried. +// [Test] + public void TestStopOnInfiniteUserFunctionCallLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@" +integer i = 0; + +ufn1() +{ + llSay(0, ""Iter ufn1() "" + (string)i++); + ufn1(); +} + +default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + ufn1(); + } +}"; + + TestStop(script); + } + + // Disabling for now as these are not particularly useful tests (since they fail due to stack overflow before + // termination can even be tried. +// [Test] + public void TestStopOnInfiniteManualEventCallLoop() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string script = +@"default +{ + state_entry() + { + integer i = 0; + llSay(0, ""Thin Lizzy""); + + llSay(0, ""Iter"" + (string)i++); + default_event_state_entry(); + } +}"; + + TestStop(script); + } + + private SceneObjectPart CreateScript(string script, string itemName, UUID userId) + { +// UUID objectId = TestHelpers.ParseTail(0x100); +// UUID itemId = TestHelpers.ParseTail(0x3); + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(1, userId, string.Format("Object for {0}", itemName), 0x100); + m_scene.AddNewSceneObject(so, true); + + InventoryItemBase itemTemplate = new InventoryItemBase(); +// itemTemplate.ID = itemId; + itemTemplate.Name = itemName; + itemTemplate.Folder = so.UUID; + itemTemplate.InvType = (int)InventoryType.LSL; + + m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; + + return m_scene.RezNewScript(userId, itemTemplate, script); + } + + private void TestSingleStatementNoStop(string script) + { + // In these tests we expect to see at least 2 chat messages to confirm that the loop is working properly. + m_chatMessagesThreshold = 2; + + UUID userId = TestHelpers.ParseTail(0x1); +// UUID objectId = TestHelpers.ParseTail(0x100); +// UUID itemId = TestHelpers.ParseTail(0x3); + string itemName = "TestNoStop"; + + SceneObjectPart partWhereRezzed = CreateScript(script, itemName, userId); + + // Wait for the script to start the event before we try stopping it. + m_chatEvent.WaitOne(60000); + + if (m_osChatMessageReceived == null) + Assert.Fail("Script did not start"); + else + Assert.That(m_chatMessagesReceived, Is.EqualTo(2)); + + bool running; + TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); + Assert.That( + SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True); + Assert.That(running, Is.True); + } + + private void TestStop(string script) + { + // In these tests we're only interested in the first message to confirm that the script has started. + m_chatMessagesThreshold = 1; + + UUID userId = TestHelpers.ParseTail(0x1); +// UUID objectId = TestHelpers.ParseTail(0x100); +// UUID itemId = TestHelpers.ParseTail(0x3); + string itemName = "TestStop"; + + SceneObjectPart partWhereRezzed = CreateScript(script, itemName, userId); + TaskInventoryItem rezzedItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); + + // Wait for the script to start the event before we try stopping it. + m_chatEvent.WaitOne(60000); + + if (m_osChatMessageReceived != null) + Console.WriteLine("Script started with message [{0}]", m_osChatMessageReceived.Message); + else + Assert.Fail("Script did not start"); + + // FIXME: This is a very poor way of trying to avoid a low-probability race condition where the script + // executes llSay() but has not started the next statement before we try to stop it. + Thread.Sleep(1000); + + // We need a way of carrying on if StopScript() fail, since it won't return if the script isn't actually + // stopped. This kind of multi-threading is far from ideal in a regression test. + new Thread(() => { m_xEngine.StopScript(rezzedItem.ItemID); m_stoppedEvent.Set(); }).Start(); + + if (!m_stoppedEvent.WaitOne(30000)) + Assert.Fail("Script did not co-operatively stop."); + + bool running; + TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); + Assert.That( + SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True); + Assert.That(running, Is.False); + } + + private void OnChatFromWorld(object sender, OSChatMessage oscm) + { + Console.WriteLine("Got chat [{0}]", oscm.Message); + m_osChatMessageReceived = oscm; + + if (++m_chatMessagesReceived >= m_chatMessagesThreshold) + { + m_scene.EventManager.OnChatFromWorld -= OnChatFromWorld; + m_chatEvent.Set(); + } + } + } +} \ 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 fcb98a5..0ca5ff3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs @@ -102,19 +102,19 @@ namespace OpenSim.Region.ScriptEngine.Shared public override string ToString() { - string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000}>", x, y, z); + string s=String.Format(Culture.FormatProvider,"<{0:0.000000},{1:0.000000},{2:0.000000}>", x, y, z); return s; } public static explicit operator LSLString(Vector3 vec) { - string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000}>", vec.x, vec.y, vec.z); + string s=String.Format(Culture.FormatProvider,"<{0:0.000000},{1:0.000000},{2:0.000000}>", vec.x, vec.y, vec.z); return new LSLString(s); } public static explicit operator string(Vector3 vec) { - string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000}>", vec.x, vec.y, vec.z); + string s=String.Format(Culture.FormatProvider,"<{0:0.000000},{1:0.000000},{2:0.000000}>", vec.x, vec.y, vec.z); return s; } @@ -371,6 +371,31 @@ namespace OpenSim.Region.ScriptEngine.Shared #endregion + #region Methods + public Quaternion Normalize() + { + double length = Math.Sqrt(x * x + y * y + z * z + s * s); + if (length < float.Epsilon) + { + x = 0; + y = 0; + z = 0; + s = 1; + } + else + { + + double invLength = 1.0 / length; + x *= invLength; + y *= invLength; + z *= invLength; + s *= invLength; + } + + return this; + } + #endregion + #region Overriders public override int GetHashCode() @@ -477,7 +502,7 @@ namespace OpenSim.Region.ScriptEngine.Shared } [Serializable] - public class list + public struct list { private object[] m_data; @@ -544,111 +569,136 @@ namespace OpenSim.Region.ScriptEngine.Shared set {m_data = value; } } - // Function to obtain LSL type from an index. This is needed - // because LSL lists allow for multiple types, and safely - // iterating in them requires a type check. + + /// + /// Obtain LSL type from an index. + /// + /// + /// This is needed because LSL lists allow for multiple types, and safely + /// iterating in them requires a type check. + /// + /// + /// public Type GetLSLListItemType(int itemIndex) { - return m_data[itemIndex].GetType(); - } - - // Member functions to obtain item as specific types. - // For cases where implicit conversions would apply if items - // were not in a list (e.g. integer to float, but not float - // to integer) functions check for alternate types so as to - // down-cast from Object to the correct type. - // Note: no checks for item index being valid are performed - + return Data[itemIndex].GetType(); + } + + /// + /// Obtain float from an index. + /// + /// + /// For cases where implicit conversions would apply if items + /// were not in a list (e.g. integer to float, but not float + /// to integer) functions check for alternate types so as to + /// down-cast from Object to the correct type. + /// Note: no checks for item index being valid are performed + /// + /// + /// public LSL_Types.LSLFloat GetLSLFloatItem(int itemIndex) { - if (m_data[itemIndex] is LSL_Types.LSLInteger) + if (Data[itemIndex] is LSL_Types.LSLInteger) { - return (LSL_Types.LSLInteger)m_data[itemIndex]; + return (LSL_Types.LSLInteger)Data[itemIndex]; } - else if (m_data[itemIndex] is Int32) + else if (Data[itemIndex] is Int32) { - return new LSL_Types.LSLFloat((int)m_data[itemIndex]); + return new LSL_Types.LSLFloat((int)Data[itemIndex]); } - else if (m_data[itemIndex] is float) + else if (Data[itemIndex] is float) { - return new LSL_Types.LSLFloat((float)m_data[itemIndex]); + return new LSL_Types.LSLFloat((float)Data[itemIndex]); } - else if (m_data[itemIndex] is Double) + else if (Data[itemIndex] is Double) { - return new LSL_Types.LSLFloat((Double)m_data[itemIndex]); + return new LSL_Types.LSLFloat((Double)Data[itemIndex]); } - else if (m_data[itemIndex] is LSL_Types.LSLString) + else if (Data[itemIndex] is LSL_Types.LSLString) { - return new LSL_Types.LSLFloat(m_data[itemIndex].ToString()); + return new LSL_Types.LSLFloat(Data[itemIndex].ToString()); } else { - return (LSL_Types.LSLFloat)m_data[itemIndex]; + return (LSL_Types.LSLFloat)Data[itemIndex]; } } public LSL_Types.LSLString GetLSLStringItem(int itemIndex) { - if (m_data[itemIndex] is LSL_Types.key) - { - return (LSL_Types.key)m_data[itemIndex]; - } - else if (m_data[itemIndex] is String) - { - return new LSL_Types.LSLString((string)m_data[itemIndex]); - } - else if (m_data[itemIndex] is LSL_Types.LSLFloat) - { - return new LSL_Types.LSLString((LSLFloat)m_data[itemIndex]); - } - else if (m_data[itemIndex] is LSL_Types.LSLInteger) - { - return new LSL_Types.LSLString((LSLInteger)m_data[itemIndex]); - } - else - { - return (LSL_Types.LSLString)m_data[itemIndex]; - } + if (Data[itemIndex] is LSL_Types.key) + { + return (LSL_Types.key)Data[itemIndex]; + } + else + { + return new LSL_Types.LSLString(Data[itemIndex].ToString()); + } } public LSL_Types.LSLInteger GetLSLIntegerItem(int itemIndex) { - if (m_data[itemIndex] is LSL_Types.LSLInteger) - return (LSL_Types.LSLInteger)m_data[itemIndex]; - if (m_data[itemIndex] is LSL_Types.LSLFloat) - return new LSLInteger((int)m_data[itemIndex]); - else if (m_data[itemIndex] is Int32) - return new LSLInteger((int)m_data[itemIndex]); - else if (m_data[itemIndex] is LSL_Types.LSLString) - return new LSLInteger(m_data[itemIndex].ToString()); + if (Data[itemIndex] is LSL_Types.LSLInteger) + return (LSL_Types.LSLInteger)Data[itemIndex]; + if (Data[itemIndex] is LSL_Types.LSLFloat) + return new LSLInteger((int)Data[itemIndex]); + else if (Data[itemIndex] is Int32) + return new LSLInteger((int)Data[itemIndex]); + else if (Data[itemIndex] is LSL_Types.LSLString) + return new LSLInteger(Data[itemIndex].ToString()); else throw new InvalidCastException(string.Format( "{0} expected but {1} given", typeof(LSL_Types.LSLInteger).Name, - m_data[itemIndex] != null ? - m_data[itemIndex].GetType().Name : "null")); + Data[itemIndex] != null ? + Data[itemIndex].GetType().Name : "null")); } public LSL_Types.Vector3 GetVector3Item(int itemIndex) { - if(m_data[itemIndex] is LSL_Types.Vector3) - return (LSL_Types.Vector3)m_data[itemIndex]; + if (Data[itemIndex] is LSL_Types.Vector3) + { + return (LSL_Types.Vector3)Data[itemIndex]; + } + else if(Data[itemIndex] is OpenMetaverse.Vector3) + { + return new LSL_Types.Vector3( + (OpenMetaverse.Vector3)Data[itemIndex]); + } else + { throw new InvalidCastException(string.Format( "{0} expected but {1} given", typeof(LSL_Types.Vector3).Name, - m_data[itemIndex] != null ? - m_data[itemIndex].GetType().Name : "null")); + Data[itemIndex] != null ? + Data[itemIndex].GetType().Name : "null")); + } } public LSL_Types.Quaternion GetQuaternionItem(int itemIndex) { - return (LSL_Types.Quaternion)m_data[itemIndex]; + if (Data[itemIndex] is LSL_Types.Quaternion) + { + return (LSL_Types.Quaternion)Data[itemIndex]; + } + else if(Data[itemIndex] is OpenMetaverse.Quaternion) + { + return new LSL_Types.Quaternion( + (OpenMetaverse.Quaternion)Data[itemIndex]); + } + else + { + throw new InvalidCastException(string.Format( + "{0} expected but {1} given", + typeof(LSL_Types.Quaternion).Name, + Data[itemIndex] != null ? + Data[itemIndex].GetType().Name : "null")); + } } public LSL_Types.key GetKeyItem(int itemIndex) { - return (LSL_Types.key)m_data[itemIndex]; + return (LSL_Types.key)Data[itemIndex]; } public static list operator +(list a, list b) @@ -662,8 +712,11 @@ namespace OpenSim.Region.ScriptEngine.Shared private void ExtendAndAdd(object o) { - Array.Resize(ref m_data, Length + 1); - m_data.SetValue(o, Length - 1); + object[] tmp; + tmp = new object[Data.Length + 1]; + Data.CopyTo(tmp, 0); + tmp.SetValue(o, tmp.Length - 1); + Data = tmp; } public static list operator +(list a, LSLString s) @@ -711,10 +764,10 @@ namespace OpenSim.Region.ScriptEngine.Shared public void Add(object o) { object[] tmp; - tmp = new object[m_data.Length + 1]; - m_data.CopyTo(tmp, 0); - tmp[m_data.Length] = o; - m_data = tmp; + tmp = new object[Data.Length + 1]; + Data.CopyTo(tmp, 0); + tmp[Data.Length] = o; // Since this is tmp.Length - 1 + Data = tmp; } public bool Contains(object o) @@ -741,53 +794,53 @@ namespace OpenSim.Region.ScriptEngine.Shared Object[] ret; if (start < 0) - start=m_data.Length+start; + start=Data.Length+start; if (start < 0) start=0; if (end < 0) - end=m_data.Length+end; + end=Data.Length+end; if (end < 0) end=0; if (start > end) { - if (end >= m_data.Length) + if (end >= Data.Length) return new list(new Object[0]); - if (start >= m_data.Length) - start=m_data.Length-1; + if (start >= Data.Length) + start=Data.Length-1; return GetSublist(end, start); } // start >= 0 && end >= 0 here - if (start >= m_data.Length) + if (start >= Data.Length) { - ret=new Object[m_data.Length]; - Array.Copy(m_data, 0, ret, 0, m_data.Length); + ret=new Object[Data.Length]; + Array.Copy(Data, 0, ret, 0, Data.Length); return new list(ret); } - if (end >= m_data.Length) - end=m_data.Length-1; + if (end >= Data.Length) + end=Data.Length-1; // now, this makes the math easier int remove=end+1-start; - ret=new Object[m_data.Length-remove]; + ret=new Object[Data.Length-remove]; if (ret.Length == 0) return new list(ret); int src; int dest=0; - for (src = 0; src < m_data.Length; src++) + for (src = 0; src < Data.Length; src++) { if (src < start || src > end) - ret[dest++]=m_data[src]; + ret[dest++]=Data[src]; } return new list(ret); @@ -807,12 +860,12 @@ namespace OpenSim.Region.ScriptEngine.Shared if (start < 0) { - start = m_data.Length + start; + start = Data.Length + start; } if (end < 0) { - end = m_data.Length + end; + end = Data.Length + end; } // The conventional case is start <= end @@ -826,15 +879,15 @@ namespace OpenSim.Region.ScriptEngine.Shared // Start sublist beyond length // Also deals with start AND end still negative - if (start >= m_data.Length || end < 0) + if (start >= Data.Length || end < 0) { return new list(); } // Sublist extends beyond the end of the supplied list - if (end >= m_data.Length) + if (end >= Data.Length) { - end = m_data.Length - 1; + end = Data.Length - 1; } // Sublist still starts before the beginning of the list @@ -845,7 +898,7 @@ namespace OpenSim.Region.ScriptEngine.Shared ret = new object[end - start + 1]; - Array.Copy(m_data, start, ret, 0, end - start + 1); + Array.Copy(Data, start, ret, 0, end - start + 1); return new list(ret); @@ -856,7 +909,7 @@ namespace OpenSim.Region.ScriptEngine.Shared else { - list result = null; + list result; // If end is negative, then prefix list is empty if (end < 0) @@ -878,7 +931,7 @@ namespace OpenSim.Region.ScriptEngine.Shared // If start is outside of list, then just return // the prefix, whatever it is. - if (start >= m_data.Length) + if (start >= Data.Length) { return result; } @@ -1056,11 +1109,11 @@ namespace OpenSim.Region.ScriptEngine.Shared { string output; output = String.Empty; - if (m_data.Length == 0) + if (Data.Length == 0) { return String.Empty; } - foreach (object o in m_data) + foreach (object o in Data) { output = output + o.ToString(); } @@ -1255,12 +1308,12 @@ namespace OpenSim.Region.ScriptEngine.Shared public string ToPrettyString() { string output; - if (m_data.Length == 0) + if (Data.Length == 0) { return "[]"; } output = "["; - foreach (object o in m_data) + foreach (object o in Data) { if (o is String) { @@ -1327,27 +1380,6 @@ namespace OpenSim.Region.ScriptEngine.Shared } } - // - // BELOW IS WORK IN PROGRESS... IT WILL CHANGE, SO DON'T USE YET! :) - // - - public struct StringTest - { - // Our own little string - internal string actualString; - public static implicit operator bool(StringTest mString) - { - if (mString.actualString.Length == 0) - return true; - return false; - } - public override string ToString() - { - return actualString; - } - - } - [Serializable] public struct key { @@ -1401,6 +1433,16 @@ namespace OpenSim.Region.ScriptEngine.Shared return false; } } + + public static bool operator true(key k) + { + return (Boolean)k; + } + + public static bool operator false(key k) + { + return !(Boolean)k; + } static public implicit operator key(string s) { 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; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] +[assembly: AssemblyVersion("0.7.6.*")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiAvatarTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiAvatarTests.cs new file mode 100644 index 0000000..af1da7c --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiAvatarTests.cs @@ -0,0 +1,158 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.AvatarFactory; +using OpenSim.Region.OptionalModules.World.NPC; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; +using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests relating directly to avatars + /// + [TestFixture] + public class LSL_ApiAvatarTests : OpenSimTestCase + { + protected Scene m_scene; + protected XEngine.XEngine m_engine; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource initConfigSource = new IniConfigSource(); + IConfig config = initConfigSource.AddConfig("XEngine"); + config.Set("Enabled", "true"); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, initConfigSource); + + m_engine = new XEngine.XEngine(); + m_engine.Initialise(initConfigSource); + m_engine.AddRegion(m_scene); + } + + /// + /// Test llSetLinkPrimtiveParams for agents. + /// + /// + /// Also testing entity updates here as well. Possibly that's putting 2 different concerns into one test and + /// this should be separated. + /// + [Test] + public void TestllSetLinkPrimitiveParamsForAgent() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; + part.RotationOffset = new Quaternion(0.7071068f, 0, 0, 0.7071068f); + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, part, null); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + + // sp has to be less than 10 meters away from 0, 0, 0 (default part position) + Vector3 startPos = new Vector3(3, 2, 1); + sp.AbsolutePosition = startPos; + + sp.HandleAgentRequestSit(sp.ControllingClient, sp.UUID, part.UUID, Vector3.Zero); + + int entityUpdates = 0; + ((TestClient)sp.ControllingClient).OnReceivedEntityUpdate += (entity, flags) => { if (entity is ScenePresence) { entityUpdates++; }}; + + // Test position + { + Vector3 newPos = new Vector3(1, 2, 3); + apiGrp1.llSetLinkPrimitiveParams(2, new LSL_Types.list(ScriptBaseClass.PRIM_POSITION, newPos)); + + Assert.That(sp.OffsetPosition, Is.EqualTo(newPos)); + + m_scene.Update(1); + Assert.That(entityUpdates, Is.EqualTo(1)); + } + + // Test small reposition + { + Vector3 newPos = new Vector3(1.001f, 2, 3); + apiGrp1.llSetLinkPrimitiveParams(2, new LSL_Types.list(ScriptBaseClass.PRIM_POSITION, newPos)); + + Assert.That(sp.OffsetPosition, Is.EqualTo(newPos)); + + m_scene.Update(1); + Assert.That(entityUpdates, Is.EqualTo(2)); + } + + // Test world rotation + { + Quaternion newRot = new Quaternion(0, 0.7071068f, 0, 0.7071068f); + apiGrp1.llSetLinkPrimitiveParams(2, new LSL_Types.list(ScriptBaseClass.PRIM_ROTATION, newRot)); + + Assert.That( + sp.Rotation, new QuaternionToleranceConstraint(part.GetWorldRotation() * newRot, 0.000001)); + + m_scene.Update(1); + Assert.That(entityUpdates, Is.EqualTo(3)); + } + + // Test local rotation + { + Quaternion newRot = new Quaternion(0, 0.7071068f, 0, 0.7071068f); + apiGrp1.llSetLinkPrimitiveParams(2, new LSL_Types.list(ScriptBaseClass.PRIM_ROT_LOCAL, newRot)); + + Assert.That( + sp.Rotation, new QuaternionToleranceConstraint(newRot, 0.000001)); + + m_scene.Update(1); + Assert.That(entityUpdates, Is.EqualTo(4)); + } + } + } +} 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..9a5ebce --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs @@ -0,0 +1,248 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.CoreModules.Scripting.LSLHttp; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for HTTP related functions in LSL + /// + [TestFixture] + public class LSL_ApiHttpTests : OpenSimTestCase + { + private Scene m_scene; + private MockScriptEngine m_engine; + private UrlModule m_urlModule; + + private TaskInventoryItem m_scriptItem; + private LSL_Api m_lslApi; + + [TestFixtureSetUp] + public void TestFixtureSetUp() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [TestFixtureTearDown] + public void TestFixureTearDown() + { + // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple + // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression + // tests really shouldn't). + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + // This is an unfortunate bit of clean up we have to do because MainServer manages things through static + // variables and the VM is not restarted between tests. + uint port = 9999; + MainServer.RemoveHttpServer(port); + + BaseHttpServer server = new BaseHttpServer(port, false, 0, ""); + MainServer.AddHttpServer(server); + MainServer.Instance = server; + + server.Start(); + + m_engine = new MockScriptEngine(); + m_urlModule = new UrlModule(); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, new IniConfigSource(), m_engine, m_urlModule); + + SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); + m_scriptItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, so.RootPart); + + // This is disconnected from the actual script - the mock engine does not set up any LSL_Api atm. + // Possibly this could be done and we could obtain it directly from the MockScriptEngine. + m_lslApi = new LSL_Api(); + m_lslApi.Initialize(m_engine, so.RootPart, m_scriptItem); + } + + [TearDown] + public void TearDown() + { + MainServer.Instance.Stop(); + } + + [Test] + public void TestLlReleaseUrl() + { + TestHelpers.InMethod(); + + m_lslApi.llRequestURL(); + string returnedUri = m_engine.PostedEvents[m_scriptItem.ItemID][0].Params[2].ToString(); + + { + // Check that the initial number of URLs is correct + Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); + } + + { + // Check releasing a non-url + m_lslApi.llReleaseURL("GARBAGE"); + Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); + } + + { + // Check releasing a non-existing url + m_lslApi.llReleaseURL("http://example.com"); + Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); + } + + { + // Check URL release + m_lslApi.llReleaseURL(returnedUri); + Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls)); + + HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri); + + bool gotExpectedException = false; + + try + { + using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) + {} + } + catch (WebException e) + { + using (HttpWebResponse response = (HttpWebResponse)e.Response) + gotExpectedException = response.StatusCode == HttpStatusCode.NotFound; + } + + Assert.That(gotExpectedException, Is.True); + } + + { + // Check releasing the same URL again + m_lslApi.llReleaseURL(returnedUri); + Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls)); + } + } + + [Test] + public void TestLlRequestUrl() + { + TestHelpers.InMethod(); + + string requestId = m_lslApi.llRequestURL(); + Assert.That(requestId, Is.Not.EqualTo(UUID.Zero.ToString())); + string returnedUri; + + { + // Check that URL is correctly set up + Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); + + Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); + + List events = m_engine.PostedEvents[m_scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + Assert.That(eventParams.EventName, Is.EqualTo("http_request")); + + UUID returnKey; + string rawReturnKey = eventParams.Params[0].ToString(); + string method = eventParams.Params[1].ToString(); + returnedUri = eventParams.Params[2].ToString(); + + Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True); + Assert.That(method, Is.EqualTo(ScriptBaseClass.URL_REQUEST_GRANTED)); + Assert.That(Uri.IsWellFormedUriString(returnedUri, UriKind.Absolute), Is.True); + } + + { + // Check that request to URL works. + string testResponse = "Hello World"; + + m_engine.ClearPostedEvents(); + m_engine.PostEventHook + += (itemId, evp) => m_lslApi.llHTTPResponse(evp.Params[0].ToString(), 200, testResponse); + +// Console.WriteLine("Trying {0}", returnedUri); + + AssertHttpResponse(returnedUri, testResponse); + + Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); + + List events = m_engine.PostedEvents[m_scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + Assert.That(eventParams.EventName, Is.EqualTo("http_request")); + + UUID returnKey; + string rawReturnKey = eventParams.Params[0].ToString(); + string method = eventParams.Params[1].ToString(); + string body = eventParams.Params[2].ToString(); + + Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True); + Assert.That(method, Is.EqualTo("GET")); + Assert.That(body, Is.EqualTo("")); + } + } + + private void AssertHttpResponse(string uri, string expectedResponse) + { + HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); + + using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) + { + using (Stream stream = webResponse.GetResponseStream()) + { + using (StreamReader reader = new StreamReader(stream)) + { + Assert.That(reader.ReadToEnd(), Is.EqualTo(expectedResponse)); + } + } + } + } + } +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs index cb7291a..9b7cab2 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs @@ -41,9 +41,10 @@ using OpenSim.Region.OptionalModules.World.NPC; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; +using PermissionMask = OpenSim.Framework.PermissionMask; namespace OpenSim.Region.ScriptEngine.Shared.Tests { @@ -90,7 +91,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests // Create an object embedded inside the first UUID itemId = TestHelpers.ParseTail(0x20); - TaskInventoryHelpers.AddSceneObject(m_scene, so1.RootPart, inventoryItemName, itemId, userId); + TaskInventoryHelpers.AddSceneObject(m_scene.AssetService, so1.RootPart, inventoryItemName, itemId, userId); LSL_Api api = new LSL_Api(); api.Initialize(m_engine, so1.RootPart, null); @@ -130,7 +131,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests // Create an object embedded inside the first UUID itemId = TestHelpers.ParseTail(0x20); - TaskInventoryHelpers.AddSceneObject(m_scene, so1.RootPart, inventoryItemName, itemId, user1Id); + TaskInventoryHelpers.AddSceneObject(m_scene.AssetService, so1.RootPart, inventoryItemName, itemId, user1Id); // Create a second object SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, user2Id, "so2", 0x100); @@ -166,5 +167,122 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests Assert.That(copiedItems[0].Name, Is.EqualTo(inventoryItemName)); } } + + /// + /// Test giving inventory from an object to an avatar that is not the object's owner. + /// + [Test] + public void TestLlGiveInventoryO2DifferentAvatar() + { + TestHelpers.InMethod(); + // TestHelpers.EnableLogging(); + + UUID user1Id = TestHelpers.ParseTail(0x1); + UUID user2Id = TestHelpers.ParseTail(0x2); + string inventoryItemName = "item1"; + + SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, user1Id, "so1", 0x10); + m_scene.AddSceneObject(so1); + LSL_Api api = new LSL_Api(); + api.Initialize(m_engine, so1.RootPart, null); + + // Create an object embedded inside the first + UUID itemId = TestHelpers.ParseTail(0x20); + TaskInventoryHelpers.AddSceneObject(m_scene.AssetService, so1.RootPart, inventoryItemName, itemId, user1Id); + + UserAccountHelpers.CreateUserWithInventory(m_scene, user2Id); + + api.llGiveInventory(user2Id.ToString(), inventoryItemName); + + InventoryItemBase receivedItem + = UserInventoryHelpers.GetInventoryItem( + m_scene.InventoryService, user2Id, string.Format("Objects/{0}", inventoryItemName)); + + Assert.IsNotNull(receivedItem); + } + + /// + /// Test giving inventory from an object to an avatar that is not the object's owner and where the next + /// permissions do not include mod. + /// + [Test] + public void TestLlGiveInventoryO2DifferentAvatarNoMod() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID user1Id = TestHelpers.ParseTail(0x1); + UUID user2Id = TestHelpers.ParseTail(0x2); + string inventoryItemName = "item1"; + + SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, user1Id, "so1", 0x10); + m_scene.AddSceneObject(so1); + LSL_Api api = new LSL_Api(); + api.Initialize(m_engine, so1.RootPart, null); + + // Create an object embedded inside the first + UUID itemId = TestHelpers.ParseTail(0x20); + TaskInventoryItem tii + = TaskInventoryHelpers.AddSceneObject(m_scene.AssetService, so1.RootPart, inventoryItemName, itemId, user1Id); + tii.NextPermissions &= ~((uint)PermissionMask.Modify); + + UserAccountHelpers.CreateUserWithInventory(m_scene, user2Id); + + api.llGiveInventory(user2Id.ToString(), inventoryItemName); + + InventoryItemBase receivedItem + = UserInventoryHelpers.GetInventoryItem( + m_scene.InventoryService, user2Id, string.Format("Objects/{0}", inventoryItemName)); + + Assert.IsNotNull(receivedItem); + Assert.AreEqual(0, receivedItem.CurrentPermissions & (uint)PermissionMask.Modify); + } + + [Test] + public void TestLlRemoteLoadScriptPin() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID user1Id = TestHelpers.ParseTail(0x1); + UUID user2Id = TestHelpers.ParseTail(0x2); + + SceneObjectGroup sourceSo = SceneHelpers.AddSceneObject(m_scene, "sourceSo", user1Id); + m_scene.AddSceneObject(sourceSo); + LSL_Api api = new LSL_Api(); + api.Initialize(m_engine, sourceSo.RootPart, null); + TaskInventoryHelpers.AddScript(m_scene.AssetService, sourceSo.RootPart, "script", "Hello World"); + + SceneObjectGroup targetSo = SceneHelpers.AddSceneObject(m_scene, "targetSo", user1Id); + SceneObjectGroup otherOwnedTargetSo = SceneHelpers.AddSceneObject(m_scene, "otherOwnedTargetSo", user2Id); + + // Test that we cannot load a script when the target pin has never been set (i.e. it is zero) + api.llRemoteLoadScriptPin(targetSo.UUID.ToString(), "script", 0, 0, 0); + Assert.IsNull(targetSo.RootPart.Inventory.GetInventoryItem("script")); + + // Test that we cannot load a script when the given pin does not match the target + targetSo.RootPart.ScriptAccessPin = 5; + api.llRemoteLoadScriptPin(targetSo.UUID.ToString(), "script", 3, 0, 0); + Assert.IsNull(targetSo.RootPart.Inventory.GetInventoryItem("script")); + + // Test that we cannot load into a prim with a different owner + otherOwnedTargetSo.RootPart.ScriptAccessPin = 3; + api.llRemoteLoadScriptPin(otherOwnedTargetSo.UUID.ToString(), "script", 3, 0, 0); + Assert.IsNull(otherOwnedTargetSo.RootPart.Inventory.GetInventoryItem("script")); + + // Test that we can load a script when given pin and dest pin match. + targetSo.RootPart.ScriptAccessPin = 3; + api.llRemoteLoadScriptPin(targetSo.UUID.ToString(), "script", 3, 0, 0); + TaskInventoryItem insertedItem = targetSo.RootPart.Inventory.GetInventoryItem("script"); + Assert.IsNotNull(insertedItem); + + // Test that we can no longer load if access pin is unset + targetSo.RootPart.Inventory.RemoveInventoryItem(insertedItem.ItemID); + Assert.IsNull(targetSo.RootPart.Inventory.GetInventoryItem("script")); + + targetSo.RootPart.ScriptAccessPin = 0; + api.llRemoteLoadScriptPin(otherOwnedTargetSo.UUID.ToString(), "script", 3, 0, 0); + Assert.IsNull(otherOwnedTargetSo.RootPart.Inventory.GetInventoryItem("script")); + } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs index d9b17d7..14b1890 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs @@ -41,10 +41,10 @@ using OpenSim.Region.OptionalModules.World.NPC; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Region.ScriptEngine.Shared.Tests { @@ -92,7 +92,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests // FIXME: This should really be a script item (with accompanying script) TaskInventoryItem grp1Item = TaskInventoryHelpers.AddNotecard( - m_scene, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); + m_scene.AssetService, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; SceneObjectGroup grp2 = SceneHelpers.CreateSceneObject(2, ownerId, "grp2-", 0x20); @@ -126,7 +126,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests // FIXME: This should really be a script item (with accompanying script) TaskInventoryItem grp1Item = TaskInventoryHelpers.AddNotecard( - m_scene, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); + m_scene.AssetService, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; @@ -140,5 +140,47 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests SceneObjectGroup grp2 = m_scene.GetSceneObjectGroup("grp1-Part1"); Assert.That(grp2, Is.Not.Null); } + + [Test] + public void TestllBreakAllLinks() + { + TestHelpers.InMethod(); + + UUID ownerId = TestHelpers.ParseTail(0x1); + + SceneObjectGroup grp1 = SceneHelpers.CreateSceneObject(3, ownerId, "grp1-", 0x10); + grp1.AbsolutePosition = new Vector3(10, 10, 10); + m_scene.AddSceneObject(grp1); + + // FIXME: This should really be a script item (with accompanying script) + TaskInventoryItem grp1Item + = TaskInventoryHelpers.AddNotecard( + m_scene.AssetService, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); + + grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item); + + apiGrp1.llBreakAllLinks(); + + { + SceneObjectGroup nowGrp = m_scene.GetSceneObjectGroup("grp1-Part1"); + Assert.That(nowGrp, Is.Not.Null); + Assert.That(nowGrp.Parts.Length, Is.EqualTo(1)); + } + + { + SceneObjectGroup nowGrp = m_scene.GetSceneObjectGroup("grp1-Part2"); + Assert.That(nowGrp, Is.Not.Null); + Assert.That(nowGrp.Parts.Length, Is.EqualTo(1)); + } + + { + SceneObjectGroup nowGrp = m_scene.GetSceneObjectGroup("grp1-Part3"); + Assert.That(nowGrp, Is.Not.Null); + Assert.That(nowGrp.Parts.Length, Is.EqualTo(1)); + } + } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs index 98017d8..34a29e6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs @@ -34,9 +34,9 @@ using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.Framework.Scenes; using Nini.Config; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenMetaverse; -using OpenSim.Tests.Common.Mock; using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; @@ -133,4 +133,4 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests } } } - } \ No newline at end of file + } 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..9ab3115 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiNotecardTests.cs @@ -0,0 +1,269 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.CoreModules.Scripting.LSLHttp; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for notecard related functions in LSL + /// + [TestFixture] + public class LSL_ApiNotecardTests : OpenSimTestCase + { + private Scene m_scene; + private MockScriptEngine m_engine; + + private SceneObjectGroup m_so; + private TaskInventoryItem m_scriptItem; + private LSL_Api m_lslApi; + + [TestFixtureSetUp] + public void TestFixtureSetUp() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [TestFixtureTearDown] + public void TestFixureTearDown() + { + // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple + // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression + // tests really shouldn't). + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + m_engine = new MockScriptEngine(); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, new IniConfigSource(), m_engine); + + m_so = SceneHelpers.AddSceneObject(m_scene); + m_scriptItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, m_so.RootPart); + + // This is disconnected from the actual script - the mock engine does not set up any LSL_Api atm. + // Possibly this could be done and we could obtain it directly from the MockScriptEngine. + m_lslApi = new LSL_Api(); + m_lslApi.Initialize(m_engine, m_so.RootPart, m_scriptItem); + } + + [Test] + public void TestLlGetNotecardLine() + { + TestHelpers.InMethod(); + + string[] ncLines = { "One", "Twoè", "Three" }; + + TaskInventoryItem ncItem + = TaskInventoryHelpers.AddNotecard(m_scene.AssetService, m_so.RootPart, "nc", "1", "10", string.Join("\n", ncLines)); + + AssertValidNotecardLine(ncItem.Name, 0, ncLines[0]); + AssertValidNotecardLine(ncItem.Name, 2, ncLines[2]); + AssertValidNotecardLine(ncItem.Name, 3, ScriptBaseClass.EOF); + AssertValidNotecardLine(ncItem.Name, 4, ScriptBaseClass.EOF); + + // XXX: Is this correct or do we really expect no dataserver event to fire at all? + AssertValidNotecardLine(ncItem.Name, -1, ""); + AssertValidNotecardLine(ncItem.Name, -2, ""); + } + + [Test] + public void TestLlGetNotecardLine_NoNotecard() + { + TestHelpers.InMethod(); + + AssertInValidNotecardLine("nc", 0); + } + + [Test] + public void TestLlGetNotecardLine_NotANotecard() + { + TestHelpers.InMethod(); + + TaskInventoryItem ncItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, m_so.RootPart, "nc1", "Not important"); + + AssertInValidNotecardLine(ncItem.Name, 0); + } + + private void AssertValidNotecardLine(string ncName, int lineNumber, string assertLine) + { + string key = m_lslApi.llGetNotecardLine(ncName, lineNumber); + Assert.That(key, Is.Not.EqualTo(UUID.Zero.ToString())); + + Assert.That(m_engine.PostedEvents.Count, Is.EqualTo(1)); + Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); + + List events = m_engine.PostedEvents[m_scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + + Assert.That(eventParams.EventName, Is.EqualTo("dataserver")); + Assert.That(eventParams.Params[0].ToString(), Is.EqualTo(key)); + Assert.That(eventParams.Params[1].ToString(), Is.EqualTo(assertLine)); + + m_engine.ClearPostedEvents(); + } + + private void AssertInValidNotecardLine(string ncName, int lineNumber) + { + string key = m_lslApi.llGetNotecardLine(ncName, lineNumber); + Assert.That(key, Is.EqualTo(UUID.Zero.ToString())); + + Assert.That(m_engine.PostedEvents.Count, Is.EqualTo(0)); + } + +// [Test] +// public void TestLlReleaseUrl() +// { +// TestHelpers.InMethod(); +// +// m_lslApi.llRequestURL(); +// string returnedUri = m_engine.PostedEvents[m_scriptItem.ItemID][0].Params[2].ToString(); +// +// { +// // Check that the initial number of URLs is correct +// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); +// } +// +// { +// // Check releasing a non-url +// m_lslApi.llReleaseURL("GARBAGE"); +// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); +// } +// +// { +// // Check releasing a non-existing url +// m_lslApi.llReleaseURL("http://example.com"); +// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); +// } +// +// { +// // Check URL release +// m_lslApi.llReleaseURL(returnedUri); +// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls)); +// +// HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri); +// +// bool gotExpectedException = false; +// +// try +// { +// using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) +// {} +// } +// catch (WebException e) +// { +// using (HttpWebResponse response = (HttpWebResponse)e.Response) +// gotExpectedException = response.StatusCode == HttpStatusCode.NotFound; +// } +// +// Assert.That(gotExpectedException, Is.True); +// } +// +// { +// // Check releasing the same URL again +// m_lslApi.llReleaseURL(returnedUri); +// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls)); +// } +// } +// +// [Test] +// public void TestLlRequestUrl() +// { +// TestHelpers.InMethod(); +// +// string requestId = m_lslApi.llRequestURL(); +// Assert.That(requestId, Is.Not.EqualTo(UUID.Zero.ToString())); +// string returnedUri; +// +// { +// // Check that URL is correctly set up +// Assert.That(m_lslApi.llGetFreeURLs().value, Is.EqualTo(m_urlModule.TotalUrls - 1)); +// +// Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); +// +// List events = m_engine.PostedEvents[m_scriptItem.ItemID]; +// Assert.That(events.Count, Is.EqualTo(1)); +// EventParams eventParams = events[0]; +// Assert.That(eventParams.EventName, Is.EqualTo("http_request")); +// +// UUID returnKey; +// string rawReturnKey = eventParams.Params[0].ToString(); +// string method = eventParams.Params[1].ToString(); +// returnedUri = eventParams.Params[2].ToString(); +// +// Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True); +// Assert.That(method, Is.EqualTo(ScriptBaseClass.URL_REQUEST_GRANTED)); +// Assert.That(Uri.IsWellFormedUriString(returnedUri, UriKind.Absolute), Is.True); +// } +// +// { +// // Check that request to URL works. +// string testResponse = "Hello World"; +// +// m_engine.ClearPostedEvents(); +// m_engine.PostEventHook +// += (itemId, evp) => m_lslApi.llHTTPResponse(evp.Params[0].ToString(), 200, testResponse); +// +//// Console.WriteLine("Trying {0}", returnedUri); +// HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri); +// +// AssertHttpResponse(returnedUri, testResponse); +// +// Assert.That(m_engine.PostedEvents.ContainsKey(m_scriptItem.ItemID)); +// +// List events = m_engine.PostedEvents[m_scriptItem.ItemID]; +// Assert.That(events.Count, Is.EqualTo(1)); +// EventParams eventParams = events[0]; +// Assert.That(eventParams.EventName, Is.EqualTo("http_request")); +// +// UUID returnKey; +// string rawReturnKey = eventParams.Params[0].ToString(); +// string method = eventParams.Params[1].ToString(); +// string body = eventParams.Params[2].ToString(); +// +// Assert.That(UUID.TryParse(rawReturnKey, out returnKey), Is.True); +// Assert.That(method, Is.EqualTo("GET")); +// Assert.That(body, Is.EqualTo("")); +// } +// } +// +// private void AssertHttpResponse(string uri, string expectedResponse) +// { +// HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); +// +// using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) +// { +// using (Stream stream = webResponse.GetResponseStream()) +// { +// using (StreamReader reader = new StreamReader(stream)) +// { +// Assert.That(reader.ReadToEnd(), Is.EqualTo(expectedResponse)); +// } +// } +// } +// } + } +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiObjectTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiObjectTests.cs new file mode 100644 index 0000000..d957bf2 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiObjectTests.cs @@ -0,0 +1,398 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.AvatarFactory; +using OpenSim.Region.OptionalModules.World.NPC; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; +using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + [TestFixture] + public class LSL_ApiObjectTests : OpenSimTestCase + { + private const double VECTOR_COMPONENT_ACCURACY = 0.0000005d; + private const float FLOAT_ACCURACY = 0.00005f; + + protected Scene m_scene; + protected XEngine.XEngine m_engine; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource initConfigSource = new IniConfigSource(); + IConfig config = initConfigSource.AddConfig("XEngine"); + config.Set("Enabled", "true"); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, initConfigSource); + + m_engine = new XEngine.XEngine(); + m_engine.Initialise(initConfigSource); + m_engine.AddRegion(m_scene); + } + + [Test] + public void TestllGetLinkPrimitiveParams() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + UUID ownerId = TestHelpers.ParseTail(0x1); + + SceneObjectGroup grp1 = SceneHelpers.CreateSceneObject(2, ownerId, "grp1-", 0x10); + grp1.AbsolutePosition = new Vector3(10, 11, 12); + m_scene.AddSceneObject(grp1); + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, grp1.RootPart, null); + + // Check simple 1 prim case + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams(1, new LSL_List(new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(1)); + } + + // Check 2 prim case + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams( + 1, + new LSL_List( + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION), + new LSL_Integer(ScriptBaseClass.PRIM_LINK_TARGET), + new LSL_Integer(2), + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(2)); + } + + // Check invalid parameters are ignored + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams(3, new LSL_List(new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(0)); + } + + // Check all parameters are ignored if an initial bad link is given + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams( + 3, + new LSL_List( + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION), + new LSL_Integer(ScriptBaseClass.PRIM_LINK_TARGET), + new LSL_Integer(1), + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(0)); + } + + // Check only subsequent parameters are ignored when we hit the first bad link number + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams( + 1, + new LSL_List( + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION), + new LSL_Integer(ScriptBaseClass.PRIM_LINK_TARGET), + new LSL_Integer(3), + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(1)); + } + } + + [Test] + // llSetPrimitiveParams and llGetPrimitiveParams test. + public void TestllSetPrimitiveParams() + { + TestHelpers.InMethod(); + + // Create Prim1. + Scene scene = new SceneHelpers().SetupScene(); + string obj1Name = "Prim1"; + UUID objUuid = new UUID("00000000-0000-0000-0000-000000000001"); + SceneObjectPart part1 = + new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, + Vector3.Zero, Quaternion.Identity, + Vector3.Zero) { Name = obj1Name, UUID = objUuid }; + Assert.That(scene.AddNewSceneObject(new SceneObjectGroup(part1), false), Is.True); + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, part1, null); + + // Note that prim hollow check is passed with the other prim params in order to allow the + // specification of a different check value from the prim param. A cylinder, prism, sphere, + // torus or ring, with a hole shape of square, is limited to a hollow of 70%. Test 5 below + // specifies a value of 95% and checks to see if 70% was properly returned. + + // Test a sphere. + CheckllSetPrimitiveParams( + apiGrp1, + "test 1", // Prim test identification string + new LSL_Types.Vector3(6.0d, 9.9d, 9.9d), // Prim size + ScriptBaseClass.PRIM_TYPE_SPHERE, // Prim type + ScriptBaseClass.PRIM_HOLE_DEFAULT, // Prim hole type + new LSL_Types.Vector3(0.0d, 0.075d, 0.0d), // Prim cut + 0.80f, // Prim hollow + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist + new LSL_Types.Vector3(0.32d, 0.76d, 0.0d), // Prim dimple + 0.80f); // Prim hollow check + + // Test a prism. + CheckllSetPrimitiveParams( + apiGrp1, + "test 2", // Prim test identification string + new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size + ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type + ScriptBaseClass.PRIM_HOLE_CIRCLE, // Prim hole type + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut + 0.90f, // Prim hollow + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist + new LSL_Types.Vector3(2.0d, 1.0d, 0.0d), // Prim taper + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear + 0.90f); // Prim hollow check + + // Test a box. + CheckllSetPrimitiveParams( + apiGrp1, + "test 3", // Prim test identification string + new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size + ScriptBaseClass.PRIM_TYPE_BOX, // Prim type + ScriptBaseClass.PRIM_HOLE_TRIANGLE, // Prim hole type + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut + 0.99f, // Prim hollow + new LSL_Types.Vector3(1.0d, 0.0d, 0.0d), // Prim twist + new LSL_Types.Vector3(1.0d, 1.0d, 0.0d), // Prim taper + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear + 0.99f); // Prim hollow check + + // Test a tube. + CheckllSetPrimitiveParams( + apiGrp1, + "test 4", // Prim test identification string + new LSL_Types.Vector3(4.2d, 4.2d, 4.2d), // Prim size + ScriptBaseClass.PRIM_TYPE_TUBE, // Prim type + ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut + 0.00f, // Prim hollow + new LSL_Types.Vector3(1.0d, -1.0d, 0.0d), // Prim twist + new LSL_Types.Vector3(1.0d, 0.05d, 0.0d), // Prim hole size + // Expression for y selected to test precision problems during byte + // cast in SetPrimitiveShapeParams. + new LSL_Types.Vector3(0.0d, 0.35d + 0.1d, 0.0d), // Prim shear + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim profile cut + // Expression for y selected to test precision problems during sbyte + // cast in SetPrimitiveShapeParams. + new LSL_Types.Vector3(-1.0d, 0.70d + 0.1d + 0.1d, 0.0d), // Prim taper + 1.11f, // Prim revolutions + 0.88f, // Prim radius + 0.95f, // Prim skew + 0.00f); // Prim hollow check + + // Test a prism. + CheckllSetPrimitiveParams( + apiGrp1, + "test 5", // Prim test identification string + new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size + ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type + ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut + 0.99f, // Prim hollow + // Expression for x selected to test precision problems during sbyte + // cast in SetPrimitiveShapeBlockParams. + new LSL_Types.Vector3(0.7d + 0.2d, 0.0d, 0.0d), // Prim twist + // Expression for y selected to test precision problems during sbyte + // cast in SetPrimitiveShapeParams. + new LSL_Types.Vector3(2.0d, (1.3d + 0.1d), 0.0d), // Prim taper + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear + 0.70f); // Prim hollow check + + // Test a sculpted prim. + CheckllSetPrimitiveParams( + apiGrp1, + "test 6", // Prim test identification string + new LSL_Types.Vector3(2.0d, 2.0d, 2.0d), // Prim size + ScriptBaseClass.PRIM_TYPE_SCULPT, // Prim type + "be293869-d0d9-0a69-5989-ad27f1946fd4", // Prim map + ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE); // Prim sculpt type + } + + // Set prim params for a box, cylinder or prism and check results. + public void CheckllSetPrimitiveParams(LSL_Api api, string primTest, + LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, + float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primTaper, LSL_Types.Vector3 primShear, + float primHollowCheck) + { + // Set the prim params. + api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, + ScriptBaseClass.PRIM_TYPE, primType, primHoleType, + primCut, primHollow, primTwist, primTaper, primShear)); + + // Get params for prim to validate settings. + LSL_Types.list primParams = + api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); + + // Validate settings. + CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size"); + Assert.AreEqual(primType, api.llList2Integer(primParams, 1), + "TestllSetPrimitiveParams " + primTest + " prim type check fail"); + Assert.AreEqual(primHoleType, api.llList2Integer(primParams, 2), + "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); + CheckllSetPrimitiveParamsVector(primCut, api.llList2Vector(primParams, 3), primTest + " prim cut"); + Assert.AreEqual(primHollowCheck, api.llList2Float(primParams, 4), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); + CheckllSetPrimitiveParamsVector(primTwist, api.llList2Vector(primParams, 5), primTest + " prim twist"); + CheckllSetPrimitiveParamsVector(primTaper, api.llList2Vector(primParams, 6), primTest + " prim taper"); + CheckllSetPrimitiveParamsVector(primShear, api.llList2Vector(primParams, 7), primTest + " prim shear"); + } + + // Set prim params for a sphere and check results. + public void CheckllSetPrimitiveParams(LSL_Api api, string primTest, + LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, + float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primDimple, float primHollowCheck) + { + // Set the prim params. + api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, + ScriptBaseClass.PRIM_TYPE, primType, primHoleType, + primCut, primHollow, primTwist, primDimple)); + + // Get params for prim to validate settings. + LSL_Types.list primParams = + api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); + + // Validate settings. + CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size"); + Assert.AreEqual(primType, api.llList2Integer(primParams, 1), + "TestllSetPrimitiveParams " + primTest + " prim type check fail"); + Assert.AreEqual(primHoleType, api.llList2Integer(primParams, 2), + "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); + CheckllSetPrimitiveParamsVector(primCut, api.llList2Vector(primParams, 3), primTest + " prim cut"); + Assert.AreEqual(primHollowCheck, api.llList2Float(primParams, 4), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); + CheckllSetPrimitiveParamsVector(primTwist, api.llList2Vector(primParams, 5), primTest + " prim twist"); + CheckllSetPrimitiveParamsVector(primDimple, api.llList2Vector(primParams, 6), primTest + " prim dimple"); + } + + // Set prim params for a torus, tube or ring and check results. + public void CheckllSetPrimitiveParams(LSL_Api api, string primTest, + LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, + float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primHoleSize, + LSL_Types.Vector3 primShear, LSL_Types.Vector3 primProfCut, LSL_Types.Vector3 primTaper, + float primRev, float primRadius, float primSkew, float primHollowCheck) + { + // Set the prim params. + api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, + ScriptBaseClass.PRIM_TYPE, primType, primHoleType, + primCut, primHollow, primTwist, primHoleSize, primShear, primProfCut, + primTaper, primRev, primRadius, primSkew)); + + // Get params for prim to validate settings. + LSL_Types.list primParams = + api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); + + // Valdate settings. + CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size"); + Assert.AreEqual(primType, api.llList2Integer(primParams, 1), + "TestllSetPrimitiveParams " + primTest + " prim type check fail"); + Assert.AreEqual(primHoleType, api.llList2Integer(primParams, 2), + "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); + CheckllSetPrimitiveParamsVector(primCut, api.llList2Vector(primParams, 3), primTest + " prim cut"); + Assert.AreEqual(primHollowCheck, api.llList2Float(primParams, 4), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); + CheckllSetPrimitiveParamsVector(primTwist, api.llList2Vector(primParams, 5), primTest + " prim twist"); + CheckllSetPrimitiveParamsVector(primHoleSize, api.llList2Vector(primParams, 6), primTest + " prim hole size"); + CheckllSetPrimitiveParamsVector(primShear, api.llList2Vector(primParams, 7), primTest + " prim shear"); + CheckllSetPrimitiveParamsVector(primProfCut, api.llList2Vector(primParams, 8), primTest + " prim profile cut"); + CheckllSetPrimitiveParamsVector(primTaper, api.llList2Vector(primParams, 9), primTest + " prim taper"); + Assert.AreEqual(primRev, api.llList2Float(primParams, 10), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim revolutions fail"); + Assert.AreEqual(primRadius, api.llList2Float(primParams, 11), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim radius fail"); + Assert.AreEqual(primSkew, api.llList2Float(primParams, 12), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim skew fail"); + } + + // Set prim params for a sculpted prim and check results. + public void CheckllSetPrimitiveParams(LSL_Api api, string primTest, + LSL_Types.Vector3 primSize, int primType, string primMap, int primSculptType) + { + // Set the prim params. + api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, + ScriptBaseClass.PRIM_TYPE, primType, primMap, primSculptType)); + + // Get params for prim to validate settings. + LSL_Types.list primParams = + api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); + + // Validate settings. + CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size"); + Assert.AreEqual(primType, api.llList2Integer(primParams, 1), + "TestllSetPrimitiveParams " + primTest + " prim type check fail"); + Assert.AreEqual(primMap, (string)api.llList2String(primParams, 2), + "TestllSetPrimitiveParams " + primTest + " prim map check fail"); + Assert.AreEqual(primSculptType, api.llList2Integer(primParams, 3), + "TestllSetPrimitiveParams " + primTest + " prim type scuplt check fail"); + } + + public void CheckllSetPrimitiveParamsVector(LSL_Types.Vector3 vecCheck, LSL_Types.Vector3 vecReturned, string msg) + { + // Check each vector component against expected result. + Assert.AreEqual(vecCheck.x, vecReturned.x, VECTOR_COMPONENT_ACCURACY, + "TestllSetPrimitiveParams " + msg + " vector check fail on x component"); + Assert.AreEqual(vecCheck.y, vecReturned.y, VECTOR_COMPONENT_ACCURACY, + "TestllSetPrimitiveParams " + msg + " vector check fail on y component"); + Assert.AreEqual(vecCheck.z, vecReturned.z, VECTOR_COMPONENT_ACCURACY, + "TestllSetPrimitiveParams " + msg + " vector check fail on z component"); + } + + } +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs index c41d1e7..d929da8 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs @@ -33,10 +33,10 @@ using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.Framework.Scenes; using Nini.Config; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenMetaverse; using System; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Region.ScriptEngine.Shared.Tests { @@ -46,9 +46,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests [TestFixture, LongRunning] public class LSL_ApiTest { - private const double ANGLE_ACCURACY_IN_RADIANS = 1E-6; private const double VECTOR_COMPONENT_ACCURACY = 0.0000005d; - private const float FLOAT_ACCURACY = 0.00005f; + private const double ANGLE_ACCURACY_IN_RADIANS = 1E-6; private LSL_Api m_lslApi; [SetUp] @@ -254,241 +253,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests } [Test] - // llSetPrimitiveParams and llGetPrimitiveParams test. - public void TestllSetPrimitiveParams() - { - TestHelpers.InMethod(); - - // Create Prim1. - Scene scene = new SceneHelpers().SetupScene(); - string obj1Name = "Prim1"; - UUID objUuid = new UUID("00000000-0000-0000-0000-000000000001"); - SceneObjectPart part1 = - new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, - Vector3.Zero, Quaternion.Identity, - Vector3.Zero) { Name = obj1Name, UUID = objUuid }; - Assert.That(scene.AddNewSceneObject(new SceneObjectGroup(part1), false), Is.True); - - // Note that prim hollow check is passed with the other prim params in order to allow the - // specification of a different check value from the prim param. A cylinder, prism, sphere, - // torus or ring, with a hole shape of square, is limited to a hollow of 70%. Test 5 below - // specifies a value of 95% and checks to see if 70% was properly returned. - - // Test a sphere. - CheckllSetPrimitiveParams( - "test 1", // Prim test identification string - new LSL_Types.Vector3(6.0d, 9.9d, 9.9d), // Prim size - ScriptBaseClass.PRIM_TYPE_SPHERE, // Prim type - ScriptBaseClass.PRIM_HOLE_DEFAULT, // Prim hole type - new LSL_Types.Vector3(0.0d, 0.075d, 0.0d), // Prim cut - 0.80f, // Prim hollow - new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist - new LSL_Types.Vector3(0.32d, 0.76d, 0.0d), // Prim dimple - 0.80f); // Prim hollow check - - // Test a prism. - CheckllSetPrimitiveParams( - "test 2", // Prim test identification string - new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size - ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type - ScriptBaseClass.PRIM_HOLE_CIRCLE, // Prim hole type - new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut - 0.90f, // Prim hollow - new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist - new LSL_Types.Vector3(2.0d, 1.0d, 0.0d), // Prim taper - new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear - 0.90f); // Prim hollow check - - // Test a box. - CheckllSetPrimitiveParams( - "test 3", // Prim test identification string - new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size - ScriptBaseClass.PRIM_TYPE_BOX, // Prim type - ScriptBaseClass.PRIM_HOLE_TRIANGLE, // Prim hole type - new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut - 0.95f, // Prim hollow - new LSL_Types.Vector3(1.0d, 0.0d, 0.0d), // Prim twist - new LSL_Types.Vector3(1.0d, 1.0d, 0.0d), // Prim taper - new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear - 0.95f); // Prim hollow check - - // Test a tube. - CheckllSetPrimitiveParams( - "test 4", // Prim test identification string - new LSL_Types.Vector3(4.2d, 4.2d, 4.2d), // Prim size - ScriptBaseClass.PRIM_TYPE_TUBE, // Prim type - ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type - new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut - 0.00f, // Prim hollow - new LSL_Types.Vector3(1.0d, -1.0d, 0.0d), // Prim twist - new LSL_Types.Vector3(1.0d, 0.05d, 0.0d), // Prim hole size - // Expression for y selected to test precision problems during byte - // cast in SetPrimitiveShapeParams. - new LSL_Types.Vector3(0.0d, 0.35d + 0.1d, 0.0d), // Prim shear - new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim profile cut - // Expression for y selected to test precision problems during sbyte - // cast in SetPrimitiveShapeParams. - new LSL_Types.Vector3(-1.0d, 0.70d + 0.1d + 0.1d, 0.0d), // Prim taper - 1.11f, // Prim revolutions - 0.88f, // Prim radius - 0.95f, // Prim skew - 0.00f); // Prim hollow check - - // Test a prism. - CheckllSetPrimitiveParams( - "test 5", // Prim test identification string - new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size - ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type - ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type - new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut - 0.95f, // Prim hollow - // Expression for x selected to test precision problems during sbyte - // cast in SetPrimitiveShapeBlockParams. - new LSL_Types.Vector3(0.7d + 0.2d, 0.0d, 0.0d), // Prim twist - // Expression for y selected to test precision problems during sbyte - // cast in SetPrimitiveShapeParams. - new LSL_Types.Vector3(2.0d, (1.3d + 0.1d), 0.0d), // Prim taper - new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear - 0.70f); // Prim hollow check - - // Test a sculpted prim. - CheckllSetPrimitiveParams( - "test 6", // Prim test identification string - new LSL_Types.Vector3(2.0d, 2.0d, 2.0d), // Prim size - ScriptBaseClass.PRIM_TYPE_SCULPT, // Prim type - "be293869-d0d9-0a69-5989-ad27f1946fd4", // Prim map - ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE); // Prim sculpt type - } - - // Set prim params for a box, cylinder or prism and check results. - public void CheckllSetPrimitiveParams(string primTest, - LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, - float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primTaper, LSL_Types.Vector3 primShear, - float primHollowCheck) - { - // Set the prim params. - m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, - ScriptBaseClass.PRIM_TYPE, primType, primHoleType, - primCut, primHollow, primTwist, primTaper, primShear)); - - // Get params for prim to validate settings. - LSL_Types.list primParams = - m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); - - // Validate settings. - CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size"); - Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1), - "TestllSetPrimitiveParams " + primTest + " prim type check fail"); - Assert.AreEqual(primHoleType, m_lslApi.llList2Integer(primParams, 2), - "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); - CheckllSetPrimitiveParamsVector(primCut, m_lslApi.llList2Vector(primParams, 3), primTest + " prim cut"); - Assert.AreEqual(primHollowCheck, m_lslApi.llList2Float(primParams, 4), FLOAT_ACCURACY, - "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); - CheckllSetPrimitiveParamsVector(primTwist, m_lslApi.llList2Vector(primParams, 5), primTest + " prim twist"); - CheckllSetPrimitiveParamsVector(primTaper, m_lslApi.llList2Vector(primParams, 6), primTest + " prim taper"); - CheckllSetPrimitiveParamsVector(primShear, m_lslApi.llList2Vector(primParams, 7), primTest + " prim shear"); - } - - // Set prim params for a sphere and check results. - public void CheckllSetPrimitiveParams(string primTest, - LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, - float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primDimple, float primHollowCheck) - { - // Set the prim params. - m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, - ScriptBaseClass.PRIM_TYPE, primType, primHoleType, - primCut, primHollow, primTwist, primDimple)); - - // Get params for prim to validate settings. - LSL_Types.list primParams = - m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); - - // Validate settings. - CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size"); - Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1), - "TestllSetPrimitiveParams " + primTest + " prim type check fail"); - Assert.AreEqual(primHoleType, m_lslApi.llList2Integer(primParams, 2), - "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); - CheckllSetPrimitiveParamsVector(primCut, m_lslApi.llList2Vector(primParams, 3), primTest + " prim cut"); - Assert.AreEqual(primHollowCheck, m_lslApi.llList2Float(primParams, 4), FLOAT_ACCURACY, - "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); - CheckllSetPrimitiveParamsVector(primTwist, m_lslApi.llList2Vector(primParams, 5), primTest + " prim twist"); - CheckllSetPrimitiveParamsVector(primDimple, m_lslApi.llList2Vector(primParams, 6), primTest + " prim dimple"); - } - - // Set prim params for a torus, tube or ring and check results. - public void CheckllSetPrimitiveParams(string primTest, - LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, - float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primHoleSize, - LSL_Types.Vector3 primShear, LSL_Types.Vector3 primProfCut, LSL_Types.Vector3 primTaper, - float primRev, float primRadius, float primSkew, float primHollowCheck) - { - // Set the prim params. - m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, - ScriptBaseClass.PRIM_TYPE, primType, primHoleType, - primCut, primHollow, primTwist, primHoleSize, primShear, primProfCut, - primTaper, primRev, primRadius, primSkew)); - - // Get params for prim to validate settings. - LSL_Types.list primParams = - m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); - - // Valdate settings. - CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size"); - Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1), - "TestllSetPrimitiveParams " + primTest + " prim type check fail"); - Assert.AreEqual(primHoleType, m_lslApi.llList2Integer(primParams, 2), - "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); - CheckllSetPrimitiveParamsVector(primCut, m_lslApi.llList2Vector(primParams, 3), primTest + " prim cut"); - Assert.AreEqual(primHollowCheck, m_lslApi.llList2Float(primParams, 4), FLOAT_ACCURACY, - "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); - CheckllSetPrimitiveParamsVector(primTwist, m_lslApi.llList2Vector(primParams, 5), primTest + " prim twist"); - CheckllSetPrimitiveParamsVector(primHoleSize, m_lslApi.llList2Vector(primParams, 6), primTest + " prim hole size"); - CheckllSetPrimitiveParamsVector(primShear, m_lslApi.llList2Vector(primParams, 7), primTest + " prim shear"); - CheckllSetPrimitiveParamsVector(primProfCut, m_lslApi.llList2Vector(primParams, 8), primTest + " prim profile cut"); - CheckllSetPrimitiveParamsVector(primTaper, m_lslApi.llList2Vector(primParams, 9), primTest + " prim taper"); - Assert.AreEqual(primRev, m_lslApi.llList2Float(primParams, 10), FLOAT_ACCURACY, - "TestllSetPrimitiveParams " + primTest + " prim revolutions fail"); - Assert.AreEqual(primRadius, m_lslApi.llList2Float(primParams, 11), FLOAT_ACCURACY, - "TestllSetPrimitiveParams " + primTest + " prim radius fail"); - Assert.AreEqual(primSkew, m_lslApi.llList2Float(primParams, 12), FLOAT_ACCURACY, - "TestllSetPrimitiveParams " + primTest + " prim skew fail"); - } - - // Set prim params for a sculpted prim and check results. - public void CheckllSetPrimitiveParams(string primTest, - LSL_Types.Vector3 primSize, int primType, string primMap, int primSculptType) - { - // Set the prim params. - m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, - ScriptBaseClass.PRIM_TYPE, primType, primMap, primSculptType)); - - // Get params for prim to validate settings. - LSL_Types.list primParams = - m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); - - // Validate settings. - CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size"); - Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1), - "TestllSetPrimitiveParams " + primTest + " prim type check fail"); - Assert.AreEqual(primMap, (string)m_lslApi.llList2String(primParams, 2), - "TestllSetPrimitiveParams " + primTest + " prim map check fail"); - Assert.AreEqual(primSculptType, m_lslApi.llList2Integer(primParams, 3), - "TestllSetPrimitiveParams " + primTest + " prim type scuplt check fail"); - } - - public void CheckllSetPrimitiveParamsVector(LSL_Types.Vector3 vecCheck, LSL_Types.Vector3 vecReturned, string msg) - { - // Check each vector component against expected result. - Assert.AreEqual(vecCheck.x, vecReturned.x, VECTOR_COMPONENT_ACCURACY, - "TestllSetPrimitiveParams " + msg + " vector check fail on x component"); - Assert.AreEqual(vecCheck.y, vecReturned.y, VECTOR_COMPONENT_ACCURACY, - "TestllSetPrimitiveParams " + msg + " vector check fail on y component"); - Assert.AreEqual(vecCheck.z, vecReturned.z, VECTOR_COMPONENT_ACCURACY, - "TestllSetPrimitiveParams " + msg + " vector check fail on z component"); - } - - [Test] public void TestllVecNorm() { TestHelpers.InMethod(); diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiUserTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiUserTests.cs new file mode 100644 index 0000000..a8964bf --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiUserTests.cs @@ -0,0 +1,157 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + [TestFixture] + public class LSL_ApiUserTests : OpenSimTestCase + { + private Scene m_scene; + private MockScriptEngine m_engine; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + m_engine = new MockScriptEngine(); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, m_engine); + } + + [Test] + public void TestLlRequestAgentDataOnline() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, userId); + + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; + TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, part); + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, part, scriptItem); + + // Initially long timeout to test cache + apiGrp1.LlRequestAgentDataCacheTimeoutMs = 20000; + + // Offline test + { + apiGrp1.llRequestAgentData(userId.ToString(), ScriptBaseClass.DATA_ONLINE); + + Assert.That(m_engine.PostedEvents.ContainsKey(scriptItem.ItemID)); + + List events = m_engine.PostedEvents[scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + Assert.That(eventParams.EventName, Is.EqualTo("dataserver")); + + string data = eventParams.Params[1].ToString(); + Assert.AreEqual(0, int.Parse(data)); + + m_engine.PostedEvents.Clear(); + } + + // Online test. Should get the 'wrong' result because of caching. + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, ua1); + + { + apiGrp1.llRequestAgentData(userId.ToString(), ScriptBaseClass.DATA_ONLINE); + + Assert.That(m_engine.PostedEvents.ContainsKey(scriptItem.ItemID)); + + List events = m_engine.PostedEvents[scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + Assert.That(eventParams.EventName, Is.EqualTo("dataserver")); + + string data = eventParams.Params[1].ToString(); + Assert.AreEqual(0, int.Parse(data)); + + m_engine.PostedEvents.Clear(); + } + + apiGrp1.LlRequestAgentDataCacheTimeoutMs = 1; + + // Make absolutely sure that we should trigger cache timeout. + Thread.Sleep(apiGrp1.LlRequestAgentDataCacheTimeoutMs + 1); + + { + apiGrp1.llRequestAgentData(userId.ToString(), ScriptBaseClass.DATA_ONLINE); + + Assert.That(m_engine.PostedEvents.ContainsKey(scriptItem.ItemID)); + + List events = m_engine.PostedEvents[scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + Assert.That(eventParams.EventName, Is.EqualTo("dataserver")); + + string data = eventParams.Params[1].ToString(); + Assert.AreEqual(1, int.Parse(data)); + + m_engine.PostedEvents.Clear(); + } + + m_scene.CloseAgent(userId, false); + + Thread.Sleep(apiGrp1.LlRequestAgentDataCacheTimeoutMs + 1 + 1); + + { + apiGrp1.llRequestAgentData(userId.ToString(), ScriptBaseClass.DATA_ONLINE); + + Assert.That(m_engine.PostedEvents.ContainsKey(scriptItem.ItemID)); + + List events = m_engine.PostedEvents[scriptItem.ItemID]; + Assert.That(events.Count, Is.EqualTo(1)); + EventParams eventParams = events[0]; + Assert.That(eventParams.EventName, Is.EqualTo("dataserver")); + + string data = eventParams.Params[1].ToString(); + Assert.AreEqual(0, int.Parse(data)); + + m_engine.PostedEvents.Clear(); + } + } + } +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs index 1381d2b..2f9a564 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs @@ -41,9 +41,9 @@ using OpenSim.Region.OptionalModules.World.NPC; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Region.ScriptEngine.Shared.Tests { @@ -158,4 +158,4 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests Assert.That(savedAppearance.AvatarHeight, Is.EqualTo(sp.Appearance.AvatarHeight)); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs index 5ed1f3d..b6b3f12 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs @@ -41,9 +41,9 @@ using OpenSim.Region.CoreModules.Framework.InventoryAccess; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Region.ScriptEngine.Shared.Tests { @@ -96,7 +96,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, 0x1); ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, ua1.PrincipalID); SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); - TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); + TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, inWorldObj.RootPart); new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); OSSL_Api osslApi = new OSSL_Api(); @@ -105,7 +105,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests // SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ua1.PrincipalID); // Create an object embedded inside the first - TaskInventoryHelpers.AddSceneObject(m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID); + TaskInventoryHelpers.AddSceneObject(m_scene.AssetService, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID); osslApi.osForceAttachToAvatarFromInventory(taskInvObjItemName, (int)attachPoint); @@ -142,7 +142,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, 0x1); ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, ua1.PrincipalID); SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); - TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); + TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, inWorldObj.RootPart); new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); OSSL_Api osslApi = new OSSL_Api(); @@ -150,7 +150,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests // Create an object embedded inside the first TaskInventoryHelpers.AddNotecard( - m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, TestHelpers.ParseTail(0x900)); + m_scene.AssetService, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, TestHelpers.ParseTail(0x900), "Hello World!"); bool exceptionCaught = false; @@ -190,14 +190,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, ua1); SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); - TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); + TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene.AssetService, inWorldObj.RootPart); new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); OSSL_Api osslApi = new OSSL_Api(); osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); // Create an object embedded inside the first - TaskInventoryHelpers.AddSceneObject(m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID); + TaskInventoryHelpers.AddSceneObject( + m_scene.AssetService, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID); ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, ua2); @@ -228,4 +229,4 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests Assert.That(sp2.Appearance.GetAttachpoint(attachmentsInAppearance2[0].ItemID), Is.EqualTo((uint)attachPoint)); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs index d6c82f1..99bff83 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs @@ -42,10 +42,10 @@ using OpenSim.Region.OptionalModules.World.NPC; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Region.ScriptEngine.Shared.Tests { @@ -179,6 +179,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests public void TestOsNpcLoadAppearance() { TestHelpers.InMethod(); + //TestHelpers.EnableLogging(); // Store an avatar with a different height from default in a notecard. UUID userId = TestHelpers.ParseTail(0x1); @@ -221,7 +222,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests // Store an avatar with a different height from default in a notecard. UUID userId = TestHelpers.ParseTail(0x1); float firstHeight = 1.9f; - float secondHeight = 2.1f; +// float secondHeight = 2.1f; string firstAppearanceNcName = "appearanceNc1"; string secondAppearanceNcName = "appearanceNc2"; @@ -347,4 +348,4 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests Assert.That(npc, Is.Null); } } -} \ No newline at end of file +} 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 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Lifetime; +using System.Security.Permissions; +using System.Threading; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; + +namespace OpenSim.Region.ScriptEngine.XEngine.ScriptBase +{ + public class XEngineScriptBase : ScriptBaseClass + { + /// + /// Used for script sleeps when we are using co-operative script termination. + /// + /// null if co-operative script termination is not active + WaitHandle m_coopSleepHandle; + + public XEngineScriptBase(WaitHandle coopSleepHandle) : base() + { + m_coopSleepHandle = coopSleepHandle; + } + + public void opensim_reserved_CheckForCoopTermination() + { + if (m_coopSleepHandle != null && m_coopSleepHandle.WaitOne(0)) + throw new ScriptCoopStopException(); + } + } +} \ 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 { myScriptEngine = _ScriptEngine; - m_log.Info("[XEngine] Hooking up to server events"); +// m_log.Info("[XEngine] Hooking up to server events"); myScriptEngine.World.EventManager.OnAttach += attach; myScriptEngine.World.EventManager.OnObjectGrab += touch_start; myScriptEngine.World.EventManager.OnObjectGrabbing += touch; @@ -62,6 +62,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine myScriptEngine.World.EventManager.OnScriptNotAtTargetEvent += not_at_target; myScriptEngine.World.EventManager.OnScriptAtRotTargetEvent += at_rot_target; myScriptEngine.World.EventManager.OnScriptNotAtRotTargetEvent += not_at_rot_target; + myScriptEngine.World.EventManager.OnScriptMovingStartEvent += moving_start; + myScriptEngine.World.EventManager.OnScriptMovingEndEvent += moving_end; myScriptEngine.World.EventManager.OnScriptControlEvent += control; myScriptEngine.World.EventManager.OnScriptColliderStart += collision_start; myScriptEngine.World.EventManager.OnScriptColliding += collision; @@ -69,7 +71,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine myScriptEngine.World.EventManager.OnScriptLandColliderStart += land_collision_start; myScriptEngine.World.EventManager.OnScriptLandColliding += land_collision; myScriptEngine.World.EventManager.OnScriptLandColliderEnd += land_collision_end; - IMoneyModule money=myScriptEngine.World.RequestModuleInterface(); + IMoneyModule money = myScriptEngine.World.RequestModuleInterface(); if (money != null) { money.OnObjectPaid+=HandleObjectPaid; @@ -419,14 +421,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine // dataserver: not handled here // link_message: not handled here - public void moving_start(uint localID, UUID itemID) + public void moving_start(uint localID) { myScriptEngine.PostObjectEvent(localID, new EventParams( "moving_start",new object[0], new DetectParams[0])); } - public void moving_end(uint localID, UUID itemID) + public void moving_end(uint localID) { myScriptEngine.PostObjectEvent(localID, new EventParams( "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..665929d 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs @@ -1,6 +1,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using Mono.Addins; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -29,5 +30,7 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + +[assembly: Addin("OpenSim.Region.ScriptEngine.XEngine", OpenSim.VersionInfo.VersionNumber)] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Region/ScriptEngine/XEngine/Resources/XEngine.addin.xml b/OpenSim/Region/ScriptEngine/XEngine/Resources/XEngine.addin.xml deleted file mode 100644 index 96c9c3a..0000000 --- a/OpenSim/Region/ScriptEngine/XEngine/Resources/XEngine.addin.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs new file mode 100644 index 0000000..878e571 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs @@ -0,0 +1,129 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Scripting.WorldComm; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.XEngine.Tests +{ + /// + /// Basic XEngine tests. + /// + [TestFixture] + public class XEngineBasicTests : OpenSimTestCase + { + private TestScene m_scene; + private XEngine m_xEngine; + private AutoResetEvent m_chatEvent = new AutoResetEvent(false); + private OSChatMessage m_osChatMessageReceived; + + [TestFixtureSetUp] + public void Init() + { + //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin"); +// Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); + m_xEngine = new XEngine(); + + IniConfigSource configSource = new IniConfigSource(); + + IConfig startupConfig = configSource.AddConfig("Startup"); + startupConfig.Set("DefaultScriptEngine", "XEngine"); + + IConfig xEngineConfig = configSource.AddConfig("XEngine"); + xEngineConfig.Set("Enabled", "true"); + xEngineConfig.Set("StartDelay", "0"); + + // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call + // to AssemblyResolver.OnAssemblyResolve fails. + xEngineConfig.Set("AppDomainLoading", "false"); + + m_scene = new SceneHelpers().SetupScene("My Test", UUID.Random(), 1000, 1000, configSource); + SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine); + m_scene.StartScripts(); + } + + /// + /// Test compilation and starting of a script. + /// + /// + /// This is a less than ideal regression test since it involves an asynchronous operation (in this case, + /// compilation of the script). + /// + [Test] + public void TestCompileAndStartScript() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); +// UUID objectId = TestHelpers.ParseTail(0x100); +// UUID itemId = TestHelpers.ParseTail(0x3); + string itemName = "TestStartScript() Item"; + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, "TestStartScriptPart_", 0x100); + m_scene.AddNewSceneObject(so, true); + + InventoryItemBase itemTemplate = new InventoryItemBase(); +// itemTemplate.ID = itemId; + itemTemplate.Name = itemName; + itemTemplate.Folder = so.UUID; + itemTemplate.InvType = (int)InventoryType.LSL; + + m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; + + SceneObjectPart partWhereRezzed = m_scene.RezNewScript(userId, itemTemplate); + + m_chatEvent.WaitOne(60000); + + Assert.That(m_osChatMessageReceived, Is.Not.Null, "No chat message received in TestStartScript()"); + Assert.That(m_osChatMessageReceived.Message, Is.EqualTo("Script running")); + + bool running; + TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); + Assert.That( + SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True); + Assert.That(running, Is.True); + } + + private void OnChatFromWorld(object sender, OSChatMessage oscm) + { +// Console.WriteLine("Got chat [{0}]", oscm.Message); + + m_osChatMessageReceived = oscm; + m_chatEvent.Set(); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineCrossingTests.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineCrossingTests.cs new file mode 100644 index 0000000..587695f --- /dev/null +++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineCrossingTests.cs @@ -0,0 +1,195 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.XEngine.Tests +{ + /// + /// XEngine tests connected with crossing scripts between regions. + /// + [TestFixture] + public class XEngineCrossingTests : OpenSimTestCase + { + [TestFixtureSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [TestFixtureTearDown] + public void TearDown() + { + // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple + // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression + // tests really shouldn't). + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + + /// + /// Test script state preservation when a script crosses between regions on the same simulator. + /// + [Test] + public void TestScriptCrossOnSameSimulator() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + int sceneObjectIdTail = 0x2; + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + XEngine xEngineA = new XEngine(); + XEngine xEngineB = new XEngine(); + xEngineA.DebugLevel = 1; + xEngineB.DebugLevel = 1; + + IConfigSource configSource = new IniConfigSource(); + + IConfig startupConfig = configSource.AddConfig("Startup"); + startupConfig.Set("DefaultScriptEngine", "XEngine"); + + IConfig xEngineConfig = configSource.AddConfig("XEngine"); + xEngineConfig.Set("Enabled", "true"); + xEngineConfig.Set("StartDelay", "0"); + + // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call + // to AssemblyResolver.OnAssemblyResolve fails. + xEngineConfig.Set("AppDomainLoading", "false"); + + IConfig modulesConfig = configSource.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000, configSource); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999, configSource); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, configSource, lscm); + SceneHelpers.SetupSceneModules(sceneA, configSource, etmA, xEngineA); + SceneHelpers.SetupSceneModules(sceneB, configSource, etmB, xEngineB); + sceneA.StartScripts(); + sceneB.StartScripts(); + + SceneObjectGroup soSceneA = SceneHelpers.AddSceneObject(sceneA, 1, userId, "so1-", sceneObjectIdTail); + soSceneA.AbsolutePosition = new Vector3(128, 10, 20); + + // CREATE SCRIPT TODO + InventoryItemBase scriptItemSceneA = new InventoryItemBase(); + // itemTemplate.ID = itemId; + scriptItemSceneA.Name = "script1"; + scriptItemSceneA.Folder = soSceneA.UUID; + scriptItemSceneA.InvType = (int)InventoryType.LSL; + + AutoResetEvent chatEvent = new AutoResetEvent(false); + OSChatMessage messageReceived = null; + sceneA.EventManager.OnChatFromWorld += (s, m) => { messageReceived = m; chatEvent.Set(); }; + + sceneA.RezNewScript(userId, scriptItemSceneA, +@"integer c = 0; + +default +{ + state_entry() + { + llSay(0, ""Script running""); + } + + changed(integer change) + { + llSay(0, ""Changed""); + } + + touch_start(integer n) + { + c = c + 1; + llSay(0, (string)c); + } +}"); + + chatEvent.WaitOne(60000); + + Assert.That(messageReceived, Is.Not.Null, "No chat message received."); + Assert.That(messageReceived.Message, Is.EqualTo("Script running")); + + { + // XXX: Should not be doing this so directly. Should call some variant of EventManager.touch() instead. + DetectParams[] det = new DetectParams[1]; + det[0] = new DetectParams(); + det[0].Key = userId; + det[0].Populate(sceneA); + + EventParams ep = new EventParams("touch_start", new Object[] { new LSL_Types.LSLInteger(1) }, det); + + xEngineA.PostObjectEvent(soSceneA.LocalId, ep); + chatEvent.WaitOne(60000); + + Assert.That(messageReceived.Message, Is.EqualTo("1")); + } + + sceneB.EventManager.OnChatFromWorld += (s, m) => { messageReceived = m; chatEvent.Set(); }; + + // Cross with a negative value + soSceneA.AbsolutePosition = new Vector3(128, -10, 20); + + chatEvent.WaitOne(60000); + Assert.That(messageReceived.Message, Is.EqualTo("Changed")); + + // TEST sending event to moved prim and output + { + SceneObjectGroup soSceneB = sceneB.GetSceneObjectGroup(soSceneA.Name); + TaskInventoryItem scriptItemSceneB = soSceneB.RootPart.Inventory.GetInventoryItem(scriptItemSceneA.Name); + + // XXX: Should not be doing this so directly. Should call some variant of EventManager.touch() instead. + DetectParams[] det = new DetectParams[1]; + det[0] = new DetectParams(); + det[0].Key = userId; + det[0].Populate(sceneB); + + EventParams ep = new EventParams("touch_start", new Object[] { new LSL_Types.LSLInteger(1) }, det); + + xEngineB.PostObjectEvent(soSceneB.LocalId, ep); + chatEvent.WaitOne(60000); + + Assert.That(messageReceived.Message, Is.EqualTo("2")); + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs new file mode 100644 index 0000000..2ef4058 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs @@ -0,0 +1,152 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.Attachments; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.XEngine; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.ScriptEngine.Tests +{ + [TestFixture] + public class XEnginePersistenceTests : OpenSimTestCase + { + private AutoResetEvent m_chatEvent = new AutoResetEvent(false); + + private void OnChatFromWorld(object sender, OSChatMessage oscm) + { + // Console.WriteLine("Got chat [{0}]", oscm.Message); + + // m_osChatMessageReceived = oscm; + m_chatEvent.Set(); + } + + private void AddCommonConfig(IConfigSource config, List modules) + { + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + AttachmentsModule attMod = new AttachmentsModule(); + attMod.DebugLevel = 1; + modules.Add(attMod); + modules.Add(new BasicInventoryAccessModule()); + } + + private void AddScriptingConfig(IConfigSource config, XEngine.XEngine xEngine, List modules) + { + IConfig startupConfig = config.AddConfig("Startup"); + startupConfig.Set("DefaultScriptEngine", "XEngine"); + + IConfig xEngineConfig = config.AddConfig("XEngine"); + xEngineConfig.Set("Enabled", "true"); + xEngineConfig.Set("StartDelay", "0"); + + // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call + // to AssemblyResolver.OnAssemblyResolve fails. + xEngineConfig.Set("AppDomainLoading", "false"); + + modules.Add(xEngine); + } + + private Scene CreateScriptingEnabledTestScene(XEngine.XEngine xEngine) + { + IConfigSource config = new IniConfigSource(); + List modules = new List(); + + AddCommonConfig(config, modules); + AddScriptingConfig(config, xEngine, modules); + + Scene scene + = new SceneHelpers().SetupScene( + "attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config); + SceneHelpers.SetupSceneModules(scene, config, modules.ToArray()); + + scene.StartScripts(); + + return scene; + } + + [Test] + public void TestScriptedAttachmentPersistence() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + XEngine.XEngine xEngine = new XEngine.XEngine(); + Scene scene = CreateScriptingEnabledTestScene(xEngine); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10); + TaskInventoryHelpers.AddScript( + scene.AssetService, + so.RootPart, + "scriptItem", + "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }"); + + InventoryItemBase userItem = UserInventoryHelpers.AddInventoryItem(scene, so, 0x100, 0x1000); + + // FIXME: Right now, we have to do a tricksy chat listen to make sure we know when the script is running. + // In the future, we need to be able to do this programatically more predicably. + scene.EventManager.OnChatFromWorld += OnChatFromWorld; + + SceneObjectGroup rezzedSo + = scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest); + TaskInventoryItem rezzedScriptItem = rezzedSo.RootPart.Inventory.GetInventoryItem("scriptItem"); + + // Wait for chat to signal rezzed script has been started. + m_chatEvent.WaitOne(60000); + + // Force save + xEngine.DoBackup(new Object[] { 0 }); + +// Console.WriteLine("ItemID {0}", rezzedScriptItem.ItemID); +// +// foreach ( +// string s in Directory.EnumerateFileSystemEntries( +// string.Format("ScriptEngines/{0}", scene.RegionInfo.RegionID))) +// Console.WriteLine(s); + + Assert.IsFalse( + File.Exists( + string.Format("ScriptEngines/{0}/{1}.state", scene.RegionInfo.RegionID, rezzedScriptItem.ItemID))); + + scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, rezzedSo); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs deleted file mode 100644 index 5abfe9a..0000000 --- a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Threading; -using Nini.Config; -using NUnit.Framework; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.CoreModules.Scripting.WorldComm; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; - -namespace OpenSim.Region.ScriptEngine.XEngine.Tests -{ - /// - /// XEngine tests. - /// - [TestFixture] - public class XEngineTest : OpenSimTestCase - { - private TestScene m_scene; - private XEngine m_xEngine; - private AutoResetEvent m_chatEvent = new AutoResetEvent(false); - private OSChatMessage m_osChatMessageReceived; - - [TestFixtureSetUp] - public void Init() - { - //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin"); -// Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); - m_xEngine = new XEngine(); - - IniConfigSource configSource = new IniConfigSource(); - - IConfig startupConfig = configSource.AddConfig("Startup"); - startupConfig.Set("DefaultScriptEngine", "XEngine"); - - IConfig xEngineConfig = configSource.AddConfig("XEngine"); - xEngineConfig.Set("Enabled", "true"); - xEngineConfig.Set("StartDelay", "0"); - - // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call - // to AssemblyResolver.OnAssemblyResolve fails. - xEngineConfig.Set("AppDomainLoading", "false"); - - m_scene = new SceneHelpers().SetupScene("My Test", UUID.Random(), 1000, 1000, configSource); - SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine); - m_scene.StartScripts(); - } - - /// - /// Test compilation and starting of a script. - /// - /// - /// This is a less than ideal regression test since it involves an asynchronous operation (in this case, - /// compilation of the script). - /// - [Test] - public void TestCompileAndStartScript() - { - TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); - - UUID userId = TestHelpers.ParseTail(0x1); -// UUID objectId = TestHelpers.ParseTail(0x100); -// UUID itemId = TestHelpers.ParseTail(0x3); - string itemName = "TestStartScript() Item"; - - SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, "TestStartScriptPart_", 0x100); - m_scene.AddNewSceneObject(so, true); - - InventoryItemBase itemTemplate = new InventoryItemBase(); -// itemTemplate.ID = itemId; - itemTemplate.Name = itemName; - itemTemplate.Folder = so.UUID; - itemTemplate.InvType = (int)InventoryType.LSL; - - m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; - - SceneObjectPart partWhereRezzed = m_scene.RezNewScript(userId, itemTemplate); - - m_chatEvent.WaitOne(60000); - - Assert.That(m_osChatMessageReceived, Is.Not.Null, "No chat message received in TestStartScript()"); - Assert.That(m_osChatMessageReceived.Message, Is.EqualTo("Script running")); - - bool running; - TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName); - Assert.That( - SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True); - Assert.That(running, Is.True); - } - - private void OnChatFromWorld(object sender, OSChatMessage oscm) - { -// Console.WriteLine("Got chat [{0}]", oscm.Message); - - m_osChatMessageReceived = oscm; - m_chatEvent.Set(); - } - } -} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs old mode 100644 new mode 100755 index 18569ca..78d4ee9 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -42,22 +42,26 @@ using OpenMetaverse.StructuredData; using log4net; using Nini.Config; using Amib.Threading; +using Mono.Addins; using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.ScriptEngine.Interfaces; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.CodeTools; using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Region.ScriptEngine.Shared.Api; using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; -using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Region.ScriptEngine.XEngine.ScriptBase; using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; using ScriptCompileQueue = OpenSim.Framework.LocklessQueue; namespace OpenSim.Region.ScriptEngine.XEngine { + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XEngine")] public class XEngine : INonSharedRegionModule, IScriptModule, IScriptEngine { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -68,7 +72,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine /// /// If DebugLevel >= 1, then we log every time that a script is started. /// -// public int DebugLevel { get; set; } + public int DebugLevel { get; set; } + + /// + /// A parameter to allow us to notify the log if at least one script has a compilation that is not compatible + /// with ScriptStopStrategy. + /// + public bool HaveNotifiedLogOfScriptStopMistmatch { get; private set; } private SmartThreadPool m_ThreadPool; private int m_MaxScriptQueue; @@ -84,6 +94,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine /// private int m_StartDelay; + /// + /// Are we stopping scripts co-operatively by inserting checks in them at C# compile time (true) or aborting + /// their threads (false)? + /// + private bool m_coopTermination; + private int m_IdleTimeout; private int m_StackSize; private int m_SleepTime; @@ -93,7 +109,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine private bool m_InitialStartup = true; private int m_ScriptFailCount; // Number of script fails since compile queue was last empty private string m_ScriptErrorMessage; - private Dictionary m_uniqueScripts = new Dictionary(); private bool m_AppDomainLoading; private Dictionary m_ScriptErrors = new Dictionary(); @@ -175,6 +190,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine get { return "XEngine"; } } + public string ScriptClassName { get; private set; } + + public string ScriptBaseClassName { get; private set; } + + public ParameterInfo[] ScriptBaseClassParameters { get; private set; } + + public string[] ScriptReferencedAssemblies { get; private set; } + public Scene World { get { return m_Scene; } @@ -229,21 +252,36 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_ScriptConfig = configSource.Configs["XEngine"]; m_ConfigSource = configSource; + + string rawScriptStopStrategy = m_ScriptConfig.GetString("ScriptStopStrategy", "co-op"); + + m_log.InfoFormat("[XEngine]: Script stop strategy is {0}", rawScriptStopStrategy); + + if (rawScriptStopStrategy == "co-op") + { + m_coopTermination = true; + ScriptClassName = "XEngineScript"; + ScriptBaseClassName = typeof(XEngineScriptBase).FullName; + ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters(); + ScriptReferencedAssemblies = new string[] { Path.GetFileName(typeof(XEngineScriptBase).Assembly.Location) }; + } + else + { + ScriptClassName = "Script"; + ScriptBaseClassName = typeof(ScriptBaseClass).FullName; + } + +// Console.WriteLine("ASSEMBLY NAME: {0}", ScriptReferencedAssemblies[0]); } public void AddRegion(Scene scene) { if (m_ScriptConfig == null) return; + m_ScriptFailCount = 0; m_ScriptErrorMessage = String.Empty; - if (m_ScriptConfig == null) - { -// m_log.ErrorFormat("[XEngine] No script configuration found. Scripts disabled"); - return; - } - m_Enabled = m_ScriptConfig.GetBoolean("Enabled", true); if (!m_Enabled) @@ -365,19 +403,19 @@ namespace OpenSim.Region.ScriptEngine.XEngine (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); MainConsole.Instance.Commands.AddCommand( - "Scripts", false, "debug scripts log", "debug scripts log ", "Extra debug logging for a script", + "Debug", false, "debug scripts log", "debug scripts log ", "Extra debug logging for a particular script.", "Activates or deactivates extra debug logging for the given script.\n" + "Level == 0, deactivate extra debug logging.\n" + "Level >= 1, log state changes.\n" + "Level >= 2, log event invocations.\n", HandleDebugScriptLogCommand); -// MainConsole.Instance.Commands.AddCommand( -// "Debug", false, "debug xengine", "debug xengine []", -// "Turn on detailed xengine debugging.", -// "If level <= 0, then no extra logging is done.\n" -// + "If level >= 1, then we log every time that a script is started.", -// HandleDebugLevelCommand); + MainConsole.Instance.Commands.AddCommand( + "Debug", false, "debug xengine log", "debug xengine log []", + "Turn on detailed xengine debugging.", + "If level <= 0, then no extra logging is done.\n" + + "If level >= 1, then we log every time that a script is started.", + HandleDebugLevelCommand); } private void HandleDebugScriptLogCommand(string module, string[] args) @@ -420,26 +458,26 @@ namespace OpenSim.Region.ScriptEngine.XEngine /// /// /// -// private void HandleDebugLevelCommand(string module, string[] args) -// { -// if (args.Length == 3) -// { -// int newDebug; -// if (int.TryParse(args[2], out newDebug)) -// { -// DebugLevel = newDebug; -// MainConsole.Instance.OutputFormat("Debug level set to {0}", newDebug); -// } -// } -// else if (args.Length == 2) -// { -// MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel); -// } -// else -// { -// MainConsole.Instance.Output("Usage: debug xengine 0..1"); -// } -// } + private void HandleDebugLevelCommand(string module, string[] args) + { + if (args.Length >= 4) + { + int newDebug; + if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, args[3], out newDebug)) + { + DebugLevel = newDebug; + MainConsole.Instance.OutputFormat("Debug level set to {0} in XEngine for region {1}", newDebug, m_Scene.Name); + } + } + else if (args.Length == 3) + { + MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel); + } + else + { + MainConsole.Instance.Output("Usage: debug xengine log "); + } + } /// /// Parse the raw item id into a script instance from the command params if it's present. @@ -459,7 +497,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine /// /// Basis on which to sort output. Can be null if no sort needs to take place private void HandleScriptsAction( - string[] cmdparams, Action action, Func keySelector) + string[] cmdparams, Action action, System.Func keySelector) { if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) return; @@ -517,7 +555,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) return; - MainConsole.Instance.OutputFormat(GetStatusReport()); + MainConsole.Instance.Output(GetStatusReport()); } public string GetStatusReport() @@ -539,7 +577,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine } sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded); - sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); sb.AppendFormat("Min threads : {0}\n", m_ThreadPool.MinThreads); @@ -616,7 +653,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); - MainConsole.Instance.OutputFormat(sb.ToString()); + MainConsole.Instance.Output(sb.ToString()); } private void HandleSuspendScript(IScriptInstance instance) @@ -662,6 +699,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine { if (instance.Running) { + instance.StayStopped = true; // the script was stopped explicitly + instance.Stop(0); SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID); @@ -685,28 +724,23 @@ namespace OpenSim.Region.ScriptEngine.XEngine { // Force a final state save // - if (m_Assemblies.ContainsKey(instance.AssetID)) + try { - string assembly = m_Assemblies[instance.AssetID]; - - try - { - instance.SaveState(assembly); - } - catch (Exception e) - { - m_log.Error( - string.Format( - "[XEngine]: Failed final state save for script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ", - instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name) - , e); - } + if (instance.StatePersistedHere) + instance.SaveState(); + } + catch (Exception e) + { + m_log.Error( + string.Format( + "[XEngine]: Failed final state save for script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ", + instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name) + , e); } // Clear the event queue and abort the instance thread // - instance.ClearQueue(); - instance.Stop(0); + instance.Stop(0, true); // Release events, timer, etc // @@ -804,23 +838,23 @@ namespace OpenSim.Region.ScriptEngine.XEngine lock (m_Scripts) { foreach (IScriptInstance instance in m_Scripts.Values) - instances.Add(instance); + { + if (instance.StatePersistedHere) + { +// m_log.DebugFormat( +// "[XEngine]: Adding script {0}.{1}, item UUID {2}, prim UUID {3} in {4} for state persistence", +// instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name); + + instances.Add(instance); + } + } } foreach (IScriptInstance i in instances) { - string assembly = String.Empty; - - lock (m_Scripts) - { - if (!m_Assemblies.ContainsKey(i.AssetID)) - continue; - assembly = m_Assemblies[i.AssetID]; - } - try { - i.SaveState(assembly); + i.SaveState(); } catch (Exception e) { @@ -832,8 +866,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine } } - instances.Clear(); - if (saveTime > 0) m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup), new Object[] { saveTime }); @@ -843,6 +875,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine public void SaveAllState() { + DoBackup(new object[] { 0 }); + } + + public object DoMaintenance(object p) + { + object[] parms = (object[])p; + int sleepTime = (int)parms[0]; + foreach (IScriptInstance inst in m_Scripts.Values) { if (inst.EventTime() > m_EventLimit) @@ -852,14 +892,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine inst.Start(); } } - } - - public object DoMaintenance(object p) - { - object[] parms = (object[])p; - int sleepTime = (int)parms[0]; - - SaveAllState(); System.Threading.Thread.Sleep(sleepTime); @@ -937,8 +969,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (restOfFirstLine.StartsWith("c#") || restOfFirstLine.StartsWith("vb") || restOfFirstLine.StartsWith("lsl") - || restOfFirstLine.StartsWith("js") - || restOfFirstLine.StartsWith("yp") || restOfFirstLine.Length == 0) warnRunningInXEngine = true; @@ -972,12 +1002,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (engine != ScriptEngineName) return; - // If we've seen this exact script text before, use that reference instead - if (m_uniqueScripts.ContainsKey(script)) - script = m_uniqueScripts[script]; - else - m_uniqueScripts[script] = script; - Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource}; if (stateSource == (int)StateSource.ScriptedRez) @@ -991,11 +1015,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine } else { - m_CompileQueue.Enqueue(parms); lock (m_CompileDict) - { m_CompileDict[itemID] = 0; - } + + // This must occur after the m_CompileDict so that an existing compile thread cannot hit the check + // in DoOnRezScript() before m_CompileDict has been updated. + m_CompileQueue.Enqueue(parms); // m_log.DebugFormat("[XEngine]: Added script {0} to compile queue", itemID); @@ -1017,49 +1042,81 @@ namespace OpenSim.Region.ScriptEngine.XEngine public Object DoOnRezScriptQueue(Object dummy) { - if (m_InitialStartup) + try { - // This delay exists to stop mono problems where script compilation and startup would stop the sim - // working properly for the session. - System.Threading.Thread.Sleep(m_StartDelay); + if (m_InitialStartup) + { + // This delay exists to stop mono problems where script compilation and startup would stop the sim + // working properly for the session. + System.Threading.Thread.Sleep(m_StartDelay); - m_log.InfoFormat("[XEngine]: Performing initial script startup on {0}", m_Scene.Name); - } + m_log.InfoFormat("[XEngine]: Performing initial script startup on {0}", m_Scene.Name); + } - object[] o; + object[] o; - int scriptsStarted = 0; + int scriptsStarted = 0; - while (m_CompileQueue.Dequeue(out o)) - { - if (DoOnRezScript(o)) + while (m_CompileQueue.Dequeue(out o)) { - scriptsStarted++; + try + { + if (DoOnRezScript(o)) + { + scriptsStarted++; - if (m_InitialStartup) - if (scriptsStarted % 50 == 0) - m_log.InfoFormat( - "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.Name); + if (m_InitialStartup) + if (scriptsStarted % 50 == 0) + m_log.InfoFormat( + "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.Name); + } + } + catch (Exception e) + { + m_log.Error( + string.Format( + "[XEngine]: Failure in DoOnRezScriptQueue() for item {0} in {1}. Continuing. Exception ", + o[1], m_Scene.Name), + e); + } } - } - if (m_InitialStartup) - m_log.InfoFormat( - "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.Name); + if (m_InitialStartup) + m_log.InfoFormat( + "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.Name); - // NOTE: Despite having a lockless queue, this lock is required - // to make sure there is never no compile thread while there - // are still scripts to compile. This could otherwise happen - // due to a race condition - // - lock (m_CompileQueue) - m_CurrentCompile = null; + } + catch (Exception e) + { + m_log.Error( + string.Format("[XEngine]: Failure in DoOnRezScriptQueue() in {0}. Exception ", m_Scene.Name), e); + } + finally + { + // FIXME: On failure we must trigger this even if the compile queue is not actually empty so that the + // RegionReadyModule is not forever waiting. This event really needs a different name. + m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, + m_ScriptErrorMessage); - m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, - m_ScriptErrorMessage); + m_ScriptFailCount = 0; + m_InitialStartup = false; - m_ScriptFailCount = 0; - m_InitialStartup = false; + // NOTE: Despite having a lockless queue, this lock is required + // to make sure there is never no compile thread while there + // are still scripts to compile. This could otherwise happen + // due to a race condition + // + lock (m_CompileQueue) + { + m_CurrentCompile = null; + + // This is to avoid a situation where the m_CompileQueue while loop above could complete but + // OnRezScript() place a new script on the queue and check m_CurrentCompile = null before we hit + // this section. + if (m_CompileQueue.Count > 0) + m_CurrentCompile = m_ThreadPool.QueueWorkItem(DoOnRezScriptQueue, null); + } + } return null; } @@ -1106,16 +1163,17 @@ namespace OpenSim.Region.ScriptEngine.XEngine return false; } - m_log.DebugFormat( - "[XEngine] Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", - part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, - part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); + if (DebugLevel > 0) + m_log.DebugFormat( + "[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", + part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, + part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); UUID assetID = item.AssetID; ScenePresence presence = m_Scene.GetScenePresence(item.OwnerID); - string assembly = ""; + string assemblyPath = ""; Culture.SetCurrentCulture(); @@ -1127,11 +1185,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine { lock (m_AddingAssemblies) { - m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap); - if (!m_AddingAssemblies.ContainsKey(assembly)) { - m_AddingAssemblies[assembly] = 1; + m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assemblyPath, out linemap); + +// m_log.DebugFormat( +// "[XENGINE]: Found assembly path {0} onrez {1} in {2}", +// assemblyPath, item.ItemID, World.Name); + + if (!m_AddingAssemblies.ContainsKey(assemblyPath)) { + m_AddingAssemblies[assemblyPath] = 1; } else { - m_AddingAssemblies[assembly]++; + m_AddingAssemblies[assemblyPath]++; } } @@ -1177,7 +1240,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine } catch (Exception e) { -// m_log.ErrorFormat("[XEngine]: Exception when rezzing script {0}{1}", e.Message, e.StackTrace); +// m_log.ErrorFormat( +// "[XEngine]: Exception when rezzing script with item ID {0}, {1}{2}", +// itemID, e.Message, e.StackTrace); // try // { @@ -1274,19 +1339,144 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_ScriptFailCount++; lock (m_AddingAssemblies) { - m_AddingAssemblies[assembly]--; + m_AddingAssemblies[assemblyPath]--; } return false; } } m_DomainScripts[appDomain].Add(itemID); + IScript scriptObj = null; + EventWaitHandle coopSleepHandle; + bool coopTerminationForThisScript; + + // Set up assembly name to point to the appropriate scriptEngines directory + AssemblyName assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(assemblyPath)); + assemblyName.CodeBase = Path.GetDirectoryName(assemblyPath); + + if (m_coopTermination) + { + try + { + coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset); + + scriptObj + = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( + assemblyName.FullName, + "SecondLife.XEngineScript", + false, + BindingFlags.Default, + null, + new object[] { coopSleepHandle }, + null, + null); + + coopTerminationForThisScript = true; + } + catch (TypeLoadException) + { + coopSleepHandle = null; + + try + { + scriptObj + = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( + assemblyName.FullName, + "SecondLife.Script", + false, + BindingFlags.Default, + null, + null, + null, + null); + } + catch (Exception e2) + { + m_log.Error( + string.Format( + "[XENGINE]: Could not load previous SecondLife.Script from assembly {0} in {1}. Not starting. Exception ", + assemblyName.FullName, World.Name), + e2); + + return false; + } + + coopTerminationForThisScript = false; + } + } + else + { + try + { + scriptObj + = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( + assemblyName.FullName, + "SecondLife.Script", + false, + BindingFlags.Default, + null, + null, + null, + null); + + coopSleepHandle = null; + coopTerminationForThisScript = false; + } + catch (TypeLoadException) + { + coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset); + + try + { + scriptObj + = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap( + assemblyName.FullName, + "SecondLife.XEngineScript", + false, + BindingFlags.Default, + null, + new object[] { coopSleepHandle }, + null, + null); + } + catch (Exception e2) + { + m_log.Error( + string.Format( + "[XENGINE]: Could not load previous SecondLife.XEngineScript from assembly {0} in {1}. Not starting. Exception ", + assemblyName.FullName, World.Name), + e2); + + return false; + } + + coopTerminationForThisScript = true; + } + } + + if (m_coopTermination != coopTerminationForThisScript && !HaveNotifiedLogOfScriptStopMistmatch) + { + // Notify the log that there is at least one script compile that doesn't match the + // ScriptStopStrategy. Operator has to manually delete old DLLs - we can't do this on Windows + // once the assembly has been loaded evne if the instantiation of a class was unsuccessful. + m_log.WarnFormat( + "[XEngine]: At least one existing compiled script DLL in {0} has {1} as ScriptStopStrategy whereas config setting is {2}." + + "\nContinuing with script compiled strategy but to remove this message please set [XEngine] DeleteScriptsOnStartup = true for one simulator session to remove old script DLLs (script state will not be lost).", + World.Name, coopTerminationForThisScript ? "co-op" : "abort", m_coopTermination ? "co-op" : "abort"); + + HaveNotifiedLogOfScriptStopMistmatch = true; + } + instance = new ScriptInstance(this, part, - itemID, assetID, assembly, - m_AppDomains[appDomain], - part.ParentGroup.RootPart.Name, - item.Name, startParam, postOnRez, - stateSource, m_MaxScriptQueue); + item, + startParam, postOnRez, + m_MaxScriptQueue); + + if ( + !instance.Load( + scriptObj, coopSleepHandle, assemblyPath, + Path.Combine(ScriptEnginePath, World.RegionInfo.RegionID.ToString()), stateSource, coopTerminationForThisScript)) + return false; // if (DebugLevel >= 1) // m_log.DebugFormat( @@ -1317,11 +1507,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine } if (!m_Assemblies.ContainsKey(assetID)) - m_Assemblies[assetID] = assembly; + m_Assemblies[assetID] = assemblyPath; lock (m_AddingAssemblies) { - m_AddingAssemblies[assembly]--; + m_AddingAssemblies[assemblyPath]--; } if (instance != null) @@ -1359,11 +1549,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_Scripts.Remove(itemID); } - instance.ClearQueue(); - - instance.Stop(m_WaitForEventCompletionOnScriptStop); - -// bool objectRemoved = false; + instance.Stop(m_WaitForEventCompletionOnScriptStop, true); lock (m_PrimObjects) { @@ -1376,14 +1562,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine // If there are no more scripts, remove prim if (m_PrimObjects[localID].Count == 0) - { m_PrimObjects.Remove(localID); -// objectRemoved = true; - } } } - instance.RemoveState(); + if (instance.StatePersistedHere) + instance.RemoveState(); + instance.DestroyScriptInstance(); m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); @@ -1489,7 +1674,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine startInfo.MaxWorkerThreads = maxThreads; startInfo.MinWorkerThreads = minThreads; startInfo.ThreadPriority = threadPriority;; - startInfo.StackSize = stackSize; + startInfo.MaxStackSize = stackSize; startInfo.StartSuspended = true; m_ThreadPool = new SmartThreadPool(startInfo); @@ -1516,7 +1701,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine IScriptInstance instance = (ScriptInstance) parms; - //m_log.DebugFormat("[XEngine]: Processing event for {0}", instance); +// m_log.DebugFormat("[XEngine]: Processing event for {0}", instance); return instance.EventProcessor(); } @@ -1681,9 +1866,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine public bool GetScriptState(UUID itemID) { IScriptInstance instance = GetInstance(itemID); - if (instance != null) - return instance.Running; - return false; + return instance != null && instance.Running; } public void ApiResetScript(UUID itemID) @@ -1691,6 +1874,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine IScriptInstance instance = GetInstance(itemID); if (instance != null) instance.ApiResetScript(); + + // Send the new number of threads that are in use by the thread + // pool, I believe that by adding them to the locations where the + // script is changing states that I will catch all changes to the + // thread pool + m_Scene.setThreadCount(m_ThreadPool.InUseThreads); } public void ResetScript(UUID itemID) @@ -1698,6 +1887,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine IScriptInstance instance = GetInstance(itemID); if (instance != null) instance.ResetScript(m_WaitForEventCompletionOnScriptStop); + + // Send the new number of threads that are in use by the thread + // pool, I believe that by adding them to the locations where the + // script is changing states that I will catch all changes to the + // thread pool + m_Scene.setThreadCount(m_ThreadPool.InUseThreads); } public void StartScript(UUID itemID) @@ -1707,6 +1902,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine instance.Start(); else m_runFlags.AddOrUpdate(itemID, true, 240); + + // Send the new number of threads that are in use by the thread + // pool, I believe that by adding them to the locations where the + // script is changing states that I will catch all changes to the + // thread pool + m_Scene.setThreadCount(m_ThreadPool.InUseThreads); } public void StopScript(UUID itemID) @@ -1714,17 +1915,29 @@ namespace OpenSim.Region.ScriptEngine.XEngine IScriptInstance instance = GetInstance(itemID); if (instance != null) + { + lock (instance.EventQueue) + instance.StayStopped = true; // the script was stopped explicitly + instance.Stop(m_WaitForEventCompletionOnScriptStop); + } else + { +// m_log.DebugFormat("[XENGINE]: Could not find script with ID {0} to stop in {1}", itemID, World.Name); m_runFlags.AddOrUpdate(itemID, false, 240); + } + + // Send the new number of threads that are in use by the thread + // pool, I believe that by adding them to the locations where the + // script is changing states that I will catch all changes to the + // thread pool + m_Scene.setThreadCount(m_ThreadPool.InUseThreads); } public DetectParams GetDetectParams(UUID itemID, int idx) { IScriptInstance instance = GetInstance(itemID); - if (instance != null) - return instance.GetDetectParams(idx); - return null; + return instance != null ? instance.GetDetectParams(idx) : null; } public void SetMinEventDelay(UUID itemID, double delay) @@ -1737,9 +1950,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine public UUID GetDetectID(UUID itemID, int idx) { IScriptInstance instance = GetInstance(itemID); - if (instance != null) - return instance.GetDetectID(idx); - return UUID.Zero; + return instance != null ? instance.GetDetectID(idx) : UUID.Zero; } public void SetState(UUID itemID, string newState) @@ -1753,9 +1964,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine public int GetStartParameter(UUID itemID) { IScriptInstance instance = GetInstance(itemID); - if (instance == null) - return 0; - return instance.StartParam; + return instance == null ? 0 : instance.StartParam; } public void OnShutdown() @@ -1789,9 +1998,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine public IScriptApi GetApi(UUID itemID, string name) { IScriptInstance instance = GetInstance(itemID); - if (instance == null) - return null; - return instance.GetApi(name); + return instance == null ? null : instance.GetApi(name); } public void OnGetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID) @@ -2090,7 +2297,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine catch (IOException ex) { // if there already exists a file at that location, it may be locked. - m_log.ErrorFormat("[XEngine]: Linemap file {0} already exists! {1}", mappath, ex.Message); + m_log.Error( + string.Format("[XEngine]: Linemap file {0} could not be written. Exception ", mappath), ex); } } } @@ -2116,6 +2324,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_log.ErrorFormat("[XEngine]: Error whilst writing state file {0}, {1}", statepath, ex.Message); } +// m_log.DebugFormat( +// "[XEngine]: Wrote state for script item with ID {0} at {1} in {2}", itemID, statepath, m_Scene.Name); + return true; } @@ -2137,7 +2348,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine public Dictionary GetObjectScriptsExecutionTimes() { - long tickNow = Util.EnvironmentTickCount(); Dictionary topScripts = new Dictionary(); lock (m_Scripts) @@ -2147,7 +2357,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (!topScripts.ContainsKey(si.LocalID)) topScripts[si.RootLocalID] = 0; - topScripts[si.RootLocalID] += CalculateAdjustedExectionTime(si, tickNow); + topScripts[si.RootLocalID] += GetExectionTime(si); } } @@ -2161,7 +2371,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine return 0.0f; } float time = 0.0f; - long tickNow = Util.EnvironmentTickCount(); IScriptInstance si; // Calculate the time for all scripts that this engine is executing // Ignore any others @@ -2170,36 +2379,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine si = GetInstance(id); if (si != null && si.Running) { - time += CalculateAdjustedExectionTime(si, tickNow); + time += GetExectionTime(si); } } return time; } - private float CalculateAdjustedExectionTime(IScriptInstance si, long tickNow) + private float GetExectionTime(IScriptInstance si) { - long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; - - // Avoid divide by zero - if (ticksElapsed == 0) - ticksElapsed = 1; - - // Scale execution time to the ideal 55 fps frame time for these reasons. - // - // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no - // 'script execution time per frame', which is the original purpose of this value. - // - // 2) Giving the raw execution times is misleading since scripts start at different times, making - // it impossible to compare scripts. - // - // 3) Scaling the raw execution time to the time that the script has been running is better but - // is still misleading since a script that has just been rezzed may appear to have been running - // for much longer. - // - // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect - // since the figure does not represent actual execution time and very hard running scripts will - // never exceed 18ms (though this is a very high number for script execution so is a warning sign). - return ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f; + return (float)si.ExecutionTime.GetSumTime().TotalMilliseconds; } public void SuspendScript(UUID itemID) @@ -2211,6 +2399,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine instance.Suspend(); // else // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID); + + // Send the new number of threads that are in use by the thread + // pool, I believe that by adding them to the locations where the + // script is changing states that I will catch all changes to the + // thread pool + m_Scene.setThreadCount(m_ThreadPool.InUseThreads); } public void ResumeScript(UUID itemID) @@ -2222,6 +2416,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine instance.Resume(); // else // m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID); + + // Send the new number of threads that are in use by the thread + // pool, I believe that by adding them to the locations where the + // script is changing states that I will catch all changes to the + // thread pool + m_Scene.setThreadCount(m_ThreadPool.InUseThreads); } public bool HasScript(UUID itemID, out bool running) @@ -2235,5 +2435,30 @@ namespace OpenSim.Region.ScriptEngine.XEngine running = instance.Running; return true; } + + public void SleepScript(UUID itemID, int delay) + { + IScriptInstance instance = GetInstance(itemID); + if (instance == null) + return; + + instance.ExecutionTimer.Stop(); + try + { + if (instance.CoopWaitHandle != null) + { + if (instance.CoopWaitHandle.WaitOne(delay)) + throw new ScriptCoopStopException(); + } + else + { + Thread.Sleep(delay); + } + } + finally + { + instance.ExecutionTimer.Start(); + } + } } } diff --git a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs index 2ac5c31..9d9dee1 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs @@ -52,13 +52,17 @@ namespace OpenSim.Region.ScriptEngine.XEngine return wr.Cancel(); } - public void Abort() + public bool Abort() { - wr.Abort(); + return wr.Cancel(true); } - public bool Wait(TimeSpan t) + public bool Wait(int t) { + // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the + // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an + // int (32-bit) we can end up with bad values. This occurs on Windows though curiously not on Mono 2.10.8 + // (or very likely other versions of Mono at least up until 3.0.3). return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); } } diff --git a/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs b/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs deleted file mode 100644 index 3243a9a..0000000 --- a/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using System.Text; -using Mono.Data.SqliteClient; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Framework.Monitoring; - -namespace OpenSim.Region.UserStatistics -{ - public class ActiveConnectionsAJAX : IStatsController - { - private Vector3 DefaultNeighborPosition = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 70); - - #region IStatsController Members - - public string ReportName - { - get { return ""; } - } - - public Hashtable ProcessModel(Hashtable pParams) - { - - List m_scene = (List)pParams["Scenes"]; - - Hashtable nh = new Hashtable(); - nh.Add("hdata", m_scene); - - return nh; - } - - public string RenderView(Hashtable pModelResult) - { - List all_scenes = (List) pModelResult["hdata"]; - - StringBuilder output = new StringBuilder(); - HTMLUtil.OL_O(ref output, ""); - foreach (Scene scene in all_scenes) - { - HTMLUtil.LI_O(ref output, String.Empty); - output.Append(scene.RegionInfo.RegionName); - HTMLUtil.OL_O(ref output, String.Empty); - scene.ForEachScenePresence(delegate(ScenePresence av) - { - Dictionary queues = new Dictionary(); - if (av.ControllingClient is IStatsCollector) - { - IStatsCollector isClient = (IStatsCollector)av.ControllingClient; - queues = decodeQueueReport(isClient.Report()); - } - HTMLUtil.LI_O(ref output, String.Empty); - output.Append(av.Name); - output.Append("      "); - output.Append((av.IsChildAgent ? "Child" : "Root")); - if (av.AbsolutePosition == DefaultNeighborPosition) - { - output.Append("
Position: ?"); - } - else - { - output.Append(string.Format("
Position: <{0},{1},{2}>", (int)av.AbsolutePosition.X, - (int)av.AbsolutePosition.Y, - (int)av.AbsolutePosition.Z)); - } - Dictionary throttles = DecodeClientThrottles(av.ControllingClient.GetThrottlesPacked(1)); - - HTMLUtil.UL_O(ref output, String.Empty); - - foreach (string throttlename in throttles.Keys) - { - HTMLUtil.LI_O(ref output, String.Empty); - output.Append(throttlename); - output.Append(":"); - output.Append(throttles[throttlename].ToString()); - if (queues.ContainsKey(throttlename)) - { - output.Append("/"); - output.Append(queues[throttlename]); - } - HTMLUtil.LI_C(ref output); - } - if (queues.ContainsKey("Incoming") && queues.ContainsKey("Outgoing")) - { - HTMLUtil.LI_O(ref output, "red"); - output.Append("SEND:"); - output.Append(queues["Outgoing"]); - output.Append("/"); - output.Append(queues["Incoming"]); - HTMLUtil.LI_C(ref output); - } - - HTMLUtil.UL_C(ref output); - HTMLUtil.LI_C(ref output); - }); - HTMLUtil.OL_C(ref output); - } - HTMLUtil.OL_C(ref output); - return output.ToString(); - } - - public Dictionary DecodeClientThrottles(byte[] throttle) - { - Dictionary returndict = new Dictionary(); - // From mantis http://opensimulator.org/mantis/view.php?id=1374 - // it appears that sometimes we are receiving empty throttle byte arrays. - // TODO: Investigate this behaviour - if (throttle.Length == 0) - { - return new Dictionary(); - } - - int tResend = -1; - int tLand = -1; - int tWind = -1; - int tCloud = -1; - int tTask = -1; - int tTexture = -1; - int tAsset = -1; - int tall = -1; - const int singlefloat = 4; - - //Agent Throttle Block contains 7 single floatingpoint values. - int j = 0; - - // Some Systems may be big endian... - // it might be smart to do this check more often... - if (!BitConverter.IsLittleEndian) - for (int i = 0; i < 7; i++) - Array.Reverse(throttle, j + i * singlefloat, singlefloat); - - // values gotten from OpenMetaverse.org/wiki/Throttle. Thanks MW_ - // bytes - // Convert to integer, since.. the full fp space isn't used. - tResend = (int)BitConverter.ToSingle(throttle, j); - returndict.Add("Resend", tResend); - j += singlefloat; - tLand = (int)BitConverter.ToSingle(throttle, j); - returndict.Add("Land", tLand); - j += singlefloat; - tWind = (int)BitConverter.ToSingle(throttle, j); - returndict.Add("Wind", tWind); - j += singlefloat; - tCloud = (int)BitConverter.ToSingle(throttle, j); - returndict.Add("Cloud", tCloud); - j += singlefloat; - tTask = (int)BitConverter.ToSingle(throttle, j); - returndict.Add("Task", tTask); - j += singlefloat; - tTexture = (int)BitConverter.ToSingle(throttle, j); - returndict.Add("Texture", tTexture); - j += singlefloat; - tAsset = (int)BitConverter.ToSingle(throttle, j); - returndict.Add("Asset", tAsset); - - tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset; - returndict.Add("All", tall); - - return returndict; - } - public Dictionary decodeQueueReport(string rep) - { - Dictionary returndic = new Dictionary(); - if (rep.Length == 79) - { - int pos = 1; - returndic.Add("All", rep.Substring((6 * pos), 8)); pos++; - returndic.Add("Incoming", rep.Substring((7 * pos), 8)); pos++; - returndic.Add("Outgoing", rep.Substring((7 * pos) , 8)); pos++; - returndic.Add("Resend", rep.Substring((7 * pos) , 8)); pos++; - returndic.Add("Land", rep.Substring((7 * pos) , 8)); pos++; - returndic.Add("Wind", rep.Substring((7 * pos) , 8)); pos++; - returndic.Add("Cloud", rep.Substring((7 * pos) , 8)); pos++; - returndic.Add("Task", rep.Substring((7 * pos) , 8)); pos++; - returndic.Add("Texture", rep.Substring((7 * pos), 8)); pos++; - returndic.Add("Asset", rep.Substring((7 * pos), 8)); - /* - * return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}", - SendQueue.Count(), - IncomingPacketQueue.Count, - OutgoingPacketQueue.Count, - ResendOutgoingPacketQueue.Count, - LandOutgoingPacketQueue.Count, - WindOutgoingPacketQueue.Count, - CloudOutgoingPacketQueue.Count, - TaskOutgoingPacketQueue.Count, - TextureOutgoingPacketQueue.Count, - AssetOutgoingPacketQueue.Count); - */ - } - - - - return returndic; - } - #endregion - } -} diff --git a/OpenSim/Region/UserStatistics/Clients_report.cs b/OpenSim/Region/UserStatistics/Clients_report.cs deleted file mode 100644 index b2bb33b..0000000 --- a/OpenSim/Region/UserStatistics/Clients_report.cs +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using Mono.Data.SqliteClient; -using OpenMetaverse; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.UserStatistics -{ - public class Clients_report : IStatsController - { - #region IStatsController Members - - public string ReportName - { - get { return "Client"; } - } - - public Hashtable ProcessModel(Hashtable pParams) - { - SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"]; - - - List clidata = new List(); - List cliRegData = new List(); - Hashtable regionTotals = new Hashtable(); - - Hashtable modeldata = new Hashtable(); - modeldata.Add("Scenes", pParams["Scenes"]); - modeldata.Add("Reports", pParams["Reports"]); - int totalclients = 0; - int totalregions = 0; - - lock (dbConn) - { - string sql = "select count(distinct region_id) as regcnt from stats_session_data"; - - SqliteCommand cmd = new SqliteCommand(sql, dbConn); - SqliteDataReader sdr = cmd.ExecuteReader(); - if (sdr.HasRows) - { - sdr.Read(); - totalregions = Convert.ToInt32(sdr["regcnt"]); - } - - sdr.Close(); - sdr.Dispose(); - - sql = - "select client_version, count(*) as cnt, avg(avg_sim_fps) as simfps from stats_session_data group by client_version order by count(*) desc LIMIT 10;"; - - cmd = new SqliteCommand(sql, dbConn); - sdr = cmd.ExecuteReader(); - if (sdr.HasRows) - { - while (sdr.Read()) - { - ClientVersionData udata = new ClientVersionData(); - udata.version = sdr["client_version"].ToString(); - udata.count = Convert.ToInt32(sdr["cnt"]); - udata.fps = Convert.ToSingle(sdr["simfps"]); - clidata.Add(udata); - totalclients += udata.count; - - } - } - sdr.Close(); - sdr.Dispose(); - - if (totalregions > 1) - { - sql = - "select region_id, client_version, count(*) as cnt, avg(avg_sim_fps) as simfps from stats_session_data group by region_id, client_version order by region_id, count(*) desc;"; - cmd = new SqliteCommand(sql, dbConn); - - sdr = cmd.ExecuteReader(); - - if (sdr.HasRows) - { - while (sdr.Read()) - { - ClientVersionData udata = new ClientVersionData(); - udata.version = sdr["client_version"].ToString(); - udata.count = Convert.ToInt32(sdr["cnt"]); - udata.fps = Convert.ToSingle(sdr["simfps"]); - udata.region_id = UUID.Parse(sdr["region_id"].ToString()); - cliRegData.Add(udata); - } - } - sdr.Close(); - sdr.Dispose(); - - - } - - } - - foreach (ClientVersionData cvd in cliRegData) - { - - if (regionTotals.ContainsKey(cvd.region_id)) - { - int regiontotal = (int)regionTotals[cvd.region_id]; - regiontotal += cvd.count; - regionTotals[cvd.region_id] = regiontotal; - } - else - { - regionTotals.Add(cvd.region_id, cvd.count); - } - - - - } - - modeldata["ClientData"] = clidata; - modeldata["ClientRegionData"] = cliRegData; - modeldata["RegionTotals"] = regionTotals; - modeldata["Total"] = totalclients; - - return modeldata; - } - - public string RenderView(Hashtable pModelResult) - { - List clidata = (List) pModelResult["ClientData"]; - int totalclients = (int)pModelResult["Total"]; - Hashtable regionTotals = (Hashtable) pModelResult["RegionTotals"]; - List cliRegData = (List) pModelResult["ClientRegionData"]; - List m_scenes = (List)pModelResult["Scenes"]; - Dictionary reports = (Dictionary)pModelResult["Reports"]; - - const string STYLESHEET = - @" - -"; - - StringBuilder output = new StringBuilder(); - HTMLUtil.HtmlHeaders_O(ref output); - output.Append(STYLESHEET); - HTMLUtil.HtmlHeaders_C(ref output); - - HTMLUtil.AddReportLinks(ref output, reports, ""); - - HTMLUtil.TABLE_O(ref output, "defaultr"); - HTMLUtil.TR_O(ref output, ""); - HTMLUtil.TD_O(ref output, "header"); - output.Append("ClientVersion"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "header"); - output.Append("Count/%"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "header"); - output.Append("SimFPS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - - foreach (ClientVersionData cvd in clidata) - { - HTMLUtil.TR_O(ref output, ""); - HTMLUtil.TD_O(ref output, "content"); - string linkhref = "sessions.report?VersionString=" + cvd.version; - HTMLUtil.A(ref output, cvd.version, linkhref, ""); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "content"); - output.Append(cvd.count); - output.Append("/"); - if (totalclients > 0) - output.Append((((float)cvd.count / (float)totalclients)*100).ToString()); - else - output.Append(0); - - output.Append("%"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "content"); - output.Append(cvd.fps); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - } - HTMLUtil.TABLE_C(ref output); - - if (cliRegData.Count > 0) - { - HTMLUtil.TABLE_O(ref output, "defaultr"); - HTMLUtil.TR_O(ref output, ""); - HTMLUtil.TD_O(ref output, "header"); - output.Append("Region"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "header"); - output.Append("ClientVersion"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "header"); - output.Append("Count/%"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "header"); - output.Append("SimFPS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - - foreach (ClientVersionData cvd in cliRegData) - { - HTMLUtil.TR_O(ref output, ""); - HTMLUtil.TD_O(ref output, "content"); - output.Append(regionNamefromUUID(m_scenes, cvd.region_id)); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "content"); - output.Append(cvd.version); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "content"); - output.Append(cvd.count); - output.Append("/"); - if ((int)regionTotals[cvd.region_id] > 0) - output.Append((((float)cvd.count / (float)((int)regionTotals[cvd.region_id])) * 100).ToString()); - else - output.Append(0); - - output.Append("%"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "content"); - output.Append(cvd.fps); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - } - HTMLUtil.TABLE_C(ref output); - - } - - output.Append(""); - output.Append(""); - return output.ToString(); - } - public string regionNamefromUUID(List scenes, UUID region_id) - { - string returnstring = string.Empty; - foreach (Scene sn in scenes) - { - if (region_id == sn.RegionInfo.originRegionID) - { - returnstring = sn.RegionInfo.RegionName; - break; - } - } - - if (returnstring.Length == 0) - { - returnstring = region_id.ToString(); - } - - return returnstring; - } - - #endregion - } - - public struct ClientVersionData - { - public UUID region_id; - public string version; - public int count; - public float fps; - } -} diff --git a/OpenSim/Region/UserStatistics/Default_Report.cs b/OpenSim/Region/UserStatistics/Default_Report.cs deleted file mode 100644 index cdc615c..0000000 --- a/OpenSim/Region/UserStatistics/Default_Report.cs +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using System.Text; -using Mono.Data.SqliteClient; -using OpenMetaverse; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Framework.Monitoring; - - -namespace OpenSim.Region.UserStatistics -{ - public class Default_Report : IStatsController - { - - public string ReportName - { - get { return "Home"; } - } - - #region IStatsController Members - - public Hashtable ProcessModel(Hashtable pParams) - { - SqliteConnection conn = (SqliteConnection)pParams["DatabaseConnection"]; - List m_scene = (List)pParams["Scenes"]; - - stats_default_page_values mData = rep_DefaultReport_data(conn, m_scene); - mData.sim_stat_data = (Dictionary)pParams["SimStats"]; - mData.stats_reports = (Dictionary) pParams["Reports"]; - - Hashtable nh = new Hashtable(); - nh.Add("hdata", mData); - nh.Add("Reports", pParams["Reports"]); - - return nh; - } - - public string RenderView(Hashtable pModelResult) - { - stats_default_page_values mData = (stats_default_page_values) pModelResult["hdata"]; - return rep_Default_report_view(mData); - } - - #endregion - - public string rep_Default_report_view(stats_default_page_values values) - { - - - StringBuilder output = new StringBuilder(); - - - - const string TableClass = "defaultr"; - const string TRClass = "defaultr"; - const string TDHeaderClass = "header"; - const string TDDataClass = "content"; - //const string TDDataClassRight = "contentright"; - const string TDDataClassCenter = "contentcenter"; - - const string STYLESHEET = - @" - -"; - HTMLUtil.HtmlHeaders_O(ref output); - - HTMLUtil.InsertProtoTypeAJAX(ref output); - string[] ajaxUpdaterDivs = new string[3]; - int[] ajaxUpdaterSeconds = new int[3]; - string[] ajaxUpdaterReportFragments = new string[3]; - - ajaxUpdaterDivs[0] = "activeconnections"; - ajaxUpdaterSeconds[0] = 10; - ajaxUpdaterReportFragments[0] = "activeconnectionsajax.html"; - - ajaxUpdaterDivs[1] = "activesimstats"; - ajaxUpdaterSeconds[1] = 20; - ajaxUpdaterReportFragments[1] = "simstatsajax.html"; - - ajaxUpdaterDivs[2] = "activelog"; - ajaxUpdaterSeconds[2] = 5; - ajaxUpdaterReportFragments[2] = "activelogajax.html"; - - HTMLUtil.InsertPeriodicUpdaters(ref output, ajaxUpdaterDivs, ajaxUpdaterSeconds, ajaxUpdaterReportFragments); - - output.Append(STYLESHEET); - HTMLUtil.HtmlHeaders_C(ref output); - HTMLUtil.AddReportLinks(ref output, values.stats_reports, ""); - HTMLUtil.TABLE_O(ref output, TableClass); - HTMLUtil.TR_O(ref output, TRClass); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("# Users Total"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("# Sessions Total"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("Avg Client FPS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("Avg Client Mem Use"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("Avg Sim FPS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("Avg Ping"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("KB Out Total"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("KB In Total"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - HTMLUtil.TR_O(ref output, TRClass); - HTMLUtil.TD_O(ref output, TDDataClass); - output.Append(values.total_num_users); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClass); - output.Append(values.total_num_sessions); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(values.avg_client_fps); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(values.avg_client_mem_use); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(values.avg_sim_fps); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(values.avg_ping); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(values.total_kb_out); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(values.total_kb_in); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - HTMLUtil.TABLE_C(ref output); - - HTMLUtil.HR(ref output, ""); - HTMLUtil.TABLE_O(ref output, ""); - HTMLUtil.TR_O(ref output, ""); - HTMLUtil.TD_O(ref output, "align_top"); - output.Append("
Active Connections loading...
"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "align_top"); - output.Append("
SimStats loading...
"); - output.Append("
ActiveLog loading...
"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - HTMLUtil.TABLE_C(ref output); - output.Append(""); - // TODO: FIXME: template - return output.ToString(); - } - - - - public stats_default_page_values rep_DefaultReport_data(SqliteConnection db, List m_scene) - { - stats_default_page_values returnstruct = new stats_default_page_values(); - returnstruct.all_scenes = m_scene.ToArray(); - lock (db) - { - string SQL = @"SELECT COUNT(DISTINCT agent_id) as agents, COUNT(*) as sessions, AVG(avg_fps) as client_fps, - AVG(avg_sim_fps) as savg_sim_fps, AVG(avg_ping) as sav_ping, SUM(n_out_kb) as num_in_kb, - SUM(n_out_pk) as num_in_packets, SUM(n_in_kb) as num_out_kb, SUM(n_in_pk) as num_out_packets, AVG(mem_use) as sav_mem_use - FROM stats_session_data;"; - SqliteCommand cmd = new SqliteCommand(SQL, db); - SqliteDataReader sdr = cmd.ExecuteReader(); - if (sdr.HasRows) - { - sdr.Read(); - returnstruct.total_num_users = Convert.ToInt32(sdr["agents"]); - returnstruct.total_num_sessions = Convert.ToInt32(sdr["sessions"]); - returnstruct.avg_client_fps = Convert.ToSingle(sdr["client_fps"]); - returnstruct.avg_sim_fps = Convert.ToSingle(sdr["savg_sim_fps"]); - returnstruct.avg_ping = Convert.ToSingle(sdr["sav_ping"]); - returnstruct.total_kb_out = Convert.ToSingle(sdr["num_out_kb"]); - returnstruct.total_kb_in = Convert.ToSingle(sdr["num_in_kb"]); - returnstruct.avg_client_mem_use = Convert.ToSingle(sdr["sav_mem_use"]); - - } - } - return returnstruct; - } - - } - - public struct stats_default_page_values - { - public int total_num_users; - public int total_num_sessions; - public float avg_client_fps; - public float avg_client_mem_use; - public float avg_sim_fps; - public float avg_ping; - public float total_kb_out; - public float total_kb_in; - public float avg_client_resends; - public Scene[] all_scenes; - public Dictionary sim_stat_data; - public Dictionary stats_reports; - } -} diff --git a/OpenSim/Region/UserStatistics/HTMLUtil.cs b/OpenSim/Region/UserStatistics/HTMLUtil.cs deleted file mode 100644 index c07619f..0000000 --- a/OpenSim/Region/UserStatistics/HTMLUtil.cs +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace OpenSim.Region.UserStatistics -{ - public static class HTMLUtil - { - - public static void TR_O(ref StringBuilder o, string pclass) - { - o.Append(" 0) - { - GenericClass(ref o, pclass); - } - o.Append(">\n\t"); - } - - public static void TR_C(ref StringBuilder o) - { - o.Append("\n"); - } - - public static void TD_O(ref StringBuilder o, string pclass) - { - TD_O(ref o, pclass, 0, 0); - } - - public static void TD_O(ref StringBuilder o, string pclass, int rowspan, int colspan) - { - o.Append(" 0) - { - GenericClass(ref o, pclass); - } - if (rowspan > 1) - { - o.Append(" rowspan=\""); - o.Append(rowspan); - o.Append("\""); - } - if (colspan > 1) - { - o.Append(" colspan=\""); - o.Append(colspan); - o.Append("\""); - } - o.Append(">"); - } - - public static void TD_C(ref StringBuilder o) - { - o.Append(""); - } - - public static void TABLE_O(ref StringBuilder o, string pclass) - { - o.Append(" 0) - { - GenericClass(ref o, pclass); - } - o.Append(">\n\t"); - } - - public static void TABLE_C(ref StringBuilder o) - { - o.Append("\n"); - } - - public static void BLOCKQUOTE_O(ref StringBuilder o, string pclass) - { - o.Append(" 0) - { - GenericClass(ref o, pclass); - } - o.Append(" />\n"); - } - - public static void BLOCKQUOTE_C(ref StringBuilder o) - { - o.Append("\n"); - } - - public static void BR(ref StringBuilder o) - { - o.Append("
\n"); - } - - public static void HR(ref StringBuilder o, string pclass) - { - o.Append(" 0) - { - GenericClass(ref o, pclass); - } - o.Append(" />\n"); - } - - public static void UL_O(ref StringBuilder o, string pclass) - { - o.Append(" 0) - { - GenericClass(ref o, pclass); - } - o.Append(" />\n"); - } - - public static void UL_C(ref StringBuilder o) - { - o.Append("\n"); - } - - public static void OL_O(ref StringBuilder o, string pclass) - { - o.Append(" 0) - { - GenericClass(ref o, pclass); - } - o.Append(" />\n"); - } - - public static void OL_C(ref StringBuilder o) - { - o.Append("\n"); - } - - public static void LI_O(ref StringBuilder o, string pclass) - { - o.Append(" 0) - { - GenericClass(ref o, pclass); - } - o.Append(" />\n"); - } - - public static void LI_C(ref StringBuilder o) - { - o.Append("\n"); - } - - public static void GenericClass(ref StringBuilder o, string pclass) - { - o.Append(" class=\""); - o.Append(pclass); - o.Append("\""); - } - - public static void InsertProtoTypeAJAX(ref StringBuilder o) - { - o.Append("\n"); - o.Append("\n"); - } - - public static void InsertPeriodicUpdaters(ref StringBuilder o, string[] divID, int[] seconds, string[] reportfrag) - { - o.Append(""); - } - - public static void HtmlHeaders_O(ref StringBuilder o) - { - o.Append("\n"); - o.Append(""); - o.Append(""); - } - - public static void HtmlHeaders_C(ref StringBuilder o) - { - o.Append(""); - o.Append(""); - } - - public static void AddReportLinks(ref StringBuilder o, Dictionary reports, string pClass) - { - int repcount = 0; - foreach (string str in reports.Keys) - { - if (reports[str].ReportName.Length > 0) - { - if (repcount > 0) - { - o.Append("|  "); - } - A(ref o, reports[str].ReportName, str, pClass); - o.Append("  "); - repcount++; - } - } - } - - public static void A(ref StringBuilder o, string linktext, string linkhref, string pClass) - { - o.Append(" 0) - { - GenericClass(ref o, pClass); - } - o.Append(" href=\""); - o.Append(linkhref); - o.Append("\">"); - o.Append(linktext); - o.Append(""); - } - } -} diff --git a/OpenSim/Region/UserStatistics/IStatsReport.cs b/OpenSim/Region/UserStatistics/IStatsReport.cs deleted file mode 100644 index e0ecce4..0000000 --- a/OpenSim/Region/UserStatistics/IStatsReport.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Collections; - -namespace OpenSim.Region.UserStatistics -{ - public interface IStatsController - { - string ReportName { get; } - Hashtable ProcessModel(Hashtable pParams); - string RenderView(Hashtable pModelResult); - } -} diff --git a/OpenSim/Region/UserStatistics/LogLinesAJAX.cs b/OpenSim/Region/UserStatistics/LogLinesAJAX.cs deleted file mode 100644 index 74de46b..0000000 --- a/OpenSim/Region/UserStatistics/LogLinesAJAX.cs +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using Mono.Data.SqliteClient; -using OpenMetaverse; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Framework.Monitoring; - -namespace OpenSim.Region.UserStatistics -{ - public class LogLinesAJAX : IStatsController - { - private Regex normalizeEndLines = new Regex(@"\r\n", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline); - - private Regex webFormat = new Regex(@"[^\s]*\s([^,]*),[^\s]*\s([A-Z]*)[^\s-][^\[]*\[([^\]]*)\]([^\n]*)", - RegexOptions.Singleline | RegexOptions.Compiled); - private Regex TitleColor = new Regex(@"[^\s]*\s(?:[^,]*),[^\s]*\s(?:[A-Z]*)[^\s-][^\[]*\[([^\]]*)\](?:[^\n]*)", - RegexOptions.Singleline | RegexOptions.Compiled); - - - #region IStatsController Members - - public string ReportName - { - get { return ""; } - } - - public Hashtable ProcessModel(Hashtable pParams) - { - Hashtable nh = new Hashtable(); - nh.Add("loglines", pParams["LogLines"]); - return nh; - } - - public string RenderView(Hashtable pModelResult) - { - StringBuilder output = new StringBuilder(); - - HTMLUtil.HR(ref output, ""); - output.Append("

ActiveLog

\n"); - - string tmp = normalizeEndLines.Replace(pModelResult["loglines"].ToString(), "\n"); - - string[] result = Regex.Split(tmp, "\n"); - - string formatopen = ""; - string formatclose = ""; - - for (int i = 0; i < result.Length; i++) - { - if (result[i].Length >= 30) - { - string logtype = result[i].Substring(24, 6); - switch (logtype) - { - case "WARN ": - formatopen = ""; - formatclose = ""; - break; - - case "ERROR ": - formatopen = ""; - formatclose = ""; - break; - - default: - formatopen = ""; - formatclose = ""; - break; - - } - } - StringBuilder replaceStr = new StringBuilder(); - //string titlecolorresults = - - string formatresult = Regex.Replace(TitleColor.Replace(result[i], "$1"), "[^ABCDEFabcdef0-9]", ""); - if (formatresult.Length > 6) - { - formatresult = formatresult.Substring(0, 6); - - } - for (int j = formatresult.Length; j <= 5; j++) - formatresult += "0"; - replaceStr.Append("$1 - [$3] $4
"); - string repstr = replaceStr.ToString(); - - output.Append(formatopen); - output.Append(webFormat.Replace(result[i], repstr)); - output.Append(formatclose); - } - - - return output.ToString(); - } - - #endregion - } -} diff --git a/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs b/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs deleted file mode 100644 index 100cf99..0000000 --- a/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenSim.Region.UserStatistics")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("http://opensimulator.org")] -[assembly: AssemblyProduct("OpenSim")] -[assembly: AssemblyCopyright("OpenSimulator developers")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("42b28288-5fdd-478f-8903-8dccbbb2d5f9")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Region/UserStatistics/Prototype_distributor.cs b/OpenSim/Region/UserStatistics/Prototype_distributor.cs deleted file mode 100644 index 53ae557..0000000 --- a/OpenSim/Region/UserStatistics/Prototype_distributor.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using OpenSim.Framework; - -namespace OpenSim.Region.UserStatistics -{ - public class Prototype_distributor : IStatsController - { - private string prototypejs=string.Empty; - - public string ReportName - { - get { return ""; } - } - public Hashtable ProcessModel(Hashtable pParams) - { - Hashtable pResult = new Hashtable(); - if (prototypejs.Length == 0) - { - StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/prototype.js", FileMode.Open)); - prototypejs = fs.ReadToEnd(); - fs.Close(); - fs.Dispose(); - } - pResult["js"] = prototypejs; - return pResult; - } - - public string RenderView(Hashtable pModelResult) - { - return pModelResult["js"].ToString(); - } - - } -} diff --git a/OpenSim/Region/UserStatistics/Sessions_Report.cs b/OpenSim/Region/UserStatistics/Sessions_Report.cs deleted file mode 100644 index 1a2d460..0000000 --- a/OpenSim/Region/UserStatistics/Sessions_Report.cs +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using Mono.Data.SqliteClient; -using OpenMetaverse; -using OpenSim.Framework; - -namespace OpenSim.Region.UserStatistics -{ - public class Sessions_Report : IStatsController - { - #region IStatsController Members - - public string ReportName - { - get { return "Sessions"; } - } - - public Hashtable ProcessModel(Hashtable pParams) - { - Hashtable modeldata = new Hashtable(); - modeldata.Add("Scenes", pParams["Scenes"]); - modeldata.Add("Reports", pParams["Reports"]); - SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"]; - List lstSessions = new List(); - Hashtable requestvars = (Hashtable) pParams["RequestVars"]; - - - string puserUUID = string.Empty; - string clientVersionString = string.Empty; - int queryparams = 0; - - if (requestvars != null) - { - if (requestvars.ContainsKey("UserID")) - { - UUID testUUID = UUID.Zero; - if (UUID.TryParse(requestvars["UserID"].ToString(), out testUUID)) - { - puserUUID = requestvars["UserID"].ToString(); - - } - } - - if (requestvars.ContainsKey("VersionString")) - { - clientVersionString = requestvars["VersionString"].ToString(); - } - } - - lock (dbConn) - { - string sql = - "SELECT distinct a.name_f, a.name_l, a.Agent_ID, b.Session_ID, b.client_version, b.last_updated, b.start_time FROM stats_session_data a LEFT OUTER JOIN stats_session_data b ON a.Agent_ID = b.Agent_ID"; - - if (puserUUID.Length > 0) - { - if (queryparams == 0) - sql += " WHERE"; - else - sql += " AND"; - - sql += " b.agent_id=:agent_id"; - queryparams++; - } - - if (clientVersionString.Length > 0) - { - if (queryparams == 0) - sql += " WHERE"; - else - sql += " AND"; - - sql += " b.client_version=:client_version"; - queryparams++; - } - - sql += " ORDER BY a.name_f, a.name_l, b.last_updated;"; - - SqliteCommand cmd = new SqliteCommand(sql, dbConn); - - if (puserUUID.Length > 0) - cmd.Parameters.Add(new SqliteParameter(":agent_id", puserUUID)); - if (clientVersionString.Length > 0) - cmd.Parameters.Add(new SqliteParameter(":client_version", clientVersionString)); - - SqliteDataReader sdr = cmd.ExecuteReader(); - - if (sdr.HasRows) - { - UUID userUUID = UUID.Zero; - - SessionList activeSessionList = new SessionList(); - activeSessionList.user_id=UUID.Random(); - while (sdr.Read()) - { - UUID readUUID = UUID.Parse(sdr["agent_id"].ToString()); - if (readUUID != userUUID) - { - activeSessionList = new SessionList(); - activeSessionList.user_id = readUUID; - activeSessionList.firstname = sdr["name_f"].ToString(); - activeSessionList.lastname = sdr["name_l"].ToString(); - activeSessionList.sessions = new List(); - lstSessions.Add(activeSessionList); - } - - ShortSessionData ssd = new ShortSessionData(); - - ssd.last_update = Utils.UnixTimeToDateTime((uint)Convert.ToInt32(sdr["last_updated"])); - ssd.start_time = Utils.UnixTimeToDateTime((uint)Convert.ToInt32(sdr["start_time"])); - ssd.session_id = UUID.Parse(sdr["session_id"].ToString()); - ssd.client_version = sdr["client_version"].ToString(); - activeSessionList.sessions.Add(ssd); - - userUUID = activeSessionList.user_id; - } - } - sdr.Close(); - sdr.Dispose(); - - } - modeldata["SessionData"] = lstSessions; - return modeldata; - } - - public string RenderView(Hashtable pModelResult) - { - List lstSession = (List) pModelResult["SessionData"]; - Dictionary reports = (Dictionary)pModelResult["Reports"]; - - const string STYLESHEET = - @" - -"; - - StringBuilder output = new StringBuilder(); - HTMLUtil.HtmlHeaders_O(ref output); - output.Append(STYLESHEET); - HTMLUtil.HtmlHeaders_C(ref output); - - HTMLUtil.AddReportLinks(ref output, reports, ""); - - HTMLUtil.TABLE_O(ref output, "defaultr"); - HTMLUtil.TR_O(ref output, "defaultr"); - HTMLUtil.TD_O(ref output, "header"); - output.Append("FirstName"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "header"); - output.Append("LastName"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "header"); - output.Append("SessionEnd"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "header"); - output.Append("SessionLength"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "header"); - output.Append("Client"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - if (lstSession.Count == 0) - { - HTMLUtil.TR_O(ref output, ""); - HTMLUtil.TD_O(ref output, "align_top", 1, 5); - output.Append("No results for that query"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - } - foreach (SessionList ssnlst in lstSession) - { - int cnt = 0; - foreach (ShortSessionData sesdata in ssnlst.sessions) - { - HTMLUtil.TR_O(ref output, ""); - if (cnt++ == 0) - { - HTMLUtil.TD_O(ref output, "align_top", ssnlst.sessions.Count, 1); - output.Append(ssnlst.firstname); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "align_top", ssnlst.sessions.Count, 1); - output.Append(ssnlst.lastname); - HTMLUtil.TD_C(ref output); - } - HTMLUtil.TD_O(ref output, "content"); - output.Append(sesdata.last_update.ToShortDateString()); - output.Append(" - "); - output.Append(sesdata.last_update.ToShortTimeString()); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "content"); - TimeSpan dtlength = sesdata.last_update.Subtract(sesdata.start_time); - if (dtlength.Days > 0) - { - output.Append(dtlength.Days); - output.Append(" Days "); - } - if (dtlength.Hours > 0) - { - output.Append(dtlength.Hours); - output.Append(" Hours "); - } - if (dtlength.Minutes > 0) - { - output.Append(dtlength.Minutes); - output.Append(" Minutes"); - } - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, "content"); - output.Append(sesdata.client_version); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - - } - HTMLUtil.TR_O(ref output, ""); - HTMLUtil.TD_O(ref output, "align_top", 1, 5); - HTMLUtil.HR(ref output, ""); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - } - HTMLUtil.TABLE_C(ref output); - output.Append("\n"); - return output.ToString(); - } - - public class SessionList - { - public string firstname; - public string lastname; - public UUID user_id; - public List sessions; - } - - public struct ShortSessionData - { - public UUID session_id; - public string client_version; - public DateTime last_update; - public DateTime start_time; - } - - #endregion - } -} diff --git a/OpenSim/Region/UserStatistics/SimStatsAJAX.cs b/OpenSim/Region/UserStatistics/SimStatsAJAX.cs deleted file mode 100644 index 28051fb..0000000 --- a/OpenSim/Region/UserStatistics/SimStatsAJAX.cs +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using System.Text; -using Mono.Data.SqliteClient; -using OpenMetaverse; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Framework.Monitoring; - -namespace OpenSim.Region.UserStatistics -{ - public class SimStatsAJAX : IStatsController - { - #region IStatsController Members - - public string ReportName - { - get { return ""; } - } - - public Hashtable ProcessModel(Hashtable pParams) - { - List m_scene = (List)pParams["Scenes"]; - - Hashtable nh = new Hashtable(); - nh.Add("hdata", m_scene); - nh.Add("simstats", pParams["SimStats"]); - return nh; - } - - public string RenderView(Hashtable pModelResult) - { - StringBuilder output = new StringBuilder(); - List all_scenes = (List) pModelResult["hdata"]; - Dictionary sdatadic = (Dictionary)pModelResult["simstats"]; - - const string TableClass = "defaultr"; - const string TRClass = "defaultr"; - const string TDHeaderClass = "header"; - const string TDDataClass = "content"; - //const string TDDataClassRight = "contentright"; - const string TDDataClassCenter = "contentcenter"; - - foreach (USimStatsData sdata in sdatadic.Values) - { - - - foreach (Scene sn in all_scenes) - { - if (sn.RegionInfo.RegionID == sdata.RegionId) - { - output.Append("

"); - output.Append(sn.RegionInfo.RegionName); - output.Append("

"); - } - } - HTMLUtil.TABLE_O(ref output, TableClass); - HTMLUtil.TR_O(ref output, TRClass); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("Dilatn"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("SimFPS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("PhysFPS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("AgntUp"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("RootAg"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("ChldAg"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("Prims"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("ATvPrm"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("AtvScr"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("ScrLPS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - HTMLUtil.TR_O(ref output, TRClass); - HTMLUtil.TD_O(ref output, TDDataClass); - output.Append(sdata.TimeDilation); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClass); - output.Append(sdata.SimFps); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.PhysicsFps); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.AgentUpdates); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.RootAgents); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.ChildAgents); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.TotalPrims); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.ActivePrims); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.ActiveScripts); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.ScriptLinesPerSecond); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - HTMLUtil.TR_O(ref output, TRClass); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("FrmMS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("AgtMS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("PhysMS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("OthrMS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("ScrLPS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("OutPPS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("InPPS"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("NoAckKB"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("PndDWN"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDHeaderClass); - output.Append("PndUP"); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - HTMLUtil.TR_O(ref output, TRClass); - HTMLUtil.TD_O(ref output, TDDataClass); - output.Append(sdata.TotalFrameTime); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClass); - output.Append(sdata.AgentFrameTime); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.PhysicsFrameTime); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.OtherFrameTime); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.ScriptLinesPerSecond); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.OutPacketsPerSecond); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.InPacketsPerSecond); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.UnackedBytes); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.PendingDownloads); - HTMLUtil.TD_C(ref output); - HTMLUtil.TD_O(ref output, TDDataClassCenter); - output.Append(sdata.PendingUploads); - HTMLUtil.TD_C(ref output); - HTMLUtil.TR_C(ref output); - HTMLUtil.TABLE_C(ref output); - - } - - return output.ToString(); - } - - #endregion - } -} diff --git a/OpenSim/Region/UserStatistics/Updater_distributor.cs b/OpenSim/Region/UserStatistics/Updater_distributor.cs deleted file mode 100644 index 9593cc9..0000000 --- a/OpenSim/Region/UserStatistics/Updater_distributor.cs +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using OpenSim.Framework; - -namespace OpenSim.Region.UserStatistics -{ - public class Updater_distributor : IStatsController - { - private string updaterjs = string.Empty; - - public string ReportName - { - get { return ""; } - } - - public Hashtable ProcessModel(Hashtable pParams) - { - Hashtable pResult = new Hashtable(); - if (updaterjs.Length == 0) - { - StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/updater.js", FileMode.Open)); - updaterjs = fs.ReadToEnd(); - fs.Close(); - fs.Dispose(); - } - pResult["js"] = updaterjs; - return pResult; - } - - public string RenderView(Hashtable pModelResult) - { - return pModelResult["js"].ToString(); - } - - } -} \ No newline at end of file diff --git a/OpenSim/Region/UserStatistics/WebStatsModule.cs b/OpenSim/Region/UserStatistics/WebStatsModule.cs deleted file mode 100644 index 64cb577..0000000 --- a/OpenSim/Region/UserStatistics/WebStatsModule.cs +++ /dev/null @@ -1,1183 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Net; // to be used for REST-->Grid shortly -using System.Reflection; -using System.Text; -using System.Threading; -using log4net; -using Nini.Config; -using OpenMetaverse; -using OpenMetaverse.StructuredData; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; -using Mono.Data.SqliteClient; -using Mono.Addins; - -using Caps = OpenSim.Framework.Capabilities.Caps; - -using OSD = OpenMetaverse.StructuredData.OSD; -using OSDMap = OpenMetaverse.StructuredData.OSDMap; - -[assembly: Addin("WebStats", "1.0")] -[assembly: AddinDependency("OpenSim", "0.5")] - -namespace OpenSim.Region.UserStatistics -{ - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebStatsModule")] - public class WebStatsModule : ISharedRegionModule - { - private static readonly ILog m_log = - LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private static SqliteConnection dbConn; - - /// - /// User statistics sessions keyed by agent ID - /// - private Dictionary m_sessions = new Dictionary(); - - private List m_scenes = new List(); - private Dictionary reports = new Dictionary(); - private Dictionary m_simstatsCounters = new Dictionary(); - private const int updateStatsMod = 6; - private int updateLogMod = 1; - private volatile int updateLogCounter = 0; - private volatile int concurrencyCounter = 0; - private bool enabled = false; - private string m_loglines = String.Empty; - private volatile int lastHit = 12000; - - #region ISharedRegionModule - - public virtual void Initialise(IConfigSource config) - { - IConfig cnfg = config.Configs["WebStats"]; - - if (cnfg != null) - enabled = cnfg.GetBoolean("enabled", false); - } - - public virtual void PostInitialise() - { - if (!enabled) - return; - - if (Util.IsWindows()) - Util.LoadArchSpecificWindowsDll("sqlite3.dll"); - - //IConfig startupConfig = config.Configs["Startup"]; - - dbConn = new SqliteConnection("URI=file:LocalUserStatistics.db,version=3"); - dbConn.Open(); - CreateTables(dbConn); - - Prototype_distributor protodep = new Prototype_distributor(); - Updater_distributor updatedep = new Updater_distributor(); - ActiveConnectionsAJAX ajConnections = new ActiveConnectionsAJAX(); - SimStatsAJAX ajSimStats = new SimStatsAJAX(); - LogLinesAJAX ajLogLines = new LogLinesAJAX(); - Default_Report defaultReport = new Default_Report(); - Clients_report clientReport = new Clients_report(); - Sessions_Report sessionsReport = new Sessions_Report(); - - reports.Add("prototype.js", protodep); - reports.Add("updater.js", updatedep); - reports.Add("activeconnectionsajax.html", ajConnections); - reports.Add("simstatsajax.html", ajSimStats); - reports.Add("activelogajax.html", ajLogLines); - reports.Add("default.report", defaultReport); - reports.Add("clients.report", clientReport); - reports.Add("sessions.report", sessionsReport); - - //// - // Add Your own Reports here (Do Not Modify Lines here Devs!) - //// - - //// - // End Own reports section - //// - - MainServer.Instance.AddHTTPHandler("/SStats/", HandleStatsRequest); - MainServer.Instance.AddHTTPHandler("/CAPS/VS/", HandleUnknownCAPSRequest); - } - - public virtual void AddRegion(Scene scene) - { - if (!enabled) - return; - - lock (m_scenes) - { - m_scenes.Add(scene); - updateLogMod = m_scenes.Count * 2; - - m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID)); - - scene.EventManager.OnRegisterCaps += OnRegisterCaps; - scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps; - scene.EventManager.OnClientClosed += OnClientClosed; - scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; - scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket; - } - } - - public void RegionLoaded(Scene scene) - { - } - - public void RemoveRegion(Scene scene) - { - if (!enabled) - return; - - lock (m_scenes) - { - m_scenes.Remove(scene); - updateLogMod = m_scenes.Count * 2; - m_simstatsCounters.Remove(scene.RegionInfo.RegionID); - } - } - - public virtual void Close() - { - if (!enabled) - return; - - dbConn.Close(); - dbConn.Dispose(); - m_sessions.Clear(); - m_scenes.Clear(); - reports.Clear(); - m_simstatsCounters.Clear(); - } - - public virtual string Name - { - get { return "ViewerStatsModule"; } - } - - public Type ReplaceableInterface - { - get { return null; } - } - - #endregion - - private void ReceiveClassicSimStatsPacket(SimStats stats) - { - if (!enabled) - return; - - try - { - // Ignore the update if there's a report running right now - // ignore the update if there hasn't been a hit in 30 seconds. - if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000) - return; - - // We will conduct this under lock so that fields such as updateLogCounter do not potentially get - // confused if a scene is removed. - // XXX: Possibly the scope of this lock could be reduced though it's not critical. - lock (m_scenes) - { - if (updateLogMod != 0 && updateLogCounter++ % updateLogMod == 0) - { - m_loglines = readLogLines(10); - - if (updateLogCounter > 10000) - updateLogCounter = 1; - } - - USimStatsData ss = m_simstatsCounters[stats.RegionUUID]; - - if ((++ss.StatsCounter % updateStatsMod) == 0) - { - ss.ConsumeSimStats(stats); - } - } - } - catch (KeyNotFoundException) - { - } - } - - private Hashtable HandleUnknownCAPSRequest(Hashtable request) - { - //string regpath = request["uri"].ToString(); - int response_code = 200; - string contenttype = "text/html"; - UpdateUserStats(ParseViewerStats(request["body"].ToString(), UUID.Zero), dbConn); - Hashtable responsedata = new Hashtable(); - - responsedata["int_response_code"] = response_code; - responsedata["content_type"] = contenttype; - responsedata["keepalive"] = false; - responsedata["str_response_string"] = string.Empty; - return responsedata; - } - - private Hashtable HandleStatsRequest(Hashtable request) - { - lastHit = System.Environment.TickCount; - Hashtable responsedata = new Hashtable(); - string regpath = request["uri"].ToString(); - int response_code = 404; - string contenttype = "text/html"; - - string strOut = string.Empty; - - regpath = regpath.Remove(0, 8); - if (regpath.Length == 0) regpath = "default.report"; - if (reports.ContainsKey(regpath)) - { - IStatsController rep = reports[regpath]; - Hashtable repParams = new Hashtable(); - - if (request.ContainsKey("requestvars")) - repParams["RequestVars"] = request["requestvars"]; - else - repParams["RequestVars"] = new Hashtable(); - - if (request.ContainsKey("querystringkeys")) - repParams["QueryStringKeys"] = request["querystringkeys"]; - else - repParams["QueryStringKeys"] = new string[0]; - - - repParams["DatabaseConnection"] = dbConn; - repParams["Scenes"] = m_scenes; - repParams["SimStats"] = m_simstatsCounters; - repParams["LogLines"] = m_loglines; - repParams["Reports"] = reports; - - concurrencyCounter++; - - strOut = rep.RenderView(rep.ProcessModel(repParams)); - - if (regpath.EndsWith("js")) - { - contenttype = "text/javascript"; - } - - concurrencyCounter--; - - response_code = 200; - } - else - { - strOut = MainServer.Instance.GetHTTP404(""); - } - - responsedata["int_response_code"] = response_code; - responsedata["content_type"] = contenttype; - responsedata["keepalive"] = false; - responsedata["str_response_string"] = strOut; - - return responsedata; - } - - private void CreateTables(SqliteConnection db) - { - using (SqliteCommand createcmd = new SqliteCommand(SQL_STATS_TABLE_CREATE, db)) - { - createcmd.ExecuteNonQuery(); - } - } - - private void OnRegisterCaps(UUID agentID, Caps caps) - { -// m_log.DebugFormat("[WEB STATS MODULE]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps); - - string capsPath = "/CAPS/VS/" + UUID.Random(); - caps.RegisterHandler( - "ViewerStats", - new RestStreamHandler( - "POST", - capsPath, - (request, path, param, httpRequest, httpResponse) - => ViewerStatsReport(request, path, param, agentID, caps), - "ViewerStats", - agentID.ToString())); - } - - private void OnDeRegisterCaps(UUID agentID, Caps caps) - { - } - - protected virtual void AddEventHandlers() - { - lock (m_scenes) - { - updateLogMod = m_scenes.Count * 2; - foreach (Scene scene in m_scenes) - { - scene.EventManager.OnRegisterCaps += OnRegisterCaps; - scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps; - scene.EventManager.OnClientClosed += OnClientClosed; - scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; - } - } - } - - private void OnMakeRootAgent(ScenePresence agent) - { -// m_log.DebugFormat( -// "[WEB STATS MODULE]: Looking for session {0} for {1} in {2}", -// agent.ControllingClient.SessionId, agent.Name, agent.Scene.Name); - - lock (m_sessions) - { - UserSession uid; - - if (!m_sessions.ContainsKey(agent.UUID)) - { - UserSessionData usd = UserSessionUtil.newUserSessionData(); - uid = new UserSession(); - uid.name_f = agent.Firstname; - uid.name_l = agent.Lastname; - uid.session_data = usd; - - m_sessions.Add(agent.UUID, uid); - } - else - { - uid = m_sessions[agent.UUID]; - } - - uid.region_id = agent.Scene.RegionInfo.RegionID; - uid.session_id = agent.ControllingClient.SessionId; - } - } - - private void OnClientClosed(UUID agentID, Scene scene) - { - lock (m_sessions) - { - if (m_sessions.ContainsKey(agentID) && m_sessions[agentID].region_id == scene.RegionInfo.RegionID) - { - m_sessions.Remove(agentID); - } - } - } - - private string readLogLines(int amount) - { - Encoding encoding = Encoding.ASCII; - int sizeOfChar = encoding.GetByteCount("\n"); - byte[] buffer = encoding.GetBytes("\n"); - string logfile = Util.logDir() + "/" + "OpenSim.log"; - FileStream fs = new FileStream(logfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - Int64 tokenCount = 0; - Int64 endPosition = fs.Length / sizeOfChar; - - for (Int64 position = sizeOfChar; position < endPosition; position += sizeOfChar) - { - fs.Seek(-position, SeekOrigin.End); - fs.Read(buffer, 0, buffer.Length); - - if (encoding.GetString(buffer) == "\n") - { - tokenCount++; - if (tokenCount == amount) - { - byte[] returnBuffer = new byte[fs.Length - fs.Position]; - fs.Read(returnBuffer, 0, returnBuffer.Length); - fs.Close(); - fs.Dispose(); - return encoding.GetString(returnBuffer); - } - } - } - - // handle case where number of tokens in file is less than numberOfTokens - fs.Seek(0, SeekOrigin.Begin); - buffer = new byte[fs.Length]; - fs.Read(buffer, 0, buffer.Length); - fs.Close(); - fs.Dispose(); - return encoding.GetString(buffer); - } - - /// - /// Callback for a viewerstats cap - /// - /// - /// - /// - /// - /// - /// - private string ViewerStatsReport(string request, string path, string param, - UUID agentID, Caps caps) - { -// m_log.DebugFormat("[WEB STATS MODULE]: Received viewer starts report from {0}", agentID); - - UpdateUserStats(ParseViewerStats(request, agentID), dbConn); - - return String.Empty; - } - - private UserSession ParseViewerStats(string request, UUID agentID) - { - UserSession uid = new UserSession(); - UserSessionData usd; - OSD message = OSDParser.DeserializeLLSDXml(request); - OSDMap mmap; - - lock (m_sessions) - { - if (agentID != UUID.Zero) - { - if (!m_sessions.ContainsKey(agentID)) - { - m_log.WarnFormat("[WEB STATS MODULE]: no session for stat disclosure for agent {0}", agentID); - return new UserSession(); - } - - uid = m_sessions[agentID]; - -// m_log.DebugFormat("[WEB STATS MODULE]: Got session {0} for {1}", uid.session_id, agentID); - } - else - { - // parse through the beginning to locate the session - if (message.Type != OSDType.Map) - return new UserSession(); - - mmap = (OSDMap)message; - { - UUID sessionID = mmap["session_id"].AsUUID(); - - if (sessionID == UUID.Zero) - return new UserSession(); - - - // search through each session looking for the owner - foreach (UUID usersessionid in m_sessions.Keys) - { - // got it! - if (m_sessions[usersessionid].session_id == sessionID) - { - agentID = usersessionid; - uid = m_sessions[usersessionid]; - break; - } - - } - - // can't find a session - if (agentID == UUID.Zero) - { - return new UserSession(); - } - } - } - } - - usd = uid.session_data; - - if (message.Type != OSDType.Map) - return new UserSession(); - - mmap = (OSDMap)message; - { - if (mmap["agent"].Type != OSDType.Map) - return new UserSession(); - OSDMap agent_map = (OSDMap)mmap["agent"]; - usd.agent_id = agentID; - usd.name_f = uid.name_f; - usd.name_l = uid.name_l; - usd.region_id = uid.region_id; - usd.a_language = agent_map["language"].AsString(); - usd.mem_use = (float)agent_map["mem_use"].AsReal(); - usd.meters_traveled = (float)agent_map["meters_traveled"].AsReal(); - usd.regions_visited = agent_map["regions_visited"].AsInteger(); - usd.run_time = (float)agent_map["run_time"].AsReal(); - usd.start_time = (float)agent_map["start_time"].AsReal(); - usd.client_version = agent_map["version"].AsString(); - - UserSessionUtil.UpdateMultiItems(ref usd, agent_map["agents_in_view"].AsInteger(), - (float)agent_map["ping"].AsReal(), - (float)agent_map["sim_fps"].AsReal(), - (float)agent_map["fps"].AsReal()); - - if (mmap["downloads"].Type != OSDType.Map) - return new UserSession(); - OSDMap downloads_map = (OSDMap)mmap["downloads"]; - usd.d_object_kb = (float)downloads_map["object_kbytes"].AsReal(); - usd.d_texture_kb = (float)downloads_map["texture_kbytes"].AsReal(); - usd.d_world_kb = (float)downloads_map["workd_kbytes"].AsReal(); - -// m_log.DebugFormat("[WEB STATS MODULE]: mmap[\"session_id\"] = [{0}]", mmap["session_id"].AsUUID()); - - usd.session_id = mmap["session_id"].AsUUID(); - - if (mmap["system"].Type != OSDType.Map) - return new UserSession(); - OSDMap system_map = (OSDMap)mmap["system"]; - - usd.s_cpu = system_map["cpu"].AsString(); - usd.s_gpu = system_map["gpu"].AsString(); - usd.s_os = system_map["os"].AsString(); - usd.s_ram = system_map["ram"].AsInteger(); - - if (mmap["stats"].Type != OSDType.Map) - return new UserSession(); - - OSDMap stats_map = (OSDMap)mmap["stats"]; - { - - if (stats_map["failures"].Type != OSDType.Map) - return new UserSession(); - OSDMap stats_failures = (OSDMap)stats_map["failures"]; - usd.f_dropped = stats_failures["dropped"].AsInteger(); - usd.f_failed_resends = stats_failures["failed_resends"].AsInteger(); - usd.f_invalid = stats_failures["invalid"].AsInteger(); - usd.f_resent = stats_failures["resent"].AsInteger(); - usd.f_send_packet = stats_failures["send_packet"].AsInteger(); - - if (stats_map["net"].Type != OSDType.Map) - return new UserSession(); - OSDMap stats_net = (OSDMap)stats_map["net"]; - { - if (stats_net["in"].Type != OSDType.Map) - return new UserSession(); - - OSDMap net_in = (OSDMap)stats_net["in"]; - usd.n_in_kb = (float)net_in["kbytes"].AsReal(); - usd.n_in_pk = net_in["packets"].AsInteger(); - - if (stats_net["out"].Type != OSDType.Map) - return new UserSession(); - OSDMap net_out = (OSDMap)stats_net["out"]; - - usd.n_out_kb = (float)net_out["kbytes"].AsReal(); - usd.n_out_pk = net_out["packets"].AsInteger(); - } - } - } - - uid.session_data = usd; - m_sessions[agentID] = uid; - -// m_log.DebugFormat( -// "[WEB STATS MODULE]: Parse data for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id); - - return uid; - } - - private void UpdateUserStats(UserSession uid, SqliteConnection db) - { -// m_log.DebugFormat( -// "[WEB STATS MODULE]: Updating user stats for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id); - - if (uid.session_id == UUID.Zero) - return; - - lock (db) - { - using (SqliteCommand updatecmd = new SqliteCommand(SQL_STATS_TABLE_INSERT, db)) - { - updatecmd.Parameters.Add(new SqliteParameter(":session_id", uid.session_data.session_id.ToString())); - updatecmd.Parameters.Add(new SqliteParameter(":agent_id", uid.session_data.agent_id.ToString())); - updatecmd.Parameters.Add(new SqliteParameter(":region_id", uid.session_data.region_id.ToString())); - updatecmd.Parameters.Add(new SqliteParameter(":last_updated", (int) uid.session_data.last_updated)); - updatecmd.Parameters.Add(new SqliteParameter(":remote_ip", uid.session_data.remote_ip)); - updatecmd.Parameters.Add(new SqliteParameter(":name_f", uid.session_data.name_f)); - updatecmd.Parameters.Add(new SqliteParameter(":name_l", uid.session_data.name_l)); - updatecmd.Parameters.Add(new SqliteParameter(":avg_agents_in_view", uid.session_data.avg_agents_in_view)); - updatecmd.Parameters.Add(new SqliteParameter(":min_agents_in_view", - (int) uid.session_data.min_agents_in_view)); - updatecmd.Parameters.Add(new SqliteParameter(":max_agents_in_view", - (int) uid.session_data.max_agents_in_view)); - updatecmd.Parameters.Add(new SqliteParameter(":mode_agents_in_view", - (int) uid.session_data.mode_agents_in_view)); - updatecmd.Parameters.Add(new SqliteParameter(":avg_fps", uid.session_data.avg_fps)); - updatecmd.Parameters.Add(new SqliteParameter(":min_fps", uid.session_data.min_fps)); - updatecmd.Parameters.Add(new SqliteParameter(":max_fps", uid.session_data.max_fps)); - updatecmd.Parameters.Add(new SqliteParameter(":mode_fps", uid.session_data.mode_fps)); - updatecmd.Parameters.Add(new SqliteParameter(":a_language", uid.session_data.a_language)); - updatecmd.Parameters.Add(new SqliteParameter(":mem_use", uid.session_data.mem_use)); - updatecmd.Parameters.Add(new SqliteParameter(":meters_traveled", uid.session_data.meters_traveled)); - updatecmd.Parameters.Add(new SqliteParameter(":avg_ping", uid.session_data.avg_ping)); - updatecmd.Parameters.Add(new SqliteParameter(":min_ping", uid.session_data.min_ping)); - updatecmd.Parameters.Add(new SqliteParameter(":max_ping", uid.session_data.max_ping)); - updatecmd.Parameters.Add(new SqliteParameter(":mode_ping", uid.session_data.mode_ping)); - updatecmd.Parameters.Add(new SqliteParameter(":regions_visited", uid.session_data.regions_visited)); - updatecmd.Parameters.Add(new SqliteParameter(":run_time", uid.session_data.run_time)); - updatecmd.Parameters.Add(new SqliteParameter(":avg_sim_fps", uid.session_data.avg_sim_fps)); - updatecmd.Parameters.Add(new SqliteParameter(":min_sim_fps", uid.session_data.min_sim_fps)); - updatecmd.Parameters.Add(new SqliteParameter(":max_sim_fps", uid.session_data.max_sim_fps)); - updatecmd.Parameters.Add(new SqliteParameter(":mode_sim_fps", uid.session_data.mode_sim_fps)); - updatecmd.Parameters.Add(new SqliteParameter(":start_time", uid.session_data.start_time)); - updatecmd.Parameters.Add(new SqliteParameter(":client_version", uid.session_data.client_version)); - updatecmd.Parameters.Add(new SqliteParameter(":s_cpu", uid.session_data.s_cpu)); - updatecmd.Parameters.Add(new SqliteParameter(":s_gpu", uid.session_data.s_gpu)); - updatecmd.Parameters.Add(new SqliteParameter(":s_os", uid.session_data.s_os)); - updatecmd.Parameters.Add(new SqliteParameter(":s_ram", uid.session_data.s_ram)); - updatecmd.Parameters.Add(new SqliteParameter(":d_object_kb", uid.session_data.d_object_kb)); - updatecmd.Parameters.Add(new SqliteParameter(":d_texture_kb", uid.session_data.d_texture_kb)); - updatecmd.Parameters.Add(new SqliteParameter(":d_world_kb", uid.session_data.d_world_kb)); - updatecmd.Parameters.Add(new SqliteParameter(":n_in_kb", uid.session_data.n_in_kb)); - updatecmd.Parameters.Add(new SqliteParameter(":n_in_pk", uid.session_data.n_in_pk)); - updatecmd.Parameters.Add(new SqliteParameter(":n_out_kb", uid.session_data.n_out_kb)); - updatecmd.Parameters.Add(new SqliteParameter(":n_out_pk", uid.session_data.n_out_pk)); - updatecmd.Parameters.Add(new SqliteParameter(":f_dropped", uid.session_data.f_dropped)); - updatecmd.Parameters.Add(new SqliteParameter(":f_failed_resends", uid.session_data.f_failed_resends)); - updatecmd.Parameters.Add(new SqliteParameter(":f_invalid", uid.session_data.f_invalid)); - updatecmd.Parameters.Add(new SqliteParameter(":f_off_circuit", uid.session_data.f_off_circuit)); - updatecmd.Parameters.Add(new SqliteParameter(":f_resent", uid.session_data.f_resent)); - updatecmd.Parameters.Add(new SqliteParameter(":f_send_packet", uid.session_data.f_send_packet)); - -// StringBuilder parameters = new StringBuilder(); -// SqliteParameterCollection spc = updatecmd.Parameters; -// foreach (SqliteParameter sp in spc) -// parameters.AppendFormat("{0}={1},", sp.ParameterName, sp.Value); -// -// m_log.DebugFormat("[WEB STATS MODULE]: Parameters {0}", parameters); - -// m_log.DebugFormat("[WEB STATS MODULE]: Database stats update for {0}", uid.session_data.agent_id); - - updatecmd.ExecuteNonQuery(); - } - } - } - - #region SQL - private const string SQL_STATS_TABLE_CREATE = @"CREATE TABLE IF NOT EXISTS stats_session_data ( - session_id VARCHAR(36) NOT NULL PRIMARY KEY, - agent_id VARCHAR(36) NOT NULL DEFAULT '', - region_id VARCHAR(36) NOT NULL DEFAULT '', - last_updated INT NOT NULL DEFAULT '0', - remote_ip VARCHAR(16) NOT NULL DEFAULT '', - name_f VARCHAR(50) NOT NULL DEFAULT '', - name_l VARCHAR(50) NOT NULL DEFAULT '', - avg_agents_in_view FLOAT NOT NULL DEFAULT '0', - min_agents_in_view INT NOT NULL DEFAULT '0', - max_agents_in_view INT NOT NULL DEFAULT '0', - mode_agents_in_view INT NOT NULL DEFAULT '0', - avg_fps FLOAT NOT NULL DEFAULT '0', - min_fps FLOAT NOT NULL DEFAULT '0', - max_fps FLOAT NOT NULL DEFAULT '0', - mode_fps FLOAT NOT NULL DEFAULT '0', - a_language VARCHAR(25) NOT NULL DEFAULT '', - mem_use FLOAT NOT NULL DEFAULT '0', - meters_traveled FLOAT NOT NULL DEFAULT '0', - avg_ping FLOAT NOT NULL DEFAULT '0', - min_ping FLOAT NOT NULL DEFAULT '0', - max_ping FLOAT NOT NULL DEFAULT '0', - mode_ping FLOAT NOT NULL DEFAULT '0', - regions_visited INT NOT NULL DEFAULT '0', - run_time FLOAT NOT NULL DEFAULT '0', - avg_sim_fps FLOAT NOT NULL DEFAULT '0', - min_sim_fps FLOAT NOT NULL DEFAULT '0', - max_sim_fps FLOAT NOT NULL DEFAULT '0', - mode_sim_fps FLOAT NOT NULL DEFAULT '0', - start_time FLOAT NOT NULL DEFAULT '0', - client_version VARCHAR(255) NOT NULL DEFAULT '', - s_cpu VARCHAR(255) NOT NULL DEFAULT '', - s_gpu VARCHAR(255) NOT NULL DEFAULT '', - s_os VARCHAR(2255) NOT NULL DEFAULT '', - s_ram INT NOT NULL DEFAULT '0', - d_object_kb FLOAT NOT NULL DEFAULT '0', - d_texture_kb FLOAT NOT NULL DEFAULT '0', - d_world_kb FLOAT NOT NULL DEFAULT '0', - n_in_kb FLOAT NOT NULL DEFAULT '0', - n_in_pk INT NOT NULL DEFAULT '0', - n_out_kb FLOAT NOT NULL DEFAULT '0', - n_out_pk INT NOT NULL DEFAULT '0', - f_dropped INT NOT NULL DEFAULT '0', - f_failed_resends INT NOT NULL DEFAULT '0', - f_invalid INT NOT NULL DEFAULT '0', - f_off_circuit INT NOT NULL DEFAULT '0', - f_resent INT NOT NULL DEFAULT '0', - f_send_packet INT NOT NULL DEFAULT '0' - );"; - - private const string SQL_STATS_TABLE_INSERT = @"INSERT OR REPLACE INTO stats_session_data ( -session_id, agent_id, region_id, last_updated, remote_ip, name_f, name_l, avg_agents_in_view, min_agents_in_view, max_agents_in_view, -mode_agents_in_view, avg_fps, min_fps, max_fps, mode_fps, a_language, mem_use, meters_traveled, avg_ping, min_ping, max_ping, mode_ping, -regions_visited, run_time, avg_sim_fps, min_sim_fps, max_sim_fps, mode_sim_fps, start_time, client_version, s_cpu, s_gpu, s_os, s_ram, -d_object_kb, d_texture_kb, d_world_kb, n_in_kb, n_in_pk, n_out_kb, n_out_pk, f_dropped, f_failed_resends, f_invalid, f_off_circuit, -f_resent, f_send_packet -) -VALUES -( -:session_id, :agent_id, :region_id, :last_updated, :remote_ip, :name_f, :name_l, :avg_agents_in_view, :min_agents_in_view, :max_agents_in_view, -:mode_agents_in_view, :avg_fps, :min_fps, :max_fps, :mode_fps, :a_language, :mem_use, :meters_traveled, :avg_ping, :min_ping, :max_ping, :mode_ping, -:regions_visited, :run_time, :avg_sim_fps, :min_sim_fps, :max_sim_fps, :mode_sim_fps, :start_time, :client_version, :s_cpu, :s_gpu, :s_os, :s_ram, -:d_object_kb, :d_texture_kb, :d_world_kb, :n_in_kb, :n_in_pk, :n_out_kb, :n_out_pk, :f_dropped, :f_failed_resends, :f_invalid, :f_off_circuit, -:f_resent, :f_send_packet -) -"; - - #endregion - - } - - public static class UserSessionUtil - { - public static UserSessionData newUserSessionData() - { - UserSessionData obj = ZeroSession(new UserSessionData()); - return obj; - } - - public static void UpdateMultiItems(ref UserSessionData s, int agents_in_view, float ping, float sim_fps, float fps) - { - // don't insert zero values here or it'll skew the statistics. - if (agents_in_view == 0 && fps == 0 && sim_fps == 0 && ping == 0) - return; - s._agents_in_view.Add(agents_in_view); - s._fps.Add(fps); - s._sim_fps.Add(sim_fps); - s._ping.Add(ping); - - int[] __agents_in_view = s._agents_in_view.ToArray(); - - s.avg_agents_in_view = ArrayAvg_i(__agents_in_view); - s.min_agents_in_view = ArrayMin_i(__agents_in_view); - s.max_agents_in_view = ArrayMax_i(__agents_in_view); - s.mode_agents_in_view = ArrayMode_i(__agents_in_view); - - float[] __fps = s._fps.ToArray(); - s.avg_fps = ArrayAvg_f(__fps); - s.min_fps = ArrayMin_f(__fps); - s.max_fps = ArrayMax_f(__fps); - s.mode_fps = ArrayMode_f(__fps); - - float[] __sim_fps = s._sim_fps.ToArray(); - s.avg_sim_fps = ArrayAvg_f(__sim_fps); - s.min_sim_fps = ArrayMin_f(__sim_fps); - s.max_sim_fps = ArrayMax_f(__sim_fps); - s.mode_sim_fps = ArrayMode_f(__sim_fps); - - float[] __ping = s._ping.ToArray(); - s.avg_ping = ArrayAvg_f(__ping); - s.min_ping = ArrayMin_f(__ping); - s.max_ping = ArrayMax_f(__ping); - s.mode_ping = ArrayMode_f(__ping); - } - - #region Statistics - - public static int ArrayMin_i(int[] arr) - { - int cnt = arr.Length; - if (cnt == 0) - return 0; - - Array.Sort(arr); - return arr[0]; - } - - public static int ArrayMax_i(int[] arr) - { - int cnt = arr.Length; - if (cnt == 0) - return 0; - - Array.Sort(arr); - return arr[cnt-1]; - } - - public static float ArrayMin_f(float[] arr) - { - int cnt = arr.Length; - if (cnt == 0) - return 0; - - Array.Sort(arr); - return arr[0]; - } - - public static float ArrayMax_f(float[] arr) - { - int cnt = arr.Length; - if (cnt == 0) - return 0; - - Array.Sort(arr); - return arr[cnt - 1]; - } - - public static float ArrayAvg_i(int[] arr) - { - int cnt = arr.Length; - - if (cnt == 0) - return 0; - - float result = arr[0]; - - for (int i = 1; i < cnt; i++) - result += arr[i]; - - return result / cnt; - } - - public static float ArrayAvg_f(float[] arr) - { - int cnt = arr.Length; - - if (cnt == 0) - return 0; - - float result = arr[0]; - - for (int i = 1; i < cnt; i++) - result += arr[i]; - - return result / cnt; - } - - public static float ArrayMode_f(float[] arr) - { - List mode = new List(); - - float[] srtArr = new float[arr.Length]; - float[,] freq = new float[arr.Length, 2]; - Array.Copy(arr, srtArr, arr.Length); - Array.Sort(srtArr); - - float tmp = srtArr[0]; - int index = 0; - int i = 0; - while (i < srtArr.Length) - { - freq[index, 0] = tmp; - - while (tmp == srtArr[i]) - { - freq[index, 1]++; - i++; - - if (i > srtArr.Length - 1) - break; - } - - if (i < srtArr.Length) - { - tmp = srtArr[i]; - index++; - } - - } - - Array.Clear(srtArr, 0, srtArr.Length); - - for (i = 0; i < srtArr.Length; i++) - srtArr[i] = freq[i, 1]; - - Array.Sort(srtArr); - - if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1) - return 0; - - float freqtest = (float)freq.Length / freq.Rank; - - for (i = 0; i < freqtest; i++) - { - if (freq[i, 1] == srtArr[index]) - mode.Add(freq[i, 0]); - - } - - return mode.ToArray()[0]; - } - - public static int ArrayMode_i(int[] arr) - { - List mode = new List(); - - int[] srtArr = new int[arr.Length]; - int[,] freq = new int[arr.Length, 2]; - Array.Copy(arr, srtArr, arr.Length); - Array.Sort(srtArr); - - int tmp = srtArr[0]; - int index = 0; - int i = 0; - while (i < srtArr.Length) - { - freq[index, 0] = tmp; - - while (tmp == srtArr[i]) - { - freq[index, 1]++; - i++; - - if (i > srtArr.Length - 1) - break; - } - - if (i < srtArr.Length) - { - tmp = srtArr[i]; - index++; - } - - } - - Array.Clear(srtArr, 0, srtArr.Length); - - for (i = 0; i < srtArr.Length; i++) - srtArr[i] = freq[i, 1]; - - Array.Sort(srtArr); - - if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1) - return 0; - - float freqtest = (float)freq.Length / freq.Rank; - - for (i = 0; i < freqtest; i++) - { - if (freq[i, 1] == srtArr[index]) - mode.Add(freq[i, 0]); - - } - - return mode.ToArray()[0]; - } - - #endregion - - private static UserSessionData ZeroSession(UserSessionData s) - { - s.session_id = UUID.Zero; - s.agent_id = UUID.Zero; - s.region_id = UUID.Zero; - s.last_updated = Util.UnixTimeSinceEpoch(); - s.remote_ip = ""; - s.name_f = ""; - s.name_l = ""; - s.avg_agents_in_view = 0; - s.min_agents_in_view = 0; - s.max_agents_in_view = 0; - s.mode_agents_in_view = 0; - s.avg_fps = 0; - s.min_fps = 0; - s.max_fps = 0; - s.mode_fps = 0; - s.a_language = ""; - s.mem_use = 0; - s.meters_traveled = 0; - s.avg_ping = 0; - s.min_ping = 0; - s.max_ping = 0; - s.mode_ping = 0; - s.regions_visited = 0; - s.run_time = 0; - s.avg_sim_fps = 0; - s.min_sim_fps = 0; - s.max_sim_fps = 0; - s.mode_sim_fps = 0; - s.start_time = 0; - s.client_version = ""; - s.s_cpu = ""; - s.s_gpu = ""; - s.s_os = ""; - s.s_ram = 0; - s.d_object_kb = 0; - s.d_texture_kb = 0; - s.d_world_kb = 0; - s.n_in_kb = 0; - s.n_in_pk = 0; - s.n_out_kb = 0; - s.n_out_pk = 0; - s.f_dropped = 0; - s.f_failed_resends = 0; - s.f_invalid = 0; - s.f_off_circuit = 0; - s.f_resent = 0; - s.f_send_packet = 0; - s._ping = new List(); - s._fps = new List(); - s._sim_fps = new List(); - s._agents_in_view = new List(); - return s; - } - } - #region structs - - public class UserSession - { - public UUID session_id; - public UUID region_id; - public string name_f; - public string name_l; - public UserSessionData session_data; - } - - public struct UserSessionData - { - public UUID session_id; - public UUID agent_id; - public UUID region_id; - public float last_updated; - public string remote_ip; - public string name_f; - public string name_l; - public float avg_agents_in_view; - public float min_agents_in_view; - public float max_agents_in_view; - public float mode_agents_in_view; - public float avg_fps; - public float min_fps; - public float max_fps; - public float mode_fps; - public string a_language; - public float mem_use; - public float meters_traveled; - public float avg_ping; - public float min_ping; - public float max_ping; - public float mode_ping; - public int regions_visited; - public float run_time; - public float avg_sim_fps; - public float min_sim_fps; - public float max_sim_fps; - public float mode_sim_fps; - public float start_time; - public string client_version; - public string s_cpu; - public string s_gpu; - public string s_os; - public int s_ram; - public float d_object_kb; - public float d_texture_kb; - public float d_world_kb; - public float n_in_kb; - public int n_in_pk; - public float n_out_kb; - public int n_out_pk; - public int f_dropped; - public int f_failed_resends; - public int f_invalid; - public int f_off_circuit; - public int f_resent; - public int f_send_packet; - public List _ping; - public List _fps; - public List _sim_fps; - public List _agents_in_view; - } - - #endregion - - public class USimStatsData - { - private UUID m_regionID = UUID.Zero; - private volatile int m_statcounter = 0; - private volatile float m_timeDilation; - private volatile float m_simFps; - private volatile float m_physicsFps; - private volatile float m_agentUpdates; - private volatile float m_rootAgents; - private volatile float m_childAgents; - private volatile float m_totalPrims; - private volatile float m_activePrims; - private volatile float m_totalFrameTime; - private volatile float m_netFrameTime; - private volatile float m_physicsFrameTime; - private volatile float m_otherFrameTime; - private volatile float m_imageFrameTime; - private volatile float m_inPacketsPerSecond; - private volatile float m_outPacketsPerSecond; - private volatile float m_unackedBytes; - private volatile float m_agentFrameTime; - private volatile float m_pendingDownloads; - private volatile float m_pendingUploads; - private volatile float m_activeScripts; - private volatile float m_scriptLinesPerSecond; - - public UUID RegionId { get { return m_regionID; } } - public int StatsCounter { get { return m_statcounter; } set { m_statcounter = value;}} - public float TimeDilation { get { return m_timeDilation; } } - public float SimFps { get { return m_simFps; } } - public float PhysicsFps { get { return m_physicsFps; } } - public float AgentUpdates { get { return m_agentUpdates; } } - public float RootAgents { get { return m_rootAgents; } } - public float ChildAgents { get { return m_childAgents; } } - public float TotalPrims { get { return m_totalPrims; } } - public float ActivePrims { get { return m_activePrims; } } - public float TotalFrameTime { get { return m_totalFrameTime; } } - public float NetFrameTime { get { return m_netFrameTime; } } - public float PhysicsFrameTime { get { return m_physicsFrameTime; } } - public float OtherFrameTime { get { return m_otherFrameTime; } } - public float ImageFrameTime { get { return m_imageFrameTime; } } - public float InPacketsPerSecond { get { return m_inPacketsPerSecond; } } - public float OutPacketsPerSecond { get { return m_outPacketsPerSecond; } } - public float UnackedBytes { get { return m_unackedBytes; } } - public float AgentFrameTime { get { return m_agentFrameTime; } } - public float PendingDownloads { get { return m_pendingDownloads; } } - public float PendingUploads { get { return m_pendingUploads; } } - public float ActiveScripts { get { return m_activeScripts; } } - public float ScriptLinesPerSecond { get { return m_scriptLinesPerSecond; } } - - public USimStatsData(UUID pRegionID) - { - m_regionID = pRegionID; - } - - public void ConsumeSimStats(SimStats stats) - { - m_regionID = stats.RegionUUID; - m_timeDilation = stats.StatsBlock[0].StatValue; - m_simFps = stats.StatsBlock[1].StatValue; - m_physicsFps = stats.StatsBlock[2].StatValue; - m_agentUpdates = stats.StatsBlock[3].StatValue; - m_rootAgents = stats.StatsBlock[4].StatValue; - m_childAgents = stats.StatsBlock[5].StatValue; - m_totalPrims = stats.StatsBlock[6].StatValue; - m_activePrims = stats.StatsBlock[7].StatValue; - m_totalFrameTime = stats.StatsBlock[8].StatValue; - m_netFrameTime = stats.StatsBlock[9].StatValue; - m_physicsFrameTime = stats.StatsBlock[10].StatValue; - m_otherFrameTime = stats.StatsBlock[11].StatValue; - m_imageFrameTime = stats.StatsBlock[12].StatValue; - m_inPacketsPerSecond = stats.StatsBlock[13].StatValue; - m_outPacketsPerSecond = stats.StatsBlock[14].StatValue; - m_unackedBytes = stats.StatsBlock[15].StatValue; - m_agentFrameTime = stats.StatsBlock[16].StatValue; - m_pendingDownloads = stats.StatsBlock[17].StatValue; - m_pendingUploads = stats.StatsBlock[18].StatValue; - m_activeScripts = stats.StatsBlock[19].StatValue; - m_scriptLinesPerSecond = stats.StatsBlock[20].StatValue; - } - } -} \ No newline at end of file diff --git a/OpenSim/Server/Base/HttpServerBase.cs b/OpenSim/Server/Base/HttpServerBase.cs index 954783c..44ef124 100644 --- a/OpenSim/Server/Base/HttpServerBase.cs +++ b/OpenSim/Server/Base/HttpServerBase.cs @@ -56,15 +56,16 @@ namespace OpenSim.Server.Base if (networkConfig == null) { - System.Console.WriteLine("Section 'Network' not found, server can't start"); - Thread.CurrentThread.Abort(); + System.Console.WriteLine("ERROR: Section [Network] not found, server can't start"); + Environment.Exit(1); } uint port = (uint)networkConfig.GetInt("port", 0); if (port == 0) { - Thread.CurrentThread.Abort(); + System.Console.WriteLine("ERROR: No 'port' entry found in [Network]. Server can't start"); + Environment.Exit(1); } bool ssl_main = networkConfig.GetBoolean("https_main",false); @@ -83,23 +84,24 @@ namespace OpenSim.Server.Base // Then, check for https settings and ADD a server to // m_Servers // - if ( !ssl_main ) + if (!ssl_main) { httpServer = new BaseHttpServer(port); } else { string cert_path = networkConfig.GetString("cert_path",String.Empty); - if ( cert_path == String.Empty ) + if (cert_path == String.Empty) { - System.Console.WriteLine("Path to X509 certificate is missing, server can't start."); - Thread.CurrentThread.Abort(); + System.Console.WriteLine("ERROR: Path to X509 certificate is missing, server can't start."); + Environment.Exit(1); } + string cert_pass = networkConfig.GetString("cert_pass",String.Empty); - if ( cert_pass == String.Empty ) + if (cert_pass == String.Empty) { - System.Console.WriteLine("Password for X509 certificate is missing, server can't start."); - Thread.CurrentThread.Abort(); + System.Console.WriteLine("ERROR: Password for X509 certificate is missing, server can't start."); + Environment.Exit(1); } httpServer = new BaseHttpServer(port, ssl_main, cert_path, cert_pass); @@ -109,21 +111,22 @@ namespace OpenSim.Server.Base MainServer.Instance = httpServer; // If https_listener = true, then add an ssl listener on the https_port... - if ( ssl_listener == true ) { - + if (ssl_listener == true) + { uint https_port = (uint)networkConfig.GetInt("https_port", 0); string cert_path = networkConfig.GetString("cert_path",String.Empty); - if ( cert_path == String.Empty ) + if (cert_path == String.Empty) { - System.Console.WriteLine("Path to X509 certificate is missing, server can't start."); - Thread.CurrentThread.Abort(); + System.Console.WriteLine("ERROR: Path to X509 certificate is missing, server can't start."); + Environment.Exit(1); } + string cert_pass = networkConfig.GetString("cert_pass",String.Empty); - if ( cert_pass == String.Empty ) + if (cert_pass == String.Empty) { - System.Console.WriteLine("Password for X509 certificate is missing, server can't start."); - Thread.CurrentThread.Abort(); + System.Console.WriteLine("ERROR: Password for X509 certificate is missing, server can't start."); + Environment.Exit(1); } MainServer.AddHttpServer(new BaseHttpServer(https_port, ssl_listener, cert_path, cert_pass)); diff --git a/OpenSim/Server/Base/Properties/AssemblyInfo.cs b/OpenSim/Server/Base/Properties/AssemblyInfo.cs index 4bbe358..3c634a7 100644 --- a/OpenSim/Server/Base/Properties/AssemblyInfo.cs +++ b/OpenSim/Server/Base/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Server/Base/ProtocolVersions.cs b/OpenSim/Server/Base/ProtocolVersions.cs index 8db5bb6..5c2278c 100644 --- a/OpenSim/Server/Base/ProtocolVersions.cs +++ b/OpenSim/Server/Base/ProtocolVersions.cs @@ -46,11 +46,11 @@ namespace OpenSim.Server.Base /// // The range of acceptable servers for client-side connectors - public readonly static int ClientProtocolVersionMin = 0; - public readonly static int ClientProtocolVersionMax = 0; + public readonly static int ClientProtocolVersionMin = 1; + public readonly static int ClientProtocolVersionMax = 1; // The range of acceptable clients in server-side handlers - public readonly static int ServerProtocolVersionMin = 0; - public readonly static int ServerProtocolVersionMax = 0; + public readonly static int ServerProtocolVersionMin = 1; + public readonly static int ServerProtocolVersionMax = 1; } } diff --git a/OpenSim/Server/Base/ServerUtils.cs b/OpenSim/Server/Base/ServerUtils.cs index 2e6d279..18a4266 100644 --- a/OpenSim/Server/Base/ServerUtils.cs +++ b/OpenSim/Server/Base/ServerUtils.cs @@ -41,7 +41,7 @@ using OpenSim.Framework.Servers.HttpServer; using OpenSim.Framework.Servers; -[assembly:AddinRoot("Robust", "0.1")] +[assembly:AddinRoot("Robust", OpenSim.VersionInfo.VersionNumber)] namespace OpenSim.Server.Base { [TypeExtensionPoint(Path="/Robust/Connector", Name="RobustConnector")] @@ -89,9 +89,9 @@ namespace OpenSim.Server.Base Config = config; Registry = new AddinRegistry(registryPath, "."); - suppress_console_output_(true); + //suppress_console_output_(true); AddinManager.Initialize(registryPath); - suppress_console_output_(false); + //suppress_console_output_(false); AddinManager.Registry.Update(); CommandManager commandmanager = new CommandManager(Registry); AddinManager.AddExtensionNodeHandler("/Robust/Connector", OnExtensionChanged); @@ -138,17 +138,17 @@ namespace OpenSim.Server.Base case ExtensionChange.Add: if (a.AddinFile.Contains(Registry.DefaultAddinsFolder)) { - m_log.InfoFormat("[SERVER]: Adding {0} from registry", a.Name); + m_log.InfoFormat("[SERVER UTILS]: Adding {0} from registry", a.Name); connector.PluginPath = System.IO.Path.Combine(Registry.DefaultAddinsFolder,a.Name.Replace(',', '.')); } else { - m_log.InfoFormat("[SERVER]: Adding {0} from ./bin", a.Name); + m_log.InfoFormat("[SERVER UTILS]: Adding {0} from ./bin", a.Name); connector.PluginPath = a.AddinFile; } LoadPlugin(connector); break; case ExtensionChange.Remove: - m_log.InfoFormat("[SERVER]: Removing {0}", a.Name); + m_log.InfoFormat("[SERVER UTILS]: Removing {0}", a.Name); UnloadPlugin(connector); break; } @@ -166,13 +166,13 @@ namespace OpenSim.Server.Base } else { - m_log.InfoFormat("[SERVER]: {0} Disabled.", connector.ConfigName); + m_log.InfoFormat("[SERVER UTILS]: {0} Disabled.", connector.ConfigName); } } private void UnloadPlugin(IRobustConnector connector) { - m_log.InfoFormat("[Server]: Unloading {0}", connector.ConfigName); + m_log.InfoFormat("[SERVER UTILS]: Unloading {0}", connector.ConfigName); connector.Unload(); } @@ -196,17 +196,19 @@ namespace OpenSim.Server.Base public static byte[] SerializeResult(XmlSerializer xs, object data) { - MemoryStream ms = new MemoryStream(); - XmlTextWriter xw = new XmlTextWriter(ms, Util.UTF8); - xw.Formatting = Formatting.Indented; - xs.Serialize(xw, data); - xw.Flush(); + using (MemoryStream ms = new MemoryStream()) + using (XmlTextWriter xw = new XmlTextWriter(ms, Util.UTF8)) + { + xw.Formatting = Formatting.Indented; + xs.Serialize(xw, data); + xw.Flush(); - ms.Seek(0, SeekOrigin.Begin); - byte[] ret = ms.GetBuffer(); - Array.Resize(ref ret, (int)ms.Length); + ms.Seek(0, SeekOrigin.Begin); + byte[] ret = ms.GetBuffer(); + Array.Resize(ref ret, (int)ms.Length); - return ret; + return ret; + } } /// @@ -266,7 +268,7 @@ namespace OpenSim.Server.Base && pluginType.ToString() != pluginType.Namespace + "." + className) continue; - Type typeInterface = pluginType.GetInterface(interfaceName, true); + Type typeInterface = pluginType.GetInterface(interfaceName); if (typeInterface != null) { @@ -280,12 +282,13 @@ namespace OpenSim.Server.Base { if (!(e is System.MissingMethodException)) { - m_log.ErrorFormat("Error loading plugin {0} from {1}. Exception: {2}, {3}", + m_log.Error(string.Format("[SERVER UTILS]: Error loading plugin {0} from {1}. Exception: {2}", interfaceName, dllName, - e.InnerException == null ? e.Message : e.InnerException.Message, - e.StackTrace); + e.InnerException == null ? e.Message : e.InnerException.Message), + e); } + m_log.ErrorFormat("[SERVER UTILS]: Error loading plugin {0}: {1} args.Length {2}", dllName, e.Message, args.Length); return null; } @@ -298,14 +301,14 @@ namespace OpenSim.Server.Base } catch (ReflectionTypeLoadException rtle) { - m_log.Error(string.Format("Error loading plugin from {0}:\n{1}", dllName, + m_log.Error(string.Format("[SERVER UTILS]: Error loading plugin from {0}:\n{1}", dllName, String.Join("\n", Array.ConvertAll(rtle.LoaderExceptions, e => e.ToString()))), rtle); return null; } catch (Exception e) { - m_log.Error(string.Format("Error loading plugin from {0}", dllName), e); + m_log.Error(string.Format("[SERVER UTILS]: Error loading plugin from {0}", dllName), e); return null; } } @@ -517,7 +520,7 @@ namespace OpenSim.Server.Base public static IConfigSource LoadInitialConfig(string url) { IConfigSource source = new XmlConfigSource(); - m_log.InfoFormat("[CONFIG]: {0} is a http:// URI, fetching ...", url); + m_log.InfoFormat("[SERVER UTILS]: {0} is a http:// URI, fetching ...", url); // The ini file path is a http URI // Try to read it @@ -529,7 +532,7 @@ namespace OpenSim.Server.Base } catch (Exception e) { - m_log.FatalFormat("[CONFIG]: Exception reading config from URI {0}\n" + e.ToString(), url); + m_log.FatalFormat("[SERVER UTILS]: Exception reading config from URI {0}\n" + e.ToString(), url); Environment.Exit(1); } diff --git a/OpenSim/Server/Base/ServicesServerBase.cs b/OpenSim/Server/Base/ServicesServerBase.cs index ecd69b0..1f2c54d 100644 --- a/OpenSim/Server/Base/ServicesServerBase.cs +++ b/OpenSim/Server/Base/ServicesServerBase.cs @@ -34,6 +34,7 @@ using System.Text; using System.Xml; using OpenSim.Framework; using OpenSim.Framework.Console; +using OpenSim.Framework.Monitoring; using OpenSim.Framework.Servers; using log4net; using log4net.Config; @@ -48,9 +49,7 @@ namespace OpenSim.Server.Base { // Logger // - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // Command line args // @@ -71,11 +70,9 @@ namespace OpenSim.Server.Base public ServicesServerBase(string prompt, string[] args) : base() { // Save raw arguments - // m_Arguments = args; // Read command line - // ArgvConfigSource argvConfig = new ArgvConfigSource(args); argvConfig.AddSwitch("Startup", "console", "c"); @@ -85,8 +82,9 @@ namespace OpenSim.Server.Base argvConfig.AddSwitch("Startup", "logconfig", "g"); // Automagically create the ini file name - // - string fileName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location); + string fileName = ""; + if (Assembly.GetEntryAssembly() != null) + fileName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location); string iniFile = fileName + ".ini"; string logConfig = null; @@ -94,19 +92,17 @@ namespace OpenSim.Server.Base if (startupConfig != null) { // Check if a file name was given on the command line - // iniFile = startupConfig.GetString("inifile", iniFile); - // + // Check if a prompt was given on the command line prompt = startupConfig.GetString("prompt", prompt); - // + // Check for a Log4Net config file on the command line - logConfig =startupConfig.GetString("logconfig",logConfig); + logConfig =startupConfig.GetString("logconfig", logConfig); } - // Find out of the file name is a URI and remote load it - // if it's possible. Load it as a local file otherwise. - // + // Find out of the file name is a URI and remote load it if possible. + // Load it as a local file otherwise. Uri configUri; try @@ -128,13 +124,16 @@ namespace OpenSim.Server.Base Environment.Exit(1); } - // Merge the configuration from the command line into the - // loaded file - // + // Merge OpSys env vars + m_log.Info("[CONFIG]: Loading environment variables for Config"); + Util.MergeEnvironmentToConfig(Config); + + // Merge the configuration from the command line into the loaded file Config.Merge(argvConfig); + Config.ReplaceKeyValues(); + // Refresh the startupConfig post merge - // if (Config.Configs["Startup"] != null) { startupConfig = Config.Configs["Startup"]; @@ -144,13 +143,10 @@ namespace OpenSim.Server.Base prompt = startupConfig.GetString("Prompt", prompt); - // Allow derived classes to load config before the console is - // opened. - // + // Allow derived classes to load config before the console is opened. ReadConfig(); // Create main console - // string consoleType = "local"; if (startupConfig != null) consoleType = startupConfig.GetString("console", consoleType); @@ -164,18 +160,17 @@ namespace OpenSim.Server.Base MainConsole.Instance = new RemoteConsole(prompt); ((RemoteConsole)MainConsole.Instance).ReadConfig(Config); } - else + else if (consoleType == "mock") + { + MainConsole.Instance = new MockConsole(); + } + else if (consoleType == "local") { - MainConsole.Instance = new LocalConsole(prompt); + MainConsole.Instance = new LocalConsole(prompt, startupConfig); } m_console = MainConsole.Instance; - // Configure the appenders for log4net - // - OpenSimAppender consoleAppender = null; - FileAppender fileAppender = null; - if (logConfig != null) { FileInfo cfg = new FileInfo(logConfig); @@ -186,6 +181,7 @@ namespace OpenSim.Server.Base XmlConfigurator.Configure(); } + LogEnvironmentInformation(); RegisterCommonAppenders(startupConfig); if (startupConfig.GetString("PIDFile", String.Empty) != String.Empty) @@ -194,20 +190,10 @@ namespace OpenSim.Server.Base } RegisterCommonCommands(); - - // Register the quit command - // - MainConsole.Instance.Commands.AddCommand("General", false, "quit", - "quit", - "Quit the application", HandleQuit); - - MainConsole.Instance.Commands.AddCommand("General", false, "shutdown", - "shutdown", - "Quit the application", HandleQuit); + RegisterCommonComponents(Config); // Allow derived classes to perform initialization that // needs to be done after the console has opened - // Initialise(); } @@ -218,6 +204,9 @@ namespace OpenSim.Server.Base public virtual int Run() { + Watchdog.Enabled = true; + MemoryWatchdog.Enabled = true; + while (m_Running) { try @@ -235,11 +224,12 @@ namespace OpenSim.Server.Base return 0; } - protected virtual void HandleQuit(string module, string[] args) + protected override void ShutdownSpecific() { m_Running = false; m_log.Info("[CONSOLE] Quitting"); + base.ShutdownSpecific(); } protected virtual void ReadConfig() @@ -250,4 +240,4 @@ namespace OpenSim.Server.Base { } } -} +} \ No newline at end of file diff --git a/OpenSim/Server/Handlers/AgentPreferences/AgentPreferencesServerPostHandler.cs b/OpenSim/Server/Handlers/AgentPreferences/AgentPreferencesServerPostHandler.cs new file mode 100644 index 0000000..713b755 --- /dev/null +++ b/OpenSim/Server/Handlers/AgentPreferences/AgentPreferencesServerPostHandler.cs @@ -0,0 +1,206 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using Nini.Config; +using log4net; +using System; +using System.Reflection; +using System.IO; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Serialization; +using System.Collections.Generic; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; +using OpenSim.Framework.Servers.HttpServer; +using OpenMetaverse; + +namespace OpenSim.Server.Handlers.AgentPreferences +{ + public class AgentPreferencesServerPostHandler : BaseStreamHandler + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IAgentPreferencesService m_AgentPreferencesService; + + public AgentPreferencesServerPostHandler(IAgentPreferencesService service, IServiceAuth auth) : + base("POST", "/agentprefs", auth) + { + m_AgentPreferencesService = service; + } + + protected override byte[] ProcessRequest(string path, Stream requestData, + IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + StreamReader sr = new StreamReader(requestData); + string body = sr.ReadToEnd(); + sr.Close(); + body = body.Trim(); + + //m_log.DebugFormat("[XXX]: query String: {0}", body); + + try + { + Dictionary request = + ServerUtils.ParseQueryString(body); + + if (!request.ContainsKey("METHOD")) + return FailureResult(); + + string method = request["METHOD"].ToString(); + + switch (method) + { + case "getagentprefs": + return GetAgentPrefs(request); + case "setagentprefs": + return SetAgentPrefs(request); + case "getagentlang": + return GetAgentLang(request); + } + m_log.DebugFormat("[AGENT PREFERENCES HANDLER]: unknown method request: {0}", method); + } + catch (Exception e) + { + m_log.DebugFormat("[AGENT PREFERENCES HANDLER]: Exception {0}", e); + } + + return FailureResult(); + } + + byte[] GetAgentPrefs(Dictionary request) + { + if (!request.ContainsKey("UserID")) + return FailureResult(); + + UUID userID; + if (!UUID.TryParse(request["UserID"].ToString(), out userID)) + return FailureResult(); + AgentPrefs prefs = m_AgentPreferencesService.GetAgentPreferences(userID); + Dictionary result = new Dictionary(); + result = prefs.ToKeyValuePairs(); + + string xmlString = ServerUtils.BuildXmlResponse(result); + + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] SetAgentPrefs(Dictionary request) + { + if (!request.ContainsKey("PrincipalID") || !request.ContainsKey("AccessPrefs") || !request.ContainsKey("HoverHeight") + || !request.ContainsKey("Language") || !request.ContainsKey("LanguageIsPublic") || !request.ContainsKey("PermEveryone") + || !request.ContainsKey("PermGroup") || !request.ContainsKey("PermNextOwner")) + { + return FailureResult(); + } + + UUID userID; + if (!UUID.TryParse(request["PrincipalID"].ToString(), out userID)) + return FailureResult(); + + AgentPrefs data = new AgentPrefs(userID); + data.AccessPrefs = request["AccessPrefs"].ToString(); + data.HoverHeight = double.Parse(request["HoverHeight"].ToString()); + data.Language = request["Language"].ToString(); + data.LanguageIsPublic = bool.Parse(request["LanguageIsPublic"].ToString()); + data.PermEveryone = int.Parse(request["PermEveryone"].ToString()); + data.PermGroup = int.Parse(request["PermGroup"].ToString()); + data.PermNextOwner = int.Parse(request["PermNextOwner"].ToString()); + + return m_AgentPreferencesService.StoreAgentPreferences(data) ? SuccessResult() : FailureResult(); + } + + byte[] GetAgentLang(Dictionary request) + { + if (!request.ContainsKey("UserID")) + return FailureResult(); + UUID userID; + if (!UUID.TryParse(request["UserID"].ToString(), out userID)) + return FailureResult(); + + string lang = "en-us"; + AgentPrefs prefs = m_AgentPreferencesService.GetAgentPreferences(userID); + if (prefs != null) + { + if (prefs.LanguageIsPublic) + lang = prefs.Language; + } + Dictionary result = new Dictionary(); + result["Language"] = lang; + string xmlString = ServerUtils.BuildXmlResponse(result); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + private byte[] SuccessResult() + { + XmlDocument doc = new XmlDocument(); + + XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration, + "", ""); + + doc.AppendChild(xmlnode); + + XmlElement rootElement = doc.CreateElement("", "ServerResponse", + ""); + + doc.AppendChild(rootElement); + + XmlElement result = doc.CreateElement("", "result", ""); + result.AppendChild(doc.CreateTextNode("Success")); + + rootElement.AppendChild(result); + + return Util.DocToBytes(doc); + } + + private byte[] FailureResult() + { + XmlDocument doc = new XmlDocument(); + + XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration, + "", ""); + + doc.AppendChild(xmlnode); + + XmlElement rootElement = doc.CreateElement("", "ServerResponse", + ""); + + doc.AppendChild(rootElement); + + XmlElement result = doc.CreateElement("", "result", ""); + result.AppendChild(doc.CreateTextNode("Failure")); + + rootElement.AppendChild(result); + + return Util.DocToBytes(doc); + } + } +} diff --git a/OpenSim/Server/Handlers/AgentPreferences/AgentPreferencesServiceConnector.cs b/OpenSim/Server/Handlers/AgentPreferences/AgentPreferencesServiceConnector.cs new file mode 100644 index 0000000..a581ea2 --- /dev/null +++ b/OpenSim/Server/Handlers/AgentPreferences/AgentPreferencesServiceConnector.cs @@ -0,0 +1,64 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +using System; +using Nini.Config; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.ServiceAuth; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; + +namespace OpenSim.Server.Handlers.AgentPreferences +{ + public class AgentPreferencesServiceConnector : ServiceConnector + { + private IAgentPreferencesService m_AgentPreferencesService; + private string m_ConfigName = "AgentPreferencesService"; + + public AgentPreferencesServiceConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + IConfig serverConfig = config.Configs[m_ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section {0} in config file", m_ConfigName)); + + string service = serverConfig.GetString("LocalServiceModule", String.Empty); + + if (String.IsNullOrWhiteSpace(service)) + throw new Exception("No LocalServiceModule in config file"); + + Object[] args = new Object[] { config }; + m_AgentPreferencesService = ServerUtils.LoadPlugin(service, args); + + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); ; + + server.AddStreamHandler(new AgentPreferencesServerPostHandler(m_AgentPreferencesService, auth)); + } + } +} diff --git a/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs b/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs index ff45d94..ab81dd6 100644 --- a/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs +++ b/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs @@ -30,6 +30,7 @@ using System.IO; using Nini.Config; using OpenMetaverse; using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Console; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; @@ -69,6 +70,8 @@ namespace OpenSim.Server.Handlers.Asset bool allowDelete = serverConfig.GetBoolean("AllowRemoteDelete", false); bool allowDeleteAllTypes = serverConfig.GetBoolean("AllowRemoteDeleteAllTypes", false); + string redirectURL = serverConfig.GetString("RedirectURL", string.Empty); + AllowedRemoteDeleteTypes allowedRemoteDeleteTypes; if (!allowDelete) @@ -83,9 +86,12 @@ namespace OpenSim.Server.Handlers.Asset allowedRemoteDeleteTypes = AllowedRemoteDeleteTypes.MapTile; } - server.AddStreamHandler(new AssetServerGetHandler(m_AssetService)); - server.AddStreamHandler(new AssetServerPostHandler(m_AssetService)); - server.AddStreamHandler(new AssetServerDeleteHandler(m_AssetService, allowedRemoteDeleteTypes)); + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); + + server.AddStreamHandler(new AssetServerGetHandler(m_AssetService, auth, redirectURL)); + server.AddStreamHandler(new AssetServerPostHandler(m_AssetService, auth)); + server.AddStreamHandler(new AssetServerDeleteHandler(m_AssetService, allowedRemoteDeleteTypes, auth)); + server.AddStreamHandler(new AssetsExistHandler(m_AssetService)); MainConsole.Instance.Commands.AddCommand("Assets", false, "show asset", @@ -119,16 +125,14 @@ namespace OpenSim.Server.Handlers.Asset if (asset == null || asset.Data.Length == 0) { - MainConsole.Instance.Output("Asset not found"); + MainConsole.Instance.OutputFormat("Could not find asset with ID {0}", args[2]); return; } - m_AssetService.Delete(args[2]); - - //MainConsole.Instance.Output("Asset deleted"); - // TODO: Implement this - - MainConsole.Instance.Output("Asset deletion not supported by database"); + if (!m_AssetService.Delete(asset.ID)) + MainConsole.Instance.OutputFormat("ERROR: Could not delete asset {0} {1}", asset.ID, asset.Name); + else + MainConsole.Instance.OutputFormat("Deleted asset {0} {1}", asset.ID, asset.Name); } void HandleDumpAsset(string module, string[] args) @@ -214,4 +218,4 @@ namespace OpenSim.Server.Handlers.Asset } } } -} \ No newline at end of file +} diff --git a/OpenSim/Server/Handlers/Asset/AssetServerDeleteHandler.cs b/OpenSim/Server/Handlers/Asset/AssetServerDeleteHandler.cs index 986394b..d85d471 100644 --- a/OpenSim/Server/Handlers/Asset/AssetServerDeleteHandler.cs +++ b/OpenSim/Server/Handlers/Asset/AssetServerDeleteHandler.cs @@ -38,6 +38,7 @@ using System.Xml.Serialization; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; namespace OpenSim.Server.Handlers.Asset @@ -70,7 +71,13 @@ namespace OpenSim.Server.Handlers.Asset m_allowedTypes = allowedTypes; } - public override byte[] Handle(string path, Stream request, + public AssetServerDeleteHandler(IAssetService service, AllowedRemoteDeleteTypes allowedTypes, IServiceAuth auth) : + base("DELETE", "/assets", auth) + { + m_AssetService = service; + m_allowedTypes = allowedTypes; + } + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { bool result = false; diff --git a/OpenSim/Server/Handlers/Asset/AssetServerGetHandler.cs b/OpenSim/Server/Handlers/Asset/AssetServerGetHandler.cs index 8f7412b..91c5c54 100644 --- a/OpenSim/Server/Handlers/Asset/AssetServerGetHandler.cs +++ b/OpenSim/Server/Handlers/Asset/AssetServerGetHandler.cs @@ -38,23 +38,34 @@ using System.Xml.Serialization; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; namespace OpenSim.Server.Handlers.Asset { public class AssetServerGetHandler : BaseStreamHandler { - // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IAssetService m_AssetService; + private string m_RedirectURL; public AssetServerGetHandler(IAssetService service) : base("GET", "/assets") { + m_AssetService = service; + } + + public AssetServerGetHandler(IAssetService service, IServiceAuth auth, string redirectURL) : + base("GET", "/assets", auth) + { m_AssetService = service; + m_RedirectURL = redirectURL; + if (!m_RedirectURL.EndsWith("/")) + m_RedirectURL = m_RedirectURL.TrimEnd('/'); } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { byte[] result = new byte[0]; @@ -64,45 +75,62 @@ namespace OpenSim.Server.Handlers.Asset if (p.Length == 0) return result; - if (p.Length > 1 && p[1] == "data") + string id = string.Empty; + if (p.Length > 1) { - result = m_AssetService.GetData(p[0]); - if (result == null) + id = p[0]; + string cmd = p[1]; + + if (cmd == "data") { - httpResponse.StatusCode = (int)HttpStatusCode.NotFound; - httpResponse.ContentType = "text/plain"; - result = new byte[0]; + result = m_AssetService.GetData(id); + if (result == null) + { + httpResponse.StatusCode = (int)HttpStatusCode.NotFound; + httpResponse.ContentType = "text/plain"; + result = new byte[0]; + } + else + { + httpResponse.StatusCode = (int)HttpStatusCode.OK; + httpResponse.ContentType = "application/octet-stream"; + } } - else + else if (cmd == "metadata") { - httpResponse.StatusCode = (int)HttpStatusCode.OK; - httpResponse.ContentType = "application/octet-stream"; - } - } - else if (p.Length > 1 && p[1] == "metadata") - { - AssetMetadata metadata = m_AssetService.GetMetadata(p[0]); + AssetMetadata metadata = m_AssetService.GetMetadata(id); - if (metadata != null) - { - XmlSerializer xs = - new XmlSerializer(typeof(AssetMetadata)); - result = ServerUtils.SerializeResult(xs, metadata); + if (metadata != null) + { + XmlSerializer xs = + new XmlSerializer(typeof(AssetMetadata)); + result = ServerUtils.SerializeResult(xs, metadata); - httpResponse.StatusCode = (int)HttpStatusCode.OK; - httpResponse.ContentType = - SLUtil.SLAssetTypeToContentType(metadata.Type); + httpResponse.StatusCode = (int)HttpStatusCode.OK; + httpResponse.ContentType = + SLUtil.SLAssetTypeToContentType(metadata.Type); + } + else + { + httpResponse.StatusCode = (int)HttpStatusCode.NotFound; + httpResponse.ContentType = "text/plain"; + result = new byte[0]; + } } else { - httpResponse.StatusCode = (int)HttpStatusCode.NotFound; + // Unknown request + httpResponse.StatusCode = (int)HttpStatusCode.BadRequest; httpResponse.ContentType = "text/plain"; result = new byte[0]; } } - else + else if (p.Length == 1) { - AssetBase asset = m_AssetService.Get(p[0]); + // Get the entire asset (metadata + data) + + id = p[0]; + AssetBase asset = m_AssetService.Get(id); if (asset != null) { @@ -120,6 +148,24 @@ namespace OpenSim.Server.Handlers.Asset result = new byte[0]; } } + else + { + // Unknown request + httpResponse.StatusCode = (int)HttpStatusCode.BadRequest; + httpResponse.ContentType = "text/plain"; + result = new byte[0]; + } + + if (httpResponse.StatusCode == (int)HttpStatusCode.NotFound && !string.IsNullOrEmpty(m_RedirectURL) && !string.IsNullOrEmpty(id)) + { + httpResponse.StatusCode = (int)HttpStatusCode.Redirect; + string rurl = m_RedirectURL; + if (!path.StartsWith("/")) + rurl += "/"; + rurl += path; + httpResponse.AddHeader("Location", rurl); + m_log.DebugFormat("[ASSET GET HANDLER]: Asset not found, redirecting to {0} ({1})", rurl, httpResponse.StatusCode); + } return result; } } diff --git a/OpenSim/Server/Handlers/Asset/AssetServerPostHandler.cs b/OpenSim/Server/Handlers/Asset/AssetServerPostHandler.cs index a006fa8..1c706a7 100644 --- a/OpenSim/Server/Handlers/Asset/AssetServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Asset/AssetServerPostHandler.cs @@ -38,6 +38,7 @@ using System.Xml.Serialization; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; namespace OpenSim.Server.Handlers.Asset @@ -54,35 +55,44 @@ namespace OpenSim.Server.Handlers.Asset m_AssetService = service; } - public override byte[] Handle(string path, Stream request, + public AssetServerPostHandler(IAssetService service, IServiceAuth auth) : + base("POST", "/assets", auth) + { + m_AssetService = service; + } + + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { AssetBase asset; - XmlSerializer xs = new XmlSerializer(typeof (AssetBase)); + XmlSerializer xs = new XmlSerializer(typeof(AssetBase)); try { asset = (AssetBase)xs.Deserialize(request); } - catch (XmlException) + catch (Exception) { httpResponse.StatusCode = (int)HttpStatusCode.BadRequest; return null; } string[] p = SplitParams(path); - if (p.Length > 1) + if (p.Length > 0) { - bool result = m_AssetService.UpdateContent(p[1], asset.Data); + string id = p[0]; + bool result = m_AssetService.UpdateContent(id, asset.Data); xs = new XmlSerializer(typeof(bool)); return ServerUtils.SerializeResult(xs, result); } + else + { + string id = m_AssetService.Store(asset); - string id = m_AssetService.Store(asset); - - xs = new XmlSerializer(typeof(string)); - return ServerUtils.SerializeResult(xs, id); + xs = new XmlSerializer(typeof(string)); + return ServerUtils.SerializeResult(xs, id); + } } } } diff --git a/OpenSim/Server/Handlers/Asset/AssetsExistHandler.cs b/OpenSim/Server/Handlers/Asset/AssetsExistHandler.cs new file mode 100644 index 0000000..32901b3 --- /dev/null +++ b/OpenSim/Server/Handlers/Asset/AssetsExistHandler.cs @@ -0,0 +1,87 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using Nini.Config; +using log4net; +using System; +using System.Reflection; +using System.IO; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Serialization; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; +using OpenSim.Framework.Servers.HttpServer; +using OpenMetaverse; + +namespace OpenSim.Server.Handlers.Asset +{ + public class AssetsExistHandler : BaseStreamHandler + { + //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IAssetService m_AssetService; + + public AssetsExistHandler(IAssetService service) : + base("POST", "/get_assets_exist") + { + m_AssetService = service; + } + + public AssetsExistHandler(IAssetService service, IServiceAuth auth) : + base("POST", "/get_assets_exist", auth) + { + m_AssetService = service; + } + + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + XmlSerializer xs; + + string[] ids; + try + { + xs = new XmlSerializer(typeof(string[])); + ids = (string[])xs.Deserialize(request); + } + catch (Exception) + { + httpResponse.StatusCode = (int)HttpStatusCode.BadRequest; + return null; + } + + bool[] exist = m_AssetService.AssetsExist(ids); + + xs = new XmlSerializer(typeof(bool[])); + return ServerUtils.SerializeResult(xs, exist); + } + } +} diff --git a/OpenSim/Server/Handlers/Asset/Tests/AssetServerPostHandlerTests.cs b/OpenSim/Server/Handlers/Asset/Tests/AssetServerPostHandlerTests.cs index 427fa16..faa6fb7 100644 --- a/OpenSim/Server/Handlers/Asset/Tests/AssetServerPostHandlerTests.cs +++ b/OpenSim/Server/Handlers/Asset/Tests/AssetServerPostHandlerTests.cs @@ -39,7 +39,6 @@ using OpenSim.Server.Handlers.Asset; using OpenSim.Services.AssetService; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Server.Handlers.Asset.Test { diff --git a/OpenSim/Server/Handlers/Authentication/AuthenticationServerConnector.cs b/OpenSim/Server/Handlers/Authentication/AuthenticationServerConnector.cs index 848a037..c9a8dce 100644 --- a/OpenSim/Server/Handlers/Authentication/AuthenticationServerConnector.cs +++ b/OpenSim/Server/Handlers/Authentication/AuthenticationServerConnector.cs @@ -29,6 +29,7 @@ using System; using Nini.Config; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Server.Handlers.Base; @@ -58,7 +59,9 @@ namespace OpenSim.Server.Handlers.Authentication Object[] args = new Object[] { config }; m_AuthenticationService = ServerUtils.LoadPlugin(authenticationService, args); - server.AddStreamHandler(new AuthenticationServerPostHandler(m_AuthenticationService, serverConfig)); + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); + + server.AddStreamHandler(new AuthenticationServerPostHandler(m_AuthenticationService, serverConfig, auth)); } } } diff --git a/OpenSim/Server/Handlers/Authentication/AuthenticationServerPostHandler.cs b/OpenSim/Server/Handlers/Authentication/AuthenticationServerPostHandler.cs index 6b93cd9..6ee98b3 100644 --- a/OpenSim/Server/Handlers/Authentication/AuthenticationServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Authentication/AuthenticationServerPostHandler.cs @@ -39,6 +39,7 @@ using System.Collections.Generic; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; using OpenMetaverse; @@ -55,10 +56,10 @@ namespace OpenSim.Server.Handlers.Authentication private bool m_AllowSetPassword = false; public AuthenticationServerPostHandler(IAuthenticationService service) : - this(service, null) {} + this(service, null, null) {} - public AuthenticationServerPostHandler(IAuthenticationService service, IConfig config) : - base("POST", "/auth") + public AuthenticationServerPostHandler(IAuthenticationService service, IConfig config, IServiceAuth auth) : + base("POST", "/auth", auth) { m_AuthenticationService = service; @@ -70,9 +71,10 @@ namespace OpenSim.Server.Handlers.Authentication } } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { +// m_log.Error("[XXX]: Authenticating..."); string[] p = SplitParams(path); if (p.Length > 0) @@ -207,7 +209,7 @@ namespace OpenSim.Server.Handlers.Authentication rootElement.AppendChild(result); - return DocToBytes(doc); + return Util.DocToBytes(doc); } byte[] GetAuthInfo(UUID principalID) @@ -277,7 +279,7 @@ namespace OpenSim.Server.Handlers.Authentication rootElement.AppendChild(result); - return DocToBytes(doc); + return Util.DocToBytes(doc); } private byte[] SuccessResult(string token) @@ -304,18 +306,7 @@ namespace OpenSim.Server.Handlers.Authentication rootElement.AppendChild(t); - return DocToBytes(doc); - } - - private byte[] DocToBytes(XmlDocument doc) - { - MemoryStream ms = new MemoryStream(); - XmlTextWriter xw = new XmlTextWriter(ms, null); - xw.Formatting = Formatting.Indented; - doc.WriteTo(xw); - xw.Flush(); - - return ms.GetBuffer(); + return Util.DocToBytes(doc); } private byte[] ResultToBytes(Dictionary result) diff --git a/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs b/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs index 18cef15..b201dc7 100644 --- a/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs +++ b/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs @@ -147,7 +147,7 @@ namespace OpenSim.Server.Handlers.Authentication #endregion } - public class OpenIdStreamHandler : IStreamHandler + public class OpenIdStreamHandler : BaseOutputStreamHandler, IStreamHandler { #region HTML @@ -191,42 +191,34 @@ For more information, see http://openid.net/. #endregion HTML - public string Name { get { return "OpenId"; } } - public string Description { get { return null; } } - public string ContentType { get { return m_contentType; } } - public string HttpMethod { get { return m_httpMethod; } } - public string Path { get { return m_path; } } - - string m_contentType; - string m_httpMethod; - string m_path; IAuthenticationService m_authenticationService; IUserAccountService m_userAccountService; ProviderMemoryStore m_openidStore = new ProviderMemoryStore(); + public override string ContentType { get { return "text/html"; } } + /// /// Constructor /// - public OpenIdStreamHandler(string httpMethod, string path, IUserAccountService userService, IAuthenticationService authService) + public OpenIdStreamHandler( + string httpMethod, string path, IUserAccountService userService, IAuthenticationService authService) + : base(httpMethod, path, "OpenId", "OpenID stream handler") { m_authenticationService = authService; m_userAccountService = userService; - m_httpMethod = httpMethod; - m_path = path; - - m_contentType = "text/html"; } /// /// Handles all GET and POST requests for OpenID identifier pages and endpoint /// server communication /// - public void Handle(string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + protected override void ProcessRequest( + string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { Uri providerEndpoint = new Uri(String.Format("{0}://{1}{2}", httpRequest.Url.Scheme, httpRequest.Url.Authority, httpRequest.Url.AbsolutePath)); // Defult to returning HTML content - m_contentType = "text/html"; + httpResponse.ContentType = ContentType; try { @@ -276,7 +268,7 @@ For more information, see http://openid.net/. string[] contentTypeValues = provider.Request.Response.Headers.GetValues("Content-Type"); if (contentTypeValues != null && contentTypeValues.Length == 1) - m_contentType = contentTypeValues[0]; + httpResponse.ContentType = contentTypeValues[0]; // Set the response code and document body based on the OpenID result httpResponse.StatusCode = (int)provider.Request.Response.Code; @@ -344,4 +336,4 @@ For more information, see http://openid.net/. return false; } } -} +} \ No newline at end of file diff --git a/OpenSim/Server/Handlers/Authorization/AuthorizationServerPostHandler.cs b/OpenSim/Server/Handlers/Authorization/AuthorizationServerPostHandler.cs index bcf9d47..c9b4e9b 100644 --- a/OpenSim/Server/Handlers/Authorization/AuthorizationServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Authorization/AuthorizationServerPostHandler.cs @@ -54,7 +54,7 @@ namespace OpenSim.Server.Handlers.Authorization m_AuthorizationService = service; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { XmlSerializer xs = new XmlSerializer(typeof (AuthorizationRequest)); diff --git a/OpenSim/Server/Handlers/Avatar/AvatarServerConnector.cs b/OpenSim/Server/Handlers/Avatar/AvatarServerConnector.cs index 9a57cd9..1831e84 100644 --- a/OpenSim/Server/Handlers/Avatar/AvatarServerConnector.cs +++ b/OpenSim/Server/Handlers/Avatar/AvatarServerConnector.cs @@ -29,6 +29,7 @@ using System; using Nini.Config; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Server.Handlers.Base; @@ -55,7 +56,9 @@ namespace OpenSim.Server.Handlers.Avatar Object[] args = new Object[] { config }; m_AvatarService = ServerUtils.LoadPlugin(avatarService, args); - server.AddStreamHandler(new AvatarServerPostHandler(m_AvatarService)); + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); + + server.AddStreamHandler(new AvatarServerPostHandler(m_AvatarService, auth)); } } } diff --git a/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs b/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs index 8cd747e..ff8699f 100644 --- a/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs @@ -39,6 +39,7 @@ using System.Collections.Generic; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; using OpenMetaverse; @@ -50,13 +51,13 @@ namespace OpenSim.Server.Handlers.Avatar private IAvatarService m_AvatarService; - public AvatarServerPostHandler(IAvatarService service) : - base("POST", "/avatar") + public AvatarServerPostHandler(IAvatarService service, IServiceAuth auth) : + base("POST", "/avatar", auth) { m_AvatarService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); @@ -246,7 +247,7 @@ namespace OpenSim.Server.Handlers.Avatar rootElement.AppendChild(result); - return DocToBytes(doc); + return Util.DocToBytes(doc); } private byte[] FailureResult() @@ -268,18 +269,7 @@ namespace OpenSim.Server.Handlers.Avatar rootElement.AppendChild(result); - return DocToBytes(doc); - } - - private byte[] DocToBytes(XmlDocument doc) - { - MemoryStream ms = new MemoryStream(); - XmlTextWriter xw = new XmlTextWriter(ms, null); - xw.Formatting = Formatting.Indented; - doc.WriteTo(xw); - xw.Flush(); - - return ms.ToArray(); + return Util.DocToBytes(doc); } } diff --git a/OpenSim/Server/Handlers/BakedTextures/XBakes.cs b/OpenSim/Server/Handlers/BakedTextures/XBakes.cs new file mode 100644 index 0000000..4e55433 --- /dev/null +++ b/OpenSim/Server/Handlers/BakedTextures/XBakes.cs @@ -0,0 +1,148 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Diagnostics; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using System.Reflection; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Server.Base; +using OpenSim.Services.Base; +using OpenSim.Services.Interfaces; +using Nini.Config; +using log4net; +using OpenMetaverse; + +namespace OpenSim.Server.Handlers.BakedTextures +{ + public class XBakes : ServiceBase, IBakedTextureService + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + protected string m_FSBase; + + private System.Text.UTF8Encoding utf8encoding = + new System.Text.UTF8Encoding(); + + public XBakes(IConfigSource config) : base(config) + { + MainConsole.Instance.Commands.AddCommand("fs", false, + "delete bakes", "delete bakes ", + "Delete agent's baked textures from server", + HandleDeleteBakes); + + IConfig assetConfig = config.Configs["BakedTextureService"]; + if (assetConfig == null) + { + throw new Exception("No BakedTextureService configuration"); + } + + m_FSBase = assetConfig.GetString("BaseDirectory", String.Empty); + if (m_FSBase == String.Empty) + { + m_log.ErrorFormat("[BAKES]: BaseDirectory not specified"); + throw new Exception("Configuration error"); + } + + m_log.Info("[BAKES]: XBakes service enabled"); + } + + public string Get(string id) + { + string file = HashToFile(id); + string diskFile = Path.Combine(m_FSBase, file); + + if (File.Exists(diskFile)) + { + try + { + byte[] content = File.ReadAllBytes(diskFile); + + return utf8encoding.GetString(content); + } + catch + { + } + } + return String.Empty; + } + + public void Store(string id, string sdata) + { + string file = HashToFile(id); + string diskFile = Path.Combine(m_FSBase, file); + + Directory.CreateDirectory(Path.GetDirectoryName(diskFile)); + + File.Delete(diskFile); + + byte[] data = utf8encoding.GetBytes(sdata); + + using (FileStream fs = File.Create(diskFile)) + fs.Write(data, 0, data.Length); + } + + private void HandleDeleteBakes(string module, string[] args) + { + if (args.Length < 3) + { + MainConsole.Instance.Output("Syntax: delete bakes "); + return; + } + + string file = HashToFile(args[2]); + string diskFile = Path.Combine(m_FSBase, file); + + if (File.Exists(diskFile)) + { + File.Delete(diskFile); + MainConsole.Instance.Output("Bakes deleted"); + return; + } + MainConsole.Instance.Output("Bakes not found"); + } + + public string HashToPath(string hash) + { + return Path.Combine(hash.Substring(0, 2), + Path.Combine(hash.Substring(2, 2), + Path.Combine(hash.Substring(4, 2), + hash.Substring(6, 4)))); + } + + public string HashToFile(string hash) + { + return Path.Combine(HashToPath(hash), hash); + } + } +} diff --git a/OpenSim/Server/Handlers/BakedTextures/XBakesGetHandler.cs b/OpenSim/Server/Handlers/BakedTextures/XBakesGetHandler.cs new file mode 100644 index 0000000..3c61673 --- /dev/null +++ b/OpenSim/Server/Handlers/BakedTextures/XBakesGetHandler.cs @@ -0,0 +1,71 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using Nini.Config; +using log4net; +using System; +using System.IO; +using System.Reflection; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Serialization; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; +using OpenSim.Framework.Servers.HttpServer; + +namespace OpenSim.Server.Handlers.BakedTextures +{ + public class BakesServerGetHandler : BaseStreamHandler + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IBakedTextureService m_BakesService; + private System.Text.UTF8Encoding utf8 = + new System.Text.UTF8Encoding(); + + public BakesServerGetHandler(IBakedTextureService service, IServiceAuth auth) : + base("GET", "/bakes", auth) + { + m_BakesService = service; + } + + protected override byte[] ProcessRequest( + string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + string[] p = SplitParams(path); + + if (p.Length == 0) + return new byte[0]; + + return utf8.GetBytes(m_BakesService.Get(p[0])); + } + } +} diff --git a/OpenSim/Server/Handlers/BakedTextures/XBakesHandler.cs b/OpenSim/Server/Handlers/BakedTextures/XBakesHandler.cs new file mode 100644 index 0000000..4c12967 --- /dev/null +++ b/OpenSim/Server/Handlers/BakedTextures/XBakesHandler.cs @@ -0,0 +1,69 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using Nini.Config; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.ServiceAuth; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; + +namespace OpenSim.Server.Handlers.BakedTextures +{ + public class XBakesConnector : ServiceConnector + { + private IBakedTextureService m_BakesService; + private string m_ConfigName = "BakedTextureService"; + + public XBakesConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + if (configName != String.Empty) + m_ConfigName = configName; + + IConfig serverConfig = config.Configs[m_ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName)); + + string assetService = serverConfig.GetString("LocalServiceModule", + String.Empty); + + if (assetService == String.Empty) + throw new Exception("No BakedTextureService in config file"); + + Object[] args = new Object[] { config }; + m_BakesService = + ServerUtils.LoadPlugin(assetService, args); + + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); + + server.AddStreamHandler(new BakesServerGetHandler(m_BakesService, auth)); + server.AddStreamHandler(new BakesServerPostHandler(m_BakesService, auth)); + } + } +} diff --git a/OpenSim/Server/Handlers/BakedTextures/XBakesPostHandler.cs b/OpenSim/Server/Handlers/BakedTextures/XBakesPostHandler.cs new file mode 100644 index 0000000..e38543b --- /dev/null +++ b/OpenSim/Server/Handlers/BakedTextures/XBakesPostHandler.cs @@ -0,0 +1,76 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using Nini.Config; +using log4net; +using System; +using System.Reflection; +using System.IO; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Serialization; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; +using OpenSim.Framework.Servers.HttpServer; + +namespace OpenSim.Server.Handlers.BakedTextures +{ + public class BakesServerPostHandler : BaseStreamHandler + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IBakedTextureService m_BakesService; + + public BakesServerPostHandler(IBakedTextureService service, IServiceAuth auth) : + base("POST", "/bakes", auth) + { + m_BakesService = service; + } + + protected override byte[] ProcessRequest( + string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + string[] p = SplitParams(path); + + if (p.Length == 0) + { + return new byte[0]; + } + + StreamReader sr = new StreamReader(request); + + m_BakesService.Store(p[0], sr.ReadToEnd()); + sr.Close(); + + return new byte[0]; + } + } +} \ No newline at end of file diff --git a/OpenSim/Server/Handlers/Estate/EstateDataRobustConnector.cs b/OpenSim/Server/Handlers/Estate/EstateDataRobustConnector.cs new file mode 100644 index 0000000..e0c2810 --- /dev/null +++ b/OpenSim/Server/Handlers/Estate/EstateDataRobustConnector.cs @@ -0,0 +1,343 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Net; + +using Nini.Config; +using log4net; +using OpenMetaverse; + +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; + +namespace OpenSim.Server.Handlers +{ + public class EstateDataRobustConnector : ServiceConnector + { + private string m_ConfigName = "EstateService"; + + public EstateDataRobustConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + IConfig serverConfig = config.Configs[m_ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section {0} in config file", m_ConfigName)); + + string service = serverConfig.GetString("LocalServiceModule", + String.Empty); + + if (service == String.Empty) + throw new Exception("No LocalServiceModule in config file"); + + Object[] args = new Object[] { config }; + IEstateDataService e_service = ServerUtils.LoadPlugin(service, args); + + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); ; + + server.AddStreamHandler(new EstateServerGetHandler(e_service, auth)); + server.AddStreamHandler(new EstateServerPostHandler(e_service, auth)); + } + } + + + public class EstateServerGetHandler : BaseStreamHandler + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + IEstateDataService m_EstateService; + + // Possibilities + // /estates/estate/?region=uuid&create=[t|f] + // /estates/estate/?eid=int + // /estates/?name=string + // /estates/?owner=uuid + // /estates/ (all) + // /estates/regions/?eid=int + + public EstateServerGetHandler(IEstateDataService service, IServiceAuth auth) : + base("GET", "/estates", auth) + { + m_EstateService = service; + } + + protected override byte[] ProcessRequest(string path, Stream request, + IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + Dictionary data = null; + + string[] p = SplitParams(path); + + // /estates/ (all) + // /estates/?name=string + // /estates/?owner=uuid + if (p.Length == 0) + data = GetEstates(httpRequest, httpResponse); + else + { + string resource = p[0]; + + // /estates/estate/?region=uuid&create=[t|f] + // /estates/estate/?eid=int + if ("estate".Equals(resource)) + data = GetEstate(httpRequest, httpResponse); + // /estates/regions/?eid=int + else if ("regions".Equals(resource)) + data = GetRegions(httpRequest, httpResponse); + } + + if (data == null) + data = new Dictionary(); + + string xmlString = ServerUtils.BuildXmlResponse(data); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + + } + + private Dictionary GetEstates(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + // /estates/ (all) + // /estates/?name=string + // /estates/?owner=uuid + + Dictionary data = null; + string name = (string)httpRequest.Query["name"]; + string owner = (string)httpRequest.Query["owner"]; + + if (!string.IsNullOrEmpty(name) || !string.IsNullOrEmpty(owner)) + { + List estateIDs = null; + if (!string.IsNullOrEmpty(name)) + { + estateIDs = m_EstateService.GetEstates(name); + } + else if (!string.IsNullOrEmpty(owner)) + { + UUID ownerID = UUID.Zero; + if (UUID.TryParse(owner, out ownerID)) + estateIDs = m_EstateService.GetEstatesByOwner(ownerID); + } + + if (estateIDs == null || (estateIDs != null && estateIDs.Count == 0)) + httpResponse.StatusCode = (int)HttpStatusCode.NotFound; + else + { + httpResponse.StatusCode = (int)HttpStatusCode.OK; + httpResponse.ContentType = "text/xml"; + data = new Dictionary(); + int i = 0; + foreach (int id in estateIDs) + data["estate" + i++] = id; + } + } + else + { + List estates = m_EstateService.LoadEstateSettingsAll(); + if (estates == null || estates.Count == 0) + { + httpResponse.StatusCode = (int)HttpStatusCode.NotFound; + } + else + { + httpResponse.StatusCode = (int)HttpStatusCode.OK; + httpResponse.ContentType = "text/xml"; + data = new Dictionary(); + int i = 0; + foreach (EstateSettings es in estates) + data["estate" + i++] = es.ToMap(); + + } + } + + return data; + } + + private Dictionary GetEstate(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + // /estates/estate/?region=uuid&create=[t|f] + // /estates/estate/?eid=int + Dictionary data = null; + string region = (string)httpRequest.Query["region"]; + string eid = (string)httpRequest.Query["eid"]; + + EstateSettings estate = null; + + if (!string.IsNullOrEmpty(region)) + { + UUID regionID = UUID.Zero; + if (UUID.TryParse(region, out regionID)) + { + string create = (string)httpRequest.Query["create"]; + bool createYN = false; + Boolean.TryParse(create, out createYN); + estate = m_EstateService.LoadEstateSettings(regionID, createYN); + } + } + else if (!string.IsNullOrEmpty(eid)) + { + int id = 0; + if (Int32.TryParse(eid, out id)) + estate = m_EstateService.LoadEstateSettings(id); + } + + if (estate != null) + { + httpResponse.StatusCode = (int)HttpStatusCode.OK; + httpResponse.ContentType = "text/xml"; + data = estate.ToMap(); + } + else + httpResponse.StatusCode = (int)HttpStatusCode.NotFound; + + return data; + } + + private Dictionary GetRegions(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + // /estates/regions/?eid=int + Dictionary data = null; + string eid = (string)httpRequest.Query["eid"]; + + httpResponse.StatusCode = (int)HttpStatusCode.NotFound; + if (!string.IsNullOrEmpty(eid)) + { + int id = 0; + if (Int32.TryParse(eid, out id)) + { + List regions = m_EstateService.GetRegions(id); + if (regions != null && regions.Count > 0) + { + data = new Dictionary(); + int i = 0; + foreach (UUID uuid in regions) + data["region" + i++] = uuid.ToString(); + httpResponse.StatusCode = (int)HttpStatusCode.OK; + httpResponse.ContentType = "text/xml"; + } + } + } + + return data; + } + } + + public class EstateServerPostHandler : BaseStreamHandler + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + IEstateDataService m_EstateService; + + // Possibilities + // /estates/estate/ (post an estate) + // /estates/estate/?eid=int®ion=uuid (link a region to an estate) + + public EstateServerPostHandler(IEstateDataService service, IServiceAuth auth) : + base("POST", "/estates", auth) + { + m_EstateService = service; + } + + protected override byte[] ProcessRequest(string path, Stream request, + IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + Dictionary data = null; + + string[] p = SplitParams(path); + + if (p.Length > 0) + { + string resource = p[0]; + + // /estates/estate/ + // /estates/estate/?eid=int®ion=uuid + if ("estate".Equals(resource)) + { + StreamReader sr = new StreamReader(request); + string body = sr.ReadToEnd(); + sr.Close(); + body = body.Trim(); + + Dictionary requestData = ServerUtils.ParseQueryString(body); + + data = UpdateEstate(requestData, httpRequest, httpResponse); + } + } + + if (data == null) + data = new Dictionary(); + + string xmlString = ServerUtils.BuildXmlResponse(data); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + + } + + private Dictionary UpdateEstate(Dictionary requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + // /estates/estate/ + // /estates/estate/?eid=int®ion=uuid + Dictionary result = new Dictionary(); + string eid = (string)httpRequest.Query["eid"]; + string region = (string)httpRequest.Query["region"]; + + httpResponse.StatusCode = (int)HttpStatusCode.NotFound; + + if (string.IsNullOrEmpty(eid) && string.IsNullOrEmpty(region) && + requestData.ContainsKey("OP") && requestData["OP"] != null && "STORE".Equals(requestData["OP"])) + { + // /estates/estate/ + EstateSettings es = new EstateSettings(requestData); + m_EstateService.StoreEstateSettings(es); + //m_log.DebugFormat("[EstateServerPostHandler]: Store estate {0}", es.ToString()); + httpResponse.StatusCode = (int)HttpStatusCode.OK; + result["Result"] = true; + } + else if (!string.IsNullOrEmpty(region) && !string.IsNullOrEmpty(eid) && + requestData.ContainsKey("OP") && requestData["OP"] != null && "LINK".Equals(requestData["OP"])) + { + int id = 0; + UUID regionID = UUID.Zero; + if (UUID.TryParse(region, out regionID) && Int32.TryParse(eid, out id)) + { + m_log.DebugFormat("[EstateServerPostHandler]: Link region {0} to estate {1}", regionID, id); + httpResponse.StatusCode = (int)HttpStatusCode.OK; + result["Result"] = m_EstateService.LinkRegion(regionID, id); + } + } + else + m_log.WarnFormat("[EstateServerPostHandler]: something wrong with POST request {0}", httpRequest.RawUrl); + + return result; + } + + } +} diff --git a/OpenSim/Server/Handlers/Friends/FriendServerConnector.cs b/OpenSim/Server/Handlers/Friends/FriendServerConnector.cs index 5784bdf..b0e6c7d 100644 --- a/OpenSim/Server/Handlers/Friends/FriendServerConnector.cs +++ b/OpenSim/Server/Handlers/Friends/FriendServerConnector.cs @@ -29,6 +29,7 @@ using System; using Nini.Config; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Server.Handlers.Base; @@ -55,7 +56,8 @@ namespace OpenSim.Server.Handlers.Friends Object[] args = new Object[] { config }; m_FriendsService = ServerUtils.LoadPlugin(theService, args); - server.AddStreamHandler(new FriendsServerPostHandler(m_FriendsService)); + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); + server.AddStreamHandler(new FriendsServerPostHandler(m_FriendsService, auth)); } } } diff --git a/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs b/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs index 47a8558..3aab30b 100644 --- a/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs @@ -40,6 +40,7 @@ using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; using OpenMetaverse; @@ -51,13 +52,13 @@ namespace OpenSim.Server.Handlers.Friends private IFriendsService m_FriendsService; - public FriendsServerPostHandler(IFriendsService service) : - base("POST", "/friends") + public FriendsServerPostHandler(IFriendsService service, IServiceAuth auth) : + base("POST", "/friends", auth) { m_FriendsService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); @@ -228,7 +229,7 @@ namespace OpenSim.Server.Handlers.Friends rootElement.AppendChild(result); - return DocToBytes(doc); + return Util.DocToBytes(doc); } private byte[] FailureResult() @@ -260,18 +261,7 @@ namespace OpenSim.Server.Handlers.Friends rootElement.AppendChild(message); - return DocToBytes(doc); - } - - private byte[] DocToBytes(XmlDocument doc) - { - MemoryStream ms = new MemoryStream(); - XmlTextWriter xw = new XmlTextWriter(ms, null); - xw.Formatting = Formatting.Indented; - doc.WriteTo(xw); - xw.Flush(); - - return ms.ToArray(); + return Util.DocToBytes(doc); } void FromKeyValuePairs(Dictionary kvp, out string principalID, out string friend, out int flags) 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 public string JsonGetGridInfoMethod(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { - string HomeURI = String.Empty; - IConfig cfg = m_Config.Configs["LoginService"]; - - if (null != cfg) - { - HomeURI = cfg.GetString("SRV_HomeURI", HomeURI); - } - OSDMap map = new OSDMap(); foreach (string k in _info.Keys) @@ -185,9 +177,20 @@ namespace OpenSim.Server.Handlers.Grid map[k] = OSD.FromString(_info[k].ToString()); } + string HomeURI = Util.GetConfigVarFromSections(m_Config, "HomeURI", + new string[] { "Startup", "Hypergrid" }, String.Empty); + if (!String.IsNullOrEmpty(HomeURI)) + map["home"] = OSD.FromString(HomeURI); + else // Legacy. Remove soon! { - map["home"] = OSD.FromString(HomeURI); + IConfig cfg = m_Config.Configs["LoginService"]; + + if (null != cfg) + HomeURI = cfg.GetString("SRV_HomeURI", HomeURI); + + if (!String.IsNullOrEmpty(HomeURI)) + map["home"] = OSD.FromString(HomeURI); } return OSDParser.SerializeJsonString(map).ToString(); diff --git a/OpenSim/Server/Handlers/Grid/GridServerConnector.cs b/OpenSim/Server/Handlers/Grid/GridServerConnector.cs index 14daf12..6eb6a79 100644 --- a/OpenSim/Server/Handlers/Grid/GridServerConnector.cs +++ b/OpenSim/Server/Handlers/Grid/GridServerConnector.cs @@ -29,6 +29,7 @@ using System; using Nini.Config; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Server.Handlers.Base; @@ -55,7 +56,9 @@ namespace OpenSim.Server.Handlers.Grid Object[] args = new Object[] { config }; m_GridService = ServerUtils.LoadPlugin(gridService, args); - server.AddStreamHandler(new GridServerPostHandler(m_GridService)); + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); + + server.AddStreamHandler(new GridServerPostHandler(m_GridService, auth)); } } } diff --git a/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs b/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs index ef5f33e..86fda36 100644 --- a/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs @@ -40,6 +40,7 @@ using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; using OpenMetaverse; @@ -49,15 +50,19 @@ namespace OpenSim.Server.Handlers.Grid { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +#pragma warning disable 414 + private static string LogHeader = "[GRID HANDLER]"; +#pragma warning restore 414 + private IGridService m_GridService; - public GridServerPostHandler(IGridService service) : - base("POST", "/grid") + public GridServerPostHandler(IGridService service, IServiceAuth auth) : + base("POST", "/grid", auth) { m_GridService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); @@ -106,6 +111,9 @@ namespace OpenSim.Server.Handlers.Grid case "get_default_regions": return GetDefaultRegions(request); + case "get_default_hypergrid_regions": + return GetDefaultHypergridRegions(request); + case "get_fallback_regions": return GetFallbackRegions(request); @@ -114,6 +122,9 @@ namespace OpenSim.Server.Handlers.Grid case "get_region_flags": return GetRegionFlags(request); + + case "get_grid_extra_features": + return GetGridExtraFeatures(request); } m_log.DebugFormat("[GRID HANDLER]: unknown method request {0}", method); @@ -148,7 +159,24 @@ namespace OpenSim.Server.Handlers.Grid m_log.WarnFormat("[GRID HANDLER]: no maximum protocol version in request to register region"); // Check the protocol version - if ((versionNumberMin > ProtocolVersions.ServerProtocolVersionMax && versionNumberMax < ProtocolVersions.ServerProtocolVersionMax)) + // This is how it works: + // Example 1: + // Client: [0 0] + // Server: [1 1] + // ==> fail + // Example 2: + // Client: [1 1] + // Server: [0 0] + // ==> fail + // Example 3: + // Client: [0 1] + // Server: [1 1] + // ==> success + // Example 4: + // Client: [1 1] + // Server: [0 1] + // ==> success + if ((versionNumberMin > ProtocolVersions.ServerProtocolVersionMax || versionNumberMax < ProtocolVersions.ServerProtocolVersionMin)) { // Can't do, there is no overlap in the acceptable ranges return FailureResult(); @@ -278,8 +306,8 @@ namespace OpenSim.Server.Handlers.Grid else m_log.WarnFormat("[GRID HANDLER]: no Y in request to get region by position"); + // m_log.DebugFormat("{0} GetRegionByPosition: loc=<{1},{2}>", LogHeader, x, y); GridRegion rinfo = m_GridService.GetRegionByPosition(scopeID, x, y); - //m_log.DebugFormat("[GRID HANDLER]: neighbours for region {0}: {1}", regionID, rinfos.Count); Dictionary result = new Dictionary(); if (rinfo == null) @@ -444,6 +472,36 @@ namespace OpenSim.Server.Handlers.Grid return Util.UTF8NoBomEncoding.GetBytes(xmlString); } + byte[] GetDefaultHypergridRegions(Dictionary request) + { + //m_log.DebugFormat("[GRID HANDLER]: GetDefaultRegions"); + UUID scopeID = UUID.Zero; + if (request.ContainsKey("SCOPEID")) + UUID.TryParse(request["SCOPEID"].ToString(), out scopeID); + else + m_log.WarnFormat("[GRID HANDLER]: no scopeID in request to get region range"); + + List rinfos = m_GridService.GetDefaultHypergridRegions(scopeID); + + Dictionary result = new Dictionary(); + if ((rinfos == null) || ((rinfos != null) && (rinfos.Count == 0))) + result["result"] = "null"; + else + { + int i = 0; + foreach (GridRegion rinfo in rinfos) + { + Dictionary rinfoDict = rinfo.ToKeyValuePairs(); + result["region" + i] = rinfoDict; + i++; + } + } + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + byte[] GetFallbackRegions(Dictionary request) { //m_log.DebugFormat("[GRID HANDLER]: GetRegionRange"); @@ -540,6 +598,22 @@ namespace OpenSim.Server.Handlers.Grid //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); return Util.UTF8NoBomEncoding.GetBytes(xmlString); } + + byte[] GetGridExtraFeatures(Dictionary request) + { + + Dictionary result = new Dictionary (); + Dictionary extraFeatures = m_GridService.GetExtraFeatures (); + + foreach (string key in extraFeatures.Keys) + { + result [key] = extraFeatures [key]; + } + + string xmlString = ServerUtils.BuildXmlResponse(result); + + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } #endregion @@ -564,7 +638,7 @@ namespace OpenSim.Server.Handlers.Grid rootElement.AppendChild(result); - return DocToBytes(doc); + return Util.DocToBytes(doc); } private byte[] FailureResult() @@ -596,18 +670,7 @@ namespace OpenSim.Server.Handlers.Grid rootElement.AppendChild(message); - return DocToBytes(doc); - } - - private byte[] DocToBytes(XmlDocument doc) - { - MemoryStream ms = new MemoryStream(); - XmlTextWriter xw = new XmlTextWriter(ms, null); - xw.Formatting = Formatting.Indented; - doc.WriteTo(xw); - xw.Flush(); - - return ms.ToArray(); + return Util.DocToBytes(doc); } #endregion diff --git a/OpenSim/Server/Handlers/GridUser/GridUserServerConnector.cs b/OpenSim/Server/Handlers/GridUser/GridUserServerConnector.cs index 66f35e3..1e29378 100644 --- a/OpenSim/Server/Handlers/GridUser/GridUserServerConnector.cs +++ b/OpenSim/Server/Handlers/GridUser/GridUserServerConnector.cs @@ -29,6 +29,7 @@ using System; using Nini.Config; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Server.Handlers.Base; @@ -55,7 +56,9 @@ namespace OpenSim.Server.Handlers.GridUser Object[] args = new Object[] { config }; m_GridUserService = ServerUtils.LoadPlugin(service, args); - server.AddStreamHandler(new GridUserServerPostHandler(m_GridUserService)); + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); ; + + server.AddStreamHandler(new GridUserServerPostHandler(m_GridUserService, auth)); } } } diff --git a/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs b/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs index 687cf8d..9237c63 100644 --- a/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs +++ b/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs @@ -39,6 +39,7 @@ using System.Collections.Generic; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; using OpenMetaverse; @@ -50,13 +51,13 @@ namespace OpenSim.Server.Handlers.GridUser private IGridUserService m_GridUserService; - public GridUserServerPostHandler(IGridUserService service) : - base("POST", "/griduser") + public GridUserServerPostHandler(IGridUserService service, IServiceAuth auth) : + base("POST", "/griduser", auth) { m_GridUserService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); @@ -185,10 +186,12 @@ namespace OpenSim.Server.Handlers.GridUser GridUserInfo guinfo = m_GridUserService.GetGridUserInfo(user); Dictionary result = new Dictionary(); - result["result"] = guinfo.ToKeyValuePairs(); + if (guinfo != null) + result["result"] = guinfo.ToKeyValuePairs(); + else + result["result"] = "null"; string xmlString = ServerUtils.BuildXmlResponse(result); - //m_log.DebugFormat("[GRID USER HANDLER]: resp string: {0}", xmlString); return Util.UTF8NoBomEncoding.GetBytes(xmlString); } @@ -276,7 +279,7 @@ namespace OpenSim.Server.Handlers.GridUser rootElement.AppendChild(result); - return DocToBytes(doc); + return Util.DocToBytes(doc); } private byte[] FailureResult() @@ -298,20 +301,8 @@ namespace OpenSim.Server.Handlers.GridUser rootElement.AppendChild(result); - return DocToBytes(doc); + return Util.DocToBytes(doc); } - private byte[] DocToBytes(XmlDocument doc) - { - MemoryStream ms = new MemoryStream(); - XmlTextWriter xw = new XmlTextWriter(ms, null); - xw.Formatting = Formatting.Indented; - doc.WriteTo(xw); - xw.Flush(); - - return ms.ToArray(); - } - - } } diff --git a/OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs b/OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs index cf1af15..95a0510 100644 --- a/OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs @@ -61,9 +61,10 @@ namespace OpenSim.Server.Handlers.Hypergrid m_Proxy = proxy; } - protected override bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason) + protected override bool CreateAgent(GridRegion source, GridRegion gatekeeper, GridRegion destination, + AgentCircuitData aCircuit, uint teleportFlags, bool fromLogin, out string reason) { - return m_GatekeeperService.LoginAgent(aCircuit, destination, out reason); + return m_GatekeeperService.LoginAgent(source, aCircuit, destination, out reason); } } } diff --git a/OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs index 0d4990a..ffe2f36 100644 --- a/OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs @@ -76,10 +76,14 @@ namespace OpenSim.Server.Handlers.Hypergrid server.AddStreamHandler(new GatekeeperAgentHandler(m_GatekeeperService, m_Proxy)); } - public GatekeeperServiceInConnector(IConfigSource config, IHttpServer server) - : this(config, server, null) + public GatekeeperServiceInConnector(IConfigSource config, IHttpServer server, string configName) + : this(config, server, (ISimulationService)null) { } + public GatekeeperServiceInConnector(IConfigSource config, IHttpServer server) + : this(config, server, String.Empty) + { + } } } diff --git a/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs b/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs index 0aa2729..37b47ed 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs @@ -68,7 +68,7 @@ namespace OpenSim.Server.Handlers.Hypergrid m_log.ErrorFormat("[HGFRIENDS HANDLER]: TheService is null!"); } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); @@ -335,7 +335,7 @@ namespace OpenSim.Server.Handlers.Hypergrid rootElement.AppendChild(result); - return DocToBytes(doc); + return Util.DocToBytes(doc); } private byte[] SuccessResult(string value) @@ -362,7 +362,7 @@ namespace OpenSim.Server.Handlers.Hypergrid rootElement.AppendChild(message); - return DocToBytes(doc); + return Util.DocToBytes(doc); } @@ -395,7 +395,7 @@ namespace OpenSim.Server.Handlers.Hypergrid rootElement.AppendChild(message); - return DocToBytes(doc); + return Util.DocToBytes(doc); } private byte[] BoolResult(bool value) @@ -417,21 +417,9 @@ namespace OpenSim.Server.Handlers.Hypergrid rootElement.AppendChild(result); - return DocToBytes(doc); + return Util.DocToBytes(doc); } - private byte[] DocToBytes(XmlDocument doc) - { - MemoryStream ms = new MemoryStream(); - XmlTextWriter xw = new XmlTextWriter(ms, null); - xw.Formatting = Formatting.Indented; - doc.WriteTo(xw); - xw.Flush(); - - return ms.ToArray(); - } - - #endregion } } diff --git a/OpenSim/Server/Handlers/Hypergrid/HeloServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/HeloServerConnector.cs index f306b1c..dac4ca8 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HeloServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HeloServerConnector.cs @@ -44,7 +44,9 @@ namespace OpenSim.Server.Handlers.Hypergrid public HeloServiceInConnector(IConfigSource config, IHttpServer server, string configName) : base(config, server, configName) { +#pragma warning disable 0612 server.AddStreamHandler(new HeloServerGetHandler("opensim-robust")); +#pragma warning restore 0612 server.AddStreamHandler(new HeloServerHeadHandler("opensim-robust")); } } @@ -91,7 +93,7 @@ namespace OpenSim.Server.Handlers.Hypergrid m_HandlersType = handlersType; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { return OKResponse(httpResponse); diff --git a/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs b/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs index 968c1e6..e787f7c 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs @@ -49,191 +49,89 @@ using log4net; namespace OpenSim.Server.Handlers.Hypergrid { - public class HomeAgentHandler + public class HomeAgentHandler : AgentPostHandler { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IUserAgentService m_UserAgentService; private string m_LoginServerIP; - private bool m_Proxy = false; - public HomeAgentHandler(IUserAgentService userAgentService, string loginServerIP, bool proxy) + public HomeAgentHandler(IUserAgentService userAgentService, string loginServerIP, bool proxy) : + base("/homeagent") { m_UserAgentService = userAgentService; m_LoginServerIP = loginServerIP; m_Proxy = proxy; } - public Hashtable Handler(Hashtable request) + protected override AgentDestinationData CreateAgentDestinationData() { -// m_log.Debug("[CONNECTION DEBUGGING]: HomeAgentHandler Called"); -// -// m_log.Debug("---------------------------"); -// m_log.Debug(" >> uri=" + request["uri"]); -// m_log.Debug(" >> content-type=" + request["content-type"]); -// m_log.Debug(" >> http-method=" + request["http-method"]); -// m_log.Debug("---------------------------\n"); - - Hashtable responsedata = new Hashtable(); - responsedata["content_type"] = "text/html"; - responsedata["keepalive"] = false; - - - UUID agentID; - UUID regionID; - string action; - if (!Utils.GetParams((string)request["uri"], out agentID, out regionID, out action)) + return new ExtendedAgentDestinationData(); + } + + protected override void UnpackData(OSDMap args, AgentDestinationData d, Hashtable request) + { + base.UnpackData(args, d, request); + ExtendedAgentDestinationData data = (ExtendedAgentDestinationData)d; + try { - m_log.InfoFormat("[HOME AGENT HANDLER]: Invalid parameters for agent message {0}", request["uri"]); - responsedata["int_response_code"] = 404; - responsedata["str_response_string"] = "false"; + if (args.ContainsKey("gatekeeper_host") && args["gatekeeper_host"] != null) + data.host = args["gatekeeper_host"].AsString(); + if (args.ContainsKey("gatekeeper_port") && args["gatekeeper_port"] != null) + Int32.TryParse(args["gatekeeper_port"].AsString(), out data.port); + if (args.ContainsKey("gatekeeper_serveruri") && args["gatekeeper_serveruri"] != null) + data.gatekeeperServerURI = args["gatekeeper_serveruri"]; + if (args.ContainsKey("destination_serveruri") && args["destination_serveruri"] != null) + data.destinationServerURI = args["destination_serveruri"]; - return responsedata; } - - // Next, let's parse the verb - string method = (string)request["http-method"]; - if (method.Equals("POST")) + catch (InvalidCastException) { - DoAgentPost(request, responsedata, agentID); - return responsedata; + m_log.ErrorFormat("[HOME AGENT HANDLER]: Bad cast in UnpackData"); } - else - { - m_log.InfoFormat("[HOME AGENT HANDLER]: method {0} not supported in agent message", method); - responsedata["int_response_code"] = HttpStatusCode.MethodNotAllowed; - responsedata["str_response_string"] = "Method not allowed"; - return responsedata; - } + string callerIP = GetCallerIP(request); + // Verify if this call came from the login server + if (callerIP == m_LoginServerIP) + data.fromLogin = true; } - protected void DoAgentPost(Hashtable request, Hashtable responsedata, UUID id) + protected override GridRegion ExtractGatekeeper(AgentDestinationData d) { - OSDMap args = Utils.GetOSDMap((string)request["body"]); - if (args == null) + if (d is ExtendedAgentDestinationData) { - responsedata["int_response_code"] = HttpStatusCode.BadRequest; - responsedata["str_response_string"] = "Bad request"; - return; + ExtendedAgentDestinationData data = (ExtendedAgentDestinationData)d; + GridRegion gatekeeper = new GridRegion(); + gatekeeper.ServerURI = data.gatekeeperServerURI; + gatekeeper.ExternalHostName = data.host; + gatekeeper.HttpPort = (uint)data.port; + gatekeeper.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0); + + return gatekeeper; } - - // retrieve the input arguments - int x = 0, y = 0; - UUID uuid = UUID.Zero; - string regionname = string.Empty; - string gatekeeper_host = string.Empty; - string gatekeeper_serveruri = string.Empty; - string destination_serveruri = string.Empty; - int gatekeeper_port = 0; - IPEndPoint client_ipaddress = null; - - if (args.ContainsKey("gatekeeper_host") && args["gatekeeper_host"] != null) - gatekeeper_host = args["gatekeeper_host"].AsString(); - if (args.ContainsKey("gatekeeper_port") && args["gatekeeper_port"] != null) - Int32.TryParse(args["gatekeeper_port"].AsString(), out gatekeeper_port); - if (args.ContainsKey("gatekeeper_serveruri") && args["gatekeeper_serveruri"] !=null) - gatekeeper_serveruri = args["gatekeeper_serveruri"]; - if (args.ContainsKey("destination_serveruri") && args["destination_serveruri"] !=null) - destination_serveruri = args["destination_serveruri"]; - - GridRegion gatekeeper = new GridRegion(); - gatekeeper.ServerURI = gatekeeper_serveruri; - gatekeeper.ExternalHostName = gatekeeper_host; - gatekeeper.HttpPort = (uint)gatekeeper_port; - gatekeeper.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0); - - if (args.ContainsKey("destination_x") && args["destination_x"] != null) - Int32.TryParse(args["destination_x"].AsString(), out x); - else - m_log.WarnFormat(" -- request didn't have destination_x"); - if (args.ContainsKey("destination_y") && args["destination_y"] != null) - Int32.TryParse(args["destination_y"].AsString(), out y); else - m_log.WarnFormat(" -- request didn't have destination_y"); - if (args.ContainsKey("destination_uuid") && args["destination_uuid"] != null) - UUID.TryParse(args["destination_uuid"].AsString(), out uuid); - if (args.ContainsKey("destination_name") && args["destination_name"] != null) - regionname = args["destination_name"].ToString(); - - if (args.ContainsKey("client_ip") && args["client_ip"] != null) - { - string ip_str = args["client_ip"].ToString(); - try - { - string callerIP = GetCallerIP(request); - // Verify if this caller has authority to send the client IP - if (callerIP == m_LoginServerIP) - client_ipaddress = new IPEndPoint(IPAddress.Parse(ip_str), 0); - else // leaving this for now, but this warning should be removed - m_log.WarnFormat("[HOME AGENT HANDLER]: Unauthorized machine {0} tried to set client ip to {1}", callerIP, ip_str); - } - catch - { - m_log.DebugFormat("[HOME AGENT HANDLER]: Exception parsing client ip address from {0}", ip_str); - } - } + m_log.WarnFormat("[HOME AGENT HANDLER]: Wrong data type"); - GridRegion destination = new GridRegion(); - destination.RegionID = uuid; - destination.RegionLocX = x; - destination.RegionLocY = y; - destination.RegionName = regionname; - destination.ServerURI = destination_serveruri; - - AgentCircuitData aCircuit = new AgentCircuitData(); - try - { - aCircuit.UnpackAgentCircuitData(args); - } - catch (Exception ex) - { - m_log.InfoFormat("[HOME AGENT HANDLER]: exception on unpacking ChildCreate message {0}", ex.Message); - responsedata["int_response_code"] = HttpStatusCode.BadRequest; - responsedata["str_response_string"] = "Bad request"; - return; - } - - OSDMap resp = new OSDMap(2); - string reason = String.Empty; - - bool result = m_UserAgentService.LoginAgentToGrid(aCircuit, gatekeeper, destination, client_ipaddress, out reason); - - resp["reason"] = OSD.FromString(reason); - resp["success"] = OSD.FromBoolean(result); - - // TODO: add reason if not String.Empty? - responsedata["int_response_code"] = HttpStatusCode.OK; - responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp); + return null; } - private string GetCallerIP(Hashtable request) - { - if (!m_Proxy) - return Util.GetCallerIP(request); - - // We're behind a proxy - Hashtable headers = (Hashtable)request["headers"]; - string xff = "X-Forwarded-For"; - if (headers.ContainsKey(xff.ToLower())) - xff = xff.ToLower(); - if (!headers.ContainsKey(xff) || headers[xff] == null) - { - m_log.WarnFormat("[AGENT HANDLER]: No XFF header"); - return Util.GetCallerIP(request); - } + protected override bool CreateAgent(GridRegion source, GridRegion gatekeeper, GridRegion destination, + AgentCircuitData aCircuit, uint teleportFlags, bool fromLogin, out string reason) + { + return m_UserAgentService.LoginAgentToGrid(source, aCircuit, gatekeeper, destination, fromLogin, out reason); + } - m_log.DebugFormat("[AGENT HANDLER]: XFF is {0}", headers[xff]); + } - IPEndPoint ep = Util.GetClientIPFromXFF((string)headers[xff]); - if (ep != null) - return ep.Address.ToString(); + public class ExtendedAgentDestinationData : AgentDestinationData + { + public string host; + public int port; + public string gatekeeperServerURI; + public string destinationServerURI; - // Oops - return Util.GetCallerIP(request); - } } } diff --git a/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs b/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs index 5d03097..c7ac9be 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HypergridHandlers.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -94,22 +94,38 @@ namespace OpenSim.Server.Handlers.Hypergrid UUID regionID = UUID.Zero; UUID.TryParse(regionID_str, out regionID); - GridRegion regInfo = m_GatekeeperService.GetHyperlinkRegion(regionID); + UUID agentID = UUID.Zero; + string agentHomeURI = null; + if (requestData.ContainsKey("agent_id")) + agentID = UUID.Parse((string)requestData["agent_id"]); + if (requestData.ContainsKey("agent_home_uri")) + agentHomeURI = (string)requestData["agent_home_uri"]; + + string message; + GridRegion regInfo = m_GatekeeperService.GetHyperlinkRegion(regionID, agentID, agentHomeURI, out message); Hashtable hash = new Hashtable(); if (regInfo == null) + { hash["result"] = "false"; + } else { hash["result"] = "true"; hash["uuid"] = regInfo.RegionID.ToString(); hash["x"] = regInfo.RegionLocX.ToString(); hash["y"] = regInfo.RegionLocY.ToString(); + hash["size_x"] = regInfo.RegionSizeX.ToString(); + hash["size_y"] = regInfo.RegionSizeY.ToString(); hash["region_name"] = regInfo.RegionName; hash["hostname"] = regInfo.ExternalHostName; hash["http_port"] = regInfo.HttpPort.ToString(); hash["internal_port"] = regInfo.InternalEndPoint.Port.ToString(); } + + if (message != null) + hash["message"] = message; + XmlRpcResponse response = new XmlRpcResponse(); response.Value = hash; return response; diff --git a/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs index 80eb5d2..8145a21 100644 --- a/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs @@ -54,10 +54,15 @@ namespace OpenSim.Server.Handlers.Hypergrid private IInstantMessage m_IMService; public InstantMessageServerConnector(IConfigSource config, IHttpServer server) : - this(config, server, null) + this(config, server, (IInstantMessageSimConnector)null) { } + public InstantMessageServerConnector(IConfigSource config, IHttpServer server, string configName) : + this(config, server) + { + } + public InstantMessageServerConnector(IConfigSource config, IHttpServer server, IInstantMessageSimConnector simConnector) : base(config, server, String.Empty) { diff --git a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs index db62aaa..e112e0e 100644 --- a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs @@ -62,10 +62,15 @@ namespace OpenSim.Server.Handlers.Hypergrid private bool m_VerifyCallers = false; public UserAgentServerConnector(IConfigSource config, IHttpServer server) : - this(config, server, null) + this(config, server, (IFriendsSimConnector)null) { } + public UserAgentServerConnector(IConfigSource config, IHttpServer server, string configName) : + this(config, server) + { + } + public UserAgentServerConnector(IConfigSource config, IHttpServer server, IFriendsSimConnector friendsConnector) : base(config, server, String.Empty) { @@ -94,8 +99,10 @@ namespace OpenSim.Server.Handlers.Hypergrid server.AddXmlRPCHandler("verify_client", VerifyClient, false); server.AddXmlRPCHandler("logout_agent", LogoutAgent, false); +#pragma warning disable 0612 server.AddXmlRPCHandler("status_notification", StatusNotification, false); server.AddXmlRPCHandler("get_online_friends", GetOnlineFriends, false); +#pragma warning restore 0612 server.AddXmlRPCHandler("get_user_info", GetUserInfo, false); server.AddXmlRPCHandler("get_server_urls", GetServerURLs, false); @@ -103,7 +110,7 @@ namespace OpenSim.Server.Handlers.Hypergrid server.AddXmlRPCHandler("get_uui", GetUUI, false); server.AddXmlRPCHandler("get_uuid", GetUUID, false); - server.AddHTTPHandler("/homeagent/", new HomeAgentHandler(m_HomeUsersService, loginServerIP, proxy).Handler); + server.AddStreamHandler(new HomeAgentHandler(m_HomeUsersService, loginServerIP, proxy)); } public XmlRpcResponse GetHomeRegion(XmlRpcRequest request, IPEndPoint remoteClient) @@ -127,6 +134,8 @@ namespace OpenSim.Server.Handlers.Hypergrid hash["uuid"] = regInfo.RegionID.ToString(); hash["x"] = regInfo.RegionLocX.ToString(); hash["y"] = regInfo.RegionLocY.ToString(); + hash["size_x"] = regInfo.RegionSizeX.ToString(); + hash["size_y"] = regInfo.RegionSizeY.ToString(); hash["region_name"] = regInfo.RegionName; hash["hostname"] = regInfo.ExternalHostName; hash["http_port"] = regInfo.HttpPort.ToString(); @@ -448,7 +457,6 @@ namespace OpenSim.Server.Handlers.Hypergrid XmlRpcResponse response = new XmlRpcResponse(); response.Value = hash; return response; - } /// @@ -466,9 +474,7 @@ namespace OpenSim.Server.Handlers.Hypergrid //string portstr = (string)requestData["port"]; if (requestData.ContainsKey("first") && requestData.ContainsKey("last")) { - UUID userID = UUID.Zero; string first = (string)requestData["first"]; - string last = (string)requestData["last"]; UUID uuid = m_HomeUsersService.GetUUID(first, last); hash["UUID"] = uuid.ToString(); @@ -477,7 +483,6 @@ namespace OpenSim.Server.Handlers.Hypergrid XmlRpcResponse response = new XmlRpcResponse(); response.Value = hash; return response; - } } -} +} \ No newline at end of file diff --git a/OpenSim/Server/Handlers/Inventory/InventoryServerInConnector.cs b/OpenSim/Server/Handlers/Inventory/InventoryServerInConnector.cs index 1d422a7..b295446 100644 --- a/OpenSim/Server/Handlers/Inventory/InventoryServerInConnector.cs +++ b/OpenSim/Server/Handlers/Inventory/InventoryServerInConnector.cs @@ -86,10 +86,6 @@ namespace OpenSim.Server.Handlers.Inventory protected virtual void AddHttpHandlers(IHttpServer m_httpServer) { m_httpServer.AddStreamHandler( - new RestDeserialiseSecureHandler( - "POST", "/GetInventory/", GetUserInventory, CheckAuthSession)); - - m_httpServer.AddStreamHandler( new RestDeserialiseSecureHandler>( "POST", "/SystemFolders/", GetSystemFolders, CheckAuthSession)); @@ -178,12 +174,6 @@ namespace OpenSim.Server.Handlers.Inventory #region Wrappers for converting the Guid parameter - public InventoryCollection GetUserInventory(Guid guid) - { - UUID userID = new UUID(guid); - return m_InventoryService.GetUserInventory(userID); - } - public List GetSystemFolders(Guid guid) { UUID userID = new UUID(guid); diff --git a/OpenSim/Server/Handlers/Inventory/InventoryServerMoveItemsHandler.cs b/OpenSim/Server/Handlers/Inventory/InventoryServerMoveItemsHandler.cs index 231e32f..e2c50fe 100644 --- a/OpenSim/Server/Handlers/Inventory/InventoryServerMoveItemsHandler.cs +++ b/OpenSim/Server/Handlers/Inventory/InventoryServerMoveItemsHandler.cs @@ -56,7 +56,7 @@ namespace OpenSim.Server.Handlers.Inventory m_InventoryService = service; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { XmlSerializer xs = new XmlSerializer(typeof (List)); diff --git a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs index 64127c2..5c4e7a9 100644 --- a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs +++ b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs @@ -33,6 +33,7 @@ using System.Collections.Generic; using System.IO; using Nini.Config; using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Framework.Servers.HttpServer; @@ -40,7 +41,9 @@ using OpenSim.Server.Handlers.Base; using log4net; using OpenMetaverse; -namespace OpenSim.Server.Handlers.Asset +using System.Threading; + +namespace OpenSim.Server.Handlers.Inventory { public class XInventoryInConnector : ServiceConnector { @@ -71,7 +74,9 @@ namespace OpenSim.Server.Handlers.Asset m_InventoryService = ServerUtils.LoadPlugin(inventoryService, args); - server.AddStreamHandler(new XInventoryConnectorPostHandler(m_InventoryService)); + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); + + server.AddStreamHandler(new XInventoryConnectorPostHandler(m_InventoryService, auth)); } } @@ -81,13 +86,13 @@ namespace OpenSim.Server.Handlers.Asset private IInventoryService m_InventoryService; - public XInventoryConnectorPostHandler(IInventoryService service) : - base("POST", "/xinventory") + public XInventoryConnectorPostHandler(IInventoryService service, IServiceAuth auth) : + base("POST", "/xinventory", auth) { m_InventoryService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); @@ -114,14 +119,14 @@ namespace OpenSim.Server.Handlers.Asset return HandleCreateUserInventory(request); case "GETINVENTORYSKELETON": return HandleGetInventorySkeleton(request); - case "GETUSERINVENTORY": - return HandleGetUserInventory(request); case "GETROOTFOLDER": return HandleGetRootFolder(request); case "GETFOLDERFORTYPE": return HandleGetFolderForType(request); case "GETFOLDERCONTENT": return HandleGetFolderContent(request); + case "GETMULTIPLEFOLDERSCONTENT": + return HandleGetMultipleFoldersContent(request); case "GETFOLDERITEMS": return HandleGetFolderItems(request); case "ADDFOLDER": @@ -144,6 +149,8 @@ namespace OpenSim.Server.Handlers.Asset return HandleDeleteItems(request); case "GETITEM": return HandleGetItem(request); + case "GETMULTIPLEITEMS": + return HandleGetMultipleItems(request); case "GETFOLDER": return HandleGetFolder(request); case "GETACTIVEGESTURES": @@ -155,7 +162,7 @@ namespace OpenSim.Server.Handlers.Asset } catch (Exception e) { - m_log.DebugFormat("[XINVENTORY HANDLER]: Exception {0}", e.StackTrace); + m_log.Error(string.Format("[XINVENTORY HANDLER]: Exception {0} ", e.Message), e); } return FailureResult(); @@ -190,18 +197,7 @@ namespace OpenSim.Server.Handlers.Asset rootElement.AppendChild(result); - return DocToBytes(doc); - } - - private byte[] DocToBytes(XmlDocument doc) - { - MemoryStream ms = new MemoryStream(); - XmlTextWriter xw = new XmlTextWriter(ms, null); - xw.Formatting = Formatting.Indented; - doc.WriteTo(xw); - xw.Flush(); - - return ms.ToArray(); + return Util.DocToBytes(doc); } byte[] HandleCreateUserInventory(Dictionary request) @@ -250,45 +246,6 @@ namespace OpenSim.Server.Handlers.Asset return Util.UTF8NoBomEncoding.GetBytes(xmlString); } - byte[] HandleGetUserInventory(Dictionary request) - { - Dictionary result = new Dictionary(); - UUID principal = UUID.Zero; - UUID.TryParse(request["PRINCIPAL"].ToString(), out principal); - - InventoryCollection icoll = m_InventoryService.GetUserInventory(principal); - if (icoll != null) - { - Dictionary folders = new Dictionary(); - int i = 0; - if (icoll.Folders != null) - { - foreach (InventoryFolderBase f in icoll.Folders) - { - folders["folder_" + i.ToString()] = EncodeFolder(f); - i++; - } - result["FOLDERS"] = folders; - } - if (icoll.Items != null) - { - i = 0; - Dictionary items = new Dictionary(); - foreach (InventoryItemBase it in icoll.Items) - { - items["item_" + i.ToString()] = EncodeItem(it); - i++; - } - result["ITEMS"] = items; - } - } - - string xmlString = ServerUtils.BuildXmlResponse(result); - - //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); - return Util.UTF8NoBomEncoding.GetBytes(xmlString); - } - byte[] HandleGetRootFolder(Dictionary request) { Dictionary result = new Dictionary(); @@ -312,7 +269,7 @@ namespace OpenSim.Server.Handlers.Asset UUID.TryParse(request["PRINCIPAL"].ToString(), out principal); int type = 0; Int32.TryParse(request["TYPE"].ToString(), out type); - InventoryFolderBase folder = m_InventoryService.GetFolderForType(principal, (AssetType)type); + InventoryFolderBase folder = m_InventoryService.GetFolderForType(principal, (FolderType)type); if (folder != null) result["folder"] = EncodeFolder(folder); @@ -333,6 +290,8 @@ namespace OpenSim.Server.Handlers.Asset InventoryCollection icoll = m_InventoryService.GetFolderContent(principal, folderID); if (icoll != null) { + result["FID"] = icoll.FolderID.ToString(); + result["VERSION"] = icoll.Version.ToString(); Dictionary folders = new Dictionary(); int i = 0; if (icoll.Folders != null) @@ -363,7 +322,71 @@ namespace OpenSim.Server.Handlers.Asset return Util.UTF8NoBomEncoding.GetBytes(xmlString); } - byte[] HandleGetFolderItems(Dictionary request) + byte[] HandleGetMultipleFoldersContent(Dictionary request) + { + Dictionary resultSet = new Dictionary(); + UUID principal = UUID.Zero; + UUID.TryParse(request["PRINCIPAL"].ToString(), out principal); + string folderIDstr = request["FOLDERS"].ToString(); + int count = 0; + Int32.TryParse(request["COUNT"].ToString(), out count); + + UUID[] fids = new UUID[count]; + string[] uuids = folderIDstr.Split(','); + int i = 0; + foreach (string id in uuids) + { + UUID fid = UUID.Zero; + if (UUID.TryParse(id, out fid)) + fids[i] = fid; + i += 1; + } + + count = 0; + InventoryCollection[] icollList = m_InventoryService.GetMultipleFoldersContent(principal, fids); + if (icollList != null && icollList.Length > 0) + { + foreach (InventoryCollection icoll in icollList) + { + Dictionary result = new Dictionary(); + result["FID"] = icoll.FolderID.ToString(); + result["VERSION"] = icoll.Version.ToString(); + result["OWNER"] = icoll.OwnerID.ToString(); + Dictionary folders = new Dictionary(); + i = 0; + if (icoll.Folders != null) + { + foreach (InventoryFolderBase f in icoll.Folders) + { + folders["folder_" + i.ToString()] = EncodeFolder(f); + i++; + } + result["FOLDERS"] = folders; + } + i = 0; + if (icoll.Items != null) + { + Dictionary items = new Dictionary(); + foreach (InventoryItemBase it in icoll.Items) + { + items["item_" + i.ToString()] = EncodeItem(it); + i++; + } + result["ITEMS"] = items; + } + + resultSet["F_" + fids[count++]] = result; + //m_log.DebugFormat("[XXX]: Sending {0} {1}", fids[count-1], icoll.FolderID); + } + } + + string xmlString = ServerUtils.BuildXmlResponse(resultSet); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + + byte[] HandleGetFolderItems(Dictionary request) { Dictionary result = new Dictionary(); UUID principal = UUID.Zero; @@ -555,6 +578,40 @@ namespace OpenSim.Server.Handlers.Asset return Util.UTF8NoBomEncoding.GetBytes(xmlString); } + byte[] HandleGetMultipleItems(Dictionary request) + { + Dictionary resultSet = new Dictionary(); + UUID principal = UUID.Zero; + UUID.TryParse(request["PRINCIPAL"].ToString(), out principal); + string itemIDstr = request["ITEMS"].ToString(); + int count = 0; + Int32.TryParse(request["COUNT"].ToString(), out count); + + UUID[] fids = new UUID[count]; + string[] uuids = itemIDstr.Split(','); + int i = 0; + foreach (string id in uuids) + { + UUID fid = UUID.Zero; + if (UUID.TryParse(id, out fid)) + fids[i] = fid; + i += 1; + } + + InventoryItemBase[] itemsList = m_InventoryService.GetMultipleItems(principal, fids); + if (itemsList != null && itemsList.Length > 0) + { + count = 0; + foreach (InventoryItemBase item in itemsList) + resultSet["item_" + count++] = (item == null) ? (object)"NULL" : EncodeItem(item); + } + + string xmlString = ServerUtils.BuildXmlResponse(resultSet); + + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + byte[] HandleGetFolder(Dictionary request) { Dictionary result = new Dictionary(); diff --git a/OpenSim/Server/Handlers/Login/LLLoginHandlers.cs b/OpenSim/Server/Handlers/Login/LLLoginHandlers.cs index f83a239..f2a5678 100644 --- a/OpenSim/Server/Handlers/Login/LLLoginHandlers.cs +++ b/OpenSim/Server/Handlers/Login/LLLoginHandlers.cs @@ -53,6 +53,7 @@ namespace OpenSim.Server.Handlers.Login private ILoginService m_LocalService; private bool m_Proxy; + public LLLoginHandlers(ILoginService service, bool hasProxy) { @@ -144,6 +145,17 @@ namespace OpenSim.Server.Handlers.Login return FailedXMLRPCResponse(); } + public XmlRpcResponse HandleXMLRPCLoginBlocked(XmlRpcRequest request, IPEndPoint client) + { + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable resp = new Hashtable(); + + resp["reason"] = "presence"; + resp["message"] = "Logins are currently restricted. Please try again later."; + resp["login"] = "false"; + response.Value = resp; + return response; + } public XmlRpcResponse HandleXMLRPCSetLoginLevel(XmlRpcRequest request, IPEndPoint remoteClient) { @@ -213,6 +225,61 @@ namespace OpenSim.Server.Handlers.Login return FailedOSDResponse(); } + public void HandleWebSocketLoginEvents(string path, WebSocketHttpServerHandler sock) + { + sock.MaxPayloadSize = 16384; //16 kb payload + sock.InitialMsgTimeout = 5000; //5 second first message to trigger at least one of these events + sock.NoDelay_TCP_Nagle = true; + sock.OnData += delegate(object sender, WebsocketDataEventArgs data) { sock.Close("fail"); }; + sock.OnPing += delegate(object sender, PingEventArgs pingdata) { sock.Close("fail"); }; + sock.OnPong += delegate(object sender, PongEventArgs pongdata) { sock.Close("fail"); }; + sock.OnText += delegate(object sender, WebsocketTextEventArgs text) + { + OSD request = null; + try + { + request = OSDParser.DeserializeJson(text.Data); + if (!(request is OSDMap)) + { + sock.SendMessage(OSDParser.SerializeJsonString(FailedOSDResponse())); + } + else + { + OSDMap req = request as OSDMap; + string first = req["firstname"].AsString(); + string last = req["lastname"].AsString(); + string passwd = req["passwd"].AsString(); + string start = req["startlocation"].AsString(); + string version = req["version"].AsString(); + string channel = req["channel"].AsString(); + string mac = req["mac"].AsString(); + string id0 = req["id0"].AsString(); + UUID scope = UUID.Zero; + IPEndPoint endPoint = + (sender as WebSocketHttpServerHandler).GetRemoteIPEndpoint(); + LoginResponse reply = null; + reply = m_LocalService.Login(first, last, passwd, start, scope, version, + channel, mac, id0, endPoint); + sock.SendMessage(OSDParser.SerializeJsonString(reply.ToOSDMap())); + + } + + } + catch (Exception) + { + sock.SendMessage(OSDParser.SerializeJsonString(FailedOSDResponse())); + } + finally + { + sock.Close("success"); + } + }; + + sock.HandshakeAndUpgrade(); + + } + + private XmlRpcResponse FailedXMLRPCResponse() { Hashtable hash = new Hashtable(); diff --git a/OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs b/OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs index 9a7ad34..f60e892 100644 --- a/OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs +++ b/OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs @@ -44,6 +44,7 @@ namespace OpenSim.Server.Handlers.Login private ILoginService m_LoginService; private bool m_Proxy; + private BasicDosProtectorOptions m_DosProtectionOptions; public LLLoginServiceInConnector(IConfigSource config, IHttpServer server, IScene scene) : base(config, server, String.Empty) @@ -60,8 +61,8 @@ namespace OpenSim.Server.Handlers.Login InitializeHandlers(server); } - public LLLoginServiceInConnector(IConfigSource config, IHttpServer server) : - base(config, server, String.Empty) + public LLLoginServiceInConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) { string loginService = ReadLocalServiceFromConfig(config); @@ -72,6 +73,11 @@ namespace OpenSim.Server.Handlers.Login InitializeHandlers(server); } + public LLLoginServiceInConnector(IConfigSource config, IHttpServer server) : + this(config, server, String.Empty) + { + } + private string ReadLocalServiceFromConfig(IConfigSource config) { IConfig serverConfig = config.Configs["LoginService"]; @@ -83,6 +89,16 @@ namespace OpenSim.Server.Handlers.Login throw new Exception(String.Format("No LocalServiceModule for LoginService in config file")); m_Proxy = serverConfig.GetBoolean("HasProxy", false); + m_DosProtectionOptions = new BasicDosProtectorOptions(); + // Dos Protection Options + m_DosProtectionOptions.AllowXForwardedFor = serverConfig.GetBoolean("DOSAllowXForwardedForHeader", false); + m_DosProtectionOptions.RequestTimeSpan = + TimeSpan.FromMilliseconds(serverConfig.GetInt("DOSRequestTimeFrameMS", 10000)); + m_DosProtectionOptions.MaxRequestsInTimeframe = serverConfig.GetInt("DOSMaxRequestsInTimeFrame", 5); + m_DosProtectionOptions.ForgetTimeSpan = + TimeSpan.FromMilliseconds(serverConfig.GetInt("DOSForgiveClientAfterMS", 120000)); + m_DosProtectionOptions.ReportingName = "LOGINDOSPROTECTION"; + return loginService; } @@ -90,9 +106,12 @@ namespace OpenSim.Server.Handlers.Login private void InitializeHandlers(IHttpServer server) { LLLoginHandlers loginHandlers = new LLLoginHandlers(m_LoginService, m_Proxy); - server.AddXmlRPCHandler("login_to_simulator", loginHandlers.HandleXMLRPCLogin, false); + server.AddXmlRPCHandler("login_to_simulator", + new XmlRpcBasicDOSProtector(loginHandlers.HandleXMLRPCLogin,loginHandlers.HandleXMLRPCLoginBlocked, + m_DosProtectionOptions).Process, false); server.AddXmlRPCHandler("set_login_level", loginHandlers.HandleXMLRPCSetLoginLevel, false); server.SetDefaultLLSDHandler(loginHandlers.HandleLLSDLogin); + server.AddWebSocketHandler("/WebSocket/GridLogin", loginHandlers.HandleWebSocketLoginEvents); } } } diff --git a/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs b/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs index 4a61969..649a27e 100644 --- a/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs +++ b/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs @@ -38,6 +38,7 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; +using OpenSim.Framework.ServiceAuth; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Server.Handlers.Base; @@ -79,7 +80,8 @@ namespace OpenSim.Server.Handlers.MapImage m_log.InfoFormat("[MAP IMAGE HANDLER]: GridService check is OFF"); bool proxy = serverConfig.GetBoolean("HasProxy", false); - server.AddStreamHandler(new MapServerPostHandler(m_MapService, m_GridService, proxy)); + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); + server.AddStreamHandler(new MapServerPostHandler(m_MapService, m_GridService, proxy, auth)); } } @@ -91,15 +93,15 @@ namespace OpenSim.Server.Handlers.MapImage private IGridService m_GridService; bool m_Proxy; - public MapServerPostHandler(IMapImageService service, IGridService grid, bool proxy) : - base("POST", "/map") + public MapServerPostHandler(IMapImageService service, IGridService grid, bool proxy, IServiceAuth auth) : + base("POST", "/map", auth) { m_MapService = service; m_GridService = grid; m_Proxy = proxy; } - public override byte[] Handle(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // m_log.DebugFormat("[MAP SERVICE IMAGE HANDLER]: Received {0}", path); StreamReader sr = new StreamReader(requestData); @@ -116,9 +118,9 @@ namespace OpenSim.Server.Handlers.MapImage httpResponse.StatusCode = (int)OSHttpStatusCode.ClientErrorBadRequest; return FailureResult("Bad request."); } - int x = 0, y = 0; - Int32.TryParse(request["X"].ToString(), out x); - Int32.TryParse(request["Y"].ToString(), out y); + uint x = 0, y = 0; + UInt32.TryParse(request["X"].ToString(), out x); + UInt32.TryParse(request["Y"].ToString(), out y); m_log.DebugFormat("[MAP ADD SERVER CONNECTOR]: Received map data for region at {0}-{1}", x, y); @@ -130,7 +132,7 @@ namespace OpenSim.Server.Handlers.MapImage if (m_GridService != null) { System.Net.IPAddress ipAddr = GetCallerIP(httpRequest); - GridRegion r = m_GridService.GetRegionByPosition(UUID.Zero, x * (int)Constants.RegionSize, y * (int)Constants.RegionSize); + GridRegion r = m_GridService.GetRegionByPosition(UUID.Zero, (int)Util.RegionToWorldLoc(x), (int)Util.RegionToWorldLoc(y)); if (r != null) { if (r.ExternalEndPoint.Address.ToString() != ipAddr.ToString()) @@ -151,7 +153,7 @@ namespace OpenSim.Server.Handlers.MapImage byte[] data = Convert.FromBase64String(request["DATA"].ToString()); string reason = string.Empty; - bool result = m_MapService.AddMapTile(x, y, data, out reason); + bool result = m_MapService.AddMapTile((int)x, (int)y, data, out reason); if (result) return SuccessResult(); @@ -186,7 +188,7 @@ namespace OpenSim.Server.Handlers.MapImage rootElement.AppendChild(result); - return DocToBytes(doc); + return Util.DocToBytes(doc); } private byte[] FailureResult(string msg) @@ -213,18 +215,7 @@ namespace OpenSim.Server.Handlers.MapImage rootElement.AppendChild(message); - return DocToBytes(doc); - } - - private byte[] DocToBytes(XmlDocument doc) - { - MemoryStream ms = new MemoryStream(); - XmlTextWriter xw = new XmlTextWriter(ms, null); - xw.Formatting = Formatting.Indented; - doc.WriteTo(xw); - xw.Flush(); - - return ms.ToArray(); + return Util.DocToBytes(doc); } private System.Net.IPAddress GetCallerIP(IOSHttpRequest request) diff --git a/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs b/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs index fb85d1c..7bb2f39 100644 --- a/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs +++ b/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs @@ -80,7 +80,7 @@ namespace OpenSim.Server.Handlers.MapImage m_MapService = service; } - public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { byte[] result = new byte[0]; diff --git a/OpenSim/Server/Handlers/Neighbour/NeighbourHandlers.cs b/OpenSim/Server/Handlers/Neighbour/NeighbourHandlers.cs index 8a1f824..3525a01 100644 --- a/OpenSim/Server/Handlers/Neighbour/NeighbourHandlers.cs +++ b/OpenSim/Server/Handlers/Neighbour/NeighbourHandlers.cs @@ -58,7 +58,7 @@ namespace OpenSim.Server.Handlers.Neighbour // TODO: unused: m_AuthenticationService = authentication; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // Not implemented yet @@ -83,7 +83,7 @@ namespace OpenSim.Server.Handlers.Neighbour // TODO: unused: m_AllowForeignGuests = foreignGuests; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { byte[] result = new byte[0]; @@ -176,7 +176,7 @@ namespace OpenSim.Server.Handlers.Neighbour // TODO: unused: m_AuthenticationService = authentication; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // Not implemented yet @@ -197,7 +197,7 @@ namespace OpenSim.Server.Handlers.Neighbour // TODO: unused: m_AuthenticationService = authentication; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // Not implemented yet diff --git a/OpenSim/Server/Handlers/Presence/PresenceServerConnector.cs b/OpenSim/Server/Handlers/Presence/PresenceServerConnector.cs index 899cd8f..7a63c36 100644 --- a/OpenSim/Server/Handlers/Presence/PresenceServerConnector.cs +++ b/OpenSim/Server/Handlers/Presence/PresenceServerConnector.cs @@ -30,6 +30,7 @@ using Nini.Config; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework.ServiceAuth; using OpenSim.Server.Handlers.Base; namespace OpenSim.Server.Handlers.Presence @@ -55,7 +56,9 @@ namespace OpenSim.Server.Handlers.Presence Object[] args = new Object[] { config }; m_PresenceService = ServerUtils.LoadPlugin(gridService, args); - server.AddStreamHandler(new PresenceServerPostHandler(m_PresenceService)); + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); + + server.AddStreamHandler(new PresenceServerPostHandler(m_PresenceService, auth)); } } } diff --git a/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs b/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs index 2d67c6d..49dbcb5 100644 --- a/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs @@ -40,6 +40,7 @@ using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Framework; using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework.ServiceAuth; using OpenMetaverse; namespace OpenSim.Server.Handlers.Presence @@ -50,13 +51,13 @@ namespace OpenSim.Server.Handlers.Presence private IPresenceService m_PresenceService; - public PresenceServerPostHandler(IPresenceService service) : - base("POST", "/presence") + public PresenceServerPostHandler(IPresenceService service, IServiceAuth auth) : + base("POST", "/presence", auth) { m_PresenceService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); @@ -264,7 +265,7 @@ namespace OpenSim.Server.Handlers.Presence rootElement.AppendChild(result); - return DocToBytes(doc); + return Util.DocToBytes(doc); } private byte[] FailureResult() @@ -286,18 +287,7 @@ namespace OpenSim.Server.Handlers.Presence rootElement.AppendChild(result); - return DocToBytes(doc); - } - - private byte[] DocToBytes(XmlDocument doc) - { - MemoryStream ms = new MemoryStream(); - XmlTextWriter xw = new XmlTextWriter(ms, null); - xw.Formatting = Formatting.Indented; - doc.WriteTo(xw); - xw.Flush(); - - return ms.ToArray(); + return Util.DocToBytes(doc); } } diff --git a/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs new file mode 100644 index 0000000..2dfb862 --- /dev/null +++ b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs @@ -0,0 +1,109 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using Nini.Config; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework; +using OpenSim.Server.Handlers.Base; +using log4net; + +namespace OpenSim.Server.Handlers.Profiles +{ + public class UserProfilesConnector: ServiceConnector + { +// static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // Our Local Module + public IUserProfilesService ServiceModule + { + get; private set; + } + + // The HTTP server. + public IHttpServer Server + { + get; private set; + } + + public bool Enabled + { + get; private set; + } + + public UserProfilesConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + ConfigName = "UserProfilesService"; + if(!string.IsNullOrEmpty(configName)) + ConfigName = configName; + + IConfig serverConfig = config.Configs[ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section {0} in config file", ConfigName)); + + if(!serverConfig.GetBoolean("Enabled",false)) + { + Enabled = false; + return; + } + + Enabled = true; + + Server = server; + + string service = serverConfig.GetString("LocalServiceModule", String.Empty); + + Object[] args = new Object[] { config, ConfigName }; + ServiceModule = ServerUtils.LoadPlugin(service, args); + + JsonRpcProfileHandlers handler = new JsonRpcProfileHandlers(ServiceModule); + + Server.AddJsonRPCHandler("avatarclassifiedsrequest", handler.AvatarClassifiedsRequest); + Server.AddJsonRPCHandler("classified_update", handler.ClassifiedUpdate); + Server.AddJsonRPCHandler("classifieds_info_query", handler.ClassifiedInfoRequest); + Server.AddJsonRPCHandler("classified_delete", handler.ClassifiedDelete); + Server.AddJsonRPCHandler("avatarpicksrequest", handler.AvatarPicksRequest); + Server.AddJsonRPCHandler("pickinforequest", handler.PickInfoRequest); + Server.AddJsonRPCHandler("picks_update", handler.PicksUpdate); + Server.AddJsonRPCHandler("picks_delete", handler.PicksDelete); + Server.AddJsonRPCHandler("avatarnotesrequest", handler.AvatarNotesRequest); + Server.AddJsonRPCHandler("avatar_notes_update", handler.NotesUpdate); + Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest); + Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate); + Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate); + Server.AddJsonRPCHandler("user_preferences_update", handler.UserPreferenecesUpdate); + Server.AddJsonRPCHandler("user_preferences_request", handler.UserPreferencesRequest); + Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest); + Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData); + Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData); + } + } +} \ No newline at end of file diff --git a/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs b/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs new file mode 100644 index 0000000..49aa8ba --- /dev/null +++ b/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs @@ -0,0 +1,513 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using log4net; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework; + +namespace OpenSim.Server.Handlers +{ + public class UserProfilesHandlers + { + public UserProfilesHandlers () + { + } + } + + public class JsonRpcProfileHandlers + { + static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + public IUserProfilesService Service + { + get; private set; + } + + public JsonRpcProfileHandlers(IUserProfilesService service) + { + Service = service; + } + + #region Classifieds + /// + /// Request avatar's classified ads. + /// + /// + /// An array containing all the calassified uuid and it's name created by the creator id + /// + /// + /// Our parameters are in the OSDMap json["params"] + /// + /// + /// If set to true response. + /// + public bool AvatarClassifiedsRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + m_log.DebugFormat ("Classified Request"); + return false; + } + + OSDMap request = (OSDMap)json["params"]; + UUID creatorId = new UUID(request["creatorId"].AsString()); + + + OSDArray data = (OSDArray) Service.AvatarClassifiedsRequest(creatorId); + response.Result = data; + + return true; + } + + public bool ClassifiedUpdate(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "Error parsing classified update request"; + m_log.DebugFormat ("Classified Update Request"); + return false; + } + + string result = string.Empty; + UserClassifiedAdd ad = new UserClassifiedAdd(); + object Ad = (object)ad; + OSD.DeserializeMembers(ref Ad, (OSDMap)json["params"]); + if(Service.ClassifiedUpdate(ad, ref result)) + { + response.Result = OSD.SerializeMembers(ad); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + + public bool ClassifiedDelete(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + m_log.DebugFormat ("Classified Delete Request"); + return false; + } + + OSDMap request = (OSDMap)json["params"]; + UUID classifiedId = new UUID(request["classifiedId"].AsString()); + + if (Service.ClassifiedDelete(classifiedId)) + return true; + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = "data error removing record"; + return false; + } + + public bool ClassifiedInfoRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("Classified Info Request"); + return false; + } + + string result = string.Empty; + UserClassifiedAdd ad = new UserClassifiedAdd(); + object Ad = (object)ad; + OSD.DeserializeMembers(ref Ad, (OSDMap)json["params"]); + if(Service.ClassifiedInfoRequest(ref ad, ref result)) + { + response.Result = OSD.SerializeMembers(ad); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + #endregion Classifieds + + #region Picks + public bool AvatarPicksRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + m_log.DebugFormat ("Avatar Picks Request"); + return false; + } + + OSDMap request = (OSDMap)json["params"]; + UUID creatorId = new UUID(request["creatorId"].AsString()); + + + OSDArray data = (OSDArray) Service.AvatarPicksRequest(creatorId); + response.Result = data; + + return true; + } + + public bool PickInfoRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("Avatar Picks Info Request"); + return false; + } + + string result = string.Empty; + UserProfilePick pick = new UserProfilePick(); + object Pick = (object)pick; + OSD.DeserializeMembers(ref Pick, (OSDMap)json["params"]); + if(Service.PickInfoRequest(ref pick, ref result)) + { + response.Result = OSD.SerializeMembers(pick); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + + public bool PicksUpdate(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("Avatar Picks Update Request"); + return false; + } + + string result = string.Empty; + UserProfilePick pick = new UserProfilePick(); + object Pick = (object)pick; + OSD.DeserializeMembers(ref Pick, (OSDMap)json["params"]); + if(Service.PicksUpdate(ref pick, ref result)) + { + response.Result = OSD.SerializeMembers(pick); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = "unable to update pick"; + + return false; + } + + public bool PicksDelete(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + m_log.DebugFormat ("Avatar Picks Delete Request"); + return false; + } + + OSDMap request = (OSDMap)json["params"]; + UUID pickId = new UUID(request["pickId"].AsString()); + if(Service.PicksDelete(pickId)) + return true; + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = "data error removing record"; + return false; + } + #endregion Picks + + #region Notes + public bool AvatarNotesRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "Params missing"; + m_log.DebugFormat ("Avatar Notes Request"); + return false; + } + + UserProfileNotes note = new UserProfileNotes(); + object Note = (object)note; + OSD.DeserializeMembers(ref Note, (OSDMap)json["params"]); + if(Service.AvatarNotesRequest(ref note)) + { + response.Result = OSD.SerializeMembers(note); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = "Error reading notes"; + return false; + } + + public bool NotesUpdate(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "No parameters"; + m_log.DebugFormat ("Avatar Notes Update Request"); + return false; + } + + string result = string.Empty; + UserProfileNotes note = new UserProfileNotes(); + object Notes = (object) note; + OSD.DeserializeMembers(ref Notes, (OSDMap)json["params"]); + if(Service.NotesUpdate(ref note, ref result)) + { + response.Result = OSD.SerializeMembers(note); + return true; + } + return true; + } + #endregion Notes + + #region Profile Properties + public bool AvatarPropertiesRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("Avatar Properties Request"); + return false; + } + + string result = string.Empty; + UserProfileProperties props = new UserProfileProperties(); + object Props = (object)props; + OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]); + if(Service.AvatarPropertiesRequest(ref props, ref result)) + { + response.Result = OSD.SerializeMembers(props); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + + public bool AvatarPropertiesUpdate(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("Avatar Properties Update Request"); + return false; + } + + string result = string.Empty; + UserProfileProperties props = new UserProfileProperties(); + object Props = (object)props; + OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]); + if(Service.AvatarPropertiesUpdate(ref props, ref result)) + { + response.Result = OSD.SerializeMembers(props); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + #endregion Profile Properties + + #region Interests + public bool AvatarInterestsUpdate(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("Avatar Interests Update Request"); + return false; + } + + string result = string.Empty; + UserProfileProperties props = new UserProfileProperties(); + object Props = (object)props; + OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]); + if(Service.AvatarInterestsUpdate(props, ref result)) + { + response.Result = OSD.SerializeMembers(props); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + #endregion Interests + + #region User Preferences + public bool UserPreferencesRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + m_log.DebugFormat ("User Preferences Request"); + return false; + } + + string result = string.Empty; + UserPreferences prefs = new UserPreferences(); + object Prefs = (object)prefs; + OSD.DeserializeMembers(ref Prefs, (OSDMap)json["params"]); + if(Service.UserPreferencesRequest(ref prefs, ref result)) + { + response.Result = OSD.SerializeMembers(prefs); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); +// m_log.InfoFormat("[PROFILES]: User preferences request error - {0}", response.Error.Message); + return false; + } + + public bool UserPreferenecesUpdate(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("User Preferences Update Request"); + return false; + } + + string result = string.Empty; + UserPreferences prefs = new UserPreferences(); + object Prefs = (object)prefs; + OSD.DeserializeMembers(ref Prefs, (OSDMap)json["params"]); + if(Service.UserPreferencesUpdate(ref prefs, ref result)) + { + response.Result = OSD.SerializeMembers(prefs); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + m_log.InfoFormat("[PROFILES]: User preferences update error - {0}", response.Error.Message); + return false; + } + #endregion User Preferences + + #region Utility + public bool AvatarImageAssetsRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + m_log.DebugFormat ("Avatar Image Assets Request"); + return false; + } + + OSDMap request = (OSDMap)json["params"]; + UUID avatarId = new UUID(request["avatarId"].AsString()); + + OSDArray data = (OSDArray) Service.AvatarImageAssetsRequest(avatarId); + response.Result = data; + + return true; + } + #endregion Utiltiy + + #region UserData + public bool RequestUserAppData(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("User Application Service URL Request: No Parameters!"); + return false; + } + + string result = string.Empty; + UserAppData props = new UserAppData(); + object Props = (object)props; + OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]); + if(Service.RequestUserAppData(ref props, ref result)) + { + OSDMap res = new OSDMap(); + res["result"] = OSD.FromString("success"); + res["token"] = OSD.FromString (result); + response.Result = res; + + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + + public bool UpdateUserAppData(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("User App Data Update Request"); + return false; + } + + string result = string.Empty; + UserAppData props = new UserAppData(); + object Props = (object)props; + OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]); + if(Service.SetUserAppData(props, ref result)) + { + response.Result = OSD.SerializeMembers(props); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + #endregion UserData + } +} + diff --git a/OpenSim/Server/Handlers/Properties/AssemblyInfo.cs b/OpenSim/Server/Handlers/Properties/AssemblyInfo.cs index 53e9737..f0b36c1 100644 --- a/OpenSim/Server/Handlers/Properties/AssemblyInfo.cs +++ b/OpenSim/Server/Handlers/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs index 012b14e..98c5312 100644 --- a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs @@ -27,11 +27,14 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; using System.IO; using System.IO.Compression; using System.Reflection; using System.Net; using System.Text; +using System.Web; using OpenSim.Server.Base; using OpenSim.Server.Handlers.Base; @@ -90,14 +93,13 @@ namespace OpenSim.Server.Handlers.Simulation // Next, let's parse the verb string method = (string)request["http-method"]; - if (method.Equals("GET")) + if (method.Equals("DELETE")) { - DoAgentGet(request, responsedata, agentID, regionID); - return responsedata; - } - else if (method.Equals("DELETE")) - { - DoAgentDelete(request, responsedata, agentID, action, regionID); + string auth_token = string.Empty; + if (request.ContainsKey("auth")) + auth_token = request["auth"].ToString(); + + DoAgentDelete(request, responsedata, agentID, action, regionID, auth_token); return responsedata; } else if (method.Equals("QUERYACCESS")) @@ -107,7 +109,7 @@ namespace OpenSim.Server.Handlers.Simulation } else { - m_log.InfoFormat("[AGENT HANDLER]: method {0} not supported in agent message", method); + m_log.ErrorFormat("[AGENT HANDLER]: method {0} not supported in agent message {1} (caller is {2})", method, (string)request["uri"], Util.GetCallerIP(request)); responsedata["int_response_code"] = HttpStatusCode.MethodNotAllowed; responsedata["str_response_string"] = "Method not allowed"; @@ -116,7 +118,7 @@ namespace OpenSim.Server.Handlers.Simulation } - protected virtual void DoQueryAccess(Hashtable request, Hashtable responsedata, UUID id, UUID regionID) + protected virtual void DoQueryAccess(Hashtable request, Hashtable responsedata, UUID agentID, UUID regionID) { if (m_SimulationService == null) { @@ -131,86 +133,155 @@ namespace OpenSim.Server.Handlers.Simulation // m_log.DebugFormat("[AGENT HANDLER]: Received QUERYACCESS with {0}", (string)request["body"]); OSDMap args = Utils.GetOSDMap((string)request["body"]); + bool viaTeleport = true; + if (args.ContainsKey("viaTeleport")) + viaTeleport = args["viaTeleport"].AsBoolean(); + Vector3 position = Vector3.Zero; if (args.ContainsKey("position")) position = Vector3.Parse(args["position"].AsString()); - GridRegion destination = new GridRegion(); - destination.RegionID = regionID; + string agentHomeURI = null; + if (args.ContainsKey("agent_home_uri")) + agentHomeURI = args["agent_home_uri"].AsString(); - string reason; - string version; - bool result = m_SimulationService.QueryAccess(destination, id, position, out version, out reason); + // Decode the legacy (string) version and extract the number + float theirVersion = 0f; + if (args.ContainsKey("my_version")) + { + string theirVersionStr = args["my_version"].AsString(); + string[] parts = theirVersionStr.Split(new char[] {'/'}); + if (parts.Length > 1) + theirVersion = float.Parse(parts[1]); + } - responsedata["int_response_code"] = HttpStatusCode.OK; + // Decode the new versioning data + float minVersionRequired = 0f; + float maxVersionRequired = 0f; + float minVersionProvided = 0f; + float maxVersionProvided = 0f; - OSDMap resp = new OSDMap(3); + if (args.ContainsKey("simulation_service_supported_min")) + minVersionProvided = (float)args["simulation_service_supported_min"].AsReal(); + if (args.ContainsKey("simulation_service_supported_max")) + maxVersionProvided = (float)args["simulation_service_supported_max"].AsReal(); - resp["success"] = OSD.FromBoolean(result); - resp["reason"] = OSD.FromString(reason); - resp["version"] = OSD.FromString(version); + if (args.ContainsKey("simulation_service_accepted_min")) + minVersionRequired = (float)args["simulation_service_accepted_min"].AsReal(); + if (args.ContainsKey("simulation_service_accepted_max")) + maxVersionRequired = (float)args["simulation_service_accepted_max"].AsReal(); - // We must preserve defaults here, otherwise a false "success" will not be put into the JSON map! - responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp, true); + responsedata["int_response_code"] = HttpStatusCode.OK; + OSDMap resp = new OSDMap(3); -// Console.WriteLine("str_response_string [{0}]", responsedata["str_response_string"]); - } + float version = 0f; - protected virtual void DoAgentGet(Hashtable request, Hashtable responsedata, UUID id, UUID regionID) - { - if (m_SimulationService == null) + float outboundVersion = 0f; + float inboundVersion = 0f; + + if (minVersionProvided == 0f) // string version or older { - m_log.Debug("[AGENT HANDLER]: Agent GET called. Harmless but useless."); - responsedata["content_type"] = "application/json"; - responsedata["int_response_code"] = HttpStatusCode.NotImplemented; - responsedata["str_response_string"] = string.Empty; + // If there is no version in the packet at all we're looking at 0.6 or + // even more ancient. Refuse it. + if(theirVersion == 0f) + { + resp["success"] = OSD.FromBoolean(false); + resp["reason"] = OSD.FromString("Your region is running a old version of opensim no longer supported. Consider updating it"); + responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp, true); + return; + } - return; + version = theirVersion; + + if (version < VersionInfo.SimulationServiceVersionAcceptedMin || + version > VersionInfo.SimulationServiceVersionAcceptedMax ) + { + resp["success"] = OSD.FromBoolean(false); + resp["reason"] = OSD.FromString(String.Format("Your region protocol version is {0} and we accept only {1} - {2}. No version overlap.", theirVersion, VersionInfo.SimulationServiceVersionAcceptedMin, VersionInfo.SimulationServiceVersionAcceptedMax)); + responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp, true); + return; + } } - - GridRegion destination = new GridRegion(); - destination.RegionID = regionID; - - IAgentData agent = null; - bool result = m_SimulationService.RetrieveAgent(destination, id, out agent); - OSDMap map = null; - if (result) + else { - if (agent != null) // just to make sure + // Test for no overlap + if (minVersionProvided > VersionInfo.SimulationServiceVersionAcceptedMax || + maxVersionProvided < VersionInfo.SimulationServiceVersionAcceptedMin) { - map = agent.Pack(); - string strBuffer = ""; - try - { - strBuffer = OSDParser.SerializeJsonString(map); - } - catch (Exception e) - { - m_log.WarnFormat("[AGENT HANDLER]: Exception thrown on serialization of DoAgentGet: {0}", e.Message); - responsedata["int_response_code"] = HttpStatusCode.InternalServerError; - // ignore. buffer will be empty, caller should check. - } - - responsedata["content_type"] = "application/json"; - responsedata["int_response_code"] = HttpStatusCode.OK; - responsedata["str_response_string"] = strBuffer; + resp["success"] = OSD.FromBoolean(false); + resp["reason"] = OSD.FromString(String.Format("Your region provide protocol versions {0} - {1} and we accept only {2} - {3}. No version overlap.", minVersionProvided, maxVersionProvided, VersionInfo.SimulationServiceVersionAcceptedMin, VersionInfo.SimulationServiceVersionAcceptedMax)); + responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp, true); + return; } - else + if (minVersionRequired > VersionInfo.SimulationServiceVersionSupportedMax || + maxVersionRequired < VersionInfo.SimulationServiceVersionSupportedMin) { - responsedata["int_response_code"] = HttpStatusCode.InternalServerError; - responsedata["str_response_string"] = "Internal error"; + resp["success"] = OSD.FromBoolean(false); + resp["reason"] = OSD.FromString(String.Format("You require region protocol versions {0} - {1} and we provide only {2} - {3}. No version overlap.", minVersionRequired, maxVersionRequired, VersionInfo.SimulationServiceVersionSupportedMin, VersionInfo.SimulationServiceVersionSupportedMax)); + responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp, true); + return; } + + // Determine versions to use + // This is intentionally inverted. Inbound and Outbound refer to the direction of the transfer. + // Therefore outbound means from the sender to the receier and inbound means from the receiver to the sender. + // So outbound is what we will accept and inbound is what we will send. Confused yet? + outboundVersion = Math.Min(maxVersionProvided, VersionInfo.SimulationServiceVersionAcceptedMax); + inboundVersion = Math.Min(maxVersionRequired, VersionInfo.SimulationServiceVersionSupportedMax); } - else + + List features = new List(); + + if (args.ContainsKey("features")) + { + OSDArray array = (OSDArray)args["features"]; + + foreach (OSD o in array) + features.Add(new UUID(o.AsString())); + } + + GridRegion destination = new GridRegion(); + destination.RegionID = regionID; + + string reason; + // We're sending the version numbers down to the local connector to do the varregion check. + EntityTransferContext ctx = new EntityTransferContext(); + ctx.InboundVersion = inboundVersion; + ctx.OutboundVersion = outboundVersion; + if (minVersionProvided == 0f) { - responsedata["int_response_code"] = HttpStatusCode.NotFound; - responsedata["str_response_string"] = "Not Found"; + ctx.InboundVersion = version; + ctx.OutboundVersion = version; } + + bool result = m_SimulationService.QueryAccess(destination, agentID, agentHomeURI, viaTeleport, position, features, ctx, out reason); + + resp["success"] = OSD.FromBoolean(result); + resp["reason"] = OSD.FromString(reason); + string legacyVersion = String.Format("SIMULATION/{0}", version); + resp["version"] = OSD.FromString(legacyVersion); + resp["negotiated_inbound_version"] = OSD.FromReal(inboundVersion); + resp["negotiated_outbound_version"] = OSD.FromReal(outboundVersion); + resp["variable_wearables_count_supported"] = OSD.FromBoolean(true); + + OSDArray featuresWanted = new OSDArray(); + foreach (UUID feature in features) + featuresWanted.Add(OSD.FromString(feature.ToString())); + + resp["features"] = featuresWanted; + + // We must preserve defaults here, otherwise a false "success" will not be put into the JSON map! + responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp, true); + +// Console.WriteLine("str_response_string [{0}]", responsedata["str_response_string"]); } - protected void DoAgentDelete(Hashtable request, Hashtable responsedata, UUID id, string action, UUID regionID) + protected void DoAgentDelete(Hashtable request, Hashtable responsedata, UUID id, string action, UUID regionID, string auth_token) { - m_log.Debug(" >>> DoDelete action:" + action + "; RegionID:" + regionID); + if (string.IsNullOrEmpty(action)) + m_log.DebugFormat("[AGENT HANDLER]: >>> DELETE <<< RegionID: {0}; from: {1}; auth_code: {2}", regionID, Util.GetCallerIP(request), auth_token); + else + m_log.DebugFormat("[AGENT HANDLER]: Release {0} to RegionID: {1}", id, regionID); GridRegion destination = new GridRegion(); destination.RegionID = regionID; @@ -218,12 +289,13 @@ namespace OpenSim.Server.Handlers.Simulation if (action.Equals("release")) ReleaseAgent(regionID, id); else - m_SimulationService.CloseAgent(destination, id); + Util.FireAndForget( + o => m_SimulationService.CloseAgent(destination, id, auth_token), null, "AgentHandler.DoAgentDelete"); responsedata["int_response_code"] = HttpStatusCode.OK; responsedata["str_response_string"] = "OpenSim agent " + id.ToString(); - m_log.DebugFormat("[AGENT HANDLER]: Agent {0} Released/Deleted from region {1}", id, regionID); + //m_log.DebugFormat("[AGENT HANDLER]: Agent {0} Released/Deleted from region {1}", id, regionID); } protected virtual void ReleaseAgent(UUID regionID, UUID id) @@ -251,7 +323,7 @@ namespace OpenSim.Server.Handlers.Simulation m_SimulationService = null; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // m_log.DebugFormat("[SIMULATION]: Stream handler called"); @@ -280,21 +352,36 @@ namespace OpenSim.Server.Handlers.Simulation httpResponse.KeepAlive = false; Encoding encoding = Encoding.UTF8; - Stream inputStream = null; - if (httpRequest.ContentType == "application/x-gzip") - inputStream = new GZipStream(request, CompressionMode.Decompress); - else if (httpRequest.ContentType == "application/json") - inputStream = request; - else // no go + if (httpRequest.ContentType != "application/json") { httpResponse.StatusCode = 406; return encoding.GetBytes("false"); } - StreamReader reader = new StreamReader(inputStream, encoding); + string requestBody; + + Stream inputStream = request; + Stream innerStream = null; + try + { + if ((httpRequest.ContentType == "application/x-gzip" || httpRequest.Headers["Content-Encoding"] == "gzip") || (httpRequest.Headers["X-Content-Encoding"] == "gzip")) + { + innerStream = inputStream; + inputStream = new GZipStream(innerStream, CompressionMode.Decompress); + } + + using (StreamReader reader = new StreamReader(inputStream, encoding)) + { + requestBody = reader.ReadToEnd(); + } + } + finally + { + if (innerStream != null) + innerStream.Dispose(); + inputStream.Dispose(); + } - string requestBody = reader.ReadToEnd(); - reader.Close(); keysvals.Add("body", requestBody); Hashtable responsedata = new Hashtable(); @@ -328,31 +415,16 @@ namespace OpenSim.Server.Handlers.Simulation return; } - // retrieve the input arguments - int x = 0, y = 0; - UUID uuid = UUID.Zero; - string regionname = string.Empty; - uint teleportFlags = 0; - if (args.ContainsKey("destination_x") && args["destination_x"] != null) - Int32.TryParse(args["destination_x"].AsString(), out x); - else - m_log.WarnFormat(" -- request didn't have destination_x"); - if (args.ContainsKey("destination_y") && args["destination_y"] != null) - Int32.TryParse(args["destination_y"].AsString(), out y); - else - m_log.WarnFormat(" -- request didn't have destination_y"); - if (args.ContainsKey("destination_uuid") && args["destination_uuid"] != null) - UUID.TryParse(args["destination_uuid"].AsString(), out uuid); - if (args.ContainsKey("destination_name") && args["destination_name"] != null) - regionname = args["destination_name"].ToString(); - if (args.ContainsKey("teleport_flags") && args["teleport_flags"] != null) - teleportFlags = args["teleport_flags"].AsUInteger(); + AgentDestinationData data = CreateAgentDestinationData(); + UnpackData(args, data, request); GridRegion destination = new GridRegion(); - destination.RegionID = uuid; - destination.RegionLocX = x; - destination.RegionLocY = y; - destination.RegionName = regionname; + destination.RegionID = data.uuid; + destination.RegionLocX = data.x; + destination.RegionLocY = data.y; + destination.RegionName = data.name; + + GridRegion gatekeeper = ExtractGatekeeper(data); AgentCircuitData aCircuit = new AgentCircuitData(); try @@ -367,13 +439,29 @@ namespace OpenSim.Server.Handlers.Simulation return; } + GridRegion source = null; + + if (args.ContainsKey("source_uuid")) + { + source = new GridRegion(); + source.RegionLocX = Int32.Parse(args["source_x"].AsString()); + source.RegionLocY = Int32.Parse(args["source_y"].AsString()); + source.RegionName = args["source_name"].AsString(); + source.RegionID = UUID.Parse(args["source_uuid"].AsString()); + + if (args.ContainsKey("source_server_uri")) + source.RawServerURI = args["source_server_uri"].AsString(); + else + source.RawServerURI = null; + } + OSDMap resp = new OSDMap(2); string reason = String.Empty; // This is the meaning of POST agent //m_regionClient.AdjustUserInformation(aCircuit); //bool result = m_SimulationService.CreateAgent(destination, aCircuit, teleportFlags, out reason); - bool result = CreateAgent(destination, aCircuit, teleportFlags, out reason); + bool result = CreateAgent(source, gatekeeper, destination, aCircuit, data.flags, data.fromLogin, out reason); resp["reason"] = OSD.FromString(reason); resp["success"] = OSD.FromBoolean(result); @@ -385,7 +473,36 @@ namespace OpenSim.Server.Handlers.Simulation responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp); } - private string GetCallerIP(Hashtable request) + protected virtual AgentDestinationData CreateAgentDestinationData() + { + return new AgentDestinationData(); + } + + protected virtual void UnpackData(OSDMap args, AgentDestinationData data, Hashtable request) + { + // retrieve the input arguments + if (args.ContainsKey("destination_x") && args["destination_x"] != null) + Int32.TryParse(args["destination_x"].AsString(), out data.x); + else + m_log.WarnFormat(" -- request didn't have destination_x"); + if (args.ContainsKey("destination_y") && args["destination_y"] != null) + Int32.TryParse(args["destination_y"].AsString(), out data.y); + else + m_log.WarnFormat(" -- request didn't have destination_y"); + if (args.ContainsKey("destination_uuid") && args["destination_uuid"] != null) + UUID.TryParse(args["destination_uuid"].AsString(), out data.uuid); + if (args.ContainsKey("destination_name") && args["destination_name"] != null) + data.name = args["destination_name"].ToString(); + if (args.ContainsKey("teleport_flags") && args["teleport_flags"] != null) + data.flags = args["teleport_flags"].AsUInteger(); + } + + protected virtual GridRegion ExtractGatekeeper(AgentDestinationData data) + { + return null; + } + + protected string GetCallerIP(Hashtable request) { if (!m_Proxy) return Util.GetCallerIP(request); @@ -418,9 +535,10 @@ namespace OpenSim.Server.Handlers.Simulation } // subclasses can override this - protected virtual bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason) + protected virtual bool CreateAgent(GridRegion source, GridRegion gatekeeper, GridRegion destination, + AgentCircuitData aCircuit, uint teleportFlags, bool fromLogin, out string reason) { - return m_SimulationService.CreateAgent(destination, aCircuit, teleportFlags, out reason); + return m_SimulationService.CreateAgent(source, destination, aCircuit, teleportFlags, out reason); } } @@ -443,7 +561,7 @@ namespace OpenSim.Server.Handlers.Simulation m_SimulationService = null; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // m_log.DebugFormat("[SIMULATION]: Stream handler called"); @@ -467,17 +585,31 @@ namespace OpenSim.Server.Handlers.Simulation keysvals.Add("headers", headervals); keysvals.Add("querystringkeys", querystringkeys); - Stream inputStream; - if (httpRequest.ContentType == "application/x-gzip") - inputStream = new GZipStream(request, CompressionMode.Decompress); - else - inputStream = request; - + String requestBody; Encoding encoding = Encoding.UTF8; - StreamReader reader = new StreamReader(inputStream, encoding); - string requestBody = reader.ReadToEnd(); - reader.Close(); + Stream inputStream = request; + Stream innerStream = null; + try + { + if ((httpRequest.ContentType == "application/x-gzip" || httpRequest.Headers["Content-Encoding"] == "gzip") || (httpRequest.Headers["X-Content-Encoding"] == "gzip")) + { + innerStream = inputStream; + inputStream = new GZipStream(innerStream, CompressionMode.Decompress); + } + + using (StreamReader reader = new StreamReader(inputStream, encoding)) + { + requestBody = reader.ReadToEnd(); + } + } + finally + { + if (innerStream != null) + innerStream.Dispose(); + inputStream.Dispose(); + } + keysvals.Add("body", requestBody); httpResponse.StatusCode = 200; @@ -562,7 +694,6 @@ namespace OpenSim.Server.Handlers.Simulation //agent.Dump(); // This is one of the meanings of PUT agent result = UpdateAgent(destination, agent); - } else if ("AgentPosition".Equals(messageType)) { @@ -593,4 +724,14 @@ namespace OpenSim.Server.Handlers.Simulation return m_SimulationService.UpdateAgent(destination, agent); } } + + public class AgentDestinationData + { + public int x; + public int y; + public string name; + public UUID uuid; + public uint flags; + public bool fromLogin; + } } diff --git a/OpenSim/Server/Handlers/UserAccounts/UserAccountServerConnector.cs b/OpenSim/Server/Handlers/UserAccounts/UserAccountServerConnector.cs index 344b513..e95e3dc 100644 --- a/OpenSim/Server/Handlers/UserAccounts/UserAccountServerConnector.cs +++ b/OpenSim/Server/Handlers/UserAccounts/UserAccountServerConnector.cs @@ -30,6 +30,7 @@ using Nini.Config; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework.ServiceAuth; using OpenSim.Server.Handlers.Base; namespace OpenSim.Server.Handlers.UserAccounts @@ -55,7 +56,9 @@ namespace OpenSim.Server.Handlers.UserAccounts Object[] args = new Object[] { config }; m_UserAccountService = ServerUtils.LoadPlugin(service, args); - server.AddStreamHandler(new UserAccountServerPostHandler(m_UserAccountService, serverConfig)); + IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); + + server.AddStreamHandler(new UserAccountServerPostHandler(m_UserAccountService, serverConfig, auth)); } } } diff --git a/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs b/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs index 72551ef..21eb790 100644 --- a/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs +++ b/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs @@ -41,6 +41,7 @@ using OpenSim.Services.Interfaces; using OpenSim.Services.UserAccountService; using OpenSim.Framework; using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework.ServiceAuth; using OpenMetaverse; namespace OpenSim.Server.Handlers.UserAccounts @@ -54,10 +55,10 @@ namespace OpenSim.Server.Handlers.UserAccounts private bool m_AllowSetAccount = false; public UserAccountServerPostHandler(IUserAccountService service) - : this(service, null) {} + : this(service, null, null) {} - public UserAccountServerPostHandler(IUserAccountService service, IConfig config) : - base("POST", "/accounts") + public UserAccountServerPostHandler(IUserAccountService service, IConfig config, IServiceAuth auth) : + base("POST", "/accounts", auth) { m_UserAccountService = service; @@ -68,7 +69,7 @@ namespace OpenSim.Server.Handlers.UserAccounts } } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); @@ -256,8 +257,7 @@ namespace OpenSim.Server.Handlers.UserAccounts byte[] CreateUser(Dictionary request) { - if (! - request.ContainsKey("FirstName") + if (! request.ContainsKey("FirstName") && request.ContainsKey("LastName") && request.ContainsKey("Password")) return FailureResult(); @@ -314,7 +314,7 @@ namespace OpenSim.Server.Handlers.UserAccounts rootElement.AppendChild(result); - return DocToBytes(doc); + return Util.DocToBytes(doc); } private byte[] FailureResult() @@ -336,18 +336,7 @@ namespace OpenSim.Server.Handlers.UserAccounts rootElement.AppendChild(result); - return DocToBytes(doc); - } - - private byte[] DocToBytes(XmlDocument doc) - { - MemoryStream ms = new MemoryStream(); - XmlTextWriter xw = new XmlTextWriter(ms, null); - xw.Formatting = Formatting.Indented; - doc.WriteTo(xw); - xw.Flush(); - - return ms.ToArray(); + return Util.DocToBytes(doc); } private byte[] ResultToBytes(Dictionary result) 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; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] +[assembly: AssemblyVersion("0.7.6.*")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Server/ServerMain.cs b/OpenSim/Server/ServerMain.cs index 8be69a9..65e9287 100644 --- a/OpenSim/Server/ServerMain.cs +++ b/OpenSim/Server/ServerMain.cs @@ -145,7 +145,7 @@ namespace OpenSim.Server } else { - m_log.InfoFormat("[SERVER]: Failed to load {0}", conn); + m_log.ErrorFormat("[SERVER]: Failed to load {0}", conn); } } diff --git a/OpenSim/Services/AssetService/AssetService.cs b/OpenSim/Services/AssetService/AssetService.cs index e7eb6fe..0aefa16 100644 --- a/OpenSim/Services/AssetService/AssetService.cs +++ b/OpenSim/Services/AssetService/AssetService.cs @@ -123,53 +123,54 @@ namespace OpenSim.Services.AssetService public virtual AssetMetadata GetMetadata(string id) { // m_log.DebugFormat("[ASSET SERVICE]: Get asset metadata for {0}", id); - - UUID assetID; - if (!UUID.TryParse(id, out assetID)) - return null; + AssetBase asset = Get(id); - AssetBase asset = m_Database.GetAsset(assetID); if (asset != null) return asset.Metadata; - - return null; + else + return null; } public virtual byte[] GetData(string id) { // m_log.DebugFormat("[ASSET SERVICE]: Get asset data for {0}", id); - - UUID assetID; - if (!UUID.TryParse(id, out assetID)) - return null; + AssetBase asset = Get(id); - AssetBase asset = m_Database.GetAsset(assetID); - return asset.Data; + if (asset != null) + return asset.Data; + else + return null; } public virtual bool Get(string id, Object sender, AssetRetrieved handler) { //m_log.DebugFormat("[AssetService]: Get asset async {0}", id); - - UUID assetID; - if (!UUID.TryParse(id, out assetID)) - return false; - - AssetBase asset = m_Database.GetAsset(assetID); - - //m_log.DebugFormat("[AssetService]: Got asset {0}", asset); - - handler(id, sender, asset); + handler(id, sender, Get(id)); return true; } + public virtual bool[] AssetsExist(string[] ids) + { + try + { + UUID[] uuid = Array.ConvertAll(ids, id => UUID.Parse(id)); + return m_Database.AssetsExist(uuid); + } + catch (Exception e) + { + m_log.Error("[ASSET SERVICE]: Exception getting assets ", e); + return new bool[ids.Length]; + } + } + public virtual string Store(AssetBase asset) { - if (!m_Database.ExistsAsset(asset.FullID)) + bool exists = m_Database.AssetsExist(new[] { asset.FullID })[0]; + if (!exists) { // m_log.DebugFormat( // "[ASSET SERVICE]: Storing asset {0} {1}, bytes {2}", asset.Name, asset.FullID, asset.Data.Length); @@ -200,4 +201,4 @@ namespace OpenSim.Services.AssetService return m_Database.Delete(id); } } -} \ No newline at end of file +} diff --git a/OpenSim/Services/AssetService/Properties/AssemblyInfo.cs b/OpenSim/Services/AssetService/Properties/AssemblyInfo.cs index 1509400..63654a6 100644 --- a/OpenSim/Services/AssetService/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/AssetService/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/AssetService/XAssetService.cs b/OpenSim/Services/AssetService/XAssetService.cs index a1d10ed..b1e5184 100644 --- a/OpenSim/Services/AssetService/XAssetService.cs +++ b/OpenSim/Services/AssetService/XAssetService.cs @@ -39,16 +39,18 @@ using OpenMetaverse; namespace OpenSim.Services.AssetService { /// - /// This will be developed into a de-duplicating asset service. - /// XXX: Currently it's a just a copy of the existing AssetService. so please don't attempt to use it. + /// A de-duplicating asset service. /// + [Obsolete] public class XAssetService : XAssetServiceBase, IAssetService { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected static XAssetService m_RootInstance; - public XAssetService(IConfigSource config) : base(config) + public XAssetService(IConfigSource config) : this(config, "AssetService") {} + + public XAssetService(IConfigSource config, string configName) : base(config, configName) { if (m_RootInstance == null) { @@ -56,22 +58,21 @@ namespace OpenSim.Services.AssetService if (m_AssetLoader != null) { - IConfig assetConfig = config.Configs["AssetService"]; + IConfig assetConfig = config.Configs[configName]; if (assetConfig == null) throw new Exception("No AssetService configuration"); - string loaderArgs = assetConfig.GetString("AssetLoaderArgs", - String.Empty); + string loaderArgs = assetConfig.GetString("AssetLoaderArgs", String.Empty); bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true); - if (assetLoaderEnabled) + if (assetLoaderEnabled && !HasChainedAssetService) { m_log.DebugFormat("[XASSET SERVICE]: Loading default asset set from {0}", loaderArgs); m_AssetLoader.ForEachDefaultXmlAsset( loaderArgs, - delegate(AssetBase a) + a => { AssetBase existingAsset = Get(a.ID); // AssetMetadata existingMetadata = GetMetadata(a.ID); @@ -85,6 +86,7 @@ namespace OpenSim.Services.AssetService } m_log.Debug("[XASSET SERVICE]: Local asset service enabled"); + m_log.Error("[XASSET SERVICE]: THIS ASSET SERVICE HAS BEEN MARKED OBSOLETE. PLEASE USE FSAssetService"); } } } @@ -103,7 +105,23 @@ namespace OpenSim.Services.AssetService try { - return m_Database.GetAsset(assetID); + AssetBase asset = m_Database.GetAsset(assetID); + + if (asset != null) + { + return asset; + } + else if (HasChainedAssetService) + { + asset = m_ChainedAssetService.Get(id); + + if (asset != null) + MigrateFromChainedService(asset); + + return asset; + } + + return null; } catch (Exception e) { @@ -120,30 +138,25 @@ namespace OpenSim.Services.AssetService public virtual AssetMetadata GetMetadata(string id) { // m_log.DebugFormat("[XASSET SERVICE]: Get asset metadata for {0}", id); - - UUID assetID; - if (!UUID.TryParse(id, out assetID)) - return null; + AssetBase asset = Get(id); - AssetBase asset = m_Database.GetAsset(assetID); if (asset != null) return asset.Metadata; - - return null; + else + return null; } public virtual byte[] GetData(string id) { // m_log.DebugFormat("[XASSET SERVICE]: Get asset data for {0}", id); - UUID assetID; + AssetBase asset = Get(id); - if (!UUID.TryParse(id, out assetID)) + if (asset != null) + return asset.Data; + else return null; - - AssetBase asset = m_Database.GetAsset(assetID); - return asset.Data; } public virtual bool Get(string id, Object sender, AssetRetrieved handler) @@ -155,7 +168,7 @@ namespace OpenSim.Services.AssetService if (!UUID.TryParse(id, out assetID)) return false; - AssetBase asset = m_Database.GetAsset(assetID); + AssetBase asset = Get(id); //m_log.DebugFormat("[XASSET SERVICE]: Got asset {0}", asset); @@ -164,9 +177,16 @@ namespace OpenSim.Services.AssetService return true; } + public virtual bool[] AssetsExist(string[] ids) + { + UUID[] uuid = Array.ConvertAll(ids, id => UUID.Parse(id)); + return m_Database.AssetsExist(uuid); + } + public virtual string Store(AssetBase asset) { - if (!m_Database.ExistsAsset(asset.FullID)) + bool exists = m_Database.AssetsExist(new[] { asset.FullID })[0]; + if (!exists) { // m_log.DebugFormat( // "[XASSET SERVICE]: Storing asset {0} {1}, bytes {2}", asset.Name, asset.FullID, asset.Data.Length); @@ -194,7 +214,16 @@ namespace OpenSim.Services.AssetService if (!UUID.TryParse(id, out assetID)) return false; + if (HasChainedAssetService) + m_ChainedAssetService.Delete(id); + return m_Database.Delete(id); } + + private void MigrateFromChainedService(AssetBase asset) + { + Store(asset); + m_ChainedAssetService.Delete(asset.ID); + } } -} \ 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 @@ using System; using System.Reflection; +using log4net; using Nini.Config; using OpenSim.Framework; using OpenSim.Data; +using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Services.Base; @@ -37,10 +39,15 @@ namespace OpenSim.Services.AssetService { public class XAssetServiceBase : ServiceBase { - protected IXAssetDataPlugin m_Database = null; - protected IAssetLoader m_AssetLoader = null; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - public XAssetServiceBase(IConfigSource config) : base(config) + protected IXAssetDataPlugin m_Database; + protected IAssetLoader m_AssetLoader; + protected IAssetService m_ChainedAssetService; + + protected bool HasChainedAssetService { get { return m_ChainedAssetService != null; } } + + public XAssetServiceBase(IConfigSource config, string configName) : base(config) { string dllName = String.Empty; string connString = String.Empty; @@ -48,7 +55,7 @@ namespace OpenSim.Services.AssetService // // Try reading the [AssetService] section first, if it exists // - IConfig assetConfig = config.Configs["AssetService"]; + IConfig assetConfig = config.Configs[configName]; if (assetConfig != null) { dllName = assetConfig.GetString("StorageProvider", dllName); @@ -77,17 +84,35 @@ namespace OpenSim.Services.AssetService if (m_Database == null) throw new Exception("Could not find a storage interface in the given module"); - m_Database.Initialise(connString); + string chainedAssetServiceDesignator = assetConfig.GetString("ChainedServiceModule", null); + + if (chainedAssetServiceDesignator != null) + { + m_log.InfoFormat( + "[XASSET SERVICE BASE]: Loading chained asset service from {0}", chainedAssetServiceDesignator); - string loaderName = assetConfig.GetString("DefaultAssetLoader", - String.Empty); + Object[] args = new Object[] { config, configName }; + m_ChainedAssetService = ServerUtils.LoadPlugin(chainedAssetServiceDesignator, args); - if (loaderName != String.Empty) + if (!HasChainedAssetService) + throw new Exception( + String.Format("Failed to load ChainedAssetService from {0}", chainedAssetServiceDesignator)); + } + + m_Database.Initialise(connString); + + if (HasChainedAssetService) { - m_AssetLoader = LoadPlugin(loaderName); + string loaderName = assetConfig.GetString("DefaultAssetLoader", + String.Empty); + + if (loaderName != String.Empty) + { + m_AssetLoader = LoadPlugin(loaderName); - if (m_AssetLoader == null) - throw new Exception("Asset loader could not be loaded"); + if (m_AssetLoader == null) + throw new Exception("Asset loader could not be loaded"); + } } } } diff --git a/OpenSim/Services/AuthenticationService/Properties/AssemblyInfo.cs b/OpenSim/Services/AuthenticationService/Properties/AssemblyInfo.cs index 0eb2ba7..f25accc 100644 --- a/OpenSim/Services/AuthenticationService/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/AuthenticationService/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/AuthorizationService/Properties/AssemblyInfo.cs b/OpenSim/Services/AuthorizationService/Properties/AssemblyInfo.cs index 6d6b11e..47d47ab 100644 --- a/OpenSim/Services/AuthorizationService/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/AuthorizationService/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/AvatarService/Properties/AssemblyInfo.cs b/OpenSim/Services/AvatarService/Properties/AssemblyInfo.cs index 0944149..a233d8a 100644 --- a/OpenSim/Services/AvatarService/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/AvatarService/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/Base/Properties/AssemblyInfo.cs b/OpenSim/Services/Base/Properties/AssemblyInfo.cs index 306b699..b113c42 100644 --- a/OpenSim/Services/Base/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/Base/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/Base/ServiceBase.cs b/OpenSim/Services/Base/ServiceBase.cs index ef30cba..a7eb2be 100644 --- a/OpenSim/Services/Base/ServiceBase.cs +++ b/OpenSim/Services/Base/ServiceBase.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Reflection; using log4net; using Nini.Config; @@ -45,9 +46,15 @@ namespace OpenSim.Services.Base public T LoadPlugin(string dllName, Object[] args) where T:class { - string[] parts = dllName.Split(new char[] {':'}); + // The path:type separator : is unfortunate because it collides + // with Windows paths like C:\... + // When the path provided includes the drive, this fails. + // Hence the root/noroot thing going on here. + string pathRoot = Path.GetPathRoot(dllName); + string noRoot = dllName.Substring(pathRoot.Length); + string[] parts = noRoot.Split(new char[] {':'}); - dllName = parts[0]; + dllName = pathRoot + parts[0]; string className = String.Empty; @@ -79,7 +86,7 @@ namespace OpenSim.Services.Base continue; Type typeInterface = - pluginType.GetInterface(interfaceName, true); + pluginType.GetInterface(interfaceName); if (typeInterface != null) { T plug = (T)Activator.CreateInstance(pluginType, diff --git a/OpenSim/Services/Connectors/AgentPreferences/AgentPreferencesConnector.cs b/OpenSim/Services/Connectors/AgentPreferences/AgentPreferencesConnector.cs new file mode 100644 index 0000000..1dbc0c8 --- /dev/null +++ b/OpenSim/Services/Connectors/AgentPreferences/AgentPreferencesConnector.cs @@ -0,0 +1,230 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using log4net; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; +using OpenSim.Services.Interfaces; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; +using IAvatarService = OpenSim.Services.Interfaces.IAvatarService; +using OpenSim.Server.Base; +using OpenMetaverse; + +namespace OpenSim.Services.Connectors +{ + public class AgentPreferencesServicesConnector : BaseServiceConnector, IAgentPreferencesService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private string m_ServerURI = String.Empty; + + public AgentPreferencesServicesConnector() + { + } + + public AgentPreferencesServicesConnector(string serverURI) + { + m_ServerURI = serverURI.TrimEnd('/'); + } + + public AgentPreferencesServicesConnector(IConfigSource source) + : base(source, "AgentPreferencesService") + { + Initialise(source); + } + + public virtual void Initialise(IConfigSource source) + { + IConfig gridConfig = source.Configs["AgentPreferencesService"]; + if (gridConfig == null) + { + m_log.Error("[AGENT PREFERENCES CONNECTOR]: AgentPreferencesService missing from OpenSim.ini"); + throw new Exception("Agent Preferences connector init error"); + } + + string serviceURI = gridConfig.GetString("AgentPreferencesServerURI", String.Empty); + + if (serviceURI == String.Empty) + { + m_log.Error("[AGENT PREFERENCES CONNECTOR]: No Server URI named in section AgentPreferences"); + throw new Exception("Agent Preferences connector init error"); + } + m_ServerURI = serviceURI; + + base.Initialise(source, "AgentPreferencesService"); + } + + #region IAgentPreferencesService + + public AgentPrefs GetAgentPreferences(UUID principalID) + { + Dictionary sendData = new Dictionary(); + + string reply = string.Empty; + string uri = String.Concat(m_ServerURI, "/agentprefs"); + + sendData["METHOD"] = "getagentprefs"; + sendData["UserID"] = principalID; + string reqString = ServerUtils.BuildQueryString(sendData); + // m_log.DebugFormat("[AGENT PREFS CONNECTOR]: queryString = {0}", reqString); + + try + { + reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString, m_Auth); + if (String.IsNullOrEmpty(reply)) + { + m_log.DebugFormat("[AGENT PREFERENCES CONNECTOR]: GetAgentPreferences received null or empty reply"); + return null; + } + } + catch (Exception e) + { + m_log.DebugFormat("[AGENT PREFERENCES CONNECTOR]: Exception when contacting agent preferences server at {0}: {1}", uri, e.Message); + } + + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + if (replyData != null) + { + if (replyData.ContainsKey("result") && + (replyData["result"].ToString() == "null" || replyData["result"].ToString() == "Failure")) + { + m_log.DebugFormat("[AGENT PREFERENCES CONNECTOR]: GetAgentPreferences received Failure response"); + return null; + } + } + else + { + m_log.DebugFormat("[AGENT PREFERENCES CONNECTOR]: GetAgentPreferences received null response"); + return null; + } + AgentPrefs prefs = new AgentPrefs(replyData); + return prefs; + } + + public bool StoreAgentPreferences(AgentPrefs data) + { + Dictionary sendData = new Dictionary(); + + sendData["METHOD"] = "setagentprefs"; + + sendData["PrincipalID"] = data.PrincipalID.ToString(); + sendData["AccessPrefs"] = data.AccessPrefs; + sendData["HoverHeight"] = data.HoverHeight.ToString(); + sendData["Language"] = data.Language; + sendData["LanguageIsPublic"] = data.LanguageIsPublic.ToString(); + sendData["PermEveryone"] = data.PermEveryone.ToString(); + sendData["PermGroup"] = data.PermGroup.ToString(); + sendData["PermNextOwner"] = data.PermNextOwner.ToString(); + + string uri = String.Concat(m_ServerURI, "/agentprefs"); + string reqString = ServerUtils.BuildQueryString(sendData); + // m_log.DebugFormat("[AGENT PREFS CONNECTOR]: queryString = {0}", reqString); + + try + { + string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString, m_Auth); + if (reply != string.Empty) + { + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + if (replyData.ContainsKey("result")) + { + if (replyData["result"].ToString().ToLower() == "success") + return true; + else + return false; + } + else + { + m_log.DebugFormat("[AGENT PREFERENCES CONNECTOR]: StoreAgentPreferences reply data does not contain result field"); + } + + } + else + m_log.DebugFormat("[AGENT PREFERENCES CONNECTOR]: StoreAgentPreferences received empty reply"); + } + catch (Exception e) + { + m_log.DebugFormat("[AGENT PREFERENCES CONNECTOR]: Exception when contacting agent preferences server at {0}: {1}", uri, e.Message); + } + + return false; + } + + public string GetLang(UUID principalID) + { + Dictionary sendData = new Dictionary(); + string reply = string.Empty; + + sendData["METHOD"] = "getagentlang"; + sendData["UserID"] = principalID.ToString(); + + string uri = String.Concat(m_ServerURI, "/agentprefs"); + string reqString = ServerUtils.BuildQueryString(sendData); + + try + { + reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString, m_Auth); + if (String.IsNullOrEmpty(reply)) + { + m_log.DebugFormat("[AGENT PREFERENCES CONNECTOR]: GetLang received null or empty reply"); + return "en-us"; // I guess? Gotta return somethin'! + } + } + catch (Exception e) + { + m_log.DebugFormat("[AGENT PREFERENCES CONNECTOR]: Exception when contacting agent preferences server at {0}: {1}", uri, e.Message); + } + + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + if (replyData != null) + { + if (replyData.ContainsKey("result") && + (replyData["result"].ToString() == "null" || replyData["result"].ToString() == "Failure")) + { + m_log.DebugFormat("[AGENT PREFERENCES CONNECTOR]: GetLang received Failure response"); + return "en-us"; + } + if (replyData.ContainsKey("Language")) + return replyData["Language"].ToString(); + } + else + { + m_log.DebugFormat("[AGENT PREFERENCES CONNECTOR]: GetLang received null response"); + + } + return "en-us"; + } + + #endregion IAgentPreferencesService + } +} diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index 2b2f11f..bd43552 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs @@ -33,13 +33,12 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Console; -using OpenSim.Framework.Communications; using OpenSim.Services.Interfaces; using OpenMetaverse; namespace OpenSim.Services.Connectors { - public class AssetServicesConnector : IAssetService + public class AssetServicesConnector : BaseServiceConnector, IAssetService { private static readonly ILog m_log = LogManager.GetLogger( @@ -55,6 +54,11 @@ namespace OpenSim.Services.Connectors // Maps: Asset ID -> Handlers which will be called when the asset has been loaded private Dictionary m_AssetHandlers = new Dictionary(); + public int MaxAssetRequestConcurrency + { + get { return m_maxAssetRequestConcurrency; } + set { m_maxAssetRequestConcurrency = value; } + } public AssetServicesConnector() { @@ -66,6 +70,7 @@ namespace OpenSim.Services.Connectors } public AssetServicesConnector(IConfigSource source) + : base(source, "AssetService") { Initialise(source); } @@ -112,8 +117,16 @@ namespace OpenSim.Services.Connectors if (asset == null) { - asset = SynchronousRestObjectRequester. - MakeRequest("GET", uri, 0, m_maxAssetRequestConcurrency); + // XXX: Commented out for now since this has either never been properly operational or not for some time + // as m_maxAssetRequestConcurrency was being passed as the timeout, not a concurrency limiting option. + // Wasn't noticed before because timeout wasn't actually used. + // Not attempting concurrency setting for now as this omission was discovered in release candidate + // phase for OpenSimulator 0.8. Need to revisit afterwards. +// asset +// = SynchronousRestObjectRequester.MakeRequest( +// "GET", uri, 0, m_maxAssetRequestConcurrency); + + asset = SynchronousRestObjectRequester.MakeRequest("GET", uri, 0, m_Auth); if (m_Cache != null) m_Cache.Cache(asset); @@ -143,8 +156,7 @@ namespace OpenSim.Services.Connectors string uri = m_ServerURI + "/assets/" + id + "/metadata"; - AssetMetadata asset = SynchronousRestObjectRequester. - MakeRequest("GET", uri, 0); + AssetMetadata asset = SynchronousRestObjectRequester.MakeRequest("GET", uri, 0, m_Auth); return asset; } @@ -158,27 +170,29 @@ namespace OpenSim.Services.Connectors return fullAsset.Data; } - RestClient rc = new RestClient(m_ServerURI); - rc.AddResourcePath("assets"); - rc.AddResourcePath(id); - rc.AddResourcePath("data"); + using (RestClient rc = new RestClient(m_ServerURI)) + { + rc.AddResourcePath("assets"); + rc.AddResourcePath(id); + rc.AddResourcePath("data"); - rc.RequestMethod = "GET"; + rc.RequestMethod = "GET"; - Stream s = rc.Request(); + Stream s = rc.Request(m_Auth); - if (s == null) - return null; + if (s == null) + return null; - if (s.Length > 0) - { - byte[] ret = new byte[s.Length]; - s.Read(ret, 0, (int)s.Length); + if (s.Length > 0) + { + byte[] ret = new byte[s.Length]; + s.Read(ret, 0, (int)s.Length); - return ret; - } + return ret; + } - return null; + return null; + } } public bool Get(string id, Object sender, AssetRetrieved handler) @@ -216,7 +230,7 @@ namespace OpenSim.Services.Connectors AsynchronousRestObjectRequester.MakeRequest("GET", uri, 0, delegate(AssetBase a) { - if (m_Cache != null) + if (a != null && m_Cache != null) m_Cache.Cache(a); AssetRetrievedEx handlers; @@ -226,7 +240,7 @@ namespace OpenSim.Services.Connectors m_AssetHandlers.Remove(id); } handlers.Invoke(a); - }, m_maxAssetRequestConcurrency); + }, m_maxAssetRequestConcurrency, m_Auth); success = true; } @@ -249,9 +263,30 @@ namespace OpenSim.Services.Connectors return true; } + public virtual bool[] AssetsExist(string[] ids) + { + string uri = m_ServerURI + "/get_assets_exist"; + + bool[] exist = null; + try + { + exist = SynchronousRestObjectRequester.MakeRequest("POST", uri, ids, m_Auth); + } + catch (Exception) + { + // This is most likely to happen because the server doesn't support this function, + // so just silently return "doesn't exist" for all the assets. + } + + if (exist == null) + exist = new bool[ids.Length]; + + return exist; + } + public string Store(AssetBase asset) { - if (asset.Temporary || asset.Local) + if (asset.Local) { if (m_Cache != null) m_Cache.Cache(asset); @@ -261,27 +296,32 @@ namespace OpenSim.Services.Connectors string uri = m_ServerURI + "/assets/"; - string newID = string.Empty; + string newID; try { - newID = SynchronousRestObjectRequester. - MakeRequest("POST", uri, asset); + newID = SynchronousRestObjectRequester.MakeRequest("POST", uri, asset, m_Auth); } catch (Exception e) { - m_log.WarnFormat("[ASSET CONNECTOR]: Unable to send asset {0} to asset server. Reason: {1}", asset.ID, e.Message); + m_log.Warn(string.Format("[ASSET CONNECTOR]: Unable to send asset {0} to asset server. Reason: {1} ", asset.ID, e.Message), e); + return string.Empty; } - if (newID != String.Empty) + // TEMPORARY: SRAS returns 'null' when it's asked to store existing assets + if (newID == null) { - // Placing this here, so that this work with old asset servers that don't send any reply back - // SynchronousRestObjectRequester returns somethins that is not an empty string - if (newID != null) - asset.ID = newID; - - if (m_Cache != null) - m_Cache.Cache(asset); + m_log.DebugFormat("[ASSET CONNECTOR]: Storing of asset {0} returned null; assuming the asset already exists", asset.ID); + return asset.ID; } + + if (string.IsNullOrEmpty(newID)) + return string.Empty; + + asset.ID = newID; + + if (m_Cache != null) + m_Cache.Cache(asset); + return newID; } @@ -305,8 +345,7 @@ namespace OpenSim.Services.Connectors string uri = m_ServerURI + "/assets/" + id; - if (SynchronousRestObjectRequester. - MakeRequest("POST", uri, asset)) + if (SynchronousRestObjectRequester.MakeRequest("POST", uri, asset, m_Auth)) { if (m_Cache != null) m_Cache.Cache(asset); @@ -320,8 +359,7 @@ namespace OpenSim.Services.Connectors { string uri = m_ServerURI + "/assets/" + id; - if (SynchronousRestObjectRequester. - MakeRequest("DELETE", uri, 0)) + if (SynchronousRestObjectRequester.MakeRequest("DELETE", uri, 0, m_Auth)) { if (m_Cache != null) m_Cache.Expire(id); diff --git a/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs b/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs index c395178..3710c86 100644 --- a/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs @@ -36,6 +36,7 @@ using OpenSim.Framework; using OpenSim.Services.Interfaces; using OpenSim.Services.Connectors.Hypergrid; using OpenSim.Services.Connectors.SimianGrid; +using OpenMetaverse; namespace OpenSim.Services.Connectors { @@ -83,39 +84,6 @@ namespace OpenSim.Services.Connectors } } - private bool StringToUrlAndAssetID(string id, out string url, out string assetID) - { - url = String.Empty; - assetID = String.Empty; - - Uri assetUri; - - if (Uri.TryCreate(id, UriKind.Absolute, out assetUri) && - assetUri.Scheme == Uri.UriSchemeHttp) - { - // Simian - if (assetUri.Query != string.Empty) - { - NameValueCollection qscoll = HttpUtility.ParseQueryString(assetUri.Query); - assetID = qscoll["id"]; - if (assetID != null) - url = id.Replace(assetID, ""); // Malformed again, as simian expects - else - url = id; // !!! best effort - } - else // robust - { - url = "http://" + assetUri.Authority; - assetID = assetUri.LocalPath.Trim(new char[] { '/' }); - } - - return true; - } - - m_log.DebugFormat("[HG ASSET SERVICE]: Malformed URL {0}", id); - return false; - } - private IAssetService GetConnector(string url) { IAssetService connector = null; @@ -149,7 +117,7 @@ namespace OpenSim.Services.Connectors string url = string.Empty; string assetID = string.Empty; - if (StringToUrlAndAssetID(id, out url, out assetID)) + if (Util.ParseForeignAssetID(id, out url, out assetID)) { IAssetService connector = GetConnector(url); return connector.Get(assetID); @@ -163,7 +131,7 @@ namespace OpenSim.Services.Connectors string url = string.Empty; string assetID = string.Empty; - if (StringToUrlAndAssetID(id, out url, out assetID)) + if (Util.ParseForeignAssetID(id, out url, out assetID)) { IAssetService connector = GetConnector(url); return connector.GetCached(assetID); @@ -177,7 +145,7 @@ namespace OpenSim.Services.Connectors string url = string.Empty; string assetID = string.Empty; - if (StringToUrlAndAssetID(id, out url, out assetID)) + if (Util.ParseForeignAssetID(id, out url, out assetID)) { IAssetService connector = GetConnector(url); return connector.GetMetadata(assetID); @@ -196,7 +164,7 @@ namespace OpenSim.Services.Connectors string url = string.Empty; string assetID = string.Empty; - if (StringToUrlAndAssetID(id, out url, out assetID)) + if (Util.ParseForeignAssetID(id, out url, out assetID)) { IAssetService connector = GetConnector(url); return connector.Get(assetID, sender, handler); @@ -205,12 +173,72 @@ namespace OpenSim.Services.Connectors return false; } + + private struct AssetAndIndex + { + public UUID assetID; + public int index; + + public AssetAndIndex(UUID assetID, int index) + { + this.assetID = assetID; + this.index = index; + } + } + + public virtual bool[] AssetsExist(string[] ids) + { + // This method is a bit complicated because it works even if the assets belong to different + // servers; that requires sending separate requests to each server. + + // Group the assets by the server they belong to + + var url2assets = new Dictionary>(); + + for (int i = 0; i < ids.Length; i++) + { + string url = string.Empty; + string assetID = string.Empty; + + if (Util.ParseForeignAssetID(ids[i], out url, out assetID)) + { + if (!url2assets.ContainsKey(url)) + url2assets.Add(url, new List()); + url2assets[url].Add(new AssetAndIndex(UUID.Parse(assetID), i)); + } + } + + // Query each of the servers in turn + + bool[] exist = new bool[ids.Length]; + + foreach (string url in url2assets.Keys) + { + IAssetService connector = GetConnector(url); + lock (EndPointLock(connector)) + { + List curAssets = url2assets[url]; + string[] assetIDs = curAssets.ConvertAll(a => a.assetID.ToString()).ToArray(); + bool[] curExist = connector.AssetsExist(assetIDs); + + int i = 0; + foreach (AssetAndIndex ai in curAssets) + { + exist[ai.index] = curExist[i]; + ++i; + } + } + } + + return exist; + } + public string Store(AssetBase asset) { string url = string.Empty; string assetID = string.Empty; - if (StringToUrlAndAssetID(asset.ID, out url, out assetID)) + if (Util.ParseForeignAssetID(asset.ID, out url, out assetID)) { IAssetService connector = GetConnector(url); // Restore the assetID to a simple UUID diff --git a/OpenSim/Services/Connectors/Authentication/AuthenticationServicesConnector.cs b/OpenSim/Services/Connectors/Authentication/AuthenticationServicesConnector.cs index 2b77154..c8a4912 100644 --- a/OpenSim/Services/Connectors/Authentication/AuthenticationServicesConnector.cs +++ b/OpenSim/Services/Connectors/Authentication/AuthenticationServicesConnector.cs @@ -32,14 +32,14 @@ using System.IO; using System.Reflection; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Communications; +using OpenSim.Framework.ServiceAuth; using OpenSim.Services.Interfaces; using OpenSim.Server.Base; using OpenMetaverse; namespace OpenSim.Services.Connectors { - public class AuthenticationServicesConnector : IAuthenticationService + public class AuthenticationServicesConnector : BaseServiceConnector, IAuthenticationService { private static readonly ILog m_log = LogManager.GetLogger( @@ -57,6 +57,7 @@ namespace OpenSim.Services.Connectors } public AuthenticationServicesConnector(IConfigSource source) + : base(source, "AuthenticationService") { Initialise(source); } @@ -79,6 +80,8 @@ namespace OpenSim.Services.Connectors throw new Exception("Authentication connector init error"); } m_ServerURI = serviceURI; + + base.Initialise(source, "AuthenticationService"); } public string Authenticate(UUID principalID, string password, int lifetime) @@ -92,7 +95,7 @@ namespace OpenSim.Services.Connectors string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI + "/auth/plain", - ServerUtils.BuildQueryString(sendData)); + ServerUtils.BuildQueryString(sendData), m_Auth); Dictionary replyData = ServerUtils.ParseXmlResponse( reply); @@ -105,6 +108,7 @@ namespace OpenSim.Services.Connectors public bool Verify(UUID principalID, string token, int lifetime) { +// m_log.Error("[XXX]: Verify"); Dictionary sendData = new Dictionary(); sendData["LIFETIME"] = lifetime.ToString(); sendData["PRINCIPAL"] = principalID.ToString(); @@ -114,7 +118,7 @@ namespace OpenSim.Services.Connectors string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI + "/auth/plain", - ServerUtils.BuildQueryString(sendData)); + ServerUtils.BuildQueryString(sendData), m_Auth); Dictionary replyData = ServerUtils.ParseXmlResponse( reply); @@ -135,7 +139,7 @@ namespace OpenSim.Services.Connectors string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI + "/auth/plain", - ServerUtils.BuildQueryString(sendData)); + ServerUtils.BuildQueryString(sendData), m_Auth); Dictionary replyData = ServerUtils.ParseXmlResponse( reply); diff --git a/OpenSim/Services/Connectors/Authorization/AuthorizationServicesConnector.cs b/OpenSim/Services/Connectors/Authorization/AuthorizationServicesConnector.cs index 35b7109..d2da85f 100644 --- a/OpenSim/Services/Connectors/Authorization/AuthorizationServicesConnector.cs +++ b/OpenSim/Services/Connectors/Authorization/AuthorizationServicesConnector.cs @@ -32,7 +32,6 @@ using System.IO; using System.Reflection; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Communications; using OpenSim.Services.Interfaces; using OpenMetaverse; @@ -105,7 +104,7 @@ namespace OpenSim.Services.Connectors catch (Exception e) { m_log.WarnFormat("[AUTHORIZATION CONNECTOR]: Unable to send authorize {0} for region {1} error thrown during comms with remote server. Reason: {2}", userID, regionID, e.Message); - message = ""; + message = e.Message; return m_ResponseOnFailure; } if (response == null) diff --git a/OpenSim/Services/Connectors/Avatar/AvatarServicesConnector.cs b/OpenSim/Services/Connectors/Avatar/AvatarServicesConnector.cs index ddfca57..3f44efa 100644 --- a/OpenSim/Services/Connectors/Avatar/AvatarServicesConnector.cs +++ b/OpenSim/Services/Connectors/Avatar/AvatarServicesConnector.cs @@ -32,7 +32,7 @@ using System.IO; using System.Reflection; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Communications; +using OpenSim.Framework.ServiceAuth; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using IAvatarService = OpenSim.Services.Interfaces.IAvatarService; @@ -41,7 +41,7 @@ using OpenMetaverse; namespace OpenSim.Services.Connectors { - public class AvatarServicesConnector : IAvatarService + public class AvatarServicesConnector : BaseServiceConnector, IAvatarService { private static readonly ILog m_log = LogManager.GetLogger( @@ -59,6 +59,7 @@ namespace OpenSim.Services.Connectors } public AvatarServicesConnector(IConfigSource source) + : base(source, "AvatarService") { Initialise(source); } @@ -81,6 +82,8 @@ namespace OpenSim.Services.Connectors throw new Exception("Avatar connector init error"); } m_ServerURI = serviceURI; + + base.Initialise(source, "AvatarService"); } @@ -114,7 +117,7 @@ namespace OpenSim.Services.Connectors // m_log.DebugFormat("[AVATAR CONNECTOR]: queryString = {0}", reqString); try { - reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString); + reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString, m_Auth); if (reply == null || (reply != null && reply == string.Empty)) { m_log.DebugFormat("[AVATAR CONNECTOR]: GetAgent received null or empty reply"); @@ -162,7 +165,7 @@ namespace OpenSim.Services.Connectors //m_log.DebugFormat("[AVATAR CONNECTOR]: queryString = {0}", reqString); try { - string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString); + string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString, m_Auth); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); @@ -207,7 +210,7 @@ namespace OpenSim.Services.Connectors // m_log.DebugFormat("[AVATAR CONNECTOR]: queryString = {0}", reqString); try { - string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString); + string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString, m_Auth); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); @@ -250,7 +253,7 @@ namespace OpenSim.Services.Connectors // m_log.DebugFormat("[AVATAR CONNECTOR]: queryString = {0}", reqString); try { - string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString); + string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString, m_Auth); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); @@ -293,7 +296,7 @@ namespace OpenSim.Services.Connectors // m_log.DebugFormat("[AVATAR CONNECTOR]: queryString = {0}", reqString); try { - string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString); + string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString, m_Auth); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); diff --git a/OpenSim/Services/Connectors/BaseServiceConnector.cs b/OpenSim/Services/Connectors/BaseServiceConnector.cs new file mode 100644 index 0000000..98cd489 --- /dev/null +++ b/OpenSim/Services/Connectors/BaseServiceConnector.cs @@ -0,0 +1,33 @@ +using System; +using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; + +using Nini.Config; + +namespace OpenSim.Services.Connectors +{ + public class BaseServiceConnector + { + protected IServiceAuth m_Auth; + + public BaseServiceConnector() { } + + public BaseServiceConnector(IConfigSource config, string section) + { + Initialise(config, section); + } + + public void Initialise(IConfigSource config, string section) + { + string authType = Util.GetConfigVarFromSections(config, "AuthType", new string[] { "Network", section }, "None"); + + switch (authType) + { + case "BasicHttpAuthentication": + m_Auth = new BasicHttpAuthentication(config, section); + break; + } + + } + } +} diff --git a/OpenSim/Services/Connectors/Estate/EstateDataConnector.cs b/OpenSim/Services/Connectors/Estate/EstateDataConnector.cs new file mode 100644 index 0000000..6412bcd --- /dev/null +++ b/OpenSim/Services/Connectors/Estate/EstateDataConnector.cs @@ -0,0 +1,338 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Net; +using System.Reflection; + +using log4net; + +using OpenMetaverse; +using Nini.Config; + +using OpenSim.Framework; +using OpenSim.Framework.ServiceAuth; +using OpenSim.Services.Connectors; +using OpenSim.Services.Interfaces; +using OpenSim.Server.Base; + +namespace OpenSim.Services.Connectors +{ + public class EstateDataRemoteConnector : BaseServiceConnector, IEstateDataService + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private string m_ServerURI = String.Empty; + private ExpiringCache> m_EstateCache = new ExpiringCache>(); + private const int EXPIRATION = 5 * 60; // 5 minutes in secs + + public EstateDataRemoteConnector(IConfigSource source) + { + Initialise(source); + } + + public virtual void Initialise(IConfigSource source) + { + IConfig gridConfig = source.Configs["EstateService"]; + if (gridConfig == null) + { + m_log.Error("[ESTATE CONNECTOR]: EstateService missing from OpenSim.ini"); + throw new Exception("Estate connector init error"); + } + + string serviceURI = gridConfig.GetString("EstateServerURI", + String.Empty); + + if (serviceURI == String.Empty) + { + m_log.Error("[ESTATE CONNECTOR]: No Server URI named in section EstateService"); + throw new Exception("Estate connector init error"); + } + m_ServerURI = serviceURI; + + base.Initialise(source, "EstateService"); + } + + #region IEstateDataService + + public List LoadEstateSettingsAll() + { + string reply = string.Empty; + string uri = m_ServerURI + "/estates"; + + reply = MakeRequest("GET", uri, string.Empty); + if (String.IsNullOrEmpty(reply)) + return new List(); + + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + List estates = new List(); + if (replyData != null && replyData.Count > 0) + { + m_log.DebugFormat("[ESTATE CONNECTOR]: LoadEstateSettingsAll returned {0} elements", replyData.Count); + Dictionary.ValueCollection estateData = replyData.Values; + foreach (object r in estateData) + { + if (r is Dictionary) + { + EstateSettings es = new EstateSettings((Dictionary)r); + estates.Add(es); + } + } + m_EstateCache.AddOrUpdate("estates", estates, EXPIRATION); + } + else + m_log.DebugFormat("[ESTATE CONNECTOR]: LoadEstateSettingsAll from {0} received null or zero response", uri); + + return estates; + + } + + public List GetEstatesAll() + { + List eids = new List(); + // If we don't have them, load them from the server + List estates = null; + if (!m_EstateCache.TryGetValue("estates", out estates)) + LoadEstateSettingsAll(); + + foreach (EstateSettings es in estates) + eids.Add((int)es.EstateID); + + return eids; + } + + public List GetEstates(string search) + { + // If we don't have them, load them from the server + List estates = null; + if (!m_EstateCache.TryGetValue("estates", out estates)) + LoadEstateSettingsAll(); + + List eids = new List(); + foreach (EstateSettings es in estates) + if (es.EstateName == search) + eids.Add((int)es.EstateID); + + return eids; + } + + public List GetEstatesByOwner(UUID ownerID) + { + // If we don't have them, load them from the server + List estates = null; + if (!m_EstateCache.TryGetValue("estates", out estates)) + LoadEstateSettingsAll(); + + List eids = new List(); + foreach (EstateSettings es in estates) + if (es.EstateOwner == ownerID) + eids.Add((int)es.EstateID); + + return eids; + } + + public List GetRegions(int estateID) + { + string reply = string.Empty; + // /estates/regions/?eid=int + string uri = m_ServerURI + "/estates/regions/?eid=" + estateID.ToString(); + + reply = MakeRequest("GET", uri, string.Empty); + if (String.IsNullOrEmpty(reply)) + return new List(); + + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + List regions = new List(); + if (replyData != null && replyData.Count > 0) + { + m_log.DebugFormat("[ESTATE CONNECTOR]: GetRegions for estate {0} returned {1} elements", estateID, replyData.Count); + Dictionary.ValueCollection data = replyData.Values; + foreach (object r in data) + { + UUID uuid = UUID.Zero; + if (UUID.TryParse(r.ToString(), out uuid)) + regions.Add(uuid); + } + } + else + m_log.DebugFormat("[ESTATE CONNECTOR]: GetRegions from {0} received null or zero response", uri); + + return regions; + } + + public EstateSettings LoadEstateSettings(UUID regionID, bool create) + { + string reply = string.Empty; + // /estates/estate/?region=uuid&create=[t|f] + string uri = m_ServerURI + string.Format("/estates/estate/?region={0}&create={1}", regionID, create); + + reply = MakeRequest("GET", uri, string.Empty); + if (String.IsNullOrEmpty(reply)) + return null; + + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + if (replyData != null && replyData.Count > 0) + { + m_log.DebugFormat("[ESTATE CONNECTOR]: LoadEstateSettings({0}) returned {1} elements", regionID, replyData.Count); + EstateSettings es = new EstateSettings(replyData); + return es; + } + else + m_log.DebugFormat("[ESTATE CONNECTOR]: LoadEstateSettings(regionID) from {0} received null or zero response", uri); + + return null; + } + + public EstateSettings LoadEstateSettings(int estateID) + { + string reply = string.Empty; + // /estates/estate/?eid=int + string uri = m_ServerURI + string.Format("/estates/estate/?eid={0}", estateID); + + reply = MakeRequest("GET", uri, string.Empty); + if (String.IsNullOrEmpty(reply)) + return null; + + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + if (replyData != null && replyData.Count > 0) + { + m_log.DebugFormat("[ESTATE CONNECTOR]: LoadEstateSettings({0}) returned {1} elements", estateID, replyData.Count); + EstateSettings es = new EstateSettings(replyData); + return es; + } + else + m_log.DebugFormat("[ESTATE CONNECTOR]: LoadEstateSettings(estateID) from {0} received null or zero response", uri); + + return null; + } + + /// + /// Forbidden operation + /// + /// + public EstateSettings CreateNewEstate() + { + // No can do + return null; + } + + public void StoreEstateSettings(EstateSettings es) + { + // /estates/estate/ + string uri = m_ServerURI + ("/estates/estate"); + + Dictionary formdata = es.ToMap(); + formdata["OP"] = "STORE"; + + PostRequest(uri, formdata); + } + + public bool LinkRegion(UUID regionID, int estateID) + { + // /estates/estate/?eid=int®ion=uuid + string uri = m_ServerURI + String.Format("/estates/estate/?eid={0}®ion={1}", estateID, regionID); + + Dictionary formdata = new Dictionary(); + formdata["OP"] = "LINK"; + return PostRequest(uri, formdata); + } + + private bool PostRequest(string uri, Dictionary sendData) + { + string reqString = ServerUtils.BuildQueryString(sendData); + + string reply = MakeRequest("POST", uri, reqString); + if (String.IsNullOrEmpty(reply)) + return false; + + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + bool result = false; + if (replyData != null && replyData.Count > 0) + { + if (replyData.ContainsKey("Result")) + { + if (Boolean.TryParse(replyData["Result"].ToString(), out result)) + m_log.DebugFormat("[ESTATE CONNECTOR]: PostRequest {0} returned {1}", uri, result); + } + } + else + m_log.DebugFormat("[ESTATE CONNECTOR]: PostRequest {0} received null or zero response", uri); + + return result; + } + + /// + /// Forbidden operation + /// + /// + public bool DeleteEstate(int estateID) + { + return false; + } + + #endregion + + private string MakeRequest(string verb, string uri, string formdata) + { + string reply = string.Empty; + try + { + reply = SynchronousRestFormsRequester.MakeRequest(verb, uri, formdata, m_Auth); + } + catch (WebException e) + { + using (HttpWebResponse hwr = (HttpWebResponse)e.Response) + { + if (hwr != null) + { + if (hwr.StatusCode == HttpStatusCode.NotFound) + m_log.Error(string.Format("[ESTATE CONNECTOR]: Resource {0} not found ", uri)); + if (hwr.StatusCode == HttpStatusCode.Unauthorized) + m_log.Error(string.Format("[ESTATE CONNECTOR]: Web request {0} requires authentication ", uri)); + } + else + m_log.Error(string.Format( + "[ESTATE CONNECTOR]: WebException for {0} {1} {2} ", + verb, uri, formdata, e)); + } + } + catch (Exception e) + { + m_log.DebugFormat("[ESTATE CONNECTOR]: Exception when contacting estate server at {0}: {1}", uri, e.Message); + } + + return reply; + } + } +} diff --git a/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs b/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs index d688299..20dc1cc 100644 --- a/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs +++ b/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs @@ -32,7 +32,7 @@ using System.Collections; using System.Reflection; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Communications; + using OpenSim.Services.Interfaces; using OpenSim.Server.Base; using OpenMetaverse; diff --git a/OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs index b1dd84e..b7702a8 100644 --- a/OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs +++ b/OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs @@ -32,7 +32,8 @@ using System.IO; using System.Reflection; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Communications; +using OpenSim.Framework.ServiceAuth; + using OpenSim.Services.Interfaces; using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; using OpenSim.Server.Base; @@ -40,7 +41,7 @@ using OpenMetaverse; namespace OpenSim.Services.Connectors.Friends { - public class FriendsServicesConnector : IFriendsService + public class FriendsServicesConnector : BaseServiceConnector, IFriendsService { private static readonly ILog m_log = LogManager.GetLogger( @@ -80,6 +81,7 @@ namespace OpenSim.Services.Connectors.Friends throw new Exception("Friends connector init error"); } m_ServerURI = serviceURI; + base.Initialise(source, "FriendsService"); } @@ -112,7 +114,7 @@ namespace OpenSim.Services.Connectors.Friends try { - string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString); + string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString, m_Auth); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); @@ -168,7 +170,7 @@ namespace OpenSim.Services.Connectors.Friends string uri = m_ServerURI + "/friends"; try { - reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, ServerUtils.BuildQueryString(sendData)); + reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, ServerUtils.BuildQueryString(sendData), m_Auth); } catch (Exception e) { @@ -223,7 +225,7 @@ namespace OpenSim.Services.Connectors.Friends string uri = m_ServerURI + "/friends"; try { - reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, ServerUtils.BuildQueryString(sendData)); + reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, ServerUtils.BuildQueryString(sendData), m_Auth); } catch (Exception e) { diff --git a/OpenSim/Services/Connectors/Grid/GridServicesConnector.cs b/OpenSim/Services/Connectors/Grid/GridServicesConnector.cs index 34ed0d7..596f867 100644 --- a/OpenSim/Services/Connectors/Grid/GridServicesConnector.cs +++ b/OpenSim/Services/Connectors/Grid/GridServicesConnector.cs @@ -32,7 +32,8 @@ using System.IO; using System.Reflection; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Communications; + +using OpenSim.Framework.ServiceAuth; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using OpenSim.Server.Base; @@ -40,7 +41,7 @@ using OpenMetaverse; namespace OpenSim.Services.Connectors { - public class GridServicesConnector : IGridService + public class GridServicesConnector : BaseServiceConnector, IGridService { private static readonly ILog m_log = LogManager.GetLogger( @@ -80,6 +81,8 @@ namespace OpenSim.Services.Connectors throw new Exception("Grid connector init error"); } m_ServerURI = serviceURI; + + base.Initialise(source, "GridService"); } @@ -102,7 +105,7 @@ namespace OpenSim.Services.Connectors // m_log.DebugFormat("[GRID CONNECTOR]: queryString = {0}", reqString); try { - string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString); + string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString, m_Auth); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); @@ -158,7 +161,7 @@ namespace OpenSim.Services.Connectors try { string reply - = SynchronousRestFormsRequester.MakeRequest("POST", uri, ServerUtils.BuildQueryString(sendData)); + = SynchronousRestFormsRequester.MakeRequest("POST", uri, ServerUtils.BuildQueryString(sendData), m_Auth); if (reply != string.Empty) { @@ -195,7 +198,7 @@ namespace OpenSim.Services.Connectors try { - reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString); + reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString, m_Auth); } catch (Exception e) { @@ -238,7 +241,7 @@ namespace OpenSim.Services.Connectors string uri = m_ServerURI + "/grid"; try { - reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, ServerUtils.BuildQueryString(sendData)); + reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, ServerUtils.BuildQueryString(sendData), m_Auth); } catch (Exception e) { @@ -285,7 +288,7 @@ namespace OpenSim.Services.Connectors { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - ServerUtils.BuildQueryString(sendData)); + ServerUtils.BuildQueryString(sendData), m_Auth); } catch (Exception e) { @@ -330,7 +333,7 @@ namespace OpenSim.Services.Connectors { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - ServerUtils.BuildQueryString(sendData)); + ServerUtils.BuildQueryString(sendData), m_Auth); } catch (Exception e) { @@ -374,7 +377,7 @@ namespace OpenSim.Services.Connectors { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - ServerUtils.BuildQueryString(sendData)); + ServerUtils.BuildQueryString(sendData), m_Auth); } catch (Exception e) { @@ -428,7 +431,7 @@ namespace OpenSim.Services.Connectors { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - ServerUtils.BuildQueryString(sendData)); + ServerUtils.BuildQueryString(sendData), m_Auth); //m_log.DebugFormat("[GRID CONNECTOR]: reply was {0}", reply); } @@ -479,7 +482,7 @@ namespace OpenSim.Services.Connectors { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - ServerUtils.BuildQueryString(sendData)); + ServerUtils.BuildQueryString(sendData), m_Auth); //m_log.DebugFormat("[GRID CONNECTOR]: reply was {0}", reply); } @@ -515,6 +518,57 @@ namespace OpenSim.Services.Connectors return rinfos; } + public List GetDefaultHypergridRegions(UUID scopeID) + { + Dictionary sendData = new Dictionary(); + + sendData["SCOPEID"] = scopeID.ToString(); + + sendData["METHOD"] = "get_default_hypergrid_regions"; + + List rinfos = new List(); + string reply = string.Empty; + string uri = m_ServerURI + "/grid"; + try + { + reply = SynchronousRestFormsRequester.MakeRequest("POST", + uri, + ServerUtils.BuildQueryString(sendData), m_Auth); + + //m_log.DebugFormat("[GRID CONNECTOR]: reply was {0}", reply); + } + catch (Exception e) + { + m_log.DebugFormat("[GRID CONNECTOR]: Exception when contacting grid server at {0}: {1}", uri, e.Message); + return rinfos; + } + + if (reply != string.Empty) + { + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + if (replyData != null) + { + Dictionary.ValueCollection rinfosList = replyData.Values; + foreach (object r in rinfosList) + { + if (r is Dictionary) + { + GridRegion rinfo = new GridRegion((Dictionary)r); + rinfos.Add(rinfo); + } + } + } + else + m_log.DebugFormat("[GRID CONNECTOR]: GetDefaultHypergridRegions {0} received null response", + scopeID); + } + else + m_log.DebugFormat("[GRID CONNECTOR]: GetDefaultHypergridRegions received null reply"); + + return rinfos; + } + public List GetFallbackRegions(UUID scopeID, int x, int y) { Dictionary sendData = new Dictionary(); @@ -532,7 +586,7 @@ namespace OpenSim.Services.Connectors { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - ServerUtils.BuildQueryString(sendData)); + ServerUtils.BuildQueryString(sendData), m_Auth); //m_log.DebugFormat("[GRID CONNECTOR]: reply was {0}", reply); } @@ -583,7 +637,7 @@ namespace OpenSim.Services.Connectors { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - ServerUtils.BuildQueryString(sendData)); + ServerUtils.BuildQueryString(sendData), m_Auth); //m_log.DebugFormat("[GRID CONNECTOR]: reply was {0}", reply); } @@ -634,7 +688,7 @@ namespace OpenSim.Services.Connectors { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - ServerUtils.BuildQueryString(sendData)); + ServerUtils.BuildQueryString(sendData), m_Auth); } catch (Exception e) { @@ -665,6 +719,45 @@ namespace OpenSim.Services.Connectors return flags; } + public Dictionary GetExtraFeatures() + { + Dictionary sendData = new Dictionary(); + Dictionary extraFeatures = new Dictionary(); + + sendData["METHOD"] = "get_grid_extra_features"; + + string reply = string.Empty; + string uri = m_ServerURI + "/grid"; + + try + { + reply = SynchronousRestFormsRequester.MakeRequest("POST", + uri, + ServerUtils.BuildQueryString(sendData), m_Auth); + } + catch (Exception e) + { + m_log.DebugFormat("[GRID CONNECTOR]: GetExtraFeatures - Exception when contacting grid server at {0}: {1}", uri, e.Message); + return extraFeatures; + } + + if (reply != string.Empty) + { + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + if ((replyData != null) && replyData.Count > 0) + { + foreach (string key in replyData.Keys) + { + extraFeatures[key] = replyData[key].ToString(); + } + } + } + else + m_log.DebugFormat("[GRID CONNECTOR]: GetExtraServiceURLs received null reply"); + + return extraFeatures; + } #endregion } diff --git a/OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs b/OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs index 94bda82..b5ca1ad 100644 --- a/OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs +++ b/OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs @@ -32,7 +32,8 @@ using System.IO; using System.Reflection; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Communications; + +using OpenSim.Framework.ServiceAuth; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using OpenSim.Server.Base; @@ -40,7 +41,7 @@ using OpenMetaverse; namespace OpenSim.Services.Connectors { - public class GridUserServicesConnector : IGridUserService + public class GridUserServicesConnector : BaseServiceConnector, IGridUserService { private static readonly ILog m_log = LogManager.GetLogger( @@ -80,6 +81,7 @@ namespace OpenSim.Services.Connectors throw new Exception("GridUser connector init error"); } m_ServerURI = serviceURI; + base.Initialise(source, "GridUserService"); } @@ -162,7 +164,8 @@ namespace OpenSim.Services.Connectors { string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - reqString); + reqString, + m_Auth); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); @@ -198,7 +201,8 @@ namespace OpenSim.Services.Connectors { string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - reqString); + reqString, + m_Auth); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); @@ -214,7 +218,7 @@ namespace OpenSim.Services.Connectors } else - m_log.DebugFormat("[GRID USER CONNECTOR]: Loggedin received empty reply"); + m_log.DebugFormat("[GRID USER CONNECTOR]: Get received empty reply"); } catch (Exception e) { @@ -243,7 +247,8 @@ namespace OpenSim.Services.Connectors { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - reqString); + reqString, + m_Auth); if (reply == null || (reply != null && reply == string.Empty)) { m_log.DebugFormat("[GRID USER CONNECTOR]: GetGridUserInfo received null or empty reply"); diff --git a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs index 5bcff48..b1663ee 100644 --- a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs @@ -53,7 +53,8 @@ namespace OpenSim.Services.Connectors.Hypergrid private IAssetService m_AssetService; - public GatekeeperServiceConnector() : base() + public GatekeeperServiceConnector() + : base() { } @@ -123,11 +124,13 @@ namespace OpenSim.Services.Connectors.Hypergrid realHandle = Convert.ToUInt64((string)hash["handle"]); //m_log.Debug(">> HERE, realHandle: " + realHandle); } - if (hash["region_image"] != null) { + if (hash["region_image"] != null) + { imageURL = (string)hash["region_image"]; //m_log.Debug(">> HERE, imageURL: " + imageURL); } - if (hash["external_name"] != null) { + if (hash["external_name"] != null) + { externalName = (string)hash["external_name"]; //m_log.Debug(">> HERE, externalName: " + externalName); } @@ -178,7 +181,7 @@ namespace OpenSim.Services.Connectors.Hypergrid //m_log.Debug("Size: " + m.PhysicalDimension.Height + "-" + m.PhysicalDimension.Width); imageData = OpenJPEG.EncodeFromImage(bitmap, true); } - + AssetBase ass = new AssetBase(UUID.Random(), "region " + name, (sbyte)AssetType.Texture, regionID.ToString()); // !!! for now @@ -199,10 +202,16 @@ namespace OpenSim.Services.Connectors.Hypergrid return mapTile; } - public GridRegion GetHyperlinkRegion(GridRegion gatekeeper, UUID regionID) + public GridRegion GetHyperlinkRegion(GridRegion gatekeeper, UUID regionID, UUID agentID, string agentHomeURI, out string message) { Hashtable hash = new Hashtable(); hash["region_uuid"] = regionID.ToString(); + if (agentID != UUID.Zero) + { + hash["agent_id"] = agentID.ToString(); + if (agentHomeURI != null) + hash["agent_home_uri"] = agentHomeURI; + } IList paramList = new ArrayList(); paramList.Add(hash); @@ -216,12 +225,14 @@ namespace OpenSim.Services.Connectors.Hypergrid } catch (Exception e) { + message = "Error contacting grid."; m_log.Debug("[GATEKEEPER SERVICE CONNECTOR]: Exception " + e.Message); return null; } if (response.IsFault) { + message = "Error contacting grid."; m_log.ErrorFormat("[GATEKEEPER SERVICE CONNECTOR]: remote call returned an error: {0}", response.FaultString); return null; } @@ -233,6 +244,14 @@ namespace OpenSim.Services.Connectors.Hypergrid { bool success = false; Boolean.TryParse((string)hash["result"], out success); + + if (hash["message"] != null) + message = (string)hash["message"]; + else if (success) + message = null; + else + message = "The teleport destination could not be found."; // probably the dest grid is old and doesn't send 'message', but the most common problem is that the region is unavailable + if (success) { GridRegion region = new GridRegion(); @@ -252,12 +271,25 @@ namespace OpenSim.Services.Connectors.Hypergrid region.RegionLocY = n; //m_log.Debug(">> HERE, y: " + region.RegionLocY); } + if (hash["size_x"] != null) + { + Int32.TryParse((string)hash["size_x"], out n); + region.RegionSizeX = n; + //m_log.Debug(">> HERE, x: " + region.RegionLocX); + } + if (hash["size_y"] != null) + { + Int32.TryParse((string)hash["size_y"], out n); + region.RegionSizeY = n; + //m_log.Debug(">> HERE, y: " + region.RegionLocY); + } if (hash["region_name"] != null) { region.RegionName = (string)hash["region_name"]; //m_log.Debug(">> HERE, region_name: " + region.RegionName); } - if (hash["hostname"] != null) { + if (hash["hostname"] != null) + { region.ExternalHostName = (string)hash["hostname"]; //m_log.Debug(">> HERE, hostname: " + region.ExternalHostName); } @@ -275,10 +307,10 @@ namespace OpenSim.Services.Connectors.Hypergrid region.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), p); //m_log.Debug(">> HERE, internal_port: " + region.InternalEndPoint); } - + if (hash["server_uri"] != null) { - region.ServerURI = (string) hash["server_uri"]; + region.ServerURI = (string)hash["server_uri"]; //m_log.Debug(">> HERE, server_uri: " + region.ServerURI); } @@ -289,61 +321,12 @@ namespace OpenSim.Services.Connectors.Hypergrid } catch (Exception e) { + message = "Error parsing response from grid."; m_log.Error("[GATEKEEPER SERVICE CONNECTOR]: Got exception while parsing hyperlink response " + e.StackTrace); return null; } return null; } - - public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string myipaddress, out string reason) - { - // m_log.DebugFormat("[GATEKEEPER SERVICE CONNECTOR]: CreateAgent start"); - - myipaddress = String.Empty; - reason = String.Empty; - - if (destination == null) - { - m_log.Debug("[GATEKEEPER SERVICE CONNECTOR]: Given destination is null"); - return false; - } - - string uri = destination.ServerURI + AgentPath() + aCircuit.AgentID + "/"; - - try - { - OSDMap args = aCircuit.PackAgentCircuitData(); - - args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); - args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); - args["destination_name"] = OSD.FromString(destination.RegionName); - args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); - args["teleport_flags"] = OSD.FromString(flags.ToString()); - - OSDMap result = WebUtil.PostToService(uri, args, 80000); - if (result["Success"].AsBoolean()) - { - OSDMap unpacked = (OSDMap)result["_Result"]; - - if (unpacked != null) - { - reason = unpacked["reason"].AsString(); - myipaddress = unpacked["your_ip"].AsString(); - return unpacked["success"].AsBoolean(); - } - } - - reason = result["Message"] != null ? result["Message"].AsString() : "error"; - return false; - } - catch (Exception e) - { - m_log.Warn("[REMOTE SIMULATION CONNECTOR]: CreateAgent failed with exception: " + e.ToString()); - reason = e.Message; - } - - return false; - } } } diff --git a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs index e984a54..622d4e1 100644 --- a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs @@ -277,7 +277,7 @@ namespace OpenSim.Services.Connectors.Hypergrid { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - ServerUtils.BuildQueryString(sendData)); + ServerUtils.BuildQueryString(sendData), 15); } catch (Exception e) { diff --git a/OpenSim/Services/Connectors/Hypergrid/HeloServicesConnector.cs b/OpenSim/Services/Connectors/Hypergrid/HeloServicesConnector.cs index 5c50936..b5e6d69 100644 --- a/OpenSim/Services/Connectors/Hypergrid/HeloServicesConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/HeloServicesConnector.cs @@ -47,16 +47,22 @@ namespace OpenSim.Services.Connectors public HeloServicesConnector(string serverURI) { - if (!serverURI.EndsWith("=")) - m_ServerURI = serverURI.TrimEnd('/') + "/helo/"; - else + try { - // Simian sends malformed urls like this: - // http://valley.virtualportland.org/simtest/Grid/?id= - // - try + Uri uri; + + if (!serverURI.EndsWith("=")) + { + // Let's check if this is a valid URI, because it may not be + uri = new Uri(serverURI); + m_ServerURI = serverURI.TrimEnd('/') + "/helo/"; + } + else { - Uri uri = new Uri(serverURI + "xxx"); + // Simian sends malformed urls like this: + // http://valley.virtualportland.org/simtest/Grid/?id= + // + uri = new Uri(serverURI + "xxx"); if (uri.Query == string.Empty) m_ServerURI = serverURI.TrimEnd('/') + "/helo/"; else @@ -66,26 +72,34 @@ namespace OpenSim.Services.Connectors m_ServerURI = m_ServerURI.TrimEnd('/') + "/helo/"; } } - catch (UriFormatException) - { - m_log.WarnFormat("[HELO SERVICE]: Malformed URL {0}", serverURI); - } + + } + catch (UriFormatException) + { + m_log.WarnFormat("[HELO SERVICE]: Malformed URL {0}", serverURI); } } - public virtual string Helo() { - HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(m_ServerURI); - // Eventually we need to switch to HEAD - /* req.Method = "HEAD"; */ + if (String.IsNullOrEmpty(m_ServerURI)) + { + m_log.WarnFormat("[HELO SERVICE]: Unable to invoke HELO due to empty URL"); + return String.Empty; + } try { - WebResponse response = req.GetResponse(); - if (response.Headers.Get("X-Handlers-Provided") == null) // just in case this ever returns a null - return string.Empty; - return response.Headers.Get("X-Handlers-Provided"); + HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(m_ServerURI); + // Eventually we need to switch to HEAD + /* req.Method = "HEAD"; */ + + using (WebResponse response = req.GetResponse()) + { + if (response.Headers.Get("X-Handlers-Provided") == null) // just in case this ever returns a null + return string.Empty; + return response.Headers.Get("X-Handlers-Provided"); + } } catch (Exception e) { @@ -95,6 +109,5 @@ namespace OpenSim.Services.Connectors // fail return string.Empty; } - } -} +} \ No newline at end of file diff --git a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs index 2f263ae..8abd046 100644 --- a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs @@ -44,13 +44,15 @@ using Nini.Config; namespace OpenSim.Services.Connectors.Hypergrid { - public class UserAgentServiceConnector : IUserAgentService + public class UserAgentServiceConnector : SimulationServiceConnector, IUserAgentService { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - string m_ServerURL; + private string m_ServerURLHost; + private string m_ServerURL; + private GridRegion m_Gatekeeper; public UserAgentServiceConnector(string url) : this(url, true) { @@ -58,7 +60,7 @@ namespace OpenSim.Services.Connectors.Hypergrid public UserAgentServiceConnector(string url, bool dnsLookup) { - m_ServerURL = url; + m_ServerURL = m_ServerURLHost = url; if (dnsLookup) { @@ -74,10 +76,11 @@ namespace OpenSim.Services.Connectors.Hypergrid } catch (Exception e) { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Malformed Uri {0}: {1}", m_ServerURL, e.Message); + m_log.DebugFormat("[USER AGENT CONNECTOR]: Malformed Uri {0}: {1}", url, e.Message); } } - m_log.DebugFormat("[USER AGENT CONNECTOR]: new connector to {0} ({1})", url, m_ServerURL); + + //m_log.DebugFormat("[USER AGENT CONNECTOR]: new connector to {0} ({1})", url, m_ServerURL); } public UserAgentServiceConnector(IConfigSource config) @@ -97,16 +100,23 @@ namespace OpenSim.Services.Connectors.Hypergrid m_log.Error("[USER AGENT CONNECTOR]: No Server URI named in section UserAgentService"); throw new Exception("UserAgent connector init error"); } - m_ServerURL = serviceURI; + + m_ServerURL = m_ServerURLHost = serviceURI; if (!m_ServerURL.EndsWith("/")) m_ServerURL += "/"; - m_log.DebugFormat("[USER AGENT CONNECTOR]: UserAgentServiceConnector started for {0}", m_ServerURL); + //m_log.DebugFormat("[USER AGENT CONNECTOR]: new connector to {0}", m_ServerURL); } + protected override string AgentPath() + { + return "homeagent/"; + } - // The Login service calls this interface with a non-null [client] ipaddress - public bool LoginAgentToGrid(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, IPEndPoint ipaddress, out string reason) + // The Login service calls this interface with fromLogin=true + // Sims call it with fromLogin=false + // Either way, this is verified by the handler + public bool LoginAgentToGrid(GridRegion source, AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, bool fromLogin, out string reason) { reason = String.Empty; @@ -117,151 +127,34 @@ namespace OpenSim.Services.Connectors.Hypergrid return false; } - string uri = m_ServerURL + "homeagent/" + aCircuit.AgentID + "/"; - - Console.WriteLine(" >>> LoginAgentToGrid <<< " + uri); - - HttpWebRequest AgentCreateRequest = (HttpWebRequest)WebRequest.Create(uri); - AgentCreateRequest.Method = "POST"; - AgentCreateRequest.ContentType = "application/json"; - AgentCreateRequest.Timeout = 10000; - //AgentCreateRequest.KeepAlive = false; - //AgentCreateRequest.Headers.Add("Authorization", authKey); - - // Fill it in - OSDMap args = PackCreateAgentArguments(aCircuit, gatekeeper, destination, ipaddress); - - string strBuffer = ""; - byte[] buffer = new byte[1]; - try - { - strBuffer = OSDParser.SerializeJsonString(args); - Encoding str = Util.UTF8; - buffer = str.GetBytes(strBuffer); - - } - catch (Exception e) - { - m_log.WarnFormat("[USER AGENT CONNECTOR]: Exception thrown on serialization of ChildCreate: {0}", e.Message); - // ignore. buffer will be empty, caller should check. - } - - Stream os = null; - try - { // send the Post - AgentCreateRequest.ContentLength = buffer.Length; //Count bytes to send - os = AgentCreateRequest.GetRequestStream(); - os.Write(buffer, 0, strBuffer.Length); //Send it - m_log.InfoFormat("[USER AGENT CONNECTOR]: Posted CreateAgent request to remote sim {0}, region {1}, x={2} y={3}", - uri, destination.RegionName, destination.RegionLocX, destination.RegionLocY); - } - //catch (WebException ex) - catch - { - //m_log.InfoFormat("[USER AGENT CONNECTOR]: Bad send on ChildAgentUpdate {0}", ex.Message); - reason = "cannot contact remote region"; - return false; - } - finally - { - if (os != null) - os.Close(); - } - - // Let's wait for the response - //m_log.Info("[USER AGENT CONNECTOR]: Waiting for a reply after DoCreateChildAgentCall"); + GridRegion home = new GridRegion(); + home.ServerURI = m_ServerURL; + home.RegionID = destination.RegionID; + home.RegionLocX = destination.RegionLocX; + home.RegionLocY = destination.RegionLocY; - WebResponse webResponse = null; - StreamReader sr = null; - try - { - webResponse = AgentCreateRequest.GetResponse(); - if (webResponse == null) - { - m_log.Info("[USER AGENT CONNECTOR]: Null reply on DoCreateChildAgentCall post"); - } - else - { + m_Gatekeeper = gatekeeper; - sr = new StreamReader(webResponse.GetResponseStream()); - string response = sr.ReadToEnd().Trim(); - m_log.InfoFormat("[USER AGENT CONNECTOR]: DoCreateChildAgentCall reply was {0} ", response); - - if (!String.IsNullOrEmpty(response)) - { - try - { - // we assume we got an OSDMap back - OSDMap r = Util.GetOSDMap(response); - bool success = r["success"].AsBoolean(); - reason = r["reason"].AsString(); - return success; - } - catch (NullReferenceException e) - { - m_log.InfoFormat("[USER AGENT CONNECTOR]: exception on reply of DoCreateChildAgentCall {0}", e.Message); - - // check for old style response - if (response.ToLower().StartsWith("true")) - return true; - - return false; - } - } - } - } - catch (WebException ex) - { - m_log.InfoFormat("[USER AGENT CONNECTOR]: exception on reply of DoCreateChildAgentCall {0}", ex.Message); - reason = "Destination did not reply"; - return false; - } - finally - { - if (sr != null) - sr.Close(); - } - - return true; + Console.WriteLine(" >>> LoginAgentToGrid <<< " + home.ServerURI); + uint flags = fromLogin ? (uint)TeleportFlags.ViaLogin : (uint)TeleportFlags.ViaHome; + return CreateAgent(source, home, aCircuit, flags, out reason); } // The simulators call this interface - public bool LoginAgentToGrid(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, out string reason) + public bool LoginAgentToGrid(GridRegion source, AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, out string reason) { - return LoginAgentToGrid(aCircuit, gatekeeper, destination, null, out reason); + return LoginAgentToGrid(source, aCircuit, gatekeeper, destination, false, out reason); } - protected OSDMap PackCreateAgentArguments(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, IPEndPoint ipaddress) + protected override void PackData(OSDMap args, GridRegion source, AgentCircuitData aCircuit, GridRegion destination, uint flags) { - OSDMap args = null; - try - { - args = aCircuit.PackAgentCircuitData(); - } - catch (Exception e) - { - m_log.Debug("[USER AGENT CONNECTOR]: PackAgentCircuitData failed with exception: " + e.Message); - } - - // Add the input arguments - args["gatekeeper_serveruri"] = OSD.FromString(gatekeeper.ServerURI); - args["gatekeeper_host"] = OSD.FromString(gatekeeper.ExternalHostName); - args["gatekeeper_port"] = OSD.FromString(gatekeeper.HttpPort.ToString()); - args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); - args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); - args["destination_name"] = OSD.FromString(destination.RegionName); - args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); + base.PackData(args, source, aCircuit, destination, flags); + args["gatekeeper_serveruri"] = OSD.FromString(m_Gatekeeper.ServerURI); + args["gatekeeper_host"] = OSD.FromString(m_Gatekeeper.ExternalHostName); + args["gatekeeper_port"] = OSD.FromString(m_Gatekeeper.HttpPort.ToString()); args["destination_serveruri"] = OSD.FromString(destination.ServerURI); - - // 10/3/2010 - // I added the client_ip up to the regular AgentCircuitData, so this doesn't need to be here. - // This need cleaning elsewhere... - //if (ipaddress != null) - // args["client_ip"] = OSD.FromString(ipaddress.Address.ToString()); - - return args; } public void SetClientToken(UUID sessionID, string token) @@ -269,96 +162,111 @@ namespace OpenSim.Services.Connectors.Hypergrid // no-op } - public GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt) + private Hashtable CallServer(string methodName, Hashtable hash) { - position = Vector3.UnitY; lookAt = Vector3.UnitY; - - Hashtable hash = new Hashtable(); - hash["userID"] = userID.ToString(); - IList paramList = new ArrayList(); paramList.Add(hash); - XmlRpcRequest request = new XmlRpcRequest("get_home_region", paramList); + XmlRpcRequest request = new XmlRpcRequest(methodName, paramList); + + // Send and get reply XmlRpcResponse response = null; try { response = request.Send(m_ServerURL, 10000); } - catch (Exception) + catch (Exception e) { - return null; + m_log.DebugFormat("[USER AGENT CONNECTOR]: {0} call to {1} failed: {2}", methodName, m_ServerURLHost, e.Message); + throw; } if (response.IsFault) { - return null; + throw new Exception(string.Format("[USER AGENT CONNECTOR]: {0} call to {1} returned an error: {2}", methodName, m_ServerURLHost, response.FaultString)); } hash = (Hashtable)response.Value; - //foreach (Object o in hash) - // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); - try + + if (hash == null) { - bool success = false; - Boolean.TryParse((string)hash["result"], out success); - if (success) - { - GridRegion region = new GridRegion(); + throw new Exception(string.Format("[USER AGENT CONNECTOR]: {0} call to {1} returned null", methodName, m_ServerURLHost)); + } - UUID.TryParse((string)hash["uuid"], out region.RegionID); - //m_log.Debug(">> HERE, uuid: " + region.RegionID); - int n = 0; - if (hash["x"] != null) - { - Int32.TryParse((string)hash["x"], out n); - region.RegionLocX = n; - //m_log.Debug(">> HERE, x: " + region.RegionLocX); - } - if (hash["y"] != null) - { - Int32.TryParse((string)hash["y"], out n); - region.RegionLocY = n; - //m_log.Debug(">> HERE, y: " + region.RegionLocY); - } - if (hash["region_name"] != null) - { - region.RegionName = (string)hash["region_name"]; - //m_log.Debug(">> HERE, name: " + region.RegionName); - } - if (hash["hostname"] != null) - region.ExternalHostName = (string)hash["hostname"]; - if (hash["http_port"] != null) - { - uint p = 0; - UInt32.TryParse((string)hash["http_port"], out p); - region.HttpPort = p; - } - if (hash.ContainsKey("server_uri") && hash["server_uri"] != null) - region.ServerURI = (string)hash["server_uri"]; + return hash; + } - if (hash["internal_port"] != null) - { - int p = 0; - Int32.TryParse((string)hash["internal_port"], out p); - region.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), p); - } - if (hash["position"] != null) - Vector3.TryParse((string)hash["position"], out position); - if (hash["lookAt"] != null) - Vector3.TryParse((string)hash["lookAt"], out lookAt); + public GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt) + { + position = Vector3.UnitY; lookAt = Vector3.UnitY; - // Successful return - return region; - } + Hashtable hash = new Hashtable(); + hash["userID"] = userID.ToString(); + + hash = CallServer("get_home_region", hash); + + bool success; + if (!Boolean.TryParse((string)hash["result"], out success) || !success) + return null; + + GridRegion region = new GridRegion(); + UUID.TryParse((string)hash["uuid"], out region.RegionID); + //m_log.Debug(">> HERE, uuid: " + region.RegionID); + int n = 0; + if (hash["x"] != null) + { + Int32.TryParse((string)hash["x"], out n); + region.RegionLocX = n; + //m_log.Debug(">> HERE, x: " + region.RegionLocX); } - catch (Exception) + if (hash["y"] != null) { - return null; + Int32.TryParse((string)hash["y"], out n); + region.RegionLocY = n; + //m_log.Debug(">> HERE, y: " + region.RegionLocY); + } + if (hash["size_x"] != null) + { + Int32.TryParse((string)hash["size_x"], out n); + region.RegionSizeX = n; + //m_log.Debug(">> HERE, x: " + region.RegionLocX); } + if (hash["size_y"] != null) + { + Int32.TryParse((string)hash["size_y"], out n); + region.RegionSizeY = n; + //m_log.Debug(">> HERE, y: " + region.RegionLocY); + } + if (hash["region_name"] != null) + { + region.RegionName = (string)hash["region_name"]; + //m_log.Debug(">> HERE, name: " + region.RegionName); + } + if (hash["hostname"] != null) + region.ExternalHostName = (string)hash["hostname"]; + if (hash["http_port"] != null) + { + uint p = 0; + UInt32.TryParse((string)hash["http_port"], out p); + region.HttpPort = p; + } + if (hash.ContainsKey("server_uri") && hash["server_uri"] != null) + region.ServerURI = (string)hash["server_uri"]; - return null; + if (hash["internal_port"] != null) + { + int p = 0; + Int32.TryParse((string)hash["internal_port"], out p); + region.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), p); + } + if (hash["position"] != null) + Vector3.TryParse((string)hash["position"], out position); + if (hash["lookAt"] != null) + Vector3.TryParse((string)hash["lookAt"], out lookAt); + + // Successful return + return region; } public bool IsAgentComingHome(UUID sessionID, string thisGridExternalName) @@ -445,14 +353,14 @@ namespace OpenSim.Services.Connectors.Hypergrid } catch { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for StatusNotification", m_ServerURL); + m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for StatusNotification", m_ServerURLHost); // reason = "Exception: " + e.Message; return friendsOnline; } if (response.IsFault) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for StatusNotification returned an error: {1}", m_ServerURL, response.FaultString); + m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for StatusNotification returned an error: {1}", m_ServerURLHost, response.FaultString); // reason = "XMLRPC Fault"; return friendsOnline; } @@ -464,7 +372,7 @@ namespace OpenSim.Services.Connectors.Hypergrid { if (hash == null) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: GetOnlineFriends Got null response from {0}! THIS IS BAAAAD", m_ServerURL); + m_log.ErrorFormat("[USER AGENT CONNECTOR]: GetOnlineFriends Got null response from {0}! THIS IS BAAAAD", m_ServerURLHost); // reason = "Internal error 1"; return friendsOnline; } @@ -517,14 +425,14 @@ namespace OpenSim.Services.Connectors.Hypergrid } catch { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetOnlineFriends", m_ServerURL); + m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetOnlineFriends", m_ServerURLHost); // reason = "Exception: " + e.Message; return online; } if (response.IsFault) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetOnlineFriends returned an error: {1}", m_ServerURL, response.FaultString); + m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetOnlineFriends returned an error: {1}", m_ServerURLHost, response.FaultString); // reason = "XMLRPC Fault"; return online; } @@ -536,7 +444,7 @@ namespace OpenSim.Services.Connectors.Hypergrid { if (hash == null) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: GetOnlineFriends Got null response from {0}! THIS IS BAAAAD", m_ServerURL); + m_log.ErrorFormat("[USER AGENT CONNECTOR]: GetOnlineFriends Got null response from {0}! THIS IS BAAAAD", m_ServerURLHost); // reason = "Internal error 1"; return online; } @@ -567,51 +475,17 @@ namespace OpenSim.Services.Connectors.Hypergrid Hashtable hash = new Hashtable(); hash["userID"] = userID.ToString(); - IList paramList = new ArrayList(); - paramList.Add(hash); - - XmlRpcRequest request = new XmlRpcRequest("get_user_info", paramList); + hash = CallServer("get_user_info", hash); Dictionary info = new Dictionary(); - XmlRpcResponse response = null; - try - { - response = request.Send(m_ServerURL, 10000); - } - catch - { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetUserInfo", m_ServerURL); - return info; - } - if (response.IsFault) + foreach (object key in hash.Keys) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetServerURLs returned an error: {1}", m_ServerURL, response.FaultString); - return info; - } - - hash = (Hashtable)response.Value; - try - { - if (hash == null) - { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: GetUserInfo Got null response from {0}! THIS IS BAAAAD", m_ServerURL); - return info; - } - - // Here is the actual response - foreach (object key in hash.Keys) + if (hash[key] != null) { - if (hash[key] != null) - { - info.Add(key.ToString(), hash[key]); - } + info.Add(key.ToString(), hash[key]); } } - catch - { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got exception on GetOnlineFriends response."); - } return info; } @@ -621,60 +495,16 @@ namespace OpenSim.Services.Connectors.Hypergrid Hashtable hash = new Hashtable(); hash["userID"] = userID.ToString(); - IList paramList = new ArrayList(); - paramList.Add(hash); - - XmlRpcRequest request = new XmlRpcRequest("get_server_urls", paramList); -// string reason = string.Empty; - - // Send and get reply - Dictionary serverURLs = new Dictionary(); - XmlRpcResponse response = null; - try - { - response = request.Send(m_ServerURL, 10000); - } - catch - { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetServerURLs", m_ServerURL); -// reason = "Exception: " + e.Message; - return serverURLs; - } - - if (response.IsFault) - { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetServerURLs returned an error: {1}", m_ServerURL, response.FaultString); -// reason = "XMLRPC Fault"; - return serverURLs; - } - - hash = (Hashtable)response.Value; - //foreach (Object o in hash) - // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); - try + hash = CallServer("get_server_urls", hash); + + Dictionary serverURLs = new Dictionary(); + foreach (object key in hash.Keys) { - if (hash == null) + if (key is string && ((string)key).StartsWith("SRV_") && hash[key] != null) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: GetServerURLs Got null response from {0}! THIS IS BAAAAD", m_ServerURL); -// reason = "Internal error 1"; - return serverURLs; + string serverType = key.ToString().Substring(4); // remove "SRV_" + serverURLs.Add(serverType, hash[key].ToString()); } - - // Here is the actual response - foreach (object key in hash.Keys) - { - if (key is string && ((string)key).StartsWith("SRV_") && hash[key] != null) - { - string serverType = key.ToString().Substring(4); // remove "SRV_" - serverURLs.Add(serverType, hash[key].ToString()); - } - } - - } - catch - { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got exception on GetOnlineFriends response."); -// reason = "Exception: " + e.Message; } return serverURLs; @@ -685,55 +515,13 @@ namespace OpenSim.Services.Connectors.Hypergrid Hashtable hash = new Hashtable(); hash["userID"] = userID.ToString(); - IList paramList = new ArrayList(); - paramList.Add(hash); + hash = CallServer("locate_user", hash); - XmlRpcRequest request = new XmlRpcRequest("locate_user", paramList); -// string reason = string.Empty; - - // Send and get reply string url = string.Empty; - XmlRpcResponse response = null; - try - { - response = request.Send(m_ServerURL, 10000); - } - catch - { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for LocateUser", m_ServerURL); -// reason = "Exception: " + e.Message; - return url; - } - if (response.IsFault) - { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for LocateUser returned an error: {1}", m_ServerURL, response.FaultString); -// reason = "XMLRPC Fault"; - return url; - } - - hash = (Hashtable)response.Value; - //foreach (Object o in hash) - // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); - try - { - if (hash == null) - { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: LocateUser Got null response from {0}! THIS IS BAAAAD", m_ServerURL); -// reason = "Internal error 1"; - return url; - } - - // Here's the actual response - if (hash.ContainsKey("URL")) - url = hash["URL"].ToString(); - - } - catch - { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got exception on LocateUser response."); -// reason = "Exception: " + e.Message; - } + // Here's the actual response + if (hash.ContainsKey("URL")) + url = hash["URL"].ToString(); return url; } @@ -744,55 +532,13 @@ namespace OpenSim.Services.Connectors.Hypergrid hash["userID"] = userID.ToString(); hash["targetUserID"] = targetUserID.ToString(); - IList paramList = new ArrayList(); - paramList.Add(hash); - - XmlRpcRequest request = new XmlRpcRequest("get_uui", paramList); -// string reason = string.Empty; + hash = CallServer("get_uui", hash); - // Send and get reply string uui = string.Empty; - XmlRpcResponse response = null; - try - { - response = request.Send(m_ServerURL, 10000); - } - catch - { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetUUI", m_ServerURL); -// reason = "Exception: " + e.Message; - return uui; - } - - if (response.IsFault) - { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetUUI returned an error: {1}", m_ServerURL, response.FaultString); -// reason = "XMLRPC Fault"; - return uui; - } - - hash = (Hashtable)response.Value; - //foreach (Object o in hash) - // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); - try - { - if (hash == null) - { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: GetUUI Got null response from {0}! THIS IS BAAAAD", m_ServerURL); -// reason = "Internal error 1"; - return uui; - } - // Here's the actual response - if (hash.ContainsKey("UUI")) - uui = hash["UUI"].ToString(); - - } - catch - { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got exception on GetUUI response."); -// reason = "Exception: " + e.Message; - } + // Here's the actual response + if (hash.ContainsKey("UUI")) + uui = hash["UUI"].ToString(); return uui; } @@ -803,54 +549,17 @@ namespace OpenSim.Services.Connectors.Hypergrid hash["first"] = first; hash["last"] = last; - IList paramList = new ArrayList(); - paramList.Add(hash); + hash = CallServer("get_uuid", hash); - XmlRpcRequest request = new XmlRpcRequest("get_uuid", paramList); - // string reason = string.Empty; - - // Send and get reply - UUID uuid = UUID.Zero; - XmlRpcResponse response = null; - try - { - response = request.Send(m_ServerURL, 10000); - } - catch + if (!hash.ContainsKey("UUID")) { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetUUID", m_ServerURL); - // reason = "Exception: " + e.Message; - return uuid; + throw new Exception(string.Format("[USER AGENT CONNECTOR]: get_uuid call to {0} didn't return a UUID", m_ServerURLHost)); } - if (response.IsFault) - { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetUUID returned an error: {1}", m_ServerURL, response.FaultString); - // reason = "XMLRPC Fault"; - return uuid; - } - - hash = (Hashtable)response.Value; - //foreach (Object o in hash) - // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); - try - { - if (hash == null) - { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: GetUUDI Got null response from {0}! THIS IS BAAAAD", m_ServerURL); - // reason = "Internal error 1"; - return uuid; - } - - // Here's the actual response - if (hash.ContainsKey("UUID")) - UUID.TryParse(hash["UUID"].ToString(), out uuid); - - } - catch + UUID uuid; + if (!UUID.TryParse(hash["UUID"].ToString(), out uuid)) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got exception on UUID response."); - // reason = "Exception: " + e.Message; + throw new Exception(string.Format("[USER AGENT CONNECTOR]: get_uuid call to {0} returned an invalid UUID: {1}", m_ServerURLHost, hash["UUID"].ToString())); } return uuid; @@ -858,7 +567,7 @@ namespace OpenSim.Services.Connectors.Hypergrid private bool GetBoolResponse(XmlRpcRequest request, out string reason) { - //m_log.Debug("[USER AGENT CONNECTOR]: GetBoolResponse from/to " + m_ServerURL); + //m_log.Debug("[USER AGENT CONNECTOR]: GetBoolResponse from/to " + m_ServerURLHost); XmlRpcResponse response = null; try { @@ -866,14 +575,14 @@ namespace OpenSim.Services.Connectors.Hypergrid } catch (Exception e) { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetBoolResponse", m_ServerURL); + m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetBoolResponse", m_ServerURLHost); reason = "Exception: " + e.Message; return false; } if (response.IsFault) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetBoolResponse returned an error: {1}", m_ServerURL, response.FaultString); + m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetBoolResponse returned an error: {1}", m_ServerURLHost, response.FaultString); reason = "XMLRPC Fault"; return false; } @@ -885,7 +594,7 @@ namespace OpenSim.Services.Connectors.Hypergrid { if (hash == null) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got null response from {0}! THIS IS BAAAAD", m_ServerURL); + m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got null response from {0}! THIS IS BAAAAD", m_ServerURLHost); reason = "Internal error 1"; return false; } @@ -896,7 +605,7 @@ namespace OpenSim.Services.Connectors.Hypergrid else { reason = "Internal error 2"; - m_log.WarnFormat("[USER AGENT CONNECTOR]: response from {0} does not have expected key 'result'", m_ServerURL); + m_log.WarnFormat("[USER AGENT CONNECTOR]: response from {0} does not have expected key 'result'", m_ServerURLHost); } return success; diff --git a/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs b/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs index dbce9f6..e19c23d 100644 --- a/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs +++ b/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs @@ -123,6 +123,7 @@ namespace OpenSim.Services.Connectors.InstantMessage gim["position_z"] = msg.Position.Z.ToString(); gim["region_id"] = msg.RegionID.ToString(); gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket, Base64FormattingOptions.None); + gim["region_id"] = new UUID(msg.RegionID).ToString(); return gim; } diff --git a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs index 44f5e01..7cecd93 100644 --- a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs +++ b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs @@ -33,22 +33,37 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Console; -using OpenSim.Framework.Communications; + +using OpenSim.Framework.Monitoring; using OpenSim.Services.Interfaces; using OpenSim.Server.Base; using OpenMetaverse; namespace OpenSim.Services.Connectors { - public class XInventoryServicesConnector : IInventoryService + public class XInventoryServicesConnector : BaseServiceConnector, IInventoryService { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Number of requests made to the remote inventory service. + /// + public int RequestsMade { get; private set; } + private string m_ServerURI = String.Empty; - private object m_Lock = new object(); + /// + /// Timeout for remote requests. + /// + /// + /// In this case, -1 is default timeout (100 seconds), not infinite. + /// + private int m_requestTimeoutSecs = -1; + + private const double CACHE_EXPIRATION_SECONDS = 20.0; + private static ExpiringCache m_ItemCache = new ExpiringCache(); public XInventoryServicesConnector() { @@ -60,20 +75,21 @@ namespace OpenSim.Services.Connectors } public XInventoryServicesConnector(IConfigSource source) + : base(source, "InventoryService") { Initialise(source); } public virtual void Initialise(IConfigSource source) { - IConfig assetConfig = source.Configs["InventoryService"]; - if (assetConfig == null) + IConfig config = source.Configs["InventoryService"]; + if (config == null) { m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini"); throw new Exception("Inventory connector init error"); } - string serviceURI = assetConfig.GetString("InventoryServerURI", + string serviceURI = config.GetString("InventoryServerURI", String.Empty); if (serviceURI == String.Empty) @@ -82,6 +98,45 @@ namespace OpenSim.Services.Connectors throw new Exception("Inventory connector init error"); } m_ServerURI = serviceURI; + + m_requestTimeoutSecs = config.GetInt("RemoteRequestTimeout", m_requestTimeoutSecs); + + StatsManager.RegisterStat( + new Stat( + "RequestsMade", + "Requests made", + "Number of requests made to the remove inventory service", + "requests", + "inventory", + serviceURI, + StatType.Pull, + MeasuresOfInterest.AverageChangeOverTime, + s => s.Value = RequestsMade, + StatVerbosity.Debug)); + } + + private bool CheckReturn(Dictionary ret) + { + if (ret == null) + return false; + + if (ret.Count == 0) + return false; + + if (ret.ContainsKey("RESULT")) + { + if (ret["RESULT"] is string) + { + bool result; + + if (bool.TryParse((string)ret["RESULT"], out result)) + return result; + + return false; + } + } + + return true; } public bool CreateUserInventory(UUID principalID) @@ -91,12 +146,7 @@ namespace OpenSim.Services.Connectors { "PRINCIPAL", principalID.ToString() } }); - if (ret == null) - return false; - if (ret.Count == 0) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public List GetInventorySkeleton(UUID principalID) @@ -106,9 +156,7 @@ namespace OpenSim.Services.Connectors { "PRINCIPAL", principalID.ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; Dictionary folders = (Dictionary)ret["FOLDERS"]; @@ -135,15 +183,13 @@ namespace OpenSim.Services.Connectors { "PRINCIPAL", principalID.ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; return BuildFolder((Dictionary)ret["folder"]); } - public InventoryFolderBase GetFolderForType(UUID principalID, AssetType type) + public InventoryFolderBase GetFolderForType(UUID principalID, FolderType type) { Dictionary ret = MakeRequest("GETFOLDERFORTYPE", new Dictionary { @@ -151,9 +197,7 @@ namespace OpenSim.Services.Connectors { "TYPE", ((int)type).ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; return BuildFolder((Dictionary)ret["folder"]); @@ -164,7 +208,7 @@ namespace OpenSim.Services.Connectors InventoryCollection inventory = new InventoryCollection(); inventory.Folders = new List(); inventory.Items = new List(); - inventory.UserID = principalID; + inventory.OwnerID = principalID; try { @@ -174,20 +218,20 @@ namespace OpenSim.Services.Connectors { "FOLDER", folderID.ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; - Dictionary folders = - (Dictionary)ret["FOLDERS"]; - Dictionary items = - (Dictionary)ret["ITEMS"]; - - foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i - inventory.Folders.Add(BuildFolder((Dictionary)o)); - foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i - inventory.Items.Add(BuildItem((Dictionary)o)); + Dictionary folders = ret.ContainsKey("FOLDERS") ? + (Dictionary)ret["FOLDERS"] : null; + Dictionary items = ret.ContainsKey("ITEMS") ? + (Dictionary)ret["ITEMS"] : null; + + if (folders != null) + foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i + inventory.Folders.Add(BuildFolder((Dictionary)o)); + if (items != null) + foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i + inventory.Items.Add(BuildItem((Dictionary)o)); } catch (Exception e) { @@ -196,6 +240,87 @@ namespace OpenSim.Services.Connectors return inventory; } + + public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs) + { + InventoryCollection[] inventoryArr = new InventoryCollection[folderIDs.Length]; + // m_log.DebugFormat("[XXX]: In GetMultipleFoldersContent {0}", String.Join(",", folderIDs)); + try + { + Dictionary resultSet = MakeRequest("GETMULTIPLEFOLDERSCONTENT", + new Dictionary { + { "PRINCIPAL", principalID.ToString() }, + { "FOLDERS", String.Join(",", folderIDs) }, + { "COUNT", folderIDs.Length.ToString() } + }); + + if (!CheckReturn(resultSet)) + return null; + + int i = 0; + foreach (KeyValuePair kvp in resultSet) + { + InventoryCollection inventory = new InventoryCollection(); + if (kvp.Key.StartsWith("F_")) + { + UUID fid = UUID.Zero; + if (UUID.TryParse(kvp.Key.Substring(2), out fid) && fid == folderIDs[i]) + { + inventory.Folders = new List(); + inventory.Items = new List(); + + Dictionary ret = (Dictionary)kvp.Value; + + if (ret.ContainsKey("FID")) + { + if (!UUID.TryParse(ret["FID"].ToString(), out inventory.FolderID)) + m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Could not parse folder id {0}", ret["FID"].ToString()); + } + else + m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: FID key not present in response"); + + inventory.Version = -1; + if (ret.ContainsKey("VERSION")) + Int32.TryParse(ret["VERSION"].ToString(), out inventory.Version); + if (ret.ContainsKey("OWNER")) + UUID.TryParse(ret["OWNER"].ToString(), out inventory.OwnerID); + + //m_log.DebugFormat("[XXX]: Received {0} ({1}) {2} {3}", inventory.FolderID, fid, inventory.Version, inventory.OwnerID); + + Dictionary folders = + (Dictionary)ret["FOLDERS"]; + Dictionary items = + (Dictionary)ret["ITEMS"]; + + foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i + { + inventory.Folders.Add(BuildFolder((Dictionary)o)); + } + foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i + { + inventory.Items.Add(BuildItem((Dictionary)o)); + } + + inventoryArr[i] = inventory; + } + else + { + m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Folder id does not match. Expected {0} got {1}", + folderIDs[i], fid); + m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: {0} {1}", String.Join(",", folderIDs), String.Join(",", resultSet.Keys)); + } + + i += 1; + } + } + } + catch (Exception e) + { + m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Exception in GetMultipleFoldersContent: {0}", e.Message); + } + + return inventoryArr; + } public List GetFolderItems(UUID principalID, UUID folderID) { @@ -205,9 +330,7 @@ namespace OpenSim.Services.Connectors { "FOLDER", folderID.ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; Dictionary items = (Dictionary)ret["ITEMS"]; @@ -230,10 +353,7 @@ namespace OpenSim.Services.Connectors { "ID", folder.ID.ToString() } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool UpdateFolder(InventoryFolderBase folder) @@ -248,10 +368,7 @@ namespace OpenSim.Services.Connectors { "ID", folder.ID.ToString() } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool MoveFolder(InventoryFolderBase folder) @@ -263,10 +380,7 @@ namespace OpenSim.Services.Connectors { "PRINCIPAL", folder.Owner.ToString() } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool DeleteFolders(UUID principalID, List folderIDs) @@ -282,10 +396,7 @@ namespace OpenSim.Services.Connectors { "FOLDERS", slist } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool PurgeFolder(InventoryFolderBase folder) @@ -295,17 +406,18 @@ namespace OpenSim.Services.Connectors { "ID", folder.ID.ToString() } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool AddItem(InventoryItemBase item) { + if (item.Description == null) + item.Description = String.Empty; if (item.CreatorData == null) item.CreatorData = String.Empty; - Dictionary ret = MakeRequest("ADDITEM", + if (item.CreatorId == null) + item.CreatorId = String.Empty; + Dictionary ret = MakeRequest("ADDITEM", new Dictionary { { "AssetID", item.AssetID.ToString() }, { "AssetType", item.AssetType.ToString() }, @@ -330,10 +442,7 @@ namespace OpenSim.Services.Connectors { "CreationDate", item.CreationDate.ToString() } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool UpdateItem(InventoryItemBase item) @@ -365,10 +474,13 @@ namespace OpenSim.Services.Connectors { "CreationDate", item.CreationDate.ToString() } }); - if (ret == null) - return false; + bool result = CheckReturn(ret); + if (result) + { + m_ItemCache.AddOrUpdate(item.ID, item, CACHE_EXPIRATION_SECONDS); + } - return bool.Parse(ret["RESULT"].ToString()); + return result; } public bool MoveItems(UUID principalID, List items) @@ -389,10 +501,7 @@ namespace OpenSim.Services.Connectors { "DESTLIST", destlist } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool DeleteItems(UUID principalID, List itemIDs) @@ -408,14 +517,17 @@ namespace OpenSim.Services.Connectors { "ITEMS", slist } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public InventoryItemBase GetItem(InventoryItemBase item) { + InventoryItemBase retrieved = null; + if (m_ItemCache.TryGetValue(item.ID, out retrieved)) + { + return retrieved; + } + try { Dictionary ret = MakeRequest("GETITEM", @@ -423,19 +535,81 @@ namespace OpenSim.Services.Connectors { "ID", item.ID.ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; - return BuildItem((Dictionary)ret["item"]); + retrieved = BuildItem((Dictionary)ret["item"]); } catch (Exception e) { m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception in GetItem: ", e); } - return null; + m_ItemCache.AddOrUpdate(item.ID, retrieved, CACHE_EXPIRATION_SECONDS); + + return retrieved; + } + + public virtual InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs) + { + //m_log.DebugFormat("[XXX]: In GetMultipleItems {0}", String.Join(",", itemIDs)); + + InventoryItemBase[] itemArr = new InventoryItemBase[itemIDs.Length]; + // Try to get them from the cache + List pending = new List(); + InventoryItemBase item = null; + int i = 0; + foreach (UUID id in itemIDs) + { + if (m_ItemCache.TryGetValue(id, out item)) + itemArr[i++] = item; + else + pending.Add(id); + } + + if (pending.Count == 0) // we're done, everything was in the cache + return itemArr; + + try + { + Dictionary resultSet = MakeRequest("GETMULTIPLEITEMS", + new Dictionary { + { "PRINCIPAL", principalID.ToString() }, + { "ITEMS", String.Join(",", pending.ToArray()) }, + { "COUNT", pending.Count.ToString() } + }); + + if (!CheckReturn(resultSet)) + { + if (i == 0) + return null; + else + return itemArr; + } + + // carry over index i where we left above + foreach (KeyValuePair kvp in resultSet) + { + InventoryCollection inventory = new InventoryCollection(); + if (kvp.Key.StartsWith("item_")) + { + if (kvp.Value is Dictionary) + { + item = BuildItem((Dictionary)kvp.Value); + m_ItemCache.AddOrUpdate(item.ID, item, CACHE_EXPIRATION_SECONDS); + itemArr[i++] = item; + } + else + itemArr[i++] = null; + } + } + } + catch (Exception e) + { + m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Exception in GetMultipleItems: {0}", e.Message); + } + + return itemArr; } public InventoryFolderBase GetFolder(InventoryFolderBase folder) @@ -447,9 +621,7 @@ namespace OpenSim.Services.Connectors { "ID", folder.ID.ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; return BuildFolder((Dictionary)ret["folder"]); @@ -469,7 +641,7 @@ namespace OpenSim.Services.Connectors { "PRINCIPAL", principalID.ToString() } }); - if (ret == null) + if (!CheckReturn(ret)) return null; List items = new List(); @@ -488,51 +660,22 @@ namespace OpenSim.Services.Connectors { "ASSET", assetID.ToString() } }); + // We cannot use CheckReturn() here because valid values for RESULT are "false" (in the case of request failure) or an int if (ret == null) return 0; - return int.Parse(ret["RESULT"].ToString()); - } - - public InventoryCollection GetUserInventory(UUID principalID) - { - InventoryCollection inventory = new InventoryCollection(); - inventory.Folders = new List(); - inventory.Items = new List(); - inventory.UserID = principalID; - - try + if (ret.ContainsKey("RESULT")) { - Dictionary ret = MakeRequest("GETUSERINVENTORY", - new Dictionary { - { "PRINCIPAL", principalID.ToString() } - }); - - if (ret == null) - return null; - if (ret.Count == 0) - return null; - - Dictionary folders = - (Dictionary)ret["FOLDERS"]; - Dictionary items = - (Dictionary)ret["ITEMS"]; + if (ret["RESULT"] is string) + { + int intResult; - foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i - inventory.Folders.Add(BuildFolder((Dictionary)o)); - foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i - inventory.Items.Add(BuildItem((Dictionary)o)); + if (int.TryParse ((string)ret["RESULT"], out intResult)) + return intResult; + } } - catch (Exception e) - { - m_log.Error("[XINVENTORY SERVICES CONNECTOR]: Exception in GetUserInventory: ", e); - } - - return inventory; - } - public void GetUserInventory(UUID principalID, InventoryReceiptCallback callback) - { + return 0; } public bool HasInventoryForUser(UUID principalID) @@ -545,13 +688,19 @@ namespace OpenSim.Services.Connectors private Dictionary MakeRequest(string method, Dictionary sendData) { - sendData["METHOD"] = method; + // Add "METHOD" as the first key in the dictionary. This ensures that it will be + // visible even when using partial logging ("debug http all 5"). + Dictionary temp = sendData; + sendData = new Dictionary{ { "METHOD", method } }; + foreach (KeyValuePair kvp in temp) + sendData.Add(kvp.Key, kvp.Value); + + RequestsMade++; - string reply = string.Empty; - lock (m_Lock) - reply = SynchronousRestFormsRequester.MakeRequest("POST", - m_ServerURI + "/xinventory", - ServerUtils.BuildQueryString(sendData)); + string reply + = SynchronousRestFormsRequester.MakeRequest( + "POST", m_ServerURI + "/xinventory", + ServerUtils.BuildQueryString(sendData), m_requestTimeoutSecs, m_Auth); Dictionary replyData = ServerUtils.ParseXmlResponse( reply); @@ -619,4 +768,4 @@ namespace OpenSim.Services.Connectors return item; } } -} \ No newline at end of file +} diff --git a/OpenSim/Services/Connectors/Land/LandServicesConnector.cs b/OpenSim/Services/Connectors/Land/LandServicesConnector.cs index 30a73a4..034c42e 100644 --- a/OpenSim/Services/Connectors/Land/LandServicesConnector.cs +++ b/OpenSim/Services/Connectors/Land/LandServicesConnector.cs @@ -33,7 +33,7 @@ using System.IO; using System.Reflection; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Communications; + using OpenSim.Services.Interfaces; using OpenMetaverse; using Nwc.XmlRpc; @@ -78,7 +78,7 @@ namespace OpenSim.Services.Connectors try { uint xpos = 0, ypos = 0; - Utils.LongToUInts(regionHandle, out xpos, out ypos); + Util.RegionHandleToWorldLoc(regionHandle, out xpos, out ypos); GridRegion info = m_GridService.GetRegionByPosition(scopeID, (int)xpos, (int)ypos); if (info != null) // just to be sure { diff --git a/OpenSim/Services/Connectors/MapImage/MapImageServicesConnector.cs b/OpenSim/Services/Connectors/MapImage/MapImageServicesConnector.cs index 30bfb70..c91ed84 100644 --- a/OpenSim/Services/Connectors/MapImage/MapImageServicesConnector.cs +++ b/OpenSim/Services/Connectors/MapImage/MapImageServicesConnector.cs @@ -35,7 +35,8 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Console; -using OpenSim.Framework.Communications; + +using OpenSim.Framework.ServiceAuth; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenMetaverse; @@ -43,7 +44,7 @@ using OpenMetaverse.StructuredData; namespace OpenSim.Services.Connectors { - public class MapImageServicesConnector : IMapImageService + public class MapImageServicesConnector : BaseServiceConnector, IMapImageService { private static readonly ILog m_log = LogManager.GetLogger( @@ -84,26 +85,26 @@ namespace OpenSim.Services.Connectors } m_ServerURI = serviceURI; m_ServerURI = serviceURI.TrimEnd('/'); + base.Initialise(source, "MapImageService"); } - public bool AddMapTile(int x, int y, byte[] jpgData, out string reason) + public bool RemoveMapTile(int x, int y, out string reason) { reason = string.Empty; int tickstart = Util.EnvironmentTickCount(); Dictionary sendData = new Dictionary(); sendData["X"] = x.ToString(); sendData["Y"] = y.ToString(); - sendData["TYPE"] = "image/jpeg"; - sendData["DATA"] = Convert.ToBase64String(jpgData); string reqString = ServerUtils.BuildQueryString(sendData); - string uri = m_ServerURI + "/map"; + string uri = m_ServerURI + "/removemap"; try { string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - reqString); + reqString, + m_Auth); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); @@ -114,7 +115,7 @@ namespace OpenSim.Services.Connectors } else if (replyData.ContainsKey("Result") && (replyData["Result"].ToString().ToLower() == "failure")) { - m_log.DebugFormat("[MAP IMAGE CONNECTOR]: Registration failed: {0}", replyData["Message"].ToString()); + m_log.DebugFormat("[MAP IMAGE CONNECTOR]: Delete failed: {0}", replyData["Message"].ToString()); reason = replyData["Message"].ToString(); return false; } @@ -142,6 +143,72 @@ namespace OpenSim.Services.Connectors { // This just dumps a warning for any operation that takes more than 100 ms int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); + m_log.DebugFormat("[MAP IMAGE CONNECTOR]: map tile deleted in {0}ms", tickdiff); + } + + return false; + } + + public bool AddMapTile(int x, int y, byte[] jpgData, out string reason) + { + reason = string.Empty; + int tickstart = Util.EnvironmentTickCount(); + Dictionary sendData = new Dictionary(); + sendData["X"] = x.ToString(); + sendData["Y"] = y.ToString(); + sendData["TYPE"] = "image/jpeg"; + sendData["DATA"] = Convert.ToBase64String(jpgData); + + string reqString = ServerUtils.BuildQueryString(sendData); + string uri = m_ServerURI + "/map"; + + try + { + string reply = SynchronousRestFormsRequester.MakeRequest("POST", + uri, + reqString, + m_Auth); + if (reply != string.Empty) + { + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + if (replyData.ContainsKey("Result") && (replyData["Result"].ToString().ToLower() == "success")) + { + return true; + } + else if (replyData.ContainsKey("Result") && (replyData["Result"].ToString().ToLower() == "failure")) + { + reason = string.Format("Map post to {0} failed: {1}", uri, replyData["Message"].ToString()); + m_log.WarnFormat("[MAP IMAGE CONNECTOR]: {0}", reason); + + return false; + } + else if (!replyData.ContainsKey("Result")) + { + reason = string.Format("Reply data from {0} does not contain result field", uri); + m_log.WarnFormat("[MAP IMAGE CONNECTOR]: {0}", reason); + } + else + { + reason = string.Format("Unexpected result {0} from {1}" + replyData["Result"].ToString(), uri); + m_log.WarnFormat("[MAP IMAGE CONNECTOR]: {0}", reason); + } + } + else + { + reason = string.Format("Map post received null reply from {0}", uri); + m_log.WarnFormat("[MAP IMAGE CONNECTOR]: {0}", reason); + } + } + catch (Exception e) + { + reason = string.Format("Exception when posting to map server at {0}: {1}", uri, e.Message); + m_log.WarnFormat("[MAP IMAGE CONNECTOR]: {0}", reason); + } + finally + { + // This just dumps a warning for any operation that takes more than 100 ms + int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); m_log.DebugFormat("[MAP IMAGE CONNECTOR]: map tile uploaded in {0}ms", tickdiff); } diff --git a/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs b/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs index 7429293..925364a 100644 --- a/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs +++ b/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs @@ -35,7 +35,7 @@ using System.Reflection; using System.Text; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Communications; + using OpenSim.Services.Interfaces; using OpenMetaverse; using OpenMetaverse.StructuredData; @@ -69,7 +69,7 @@ namespace OpenSim.Services.Connectors public virtual GridRegion HelloNeighbour(ulong regionHandle, RegionInfo thisRegion) { uint x = 0, y = 0; - Utils.LongToUInts(regionHandle, out x, out y); + Util.RegionHandleToWorldLoc(regionHandle, out x, out y); GridRegion regInfo = m_GridService.GetRegionByPosition(thisRegion.ScopeID, (int)x, (int)y); if ((regInfo != null) && // Don't remote-call this instance; that's a startup hickup @@ -97,9 +97,9 @@ namespace OpenSim.Services.Connectors } catch (Exception e) { - m_log.WarnFormat( - "[NEIGHBOUR SERVICE CONNCTOR]: Unable to parse uri {0} to send HelloNeighbour from {1} to {2}. Exception {3}{4}", - uri, thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); + m_log.Warn(string.Format( + "[NEIGHBOUR SERVICES CONNECTOR]: Unable to parse uri {0} to send HelloNeighbour from {1} to {2}. Exception {3} ", + uri, thisRegion.RegionName, region.RegionName, e.Message), e); return false; } @@ -116,9 +116,9 @@ namespace OpenSim.Services.Connectors } catch (Exception e) { - m_log.WarnFormat( - "[NEIGHBOUR SERVICE CONNCTOR]: PackRegionInfoData failed for HelloNeighbour from {0} to {1}. Exception {2}{3}", - thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); + m_log.Warn(string.Format( + "[NEIGHBOUR SERVICES CONNECTOR]: PackRegionInfoData failed for HelloNeighbour from {0} to {1}. Exception {2} ", + thisRegion.RegionName, region.RegionName, e.Message), e); return false; } @@ -136,9 +136,9 @@ namespace OpenSim.Services.Connectors } catch (Exception e) { - m_log.WarnFormat( - "[NEIGHBOUR SERVICE CONNCTOR]: Exception thrown on serialization of HelloNeighbour from {0} to {1}. Exception {2}{3}", - thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); + m_log.Warn(string.Format( + "[NEIGHBOUR SERVICES CONNECTOR]: Exception thrown on serialization of HelloNeighbour from {0} to {1}. Exception {2} ", + thisRegion.RegionName, region.RegionName, e.Message), e); return false; } @@ -153,53 +153,53 @@ namespace OpenSim.Services.Connectors } catch (Exception e) { - m_log.WarnFormat( - "[NEIGHBOUR SERVICE CONNCTOR]: Unable to send HelloNeighbour from {0} to {1}. Exception {2}{3}", - thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); + m_log.Warn(string.Format( + "[NEIGHBOUR SERVICES CONNECTOR]: Unable to send HelloNeighbour from {0} to {1} (uri {2}). Exception {3} ", + thisRegion.RegionName, region.RegionName, uri, e.Message), e); return false; } finally { if (os != null) - os.Close(); + os.Dispose(); } // Let's wait for the response //m_log.Info("[REST COMMS]: Waiting for a reply after DoHelloNeighbourCall"); - StreamReader sr = null; try { - WebResponse webResponse = helloNeighbourRequest.GetResponse(); - if (webResponse == null) + using (WebResponse webResponse = helloNeighbourRequest.GetResponse()) { - m_log.DebugFormat( - "[REST COMMS]: Null reply on DoHelloNeighbourCall post from {0} to {1}", - thisRegion.RegionName, region.RegionName); + if (webResponse == null) + { + m_log.DebugFormat( + "[NEIGHBOUR SERVICES CONNECTOR]: Null reply on DoHelloNeighbourCall post from {0} to {1}", + thisRegion.RegionName, region.RegionName); + } + + using (Stream s = webResponse.GetResponseStream()) + { + using (StreamReader sr = new StreamReader(s)) + { + //reply = sr.ReadToEnd().Trim(); + sr.ReadToEnd().Trim(); + //m_log.InfoFormat("[REST COMMS]: DoHelloNeighbourCall reply was {0} ", reply); + } + } } - - sr = new StreamReader(webResponse.GetResponseStream()); - //reply = sr.ReadToEnd().Trim(); - sr.ReadToEnd().Trim(); - //m_log.InfoFormat("[REST COMMS]: DoHelloNeighbourCall reply was {0} ", reply); - } catch (Exception e) { - m_log.WarnFormat( - "[NEIGHBOUR SERVICE CONNCTOR]: Exception on reply of DoHelloNeighbourCall from {0} back to {1}. Exception {2}{3}", - region.RegionName, thisRegion.RegionName, e.Message, e.StackTrace); + m_log.Warn(string.Format( + "[NEIGHBOUR SERVICES CONNECTOR]: Exception on reply of DoHelloNeighbourCall from {0} back to {1}. Exception {2} ", + region.RegionName, thisRegion.RegionName, e.Message), e); return false; } - finally - { - if (sr != null) - sr.Close(); - } return true; } } -} \ No newline at end of file +} diff --git a/OpenSim/Services/Connectors/Presence/PresenceServicesConnector.cs b/OpenSim/Services/Connectors/Presence/PresenceServicesConnector.cs index f7d8c53..b7e95c4 100644 --- a/OpenSim/Services/Connectors/Presence/PresenceServicesConnector.cs +++ b/OpenSim/Services/Connectors/Presence/PresenceServicesConnector.cs @@ -32,7 +32,8 @@ using System.IO; using System.Reflection; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Communications; + +using OpenSim.Framework.ServiceAuth; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using OpenSim.Server.Base; @@ -40,7 +41,7 @@ using OpenMetaverse; namespace OpenSim.Services.Connectors { - public class PresenceServicesConnector : IPresenceService + public class PresenceServicesConnector : BaseServiceConnector, IPresenceService { private static readonly ILog m_log = LogManager.GetLogger( @@ -80,6 +81,8 @@ namespace OpenSim.Services.Connectors throw new Exception("Presence connector init error"); } m_ServerURI = serviceURI; + + base.Initialise(source, "PresenceService"); } @@ -104,7 +107,8 @@ namespace OpenSim.Services.Connectors { string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - reqString); + reqString, + m_Auth); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); @@ -149,7 +153,8 @@ namespace OpenSim.Services.Connectors { string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - reqString); + reqString, + m_Auth); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); @@ -193,7 +198,8 @@ namespace OpenSim.Services.Connectors { string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - reqString); + reqString, + m_Auth); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); @@ -238,7 +244,8 @@ namespace OpenSim.Services.Connectors { string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - reqString); + reqString, + m_Auth); if (reply != string.Empty) { Dictionary replyData = ServerUtils.ParseXmlResponse(reply); @@ -283,7 +290,8 @@ namespace OpenSim.Services.Connectors { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - reqString); + reqString, + m_Auth); if (reply == null || (reply != null && reply == string.Empty)) { m_log.DebugFormat("[PRESENCE CONNECTOR]: GetAgent received null or empty reply"); @@ -293,6 +301,7 @@ namespace OpenSim.Services.Connectors catch (Exception e) { m_log.DebugFormat("[PRESENCE CONNECTOR]: Exception when contacting presence server at {0}: {1}", uri, e.Message); + return null; } Dictionary replyData = ServerUtils.ParseXmlResponse(reply); @@ -327,7 +336,8 @@ namespace OpenSim.Services.Connectors { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - reqString); + reqString, + m_Auth); if (reply == null || (reply != null && reply == string.Empty)) { m_log.DebugFormat("[PRESENCE CONNECTOR]: GetAgents received null or empty reply"); diff --git a/OpenSim/Services/Connectors/Properties/AssemblyInfo.cs b/OpenSim/Services/Connectors/Properties/AssemblyInfo.cs index bfb681b..c581a59 100644 --- a/OpenSim/Services/Connectors/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/Connectors/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs index 95e4bab..cd4781d 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs @@ -69,7 +69,7 @@ namespace OpenSim.Services.Connectors.SimianGrid Util.FireAndForget(delegate(object o) { m_GridUserService.SetLastPosition(sp.UUID.ToString(), sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); - }); + }, null, "SimianActivityDetector.SetLastPositionOnMakeRootAgent"); } public void OnNewClient(IClientAPI client) @@ -94,7 +94,7 @@ namespace OpenSim.Services.Connectors.SimianGrid Util.FireAndForget(delegate(object o) { m_GridUserService.SetLastPosition(sp.UUID.ToString(), sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); - }); + }, null, "SimianActivityDetector.SetLastPositionOnEnteringNewParcel"); } } } \ No newline at end of file diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs index 63a32e7..9ad4a7a 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.IO; using System.Net; using System.Reflection; @@ -122,7 +123,7 @@ namespace OpenSim.Services.Connectors.SimianGrid m_Enabled = true; } - #region IAssetService +#region IAssetService public AssetBase Get(string id) { @@ -140,8 +141,9 @@ namespace OpenSim.Services.Connectors.SimianGrid return asset; } - return GetRemote(id); + return SimianGetOperation(id); } + public AssetBase GetCached(string id) { @@ -164,8 +166,6 @@ namespace OpenSim.Services.Connectors.SimianGrid throw new InvalidOperationException(); } - AssetMetadata metadata = null; - // Cache fetch if (m_cache != null) { @@ -174,50 +174,18 @@ namespace OpenSim.Services.Connectors.SimianGrid return asset.Metadata; } - Uri url; - - // Determine if id is an absolute URL or a grid-relative UUID - if (!Uri.TryCreate(id, UriKind.Absolute, out url)) - url = new Uri(m_serverUrl + id); - - try - { - HttpWebRequest request = UntrustedHttpWebRequest.Create(url); - request.Method = "HEAD"; - - using (WebResponse response = request.GetResponse()) - { - using (Stream responseStream = response.GetResponseStream()) - { - // Create the metadata object - metadata = new AssetMetadata(); - metadata.ContentType = response.ContentType; - metadata.ID = id; - - UUID uuid; - if (UUID.TryParse(id, out uuid)) - metadata.FullID = uuid; - - string lastModifiedStr = response.Headers.Get("Last-Modified"); - if (!String.IsNullOrEmpty(lastModifiedStr)) - { - DateTime lastModified; - if (DateTime.TryParse(lastModifiedStr, out lastModified)) - metadata.CreationDate = lastModified; - } - } - } - } - catch (Exception ex) - { - m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset HEAD from " + url + " failed: " + ex.Message); - } - - return metadata; + // return GetRemoteMetadata(id); + return SimianGetMetadataOperation(id); } - + public byte[] GetData(string id) { + if (String.IsNullOrEmpty(m_serverUrl)) + { + m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured"); + throw new InvalidOperationException(); + } + AssetBase asset = Get(id); if (asset != null) @@ -255,14 +223,34 @@ namespace OpenSim.Services.Connectors.SimianGrid Util.FireAndForget( delegate(object o) { - AssetBase asset = GetRemote(id); + AssetBase asset = SimianGetOperation(id); handler(id, sender, asset); - } + }, null, "SimianAssetServiceConnector.GetFromService" ); return true; } + public bool[] AssetsExist(string[] ids) + { + if (String.IsNullOrEmpty(m_serverUrl)) + { + m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured"); + throw new InvalidOperationException(); + } + + bool[] exist = new bool[ids.Length]; + + for (int i = 0; i < ids.Length; i++) + { + AssetMetadata metadata = GetMetadata(ids[i]); + if (metadata != null) + exist[i] = true; + } + + return exist; + } + /// /// Creates a new asset /// @@ -278,7 +266,6 @@ namespace OpenSim.Services.Connectors.SimianGrid } bool storedInCache = false; - string errorMessage = null; // AssetID handling if (String.IsNullOrEmpty(asset.ID) || asset.ID == ZeroID) @@ -307,80 +294,9 @@ namespace OpenSim.Services.Connectors.SimianGrid return asset.ID; } - // Distinguish public and private assets - bool isPublic = true; - switch ((AssetType)asset.Type) - { - case AssetType.CallingCard: - case AssetType.Gesture: - case AssetType.LSLBytecode: - case AssetType.LSLText: - isPublic = false; - break; - } - - // Make sure ContentType is set - if (String.IsNullOrEmpty(asset.Metadata.ContentType)) - asset.Metadata.ContentType = SLUtil.SLAssetTypeToContentType(asset.Type); - - // Build the remote storage request - List postParameters = new List() - { - new MultipartForm.Parameter("AssetID", asset.FullID.ToString()), - new MultipartForm.Parameter("CreatorID", asset.Metadata.CreatorID), - new MultipartForm.Parameter("Temporary", asset.Temporary ? "1" : "0"), - new MultipartForm.Parameter("Public", isPublic ? "1" : "0"), - new MultipartForm.File("Asset", asset.Name, asset.Metadata.ContentType, asset.Data) - }; - - // Make the remote storage request - try - { - // Simian does not require the asset ID to be in the URL because it's in the post data. - // By appending it to the URL also, we allow caching proxies (squid) to invalidate asset URLs - HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl + asset.FullID.ToString()); - - HttpWebResponse response = MultipartForm.Post(request, postParameters); - using (Stream responseStream = response.GetResponseStream()) - { - string responseStr = null; - - try - { - responseStr = responseStream.GetStreamString(); - OSD responseOSD = OSDParser.Deserialize(responseStr); - if (responseOSD.Type == OSDType.Map) - { - OSDMap responseMap = (OSDMap)responseOSD; - if (responseMap["Success"].AsBoolean()) - return asset.ID; - else - errorMessage = "Upload failed: " + responseMap["Message"].AsString(); - } - else - { - errorMessage = "Response format was invalid:\n" + responseStr; - } - } - catch (Exception ex) - { - if (!String.IsNullOrEmpty(responseStr)) - errorMessage = "Failed to parse the response:\n" + responseStr; - else - errorMessage = "Failed to retrieve the response: " + ex.Message; - } - } - } - catch (WebException ex) - { - errorMessage = ex.Message; - } - - m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}", - asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage); - return null; + return SimianStoreOperation(asset); } - + /// /// Update an asset's content /// @@ -390,11 +306,17 @@ namespace OpenSim.Services.Connectors.SimianGrid /// public bool UpdateContent(string id, byte[] data) { + if (String.IsNullOrEmpty(m_serverUrl)) + { + m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured"); + throw new InvalidOperationException(); + } + AssetBase asset = Get(id); if (asset == null) { - m_log.Warn("[SIMIAN ASSET CONNECTOR]: Failed to fetch asset " + id + " for updating"); + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to fetch asset {0} for updating", id); return false; } @@ -417,83 +339,347 @@ namespace OpenSim.Services.Connectors.SimianGrid throw new InvalidOperationException(); } - //string errorMessage = String.Empty; - string url = m_serverUrl + id; - if (m_cache != null) m_cache.Expire(id); + return SimianDeleteOperation(id); + } + +#endregion IAssetService + +#region SimianOperations + /// + /// Invokes the xRemoveAsset operation on the simian server to delete an asset + /// + /// + /// + private bool SimianDeleteOperation(string id) + { try { - HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); - request.Method = "DELETE"; + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "xRemoveAsset" }, + { "AssetID", id } + }; - using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) + OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs); + if (! response["Success"].AsBoolean()) { - if (response.StatusCode != HttpStatusCode.NoContent) - { - m_log.Warn("[SIMIAN ASSET CONNECTOR]: Unexpected response when deleting asset " + url + ": " + - response.StatusCode + " (" + response.StatusDescription + ")"); - } + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to delete asset; {0}",response["Message"].AsString()); + return false; } - + return true; + } catch (Exception ex) { - m_log.Warn("[SIMIAN ASSET CONNECTOR]: Failed to delete asset " + id + " from the asset service: " + ex.Message); - return false; + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to delete asset {0}; {1}", id, ex.Message); } - } - #endregion IAssetService + return false; + } - private AssetBase GetRemote(string id) + /// + /// Invokes the xAddAsset operation on the simian server to create or update an asset + /// + /// + /// + private string SimianStoreOperation(AssetBase asset) { - AssetBase asset = null; - Uri url; + try + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "xAddAsset" }, + { "ContentType", asset.Metadata.ContentType }, + { "EncodedData", Convert.ToBase64String(asset.Data) }, + { "AssetID", asset.FullID.ToString() }, + { "CreatorID", asset.Metadata.CreatorID }, + { "Temporary", asset.Temporary ? "1" : "0" }, + { "Name", asset.Name } + }; + + OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs); + if (! response["Success"].AsBoolean()) + { + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR] failed to store asset; {0}",response["Message"].AsString()); + return null; + } - // Determine if id is an absolute URL or a grid-relative UUID - if (!Uri.TryCreate(id, UriKind.Absolute, out url)) - url = new Uri(m_serverUrl + id); + // asset.ID is always set before calling this function + return asset.ID; + + } + catch (Exception ex) + { + m_log.ErrorFormat("[SIMIAN ASSET CONNECTOR] failed to store asset; {0}",ex.Message); + } + + return null; + } - try + /// + /// Invokes the xGetAsset operation on the simian server to get data associated with an asset + /// + /// + /// + private AssetBase SimianGetOperation(string id) + { + try { - HttpWebRequest request = UntrustedHttpWebRequest.Create(url); + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "xGetAsset" }, + { "ID", id } + }; - using (WebResponse response = request.GetResponse()) + OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs); + if (! response["Success"].AsBoolean()) { - using (Stream responseStream = response.GetResponseStream()) - { - string creatorID = response.Headers.GetOne("X-Asset-Creator-Id") ?? String.Empty; - - // Create the asset object - asset = new AssetBase(id, String.Empty, SLUtil.ContentTypeToSLAssetType(response.ContentType), creatorID); - - UUID assetID; - if (UUID.TryParse(id, out assetID)) - asset.FullID = assetID; - - // Grab the asset data from the response stream - using (MemoryStream stream = new MemoryStream()) - { - responseStream.CopyStream(stream, Int32.MaxValue); - asset.Data = stream.ToArray(); - } - } + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR] Failed to get asset; {0}",response["Message"].AsString()); + return null; } + + AssetBase asset = new AssetBase(); - // Cache store - if (m_cache != null && asset != null) - m_cache.Cache(asset); + asset.ID = id; + asset.Name = String.Empty; + asset.Metadata.ContentType = response["ContentType"].AsString(); // this will also set the asset Type property + asset.CreatorID = response["CreatorID"].AsString(); + asset.Data = System.Convert.FromBase64String(response["EncodedData"].AsString()); + asset.Local = false; + asset.Temporary = response["Temporary"]; return asset; } catch (Exception ex) { - m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message); - return null; + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to retrieve asset {0}; {1}", id, ex.Message); + } + + return null; + } + + /// + /// Invokes the xGetAssetMetadata operation on the simian server to retrieve metadata for an asset + /// This operation is generally used to determine if an asset exists in the database + /// + /// + /// + private AssetMetadata SimianGetMetadataOperation(string id) + { + try + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "xGetAssetMetadata" }, + { "ID", id } + }; + + OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs); + if (! response["Success"].AsBoolean()) + { + // this is not really an error, this call is used to test existence + // m_log.DebugFormat("[SIMIAN ASSET CONNECTOR] Failed to get asset metadata; {0}",response["Message"].AsString()); + return null; + } + + AssetMetadata metadata = new AssetMetadata(); + metadata.ID = id; + metadata.ContentType = response["ContentType"].AsString(); + metadata.CreatorID = response["CreatorID"].AsString(); + metadata.Local = false; + metadata.Temporary = response["Temporary"]; + + string lastModifiedStr = response["Last-Modified"].AsString(); + if (! String.IsNullOrEmpty(lastModifiedStr)) + { + DateTime lastModified; + if (DateTime.TryParse(lastModifiedStr, out lastModified)) + metadata.CreationDate = lastModified; + } + + return metadata; + } + catch (Exception ex) + { + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to get asset metadata; {0}", ex.Message); } + + return null; } +#endregion + + // private AssetMetadata GetRemoteMetadata(string id) + // { + // Uri url; + // AssetMetadata metadata = null; + + // // Determine if id is an absolute URL or a grid-relative UUID + // if (!Uri.TryCreate(id, UriKind.Absolute, out url)) + // url = new Uri(m_serverUrl + id); + + // try + // { + // HttpWebRequest request = UntrustedHttpWebRequest.Create(url); + // request.Method = "HEAD"; + + // using (WebResponse response = request.GetResponse()) + // { + // using (Stream responseStream = response.GetResponseStream()) + // { + // // Create the metadata object + // metadata = new AssetMetadata(); + // metadata.ContentType = response.ContentType; + // metadata.ID = id; + + // UUID uuid; + // if (UUID.TryParse(id, out uuid)) + // metadata.FullID = uuid; + + // string lastModifiedStr = response.Headers.Get("Last-Modified"); + // if (!String.IsNullOrEmpty(lastModifiedStr)) + // { + // DateTime lastModified; + // if (DateTime.TryParse(lastModifiedStr, out lastModified)) + // metadata.CreationDate = lastModified; + // } + // } + // } + // } + // catch (Exception ex) + // { + // m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset HEAD from " + url + " failed: " + ex.Message); + // } + + // return metadata; + // } + + // private AssetBase GetRemote(string id) + // { + // AssetBase asset = null; + // Uri url; + + // // Determine if id is an absolute URL or a grid-relative UUID + // if (!Uri.TryCreate(id, UriKind.Absolute, out url)) + // url = new Uri(m_serverUrl + id); + + // try + // { + // HttpWebRequest request = UntrustedHttpWebRequest.Create(url); + + // using (WebResponse response = request.GetResponse()) + // { + // using (Stream responseStream = response.GetResponseStream()) + // { + // string creatorID = response.Headers.GetOne("X-Asset-Creator-Id") ?? String.Empty; + + // // Create the asset object + // asset = new AssetBase(id, String.Empty, SLUtil.ContentTypeToSLAssetType(response.ContentType), creatorID); + + // UUID assetID; + // if (UUID.TryParse(id, out assetID)) + // asset.FullID = assetID; + + // // Grab the asset data from the response stream + // using (MemoryStream stream = new MemoryStream()) + // { + // responseStream.CopyStream(stream, Int32.MaxValue); + // asset.Data = stream.ToArray(); + // } + // } + // } + + // // Cache store + // if (m_cache != null && asset != null) + // m_cache.Cache(asset); + + // return asset; + // } + // catch (Exception ex) + // { + // m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message); + // return null; + // } + // } + + // private string StoreRemote(AssetBase asset) + // { + // // Distinguish public and private assets + // bool isPublic = true; + // switch ((AssetType)asset.Type) + // { + // case AssetType.CallingCard: + // case AssetType.Gesture: + // case AssetType.LSLBytecode: + // case AssetType.LSLText: + // isPublic = false; + // break; + // } + + // string errorMessage = null; + + // // Build the remote storage request + // List postParameters = new List() + // { + // new MultipartForm.Parameter("AssetID", asset.FullID.ToString()), + // new MultipartForm.Parameter("CreatorID", asset.Metadata.CreatorID), + // new MultipartForm.Parameter("Temporary", asset.Temporary ? "1" : "0"), + // new MultipartForm.Parameter("Public", isPublic ? "1" : "0"), + // new MultipartForm.File("Asset", asset.Name, asset.Metadata.ContentType, asset.Data) + // }; + + // // Make the remote storage request + // try + // { + // // Simian does not require the asset ID to be in the URL because it's in the post data. + // // By appending it to the URL also, we allow caching proxies (squid) to invalidate asset URLs + // HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl + asset.FullID.ToString()); + + // using (HttpWebResponse response = MultipartForm.Post(request, postParameters)) + // { + // using (Stream responseStream = response.GetResponseStream()) + // { + // string responseStr = null; + + // try + // { + // responseStr = responseStream.GetStreamString(); + // OSD responseOSD = OSDParser.Deserialize(responseStr); + // if (responseOSD.Type == OSDType.Map) + // { + // OSDMap responseMap = (OSDMap)responseOSD; + // if (responseMap["Success"].AsBoolean()) + // return asset.ID; + // else + // errorMessage = "Upload failed: " + responseMap["Message"].AsString(); + // } + // else + // { + // errorMessage = "Response format was invalid:\n" + responseStr; + // } + // } + // catch (Exception ex) + // { + // if (!String.IsNullOrEmpty(responseStr)) + // errorMessage = "Failed to parse the response:\n" + responseStr; + // else + // errorMessage = "Failed to retrieve the response: " + ex.Message; + // } + // } + // } + // } + // catch (WebException ex) + // { + // errorMessage = ex.Message; + // } + + // m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}", + // asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage); + + // return null; + // } } } diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs index 6603f6e..3bd11d9 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs @@ -110,7 +110,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", principalID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Identities"] is OSDArray) { bool md5hashFound = false; @@ -153,7 +153,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "SessionID", token } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { return true; @@ -175,7 +175,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", principalID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { return true; @@ -198,7 +198,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", principalID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["User"] is OSDMap) { OSDMap userMap = (OSDMap)response["User"]; @@ -218,7 +218,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", principalID.ToString() } }; - response = WebUtil.PostToService(m_serverUrl, requestArgs); + response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -297,7 +297,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) return response["SessionID"].AsUUID().ToString(); else diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs index 841bfa0..a397740 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs @@ -122,7 +122,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { OSDMap map = null; @@ -168,7 +168,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "LLPackedAppearance", OSDParser.SerializeJsonString(map) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (! success) @@ -189,7 +189,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { OSDMap map = null; @@ -306,7 +306,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "LLAttachments", OSDParser.SerializeJsonString(items) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs b/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs new file mode 100644 index 0000000..764e71f --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs @@ -0,0 +1,180 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.IO; +using System.Web; + +using log4net; +using Nini.Config; +using Mono.Addins; + +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using Caps = OpenSim.Framework.Capabilities.Caps; + +namespace OpenSim.Services.Connectors.SimianGrid +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianExternalCapsModule")] + public class SimianExternalCapsModule : INonSharedRegionModule, IExternalCapsModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private bool m_enabled = true; + private Scene m_scene; + private String m_simianURL; + +#region IRegionModule Members + + public string Name + { + get { return this.GetType().Name; } + } + + public void Initialise(IConfigSource config) + { + try + { + IConfig m_config; + + if ((m_config = config.Configs["SimianExternalCaps"]) != null) + { + m_enabled = m_config.GetBoolean("Enabled", m_enabled); + if ((m_config = config.Configs["SimianGrid"]) != null) + { + m_simianURL = m_config.GetString("SimianServiceURL"); + if (String.IsNullOrEmpty(m_simianURL)) + { + //m_log.DebugFormat("[SimianGrid] service URL is not defined"); + m_enabled = false; + return; + } + } + } + else + m_enabled = false; + } + catch (Exception e) + { + m_log.ErrorFormat("[SimianExternalCaps] initialization error: {0}",e.Message); + return; + } + } + + public void PostInitialise() { } + public void Close() { } + + public void AddRegion(Scene scene) + { + if (! m_enabled) + return; + + m_scene = scene; + m_scene.RegisterModuleInterface(this); + } + + public void RemoveRegion(Scene scene) + { + if (! m_enabled) + return; + + m_scene.EventManager.OnRegisterCaps -= RegisterCapsEventHandler; + m_scene.EventManager.OnDeregisterCaps -= DeregisterCapsEventHandler; + } + + public void RegionLoaded(Scene scene) + { + if (! m_enabled) + return; + + m_scene.EventManager.OnRegisterCaps += RegisterCapsEventHandler; + m_scene.EventManager.OnDeregisterCaps += DeregisterCapsEventHandler; + } + + public Type ReplaceableInterface + { + get { return null; } + } + +#endregion + +#region IExternalCapsModule + // Eg http://grid.sciencesim.com/GridPublic/%CAP%/%OP%/" + public bool RegisterExternalUserCapsHandler(UUID agentID, Caps caps, String capName, String urlSkel) + { + UUID cap = UUID.Random(); + + // Call to simian to register the cap we generated + // NameValueCollection requestArgs = new NameValueCollection + // { + // { "RequestMethod", "AddCapability" }, + // { "Resource", "user" }, + // { "Expiration", 0 }, + // { "OwnerID", agentID.ToString() }, + // { "CapabilityID", cap.ToString() } + // }; + + // OSDMap response = SimianGrid.PostToService(m_simianURL, requestArgs); + + Dictionary subs = new Dictionary(); + subs["%OP%"] = capName; + subs["%USR%"] = agentID.ToString(); + subs["%CAP%"] = cap.ToString(); + subs["%SIM%"] = m_scene.RegionInfo.RegionID.ToString(); + + caps.RegisterHandler(capName,ExpandSkeletonURL(urlSkel,subs)); + return true; + } + +#endregion + +#region EventHandlers + public void RegisterCapsEventHandler(UUID agentID, Caps caps) { } + public void DeregisterCapsEventHandler(UUID agentID, Caps caps) { } +#endregion + + private String ExpandSkeletonURL(String urlSkel, Dictionary subs) + { + String result = urlSkel; + + foreach (KeyValuePair kvp in subs) + { + result = result.Replace(kvp.Key,kvp.Value); + } + + return result; + } + } +} \ No newline at end of file diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs index 7422d94..9a8164c 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs @@ -153,7 +153,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Value", flags.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -180,7 +180,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Key", friend } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -200,7 +200,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Type", "Friend" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Entries"] is OSDArray) { return (OSDArray)response["Entries"]; @@ -221,7 +221,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Type", "Friend" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Entries"] is OSDArray) { return (OSDArray)response["Entries"]; diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs index 847319c..a35d749 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs @@ -26,8 +26,122 @@ */ using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Reflection; +using log4net; using Mono.Addins; using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenMetaverse; +using OpenMetaverse.StructuredData; -[assembly: Addin("SimianGrid", "1.0")] -[assembly: AddinDependency("OpenSim", "0.5")] +[assembly: Addin("SimianGrid", OpenSim.VersionInfo.VersionNumber)] +[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] + +namespace OpenSim.Services.Connectors.SimianGrid +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianExternalCapsModule")] + public class SimianGrid : ISharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IConfig m_config = null; + + private String m_simianURL; + +#region IRegionModule Members + + public string Name + { + get { return this.GetType().Name; } + } + + public void Initialise(IConfigSource config) + { + try + { + m_config = config.Configs["SimianGrid"]; + + if (m_config != null) + { + m_simianURL = m_config.GetString("SimianServiceURL"); + if (String.IsNullOrEmpty(m_simianURL)) + { + // m_log.DebugFormat("[SimianGrid] service URL is not defined"); + return; + } + + InitialiseSimCap(); + SimulatorCapability = SimulatorCapability.Trim(); + m_log.InfoFormat("[SimianExternalCaps] using {0} as simulator capability",SimulatorCapability); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[SimianExternalCaps] initialization error: {0}",e.Message); + return; + } + } + + public void PostInitialise() { } + public void Close() { } + public void AddRegion(Scene scene) { } + public void RemoveRegion(Scene scene) { } + public void RegionLoaded(Scene scene) { } + + public Type ReplaceableInterface + { + get { return null; } + } + + /// + /// Try a variety of methods for finding the simian simulator capability; first check the + /// configuration itself, then look for a file that contains the cap, then finally look + /// for an environment variable that contains it. + /// + private void InitialiseSimCap() + { + if (m_config.Contains("SimulatorCapability")) + { + SimulatorCapability = m_config.GetString("SimulatorCapability"); + return; + } + + if (m_config.Contains("SimulatorCapabilityFile")) + { + String filename = m_config.GetString("SimulatorCapabilityFile"); + if (System.IO.File.Exists(filename)) + { + SimulatorCapability = System.IO.File.ReadAllText(filename); + return; + } + } + + if (m_config.Contains("SimulatorCapabilityVariable")) + { + String envname = m_config.GetString("SimulatorCapabilityVariable"); + String envvalue = System.Environment.GetEnvironmentVariable(envname); + if (envvalue != null) + { + SimulatorCapability = envvalue; + return; + } + } + + m_log.WarnFormat("[SimianExternalCaps] no method specified for simulator capability"); + } + +#endregion + + public static String SimulatorCapability = UUID.Zero.ToString(); + public static OSDMap PostToService(string url, NameValueCollection data) + { + data["cap"] = SimulatorCapability; + return WebUtil.PostToService(url, data); + } + } +} \ No newline at end of file diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs index 93fdae3..8375c95 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.Reflection; using System.Net; using System.IO; @@ -43,7 +44,8 @@ using OpenSim.Region.Framework.Scenes; using OpenMetaverse; using OpenMetaverse.StructuredData; -namespace OpenSim.Region.OptionalModules.Simian +//namespace OpenSim.Region.OptionalModules.Simian +namespace OpenSim.Services.Connectors.SimianGrid { /// /// @@ -179,7 +181,6 @@ namespace OpenSim.Region.OptionalModules.Simian m_log.DebugFormat("[SIMIAN MAPTILE]: upload maptile for {0}",scene.RegionInfo.RegionName); // Create a PNG map tile and upload it to the AddMapTile API - byte[] pngData = Utils.EmptyBytes; IMapImageGenerator tileGenerator = scene.RequestModuleInterface(); if (tileGenerator == null) { @@ -187,76 +188,79 @@ namespace OpenSim.Region.OptionalModules.Simian return; } - using (Image mapTile = tileGenerator.CreateMapTile()) - { - using (MemoryStream stream = new MemoryStream()) - { - mapTile.Save(stream, ImageFormat.Png); - pngData = stream.ToArray(); - } - } - - List postParameters = new List() - { - new MultipartForm.Parameter("X", scene.RegionInfo.RegionLocX.ToString()), - new MultipartForm.Parameter("Y", scene.RegionInfo.RegionLocY.ToString()), - new MultipartForm.File("Tile", "tile.png", "image/png", pngData) - }; - - string errorMessage = null; - int tickstart = Util.EnvironmentTickCount(); - - // Make the remote storage request - try + using (Bitmap mapTile = tileGenerator.CreateMapTile()) { - HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl); - request.Timeout = 20000; - request.ReadWriteTimeout = 5000; - - using (HttpWebResponse response = MultipartForm.Post(request, postParameters)) + if (mapTile != null) { - using (Stream responseStream = response.GetResponseStream()) + // If the region/maptile is legacy sized, just upload the one tile like it has always been done + if (mapTile.Width == Constants.RegionSize && mapTile.Height == Constants.RegionSize) { - string responseStr = responseStream.GetStreamString(); - OSD responseOSD = OSDParser.Deserialize(responseStr); - if (responseOSD.Type == OSDType.Map) + ConvertAndUploadMaptile(mapTile, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY); + } + else + { + // For larger regions (varregion) we must cut the region image into legacy sized + // pieces since that is how the maptile system works. + // Note the assumption that varregions are always a multiple of legacy size. + for (uint xx = 0; xx < mapTile.Width; xx += Constants.RegionSize) { - OSDMap responseMap = (OSDMap)responseOSD; - if (responseMap["Success"].AsBoolean()) - return; + for (uint yy = 0; yy < mapTile.Height; yy += Constants.RegionSize) + { + // Images are addressed from the upper left corner so have to do funny + // math to pick out the sub-tile since regions are numbered from + // the lower left. + Rectangle rect = new Rectangle( + (int)xx, + mapTile.Height - (int)yy - (int)Constants.RegionSize, + (int)Constants.RegionSize, (int)Constants.RegionSize); - errorMessage = "Upload failed: " + responseMap["Message"].AsString(); - } - else - { - errorMessage = "Response format was invalid:\n" + responseStr; + using (Bitmap subMapTile = mapTile.Clone(rect, mapTile.PixelFormat)) + { + uint locX = scene.RegionInfo.RegionLocX + (xx / Constants.RegionSize); + uint locY = scene.RegionInfo.RegionLocY + (yy / Constants.RegionSize); + + ConvertAndUploadMaptile(subMapTile, locX, locY); + } + } } } } - } - catch (WebException we) - { - errorMessage = we.Message; - if (we.Status == WebExceptionStatus.ProtocolError) + else { - HttpWebResponse webResponse = (HttpWebResponse)we.Response; - errorMessage = String.Format("[{0}] {1}", - webResponse.StatusCode,webResponse.StatusDescription); + m_log.WarnFormat("[SIMIAN MAPTILE] Tile image generation failed"); } } - catch (Exception ex) + + } + + /// + /// + /// + private void ConvertAndUploadMaptile(Image mapTile, uint locX, uint locY) + { + //m_log.DebugFormat("[SIMIAN MAPTILE]: upload maptile for location {0}, {1}", locX, locY); + + byte[] pngData = Utils.EmptyBytes; + using (MemoryStream stream = new MemoryStream()) { - errorMessage = ex.Message; + mapTile.Save(stream, ImageFormat.Png); + pngData = stream.ToArray(); } - finally + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "xAddMapTile" }, + { "X", locX.ToString() }, + { "Y", locY.ToString() }, + { "ContentType", "image/png" }, + { "EncodedData", System.Convert.ToBase64String(pngData) } + }; + + OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs); + if (! response["Success"].AsBoolean()) { - // This just dumps a warning for any operation that takes more than 100 ms - int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); - m_log.DebugFormat("[SIMIAN MAPTILE]: map tile uploaded in {0}ms",tickdiff); + m_log.WarnFormat("[SIMIAN MAPTILE] failed to store map tile; {0}",response["Message"].AsString()); } - - m_log.WarnFormat("[SIMIAN MAPTILE]: Failed to store {0} byte tile for {1}: {2}", - pngData.Length, scene.RegionInfo.RegionName, errorMessage); } } } \ No newline at end of file diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs index 038a4bf..b031f21 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs @@ -101,7 +101,7 @@ namespace OpenSim.Services.Connectors.SimianGrid public string RegisterRegion(UUID scopeID, GridRegion regionInfo) { Vector3d minPosition = new Vector3d(regionInfo.RegionLocX, regionInfo.RegionLocY, 0.0); - Vector3d maxPosition = minPosition + new Vector3d(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); + Vector3d maxPosition = minPosition + new Vector3d(regionInfo.RegionSizeX, regionInfo.RegionSizeY, Constants.RegionHeight); OSDMap extraData = new OSDMap { @@ -129,7 +129,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ExtraData", OSDParser.SerializeJsonString(extraData) } }; - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) return String.Empty; else @@ -145,7 +145,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Enabled", "0" } }; - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -156,15 +156,15 @@ namespace OpenSim.Services.Connectors.SimianGrid public List GetNeighbours(UUID scopeID, UUID regionID) { - const int NEIGHBOR_RADIUS = 128; - GridRegion region = GetRegionByUUID(scopeID, regionID); + int NEIGHBOR_RADIUS = Math.Max(region.RegionSizeX, region.RegionSizeY) / 2; + if (region != null) { List regions = GetRegionRange(scopeID, - region.RegionLocX - NEIGHBOR_RADIUS, region.RegionLocX + (int)Constants.RegionSize + NEIGHBOR_RADIUS, - region.RegionLocY - NEIGHBOR_RADIUS, region.RegionLocY + (int)Constants.RegionSize + NEIGHBOR_RADIUS); + region.RegionLocX - NEIGHBOR_RADIUS, region.RegionLocX + region.RegionSizeX + NEIGHBOR_RADIUS, + region.RegionLocY - NEIGHBOR_RADIUS, region.RegionLocY + region.RegionSizeY + NEIGHBOR_RADIUS); for (int i = 0; i < regions.Count; i++) { @@ -192,7 +192,7 @@ namespace OpenSim.Services.Connectors.SimianGrid // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request region with uuid {0}",regionID.ToString()); - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] uuid request successful {0}",response["Name"].AsString()); @@ -220,7 +220,7 @@ namespace OpenSim.Services.Connectors.SimianGrid // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request grid at {0}",position.ToString()); - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] position request successful {0}",response["Name"].AsString()); @@ -229,7 +229,7 @@ namespace OpenSim.Services.Connectors.SimianGrid else { // m_log.InfoFormat("[SIMIAN GRID CONNECTOR]: Grid service did not find a match for region at {0},{1}", - // x / Constants.RegionSize, y / Constants.RegionSize); + // Util.WorldToRegionLoc(x), Util.WorldToRegionLoc(y)); return null; } } @@ -261,7 +261,7 @@ namespace OpenSim.Services.Connectors.SimianGrid // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request regions with name {0}",name); - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] found regions with name {0}",name); @@ -299,7 +299,7 @@ namespace OpenSim.Services.Connectors.SimianGrid //m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request regions by range {0} to {1}",minPosition.ToString(),maxPosition.ToString()); - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { OSDArray array = response["Scenes"] as OSDArray; @@ -330,6 +330,12 @@ namespace OpenSim.Services.Connectors.SimianGrid return new List(0); } + public List GetDefaultHypergridRegions(UUID scopeID) + { + // TODO: Allow specifying the default grid location + return GetDefaultRegions(scopeID); + } + public List GetFallbackRegions(UUID scopeID, int x, int y) { GridRegion defRegion = GetNearestRegion(new Vector3d(x, y, 0.0), true); @@ -350,7 +356,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Enabled", "1" } }; - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] found regions with name {0}",name); @@ -380,7 +386,7 @@ namespace OpenSim.Services.Connectors.SimianGrid m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request region flags for {0}",regionID.ToString()); - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { OSDMap extraData = response["ExtraData"] as OSDMap; @@ -396,6 +402,13 @@ namespace OpenSim.Services.Connectors.SimianGrid return -1; } } + + public Dictionary GetExtraFeatures() + { + /// See SimulatorFeaturesModule - Need to get map, search and destination guide + Dictionary extraFeatures = new Dictionary(); + return extraFeatures; + } #endregion IGridService @@ -410,7 +423,7 @@ namespace OpenSim.Services.Connectors.SimianGrid if (onlyEnabled) requestArgs["Enabled"] = "1"; - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { return ResponseToGridRegion(response); @@ -437,9 +450,13 @@ namespace OpenSim.Services.Connectors.SimianGrid region.RegionName = response["Name"].AsString(); Vector3d minPosition = response["MinPosition"].AsVector3d(); + Vector3d maxPosition = response["MaxPosition"].AsVector3d(); region.RegionLocX = (int)minPosition.X; region.RegionLocY = (int)minPosition.Y; - + + region.RegionSizeX = (int)maxPosition.X - (int)minPosition.X; + region.RegionSizeY = (int)maxPosition.Y - (int)minPosition.Y; + if ( ! extraData["HyperGrid"] ) { Uri httpAddress = response["Address"].AsUri(); region.ExternalHostName = httpAddress.Host; diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs index a391275..e793420 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs @@ -38,12 +38,14 @@ using OpenSim.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; +using PermissionMask = OpenSim.Framework.PermissionMask; namespace OpenSim.Services.Connectors.SimianGrid { /// /// Permissions bitflags /// + /* [Flags] public enum PermissionMask : uint { @@ -55,6 +57,7 @@ namespace OpenSim.Services.Connectors.SimianGrid Damage = 1 << 20, All = 0x7FFFFFFF } + */ /// /// Connects avatar inventories to the SimianGrid backend @@ -71,6 +74,9 @@ namespace OpenSim.Services.Connectors.SimianGrid // private object m_gestureSyncRoot = new object(); private bool m_Enabled = false; + private const double CACHE_EXPIRATION_SECONDS = 20.0; + private static ExpiringCache m_ItemCache; + #region ISharedRegionModule public Type ReplaceableInterface { get { return null; } } @@ -96,6 +102,9 @@ namespace OpenSim.Services.Connectors.SimianGrid url = url + '/'; m_serverUrl = url; + if (m_ItemCache == null) + m_ItemCache = new ExpiringCache(); + } public void Initialise(IConfigSource source) @@ -129,6 +138,8 @@ namespace OpenSim.Services.Connectors.SimianGrid { m_userServerUrl = serviceUrl; m_Enabled = true; + if (m_ItemCache == null) + m_ItemCache = new ExpiringCache(); } } } @@ -153,7 +164,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "OwnerID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -179,7 +190,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ChildrenOnly", "0" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Items"] is OSDArray) { OSDArray items = (OSDArray)response["Items"]; @@ -194,37 +205,6 @@ namespace OpenSim.Services.Connectors.SimianGrid } /// - /// Synchronous inventory fetch. - /// - /// - /// - [Obsolete] - public InventoryCollection GetUserInventory(UUID userID) - { - m_log.Error("[SIMIAN INVENTORY CONNECTOR]: Obsolete GetUserInventory called for " + userID); - - InventoryCollection inventory = new InventoryCollection(); - inventory.UserID = userID; - inventory.Folders = new List(); - inventory.Items = new List(); - - return inventory; - } - - /// - /// Request the inventory for a user. This is an asynchronous operation that will call the callback when the - /// inventory has been received - /// - /// - /// - [Obsolete] - public void GetUserInventory(UUID userID, InventoryReceiptCallback callback) - { - m_log.Error("[SIMIAN INVENTORY CONNECTOR]: Obsolete GetUserInventory called for " + userID); - callback(new List(0), new List(0)); - } - - /// /// Retrieve the root inventory folder for the given user. /// /// @@ -241,7 +221,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ChildrenOnly", "1" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Items"] is OSDArray) { OSDArray items = (OSDArray)response["Items"]; @@ -260,7 +240,7 @@ namespace OpenSim.Services.Connectors.SimianGrid /// /// /// - public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) + public InventoryFolderBase GetFolderForType(UUID userID, FolderType type) { string contentType = SLUtil.SLAssetTypeToContentType((int)type); @@ -271,7 +251,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "OwnerID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Folder"] is OSDMap) { OSDMap folder = (OSDMap)response["Folder"]; @@ -299,6 +279,10 @@ namespace OpenSim.Services.Connectors.SimianGrid /// public InventoryItemBase GetItem(InventoryItemBase item) { + InventoryItemBase retrieved = null; + if (m_ItemCache.TryGetValue(item.ID, out retrieved)) + return retrieved; + NameValueCollection requestArgs = new NameValueCollection { { "RequestMethod", "GetInventoryNode" }, @@ -309,7 +293,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ChildrenOnly", "1" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Items"] is OSDArray) { List items = GetItemsFromResponse((OSDArray)response["Items"]); @@ -320,7 +304,11 @@ namespace OpenSim.Services.Connectors.SimianGrid for (int i = 0; i < items.Count; i++) { if (items[i].ID == item.ID) - return items[i]; + { + retrieved = items[i]; + m_ItemCache.AddOrUpdate(item.ID, retrieved, CACHE_EXPIRATION_SECONDS); + return retrieved; + } } } } @@ -329,6 +317,21 @@ namespace OpenSim.Services.Connectors.SimianGrid return null; } + public InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs) + { + InventoryItemBase[] result = new InventoryItemBase[itemIDs.Length]; + int i = 0; + InventoryItemBase item = new InventoryItemBase(); + item.Owner = principalID; + foreach (UUID id in itemIDs) + { + item.ID = id; + result[i++] = GetItem(item); + } + + return result; + } + /// /// Get a folder, given by its UUID /// @@ -346,7 +349,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ChildrenOnly", "1" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Items"] is OSDArray) { OSDArray items = (OSDArray)response["Items"]; @@ -368,7 +371,7 @@ namespace OpenSim.Services.Connectors.SimianGrid public InventoryCollection GetFolderContent(UUID userID, UUID folderID) { InventoryCollection inventory = new InventoryCollection(); - inventory.UserID = userID; + inventory.OwnerID = userID; NameValueCollection requestArgs = new NameValueCollection { @@ -380,7 +383,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ChildrenOnly", "1" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Items"] is OSDArray) { OSDArray items = (OSDArray)response["Items"]; @@ -399,6 +402,18 @@ namespace OpenSim.Services.Connectors.SimianGrid return inventory; } + public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs) + { + InventoryCollection[] invColl = new InventoryCollection[folderIDs.Length]; + int i = 0; + foreach (UUID fid in folderIDs) + { + invColl[i++] = GetFolderContent(principalID, fid); + } + + return invColl; + } + /// /// Gets the items inside a folder /// @@ -408,7 +423,7 @@ namespace OpenSim.Services.Connectors.SimianGrid public List GetFolderItems(UUID userID, UUID folderID) { InventoryCollection inventory = new InventoryCollection(); - inventory.UserID = userID; + inventory.OwnerID = userID; NameValueCollection requestArgs = new NameValueCollection { @@ -420,7 +435,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ChildrenOnly", "1" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Items"] is OSDArray) { OSDArray items = (OSDArray)response["Items"]; @@ -451,7 +466,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ContentType", SLUtil.SLAssetTypeToContentType(folder.Type) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -515,7 +530,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ItemID", itemID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -543,7 +558,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "FolderID", folder.ID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -565,7 +580,9 @@ namespace OpenSim.Services.Connectors.SimianGrid // A folder of UUID.Zero means we need to find the most appropriate home for this item if (item.Folder == UUID.Zero) { - InventoryFolderBase folder = GetFolderForType(item.Owner, (AssetType)item.AssetType); + InventoryFolderBase folder = null; + if (Enum.IsDefined(typeof(FolderType), (sbyte)item.AssetType)) + folder = GetFolderForType(item.Owner, (FolderType)item.AssetType); if (folder != null && folder.ID != UUID.Zero) item.Folder = folder.ID; else @@ -620,7 +637,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ExtraData", OSDParser.SerializeJsonString(extraData) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -844,7 +861,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Items", String.Join(",", itemIDs) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -882,7 +899,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_userServerUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_userServerUrl, requestArgs); if (response["Success"].AsBoolean()) { OSDMap user = response["User"] as OSDMap; @@ -913,7 +930,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Gestures", OSDParser.SerializeJsonString(gestures) } }; - OSDMap response = WebUtil.PostToService(m_userServerUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_userServerUrl, requestArgs); if (!response["Success"].AsBoolean()) { m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Failed to save active gestures for " + userID + ": " + diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs index 854bea4..211b775 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs @@ -65,7 +65,7 @@ namespace OpenSim.Services.Connectors.SimianGrid public void PostInitialise() { } public void Close() { } - public SimianPresenceServiceConnector() { m_activityDetector = new SimianActivityDetector(this); } + public SimianPresenceServiceConnector() { } public string Name { get { return "SimianPresenceServiceConnector"; } } public void AddRegion(Scene scene) { @@ -121,6 +121,7 @@ namespace OpenSim.Services.Connectors.SimianGrid if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("=")) serviceUrl = serviceUrl + '/'; m_serverUrl = serviceUrl; + m_activityDetector = new SimianActivityDetector(this); m_Enabled = true; } } @@ -137,17 +138,18 @@ namespace OpenSim.Services.Connectors.SimianGrid userID, sessionID, secureSessionID); NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "AddSession" }, - { "UserID", userID.ToString() } - }; + { + { "RequestMethod", "AddSession" }, + { "UserID", userID.ToString() } + }; + if (sessionID != UUID.Zero) { requestArgs["SessionID"] = sessionID.ToString(); requestArgs["SecureSessionID"] = secureSessionID.ToString(); } - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -158,15 +160,15 @@ namespace OpenSim.Services.Connectors.SimianGrid public bool LogoutAgent(UUID sessionID) { -// m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID); + // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID); NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "RemoveSession" }, - { "SessionID", sessionID.ToString() } - }; + { + { "RequestMethod", "RemoveSession" }, + { "SessionID", sessionID.ToString() } + }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -177,15 +179,15 @@ namespace OpenSim.Services.Connectors.SimianGrid public bool LogoutRegionAgents(UUID regionID) { -// m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID); + // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID); NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "RemoveSessions" }, - { "SceneID", regionID.ToString() } - }; + { + { "RequestMethod", "RemoveSessions" }, + { "SceneID", regionID.ToString() } + }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -202,49 +204,46 @@ namespace OpenSim.Services.Connectors.SimianGrid public PresenceInfo GetAgent(UUID sessionID) { -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent with sessionID " + sessionID); - - NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "GetSession" }, - { "SessionID", sessionID.ToString() } - }; - - OSDMap sessionResponse = WebUtil.PostToService(m_serverUrl, requestArgs); - if (sessionResponse["Success"].AsBoolean()) + OSDMap sessionResponse = GetSessionDataFromSessionID(sessionID); + if (sessionResponse == null) { - UUID userID = sessionResponse["UserID"].AsUUID(); - m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); - - requestArgs = new NameValueCollection - { - { "RequestMethod", "GetUser" }, - { "UserID", userID.ToString() } - }; - - OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs); - if (userResponse["Success"].AsBoolean()) - return ResponseToPresenceInfo(sessionResponse, userResponse); - else - m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString()); + m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session {0}: {1}",sessionID.ToString(),sessionResponse["Message"].AsString()); + return null; } - else + + UUID userID = sessionResponse["UserID"].AsUUID(); + OSDMap userResponse = GetUserData(userID); + if (userResponse == null) { - m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session " + sessionID + ": " + sessionResponse["Message"].AsString()); + m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID.ToString(),userResponse["Message"].AsString()); + return null; } - return null; + return ResponseToPresenceInfo(sessionResponse); } public PresenceInfo[] GetAgents(string[] userIDs) { - List presences = new List(userIDs.Length); + List presences = new List(); + + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetSessions" }, + { "UserIDList", String.Join(",",userIDs) } + }; - for (int i = 0; i < userIDs.Length; i++) + OSDMap sessionListResponse = SimianGrid.PostToService(m_serverUrl, requestArgs); + if (! sessionListResponse["Success"].AsBoolean()) { - UUID userID; - if (UUID.TryParse(userIDs[i], out userID) && userID != UUID.Zero) - presences.AddRange(GetSessions(userID)); + m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve sessions: {0}",sessionListResponse["Message"].AsString()); + return null; + } + + OSDArray sessionList = sessionListResponse["Sessions"] as OSDArray; + for (int i = 0; i < sessionList.Count; i++) + { + OSDMap sessionInfo = sessionList[i] as OSDMap; + presences.Add(ResponseToPresenceInfo(sessionInfo)); } return presences.ToArray(); @@ -262,7 +261,7 @@ namespace OpenSim.Services.Connectors.SimianGrid public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) { -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID); + // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID); // Remove the session to mark this user offline if (!LogoutAgent(sessionID)) @@ -270,13 +269,13 @@ namespace OpenSim.Services.Connectors.SimianGrid // Save our last position as user data NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "AddUserData" }, - { "UserID", userID.ToString() }, - { "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) } - }; + { + { "RequestMethod", "AddUserData" }, + { "UserID", userID.ToString() }, + { "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) } + }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -287,16 +286,16 @@ namespace OpenSim.Services.Connectors.SimianGrid public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt) { -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID); + // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID); NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "AddUserData" }, - { "UserID", userID.ToString() }, - { "HomeLocation", SerializeLocation(regionID, position, lookAt) } - }; + { + { "RequestMethod", "AddUserData" }, + { "UserID", userID.ToString() }, + { "HomeLocation", SerializeLocation(regionID, position, lookAt) } + }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -312,24 +311,19 @@ namespace OpenSim.Services.Connectors.SimianGrid public GridUserInfo GetGridUserInfo(string user) { -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user); + // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user); UUID userID = new UUID(user); -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); + OSDMap userResponse = GetUserData(userID); - NameValueCollection requestArgs = new NameValueCollection + if (userResponse == null) { - { "RequestMethod", "GetUser" }, - { "UserID", userID.ToString() } - }; + m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}", userID); + } - OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs); - if (userResponse["Success"].AsBoolean()) - return ResponseToGridUserInfo(userResponse); - else - m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString()); + // Note that ResponseToGridUserInfo properly checks for and returns a null if passed a null. + return ResponseToGridUserInfo(userResponse); - return null; } #endregion @@ -338,67 +332,51 @@ namespace OpenSim.Services.Connectors.SimianGrid private OSDMap GetUserData(UUID userID) { -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); + // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "GetUser" }, - { "UserID", userID.ToString() } - }; + { + { "RequestMethod", "GetUser" }, + { "UserID", userID.ToString() } + }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["User"] is OSDMap) return response; - else - m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + response["Message"].AsString()); + m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}; {1}",userID.ToString(),response["Message"].AsString()); return null; } - private List GetSessions(UUID userID) + private OSDMap GetSessionDataFromSessionID(UUID sessionID) { - List presences = new List(1); - - OSDMap userResponse = GetUserData(userID); - if (userResponse != null) - { -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting sessions for " + userID); - - NameValueCollection requestArgs = new NameValueCollection + NameValueCollection requestArgs = new NameValueCollection { - { "RequestMethod", "GetSession" }, - { "UserID", userID.ToString() } + { "RequestMethod", "GetSession" }, + { "SessionID", sessionID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); - if (response["Success"].AsBoolean()) - { - PresenceInfo presence = ResponseToPresenceInfo(response, userResponse); - if (presence != null) - presences.Add(presence); - } -// else -// { -// m_log.Debug("[SIMIAN PRESENCE CONNECTOR]: No session returned for " + userID + ": " + response["Message"].AsString()); -// } - } + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + return response; - return presences; + m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session data for {0}; {1}",sessionID.ToString(),response["Message"].AsString()); + return null; } private bool UpdateSession(UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) { // Save our current location as session data NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "UpdateSession" }, - { "SessionID", sessionID.ToString() }, - { "SceneID", regionID.ToString() }, - { "ScenePosition", lastPosition.ToString() }, - { "SceneLookAt", lastLookAt.ToString() } - }; + { + { "RequestMethod", "UpdateSession" }, + { "SessionID", sessionID.ToString() }, + { "SceneID", regionID.ToString() }, + { "ScenePosition", lastPosition.ToString() }, + { "SceneLookAt", lastLookAt.ToString() } + }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -407,7 +385,7 @@ namespace OpenSim.Services.Connectors.SimianGrid return success; } - private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse, OSDMap userResponse) + private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse) { if (sessionResponse == null) return null; diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs index bd8069f..8fc766d 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs @@ -392,7 +392,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", client.AgentId.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); string email = response["Email"].AsString(); if (!response["Success"].AsBoolean()) @@ -425,7 +425,7 @@ namespace OpenSim.Services.Connectors.SimianGrid estate.EstateID, admin.Name); estate.EstateOwner = admin.PrincipalID; - estate.Save(); + scene.EstateDataService.StoreEstateSettings(estate); } else { @@ -443,7 +443,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { key, OSDParser.SerializeJsonString(value) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -462,7 +462,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["User"] is OSDMap) { return (OSDMap)response["User"]; diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs index 6e32b3a..698c4c0 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs @@ -165,7 +165,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "NameQuery", query } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { OSDArray array = response["Users"] as OSDArray; @@ -191,6 +191,11 @@ namespace OpenSim.Services.Connectors.SimianGrid return accounts; } + public void InvalidateCache(UUID userID) + { + m_accountCache.Remove(userID); + } + public bool StoreUserAccount(UserAccount data) { // m_log.InfoFormat("[SIMIAN ACCOUNT CONNECTOR]: Storing user account for " + data.Name); @@ -204,7 +209,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "AccessLevel", data.UserLevel.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { @@ -219,7 +224,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserTitle", data.UserTitle } }; - response = WebUtil.PostToService(m_serverUrl, requestArgs); + response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (success) @@ -252,7 +257,7 @@ namespace OpenSim.Services.Connectors.SimianGrid string lookupValue = (requestArgs.Count > 1) ? requestArgs[1] : "(Unknown)"; // m_log.DebugFormat("[SIMIAN ACCOUNT CONNECTOR]: Looking up user account with query: " + lookupValue); - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { OSDMap user = response["User"] as OSDMap; diff --git a/OpenSim/Services/Connectors/Simulation/EstateDataService.cs b/OpenSim/Services/Connectors/Simulation/EstateDataService.cs deleted file mode 100644 index cdcdecf..0000000 --- a/OpenSim/Services/Connectors/Simulation/EstateDataService.cs +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using OpenMetaverse; -using log4net; -using Mono.Addins; -using Nini.Config; -using System.Reflection; -using OpenSim.Services.Base; -using OpenSim.Services.Interfaces; -using OpenSim.Data; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Services.Connectors -{ - public class EstateDataService : ServiceBase, IEstateDataService - { -// private static readonly ILog m_log = -// LogManager.GetLogger( -// MethodBase.GetCurrentMethod().DeclaringType); - - protected IEstateDataStore m_database; - - public EstateDataService(IConfigSource config) - : base(config) - { - string dllName = String.Empty; - string connString = String.Empty; - - // Try reading the [DatabaseService] section, if it exists - IConfig dbConfig = config.Configs["DatabaseService"]; - if (dbConfig != null) - { - dllName = dbConfig.GetString("StorageProvider", String.Empty); - connString = dbConfig.GetString("ConnectionString", String.Empty); - connString = dbConfig.GetString("EstateConnectionString", connString); - } - - // Try reading the [EstateDataStore] section, if it exists - IConfig estConfig = config.Configs["EstateDataStore"]; - if (estConfig != null) - { - dllName = estConfig.GetString("StorageProvider", dllName); - connString = estConfig.GetString("ConnectionString", connString); - } - - // We tried, but this doesn't exist. We can't proceed - if (dllName == String.Empty) - throw new Exception("No StorageProvider configured"); - - m_database = LoadPlugin(dllName, new Object[] { connString }); - if (m_database == null) - throw new Exception("Could not find a storage interface in the given module"); - } - - public EstateSettings LoadEstateSettings(UUID regionID, bool create) - { - return m_database.LoadEstateSettings(regionID, create); - } - - public EstateSettings LoadEstateSettings(int estateID) - { - return m_database.LoadEstateSettings(estateID); - } - - public EstateSettings CreateNewEstate() - { - return m_database.CreateNewEstate(); - } - - public List LoadEstateSettingsAll() - { - return m_database.LoadEstateSettingsAll(); - } - - public void StoreEstateSettings(EstateSettings es) - { - m_database.StoreEstateSettings(es); - } - - public List GetEstates(string search) - { - return m_database.GetEstates(search); - } - - public List GetEstatesAll() - { - return m_database.GetEstatesAll(); - } - - public List GetEstatesByOwner(UUID ownerID) - { - return m_database.GetEstatesByOwner(ownerID); - } - - public bool LinkRegion(UUID regionID, int estateID) - { - return m_database.LinkRegion(regionID, estateID); - } - - public List GetRegions(int estateID) - { - return m_database.GetRegions(estateID); - } - - public bool DeleteEstate(int estateID) - { - return m_database.DeleteEstate(estateID); - } - } -} diff --git a/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs b/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs deleted file mode 100644 index 504fcaf..0000000 --- a/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using OpenMetaverse; -using log4net; -using Mono.Addins; -using Nini.Config; -using System.Reflection; -using OpenSim.Services.Base; -using OpenSim.Services.Interfaces; -using OpenSim.Data; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Services.Connectors -{ - public class SimulationDataService : ServiceBase, ISimulationDataService - { -// private static readonly ILog m_log = -// LogManager.GetLogger( -// MethodBase.GetCurrentMethod().DeclaringType); - - protected ISimulationDataStore m_database; - - public SimulationDataService(IConfigSource config) - : base(config) - { - string dllName = String.Empty; - string connString = String.Empty; - - // Try reading the [DatabaseService] section, if it exists - IConfig dbConfig = config.Configs["DatabaseService"]; - if (dbConfig != null) - { - dllName = dbConfig.GetString("StorageProvider", String.Empty); - connString = dbConfig.GetString("ConnectionString", String.Empty); - } - - // Try reading the [SimulationDataStore] section - IConfig simConfig = config.Configs["SimulationDataStore"]; - if (simConfig != null) - { - dllName = simConfig.GetString("StorageProvider", dllName); - connString = simConfig.GetString("ConnectionString", connString); - } - - // We tried, but this doesn't exist. We can't proceed - if (dllName == String.Empty) - throw new Exception("No StorageProvider configured"); - - m_database = LoadPlugin(dllName, new Object[] { connString }); - if (m_database == null) - throw new Exception("Could not find a storage interface in the given module"); - } - - public void StoreObject(SceneObjectGroup obj, UUID regionUUID) - { - m_database.StoreObject(obj, regionUUID); - } - - public void RemoveObject(UUID uuid, UUID regionUUID) - { - m_database.RemoveObject(uuid, regionUUID); - } - - public void StorePrimInventory(UUID primID, ICollection items) - { - m_database.StorePrimInventory(primID, items); - } - - public List LoadObjects(UUID regionUUID) - { - return m_database.LoadObjects(regionUUID); - } - - public void StoreTerrain(double[,] terrain, UUID regionID) - { - m_database.StoreTerrain(terrain, regionID); - } - - public double[,] LoadTerrain(UUID regionID) - { - return m_database.LoadTerrain(regionID); - } - - public void StoreLandObject(ILandObject Parcel) - { - m_database.StoreLandObject(Parcel); - } - - public void RemoveLandObject(UUID globalID) - { - m_database.RemoveLandObject(globalID); - } - - public List LoadLandObjects(UUID regionUUID) - { - return m_database.LoadLandObjects(regionUUID); - } - - public void StoreRegionSettings(RegionSettings rs) - { - m_database.StoreRegionSettings(rs); - } - - public RegionSettings LoadRegionSettings(UUID regionUUID) - { - return m_database.LoadRegionSettings(regionUUID); - } - - public RegionLightShareData LoadRegionWindlightSettings(UUID regionUUID) - { - return m_database.LoadRegionWindlightSettings(regionUUID); - } - - public void StoreRegionWindlightSettings(RegionLightShareData wl) - { - m_database.StoreRegionWindlightSettings(wl); - } - public void RemoveRegionWindlightSettings(UUID regionID) - { - m_database.RemoveRegionWindlightSettings(regionID); - } - - public string LoadRegionEnvironmentSettings(UUID regionUUID) - { - return m_database.LoadRegionEnvironmentSettings(regionUUID); - } - - public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) - { - m_database.StoreRegionEnvironmentSettings(regionUUID, settings); - } - - public void RemoveRegionEnvironmentSettings(UUID regionUUID) - { - m_database.RemoveRegionEnvironmentSettings(regionUUID); - } - - public void SaveExtra(UUID regionID, string name, string val) - { - m_database.SaveExtra(regionID, name, val); - } - - public void RemoveExtra(UUID regionID, string name) - { - m_database.RemoveExtra(regionID, name); - } - - public Dictionary GetExtra(UUID regionID) - { - return m_database.GetExtra(regionID); - } - } -} diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs index 57f2ffa..cea870b 100644 --- a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs @@ -79,11 +79,37 @@ namespace OpenSim.Services.Connectors.Simulation return "agent/"; } - public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string reason) + protected virtual void PackData(OSDMap args, GridRegion source, AgentCircuitData aCircuit, GridRegion destination, uint flags) { - // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CreateAgent start"); - + if (source != null) + { + args["source_x"] = OSD.FromString(source.RegionLocX.ToString()); + args["source_y"] = OSD.FromString(source.RegionLocY.ToString()); + args["source_name"] = OSD.FromString(source.RegionName); + args["source_uuid"] = OSD.FromString(source.RegionID.ToString()); + if (!String.IsNullOrEmpty(source.RawServerURI)) + args["source_server_uri"] = OSD.FromString(source.RawServerURI); + } + + args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); + args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); + args["destination_name"] = OSD.FromString(destination.RegionName); + args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); + args["teleport_flags"] = OSD.FromString(flags.ToString()); + } + + public bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint flags, out string reason) + { + string tmp = String.Empty; + return CreateAgent(source, destination, aCircuit, flags, out tmp, out reason); + } + + public bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint flags, out string myipaddress, out string reason) + { + m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: Creating agent at {0}", destination.ServerURI); reason = String.Empty; + myipaddress = String.Empty; + if (destination == null) { m_log.Debug("[REMOTE SIMULATION CONNECTOR]: Given destination is null"); @@ -95,12 +121,7 @@ namespace OpenSim.Services.Connectors.Simulation try { OSDMap args = aCircuit.PackAgentCircuitData(); - - args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); - args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); - args["destination_name"] = OSD.FromString(destination.RegionName); - args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); - args["teleport_flags"] = OSD.FromString(flags.ToString()); + PackData(args, source, aCircuit, destination, flags); OSDMap result = WebUtil.PostToServiceCompressed(uri, args, 30000); bool success = result["success"].AsBoolean(); @@ -110,11 +131,12 @@ namespace OpenSim.Services.Connectors.Simulation reason = data["reason"].AsString(); success = data["success"].AsBoolean(); + myipaddress = data["your_ip"].AsString(); return success; } // Try the old version, uncompressed - result = WebUtil.PostToService(uri, args, 30000); + result = WebUtil.PostToService(uri, args, 30000, false); if (result["Success"].AsBoolean()) { @@ -124,6 +146,7 @@ namespace OpenSim.Services.Connectors.Simulation reason = data["reason"].AsString(); success = data["success"].AsBoolean(); + myipaddress = data["your_ip"].AsString(); m_log.WarnFormat( "[REMOTE SIMULATION CONNECTOR]: Remote simulator {0} did not accept compressed transfer, suggest updating it.", destination.RegionName); return success; @@ -228,7 +251,7 @@ namespace OpenSim.Services.Connectors.Simulation /// private bool UpdateAgent(GridRegion destination, IAgentData cAgentData, int timeout) { - // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: UpdateAgent start"); + // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: UpdateAgent in {0}", destination.ServerURI); // Eventually, we want to use a caps url instead of the agentID string uri = destination.ServerURI + AgentPath() + cAgentData.AgentID + "/"; @@ -258,48 +281,10 @@ namespace OpenSim.Services.Connectors.Simulation return false; } - /// - /// Not sure what sequence causes this function to be invoked. The only calling - /// path is through the GET method - /// - public bool RetrieveAgent(GridRegion destination, UUID id, out IAgentData agent) - { - // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: RetrieveAgent start"); - - agent = null; - - // Eventually, we want to use a caps url instead of the agentID - string uri = destination.ServerURI + AgentPath() + id + "/" + destination.RegionID.ToString() + "/"; - - try - { - OSDMap result = WebUtil.GetFromService(uri, 10000); - if (result["Success"].AsBoolean()) - { - // OSDMap args = Util.GetOSDMap(result["_RawResult"].AsString()); - OSDMap args = (OSDMap)result["_Result"]; - if (args != null) - { - agent = new CompleteAgentData(); - agent.Unpack(args, null); - return true; - } - } - } - catch (Exception e) - { - m_log.Warn("[REMOTE SIMULATION CONNECTOR]: UpdateAgent failed with exception: " + e.ToString()); - } - - return false; - } - /// - /// - public bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason) + public bool QueryAccess(GridRegion destination, UUID agentID, string agentHomeURI, bool viaTeleport, Vector3 position, List featuresAvailable, EntityTransferContext ctx, out string reason) { reason = "Failed to contact destination"; - version = "Unknown"; // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: QueryAccess start, position={0}", position); @@ -307,14 +292,32 @@ namespace OpenSim.Services.Connectors.Simulation if (ext == null) return false; // Eventually, we want to use a caps url instead of the agentID - string uri = destination.ServerURI + AgentPath() + id + "/" + destination.RegionID.ToString() + "/"; + string uri = destination.ServerURI + AgentPath() + agentID + "/" + destination.RegionID.ToString() + "/"; OSDMap request = new OSDMap(); + request.Add("viaTeleport", OSD.FromBoolean(viaTeleport)); request.Add("position", OSD.FromString(position.ToString())); + // To those who still understad this field, we're telling them + // the lowest version just to be safe + request.Add("my_version", OSD.FromString(String.Format("SIMULATION/{0}", VersionInfo.SimulationServiceVersionSupportedMin))); + // New simulation service negotiation + request.Add("simulation_service_supported_min", OSD.FromReal(VersionInfo.SimulationServiceVersionSupportedMin)); + request.Add("simulation_service_supported_max", OSD.FromReal(VersionInfo.SimulationServiceVersionSupportedMax)); + request.Add("simulation_service_accepted_min", OSD.FromReal(VersionInfo.SimulationServiceVersionAcceptedMin)); + request.Add("simulation_service_accepted_max", OSD.FromReal(VersionInfo.SimulationServiceVersionAcceptedMax)); + + OSDArray features = new OSDArray(); + foreach (UUID feature in featuresAvailable) + features.Add(OSD.FromString(feature.ToString())); + + request.Add("features", features); + + if (agentHomeURI != null) + request.Add("agent_home_uri", OSD.FromString(agentHomeURI)); try { - OSDMap result = WebUtil.ServiceOSDRequest(uri, request, "QUERYACCESS", 30000, false); + OSDMap result = WebUtil.ServiceOSDRequest(uri, request, "QUERYACCESS", 30000, false, false); bool success = result["success"].AsBoolean(); if (result.ContainsKey("_Result")) { @@ -325,15 +328,32 @@ namespace OpenSim.Services.Connectors.Simulation success = data["success"]; reason = data["reason"].AsString(); - if (data["version"] != null && data["version"].AsString() != string.Empty) - version = data["version"].AsString(); + // We will need to plumb this and start sing the outbound version as well + // TODO: lay the pipe for version plumbing + if (data.ContainsKey("negotiated_inbound_version") && data["negotiated_inbound_version"] != null) + { + ctx.InboundVersion = (float)data["negotiated_inbound_version"].AsReal(); + ctx.OutboundVersion = (float)data["negotiated_outbound_version"].AsReal(); + } + else if (data["version"] != null && data["version"].AsString() != string.Empty) + { + string versionString = data["version"].AsString(); + String[] parts = versionString.Split(new char[] {'/'}); + if (parts.Length > 1) + { + ctx.InboundVersion = float.Parse(parts[1]); + ctx.OutboundVersion = float.Parse(parts[1]); + } + } + if (data.ContainsKey("variable_wearables_count_supported")) + ctx.VariableWearablesSupported = true; m_log.DebugFormat( - "[REMOTE SIMULATION CONNECTOR]: QueryAccess to {0} returned {1}, reason {2}, version {3} ({4})", - uri, success, reason, version, data["version"].AsString()); + "[REMOTE SIMULATION CONNECTOR]: QueryAccess to {0} returned {1}, reason {2}, version {3}/{4}", + uri, success, reason, ctx.InboundVersion, ctx.OutboundVersion); } - if (!success) + if (!success || ctx.InboundVersion == 0f || ctx.OutboundVersion == 0f) { // If we don't check this then OpenSimulator 0.7.3.1 and some period before will never see the // actual failure message @@ -359,6 +379,17 @@ namespace OpenSim.Services.Connectors.Simulation return false; } + + featuresAvailable.Clear(); + + if (result.ContainsKey("features")) + { + OSDArray array = (OSDArray)result["features"]; + + foreach (OSD o in array) + featuresAvailable.Add(new UUID(o.AsString())); + } + return success; } catch (Exception e) @@ -377,7 +408,7 @@ namespace OpenSim.Services.Connectors.Simulation try { - WebUtil.ServiceOSDRequest(uri, null, "DELETE", 10000, false); + WebUtil.ServiceOSDRequest(uri, null, "DELETE", 10000, false, false); } catch (Exception e) { @@ -389,15 +420,14 @@ namespace OpenSim.Services.Connectors.Simulation /// /// - public bool CloseAgent(GridRegion destination, UUID id) + public bool CloseAgent(GridRegion destination, UUID id, string auth_code) { -// m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CloseAgent start"); - - string uri = destination.ServerURI + AgentPath() + id + "/" + destination.RegionID.ToString() + "/"; + string uri = destination.ServerURI + AgentPath() + id + "/" + destination.RegionID.ToString() + "/?auth=" + auth_code; + m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CloseAgent {0}", uri); try { - WebUtil.ServiceOSDRequest(uri, null, "DELETE", 10000, false); + WebUtil.ServiceOSDRequest(uri, null, "DELETE", 10000, false, false); } catch (Exception e) { @@ -444,11 +474,18 @@ namespace OpenSim.Services.Connectors.Simulation args["destination_name"] = OSD.FromString(destination.RegionName); args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); - WebUtil.PostToService(uri, args, 40000); + OSDMap result = WebUtil.PostToService(uri, args, 40000, false); + + if (result == null) + return false; + bool success = result["success"].AsBoolean(); + if (!success) + return false; } catch (Exception e) { m_log.WarnFormat("[REMOTE SIMULATION CONNECTOR] CreateObject failed with exception; {0}",e.ToString()); + return false; } return true; diff --git a/OpenSim/Services/Connectors/UserAccounts/UserAccountServicesConnector.cs b/OpenSim/Services/Connectors/UserAccounts/UserAccountServicesConnector.cs index 6d5ce28..c21db54 100644 --- a/OpenSim/Services/Connectors/UserAccounts/UserAccountServicesConnector.cs +++ b/OpenSim/Services/Connectors/UserAccounts/UserAccountServicesConnector.cs @@ -32,14 +32,15 @@ using System.IO; using System.Reflection; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Communications; + +using OpenSim.Framework.ServiceAuth; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenMetaverse; namespace OpenSim.Services.Connectors { - public class UserAccountServicesConnector : IUserAccountService + public class UserAccountServicesConnector : BaseServiceConnector, IUserAccountService { private static readonly ILog m_log = LogManager.GetLogger( @@ -79,6 +80,8 @@ namespace OpenSim.Services.Connectors throw new Exception("User account connector init error"); } m_ServerURI = serviceURI; + + base.Initialise(source, "UserAccountService"); } public virtual UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) @@ -144,7 +147,8 @@ namespace OpenSim.Services.Connectors { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - reqString); + reqString, + m_Auth); if (reply == null || (reply != null && reply == string.Empty)) { m_log.DebugFormat("[ACCOUNT CONNECTOR]: GetUserAccounts received null or empty reply"); @@ -162,7 +166,7 @@ namespace OpenSim.Services.Connectors if (replyData != null) { - if (replyData.ContainsKey("result") && replyData.ContainsKey("result").ToString() == "null") + if (replyData.ContainsKey("result") && replyData["result"].ToString() == "null") { return accounts; } @@ -187,6 +191,10 @@ namespace OpenSim.Services.Connectors return accounts; } + public void InvalidateCache(UUID userID) + { + } + public virtual bool StoreUserAccount(UserAccount data) { Dictionary sendData = new Dictionary(); @@ -207,9 +215,39 @@ namespace OpenSim.Services.Connectors sendData[kvp.Key] = kvp.Value.ToString(); } - return SendAndGetBoolReply(sendData); + if (SendAndGetReply(sendData) != null) + return true; + else + return false; } + /// + /// Create user remotely. Note this this is not part of the IUserAccountsService + /// + /// + /// + /// + /// + /// + /// + public virtual UserAccount CreateUser(string first, string last, string password, string email, UUID scopeID) + { + Dictionary sendData = new Dictionary(); + //sendData["SCOPEID"] = scopeID.ToString(); + sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); + sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); + sendData["METHOD"] = "createuser"; + + sendData["FirstName"] = first; + sendData["LastName"] = last; + sendData["Password"] = password; + if (!string.IsNullOrEmpty(email)) + sendData["Email"] = first; + sendData["ScopeID"] = scopeID.ToString(); + + return SendAndGetReply(sendData); + } + private UserAccount SendAndGetReply(Dictionary sendData) { string reply = string.Empty; @@ -220,7 +258,8 @@ namespace OpenSim.Services.Connectors { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - reqString); + reqString, + m_Auth); if (reply == null || (reply != null && reply == string.Empty)) { m_log.DebugFormat("[ACCOUNT CONNECTOR]: GetUserAccount received null or empty reply"); @@ -251,14 +290,16 @@ namespace OpenSim.Services.Connectors { string reqString = ServerUtils.BuildQueryString(sendData); string uri = m_ServerURI + "/accounts"; - // m_log.DebugFormat("[ACCOUNTS CONNECTOR]: queryString = {0}", reqString); + //m_log.DebugFormat("[ACCOUNTS CONNECTOR]: queryString = {0}", reqString); try { string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - reqString); + reqString, + m_Auth); if (reply != string.Empty) { + //m_log.DebugFormat("[ACCOUNTS CONNECTOR]: reply = {0}", reply); Dictionary replyData = ServerUtils.ParseXmlResponse(reply); if (replyData.ContainsKey("result")) diff --git a/OpenSim/Services/EstateService/EstateDataService.cs b/OpenSim/Services/EstateService/EstateDataService.cs new file mode 100644 index 0000000..f6a8654 --- /dev/null +++ b/OpenSim/Services/EstateService/EstateDataService.cs @@ -0,0 +1,136 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse; +using log4net; +using Nini.Config; +using System.Reflection; +using OpenSim.Services.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Data; +using OpenSim.Framework; + +namespace OpenSim.Services.EstateService +{ + public class EstateDataService : ServiceBase, IEstateDataService + { +// private static readonly ILog m_log = +// LogManager.GetLogger( +// MethodBase.GetCurrentMethod().DeclaringType); + + protected IEstateDataStore m_database; + + public EstateDataService(IConfigSource config) + : base(config) + { + string dllName = String.Empty; + string connString = String.Empty; + + // Try reading the [DatabaseService] section, if it exists + IConfig dbConfig = config.Configs["DatabaseService"]; + if (dbConfig != null) + { + dllName = dbConfig.GetString("StorageProvider", String.Empty); + connString = dbConfig.GetString("ConnectionString", String.Empty); + connString = dbConfig.GetString("EstateConnectionString", connString); + } + + // Try reading the [EstateDataStore] section, if it exists + IConfig estConfig = config.Configs["EstateDataStore"]; + if (estConfig != null) + { + dllName = estConfig.GetString("StorageProvider", dllName); + connString = estConfig.GetString("ConnectionString", connString); + } + + // We tried, but this doesn't exist. We can't proceed + if (dllName == String.Empty) + throw new Exception("No StorageProvider configured"); + + m_database = LoadPlugin(dllName, new Object[] { connString }); + if (m_database == null) + throw new Exception("Could not find a storage interface in the given module"); + } + + public EstateSettings LoadEstateSettings(UUID regionID, bool create) + { + return m_database.LoadEstateSettings(regionID, create); + } + + public EstateSettings LoadEstateSettings(int estateID) + { + return m_database.LoadEstateSettings(estateID); + } + + public EstateSettings CreateNewEstate() + { + return m_database.CreateNewEstate(); + } + + public List LoadEstateSettingsAll() + { + return m_database.LoadEstateSettingsAll(); + } + + public void StoreEstateSettings(EstateSettings es) + { + m_database.StoreEstateSettings(es); + } + + public List GetEstates(string search) + { + return m_database.GetEstates(search); + } + + public List GetEstatesAll() + { + return m_database.GetEstatesAll(); + } + + public List GetEstatesByOwner(UUID ownerID) + { + return m_database.GetEstatesByOwner(ownerID); + } + + public bool LinkRegion(UUID regionID, int estateID) + { + return m_database.LinkRegion(regionID, estateID); + } + + public List GetRegions(int estateID) + { + return m_database.GetRegions(estateID); + } + + public bool DeleteEstate(int estateID) + { + return m_database.DeleteEstate(estateID); + } + } +} diff --git a/OpenSim/Services/FSAssetService/FSAssetService.cs b/OpenSim/Services/FSAssetService/FSAssetService.cs new file mode 100644 index 0000000..1bab687 --- /dev/null +++ b/OpenSim/Services/FSAssetService/FSAssetService.cs @@ -0,0 +1,723 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Diagnostics; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Text; +using System.Threading; +using System.Reflection; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Framework.Serialization.External; +using OpenSim.Framework.Console; +using OpenSim.Server.Base; +using OpenSim.Services.Base; +using OpenSim.Services.Interfaces; +using Nini.Config; +using log4net; +using OpenMetaverse; +using System.Security.Cryptography; + +namespace OpenSim.Services.FSAssetService +{ + public class FSAssetConnector : ServiceBase, IAssetService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + static System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + static SHA256CryptoServiceProvider SHA256 = new SHA256CryptoServiceProvider(); + + static byte[] ToCString(string s) + { + byte[] ret = enc.GetBytes(s); + Array.Resize(ref ret, ret.Length + 1); + ret[ret.Length - 1] = 0; + + return ret; + } + + protected IAssetLoader m_AssetLoader = null; + protected IFSAssetDataPlugin m_DataConnector = null; + protected IAssetService m_FallbackService; + protected Thread m_WriterThread; + protected Thread m_StatsThread; + protected string m_SpoolDirectory; + protected object m_readLock = new object(); + protected object m_statsLock = new object(); + protected int m_readCount = 0; + protected int m_readTicks = 0; + protected int m_missingAssets = 0; + protected int m_missingAssetsFS = 0; + protected string m_FSBase; + + private static bool m_Initialized; + private bool m_MainInstance; + + public FSAssetConnector(IConfigSource config) + : this(config, "AssetService") + { + } + + public FSAssetConnector(IConfigSource config, string configName) : base(config) + { + if (!m_Initialized) + { + m_Initialized = true; + m_MainInstance = true; + + MainConsole.Instance.Commands.AddCommand("fs", false, + "show assets", "show assets", "Show asset stats", + HandleShowAssets); + MainConsole.Instance.Commands.AddCommand("fs", false, + "show digest", "show digest ", "Show asset digest", + HandleShowDigest); + MainConsole.Instance.Commands.AddCommand("fs", false, + "delete asset", "delete asset ", + "Delete asset from database", + HandleDeleteAsset); + MainConsole.Instance.Commands.AddCommand("fs", false, + "import", "import [ ]", + "Import legacy assets", + HandleImportAssets); + MainConsole.Instance.Commands.AddCommand("fs", false, + "force import", "force import
[ ]", + "Import legacy assets, overwriting current content", + HandleImportAssets); + } + + IConfig assetConfig = config.Configs[configName]; + + if (assetConfig == null) + throw new Exception("No AssetService configuration"); + + // Get Database Connector from Asset Config (If present) + string dllName = assetConfig.GetString("StorageProvider", string.Empty); + string m_ConnectionString = assetConfig.GetString("ConnectionString", string.Empty); + string m_Realm = assetConfig.GetString("Realm", "fsassets"); + + int SkipAccessTimeDays = assetConfig.GetInt("DaysBetweenAccessTimeUpdates", 0); + + // If not found above, fallback to Database defaults + IConfig dbConfig = config.Configs["DatabaseService"]; + + if (dbConfig != null) + { + if (dllName == String.Empty) + dllName = dbConfig.GetString("StorageProvider", String.Empty); + + if (m_ConnectionString == String.Empty) + m_ConnectionString = dbConfig.GetString("ConnectionString", String.Empty); + } + + // No databse connection found in either config + if (dllName.Equals(String.Empty)) + throw new Exception("No StorageProvider configured"); + + if (m_ConnectionString.Equals(String.Empty)) + throw new Exception("Missing database connection string"); + + // Create Storage Provider + m_DataConnector = LoadPlugin(dllName); + + if (m_DataConnector == null) + throw new Exception(string.Format("Could not find a storage interface in the module {0}", dllName)); + + // Initialize DB And perform any migrations required + m_DataConnector.Initialise(m_ConnectionString, m_Realm, SkipAccessTimeDays); + + // Setup Fallback Service + string str = assetConfig.GetString("FallbackService", string.Empty); + + if (str != string.Empty) + { + object[] args = new object[] { config }; + m_FallbackService = LoadPlugin(str, args); + if (m_FallbackService != null) + { + m_log.Info("[FSASSETS]: Fallback service loaded"); + } + else + { + m_log.Error("[FSASSETS]: Failed to load fallback service"); + } + } + + // Setup directory structure including temp directory + m_SpoolDirectory = assetConfig.GetString("SpoolDirectory", "/tmp"); + + string spoolTmp = Path.Combine(m_SpoolDirectory, "spool"); + + Directory.CreateDirectory(spoolTmp); + + m_FSBase = assetConfig.GetString("BaseDirectory", String.Empty); + if (m_FSBase == String.Empty) + { + m_log.ErrorFormat("[FSASSETS]: BaseDirectory not specified"); + throw new Exception("Configuration error"); + } + + if (m_MainInstance) + { + string loader = assetConfig.GetString("DefaultAssetLoader", string.Empty); + if (loader != string.Empty) + { + m_AssetLoader = LoadPlugin(loader); + string loaderArgs = assetConfig.GetString("AssetLoaderArgs", string.Empty); + m_log.InfoFormat("[FSASSETS]: Loading default asset set from {0}", loaderArgs); + m_AssetLoader.ForEachDefaultXmlAsset(loaderArgs, + delegate(AssetBase a) + { + Store(a, false); + }); + } + + m_WriterThread = new Thread(Writer); + m_WriterThread.Start(); + m_StatsThread = new Thread(Stats); + m_StatsThread.Start(); + } + + m_log.Info("[FSASSETS]: FS asset service enabled"); + } + + private void Stats() + { + while (true) + { + Thread.Sleep(60000); + + lock (m_statsLock) + { + if (m_readCount > 0) + { + double avg = (double)m_readTicks / (double)m_readCount; +// if (avg > 10000) +// Environment.Exit(0); + m_log.InfoFormat("[FSASSETS]: Read stats: {0} files, {1} ticks, avg {2:F2}, missing {3}, FS {4}", m_readCount, m_readTicks, (double)m_readTicks / (double)m_readCount, m_missingAssets, m_missingAssetsFS); + } + m_readCount = 0; + m_readTicks = 0; + m_missingAssets = 0; + m_missingAssetsFS = 0; + } + } + } + + private void Writer() + { + m_log.Info("[FSASSETS]: Writer started"); + + while (true) + { + string[] files = Directory.GetFiles(m_SpoolDirectory); + + if (files.Length > 0) + { + int tickCount = Environment.TickCount; + for (int i = 0 ; i < files.Length ; i++) + { + string hash = Path.GetFileNameWithoutExtension(files[i]); + string s = HashToFile(hash); + string diskFile = Path.Combine(m_FSBase, s); + + Directory.CreateDirectory(Path.GetDirectoryName(diskFile)); + try + { + byte[] data = File.ReadAllBytes(files[i]); + + using (GZipStream gz = new GZipStream(new FileStream(diskFile + ".gz", FileMode.Create), CompressionMode.Compress)) + { + gz.Write(data, 0, data.Length); + gz.Close(); + } + File.Delete(files[i]); + + //File.Move(files[i], diskFile); + } + catch(System.IO.IOException e) + { + if (e.Message.StartsWith("Win32 IO returned ERROR_ALREADY_EXISTS")) + File.Delete(files[i]); + else + throw; + } + } + int totalTicks = System.Environment.TickCount - tickCount; + if (totalTicks > 0) // Wrap? + { + m_log.InfoFormat("[FSASSETS]: Write cycle complete, {0} files, {1} ticks, avg {2:F2}", files.Length, totalTicks, (double)totalTicks / (double)files.Length); + } + } + + Thread.Sleep(1000); + } + } + + string GetSHA256Hash(byte[] data) + { + byte[] hash = SHA256.ComputeHash(data); + + return BitConverter.ToString(hash).Replace("-", String.Empty); + } + + public string HashToPath(string hash) + { + if (hash == null || hash.Length < 10) + return "junkyard"; + + return Path.Combine(hash.Substring(0, 3), + Path.Combine(hash.Substring(3, 3))); + /* + * The below is what core would normally use. + * This is modified to work in OSGrid, as seen + * above, because the SRAS data is structured + * that way. + */ + /* + return Path.Combine(hash.Substring(0, 2), + Path.Combine(hash.Substring(2, 2), + Path.Combine(hash.Substring(4, 2), + hash.Substring(6, 4)))); + */ + } + + private bool AssetExists(string hash) + { + string s = HashToFile(hash); + string diskFile = Path.Combine(m_FSBase, s); + + if (File.Exists(diskFile + ".gz") || File.Exists(diskFile)) + return true; + + return false; + } + + public virtual bool[] AssetsExist(string[] ids) + { + UUID[] uuid = Array.ConvertAll(ids, id => UUID.Parse(id)); + return m_DataConnector.AssetsExist(uuid); + } + + public string HashToFile(string hash) + { + return Path.Combine(HashToPath(hash), hash); + } + + public virtual AssetBase Get(string id) + { + string hash; + + return Get(id, out hash); + } + + private AssetBase Get(string id, out string sha) + { + string hash = string.Empty; + + int startTime = System.Environment.TickCount; + AssetMetadata metadata; + + lock (m_readLock) + { + metadata = m_DataConnector.Get(id, out hash); + } + + sha = hash; + + if (metadata == null) + { + AssetBase asset = null; + if (m_FallbackService != null) + { + asset = m_FallbackService.Get(id); + if (asset != null) + { + asset.Metadata.ContentType = + SLUtil.SLAssetTypeToContentType((int)asset.Type); + sha = GetSHA256Hash(asset.Data); + m_log.InfoFormat("[FSASSETS]: Added asset {0} from fallback to local store", id); + Store(asset); + } + } + if (asset == null) + { + // m_log.InfoFormat("[FSASSETS]: Asset {0} not found", id); + m_missingAssets++; + } + return asset; + } + AssetBase newAsset = new AssetBase(); + newAsset.Metadata = metadata; + try + { + newAsset.Data = GetFsData(hash); + if (newAsset.Data.Length == 0) + { + AssetBase asset = null; + if (m_FallbackService != null) + { + asset = m_FallbackService.Get(id); + if (asset != null) + { + asset.Metadata.ContentType = + SLUtil.SLAssetTypeToContentType((int)asset.Type); + sha = GetSHA256Hash(asset.Data); + m_log.InfoFormat("[FSASSETS]: Added asset {0} from fallback to local store", id); + Store(asset); + } + } + if (asset == null) + m_missingAssetsFS++; + // m_log.InfoFormat("[FSASSETS]: Asset {0}, hash {1} not found in FS", id, hash); + else + { + // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) + // Fix bad assets before sending them elsewhere + if (asset.Type == (int)AssetType.Object && asset.Data != null) + { + string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data)); + asset.Data = Utils.StringToBytes(xml); + } + return asset; + } + } + + lock (m_statsLock) + { + m_readTicks += Environment.TickCount - startTime; + m_readCount++; + } + + // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) + // Fix bad assets before sending them elsewhere + if (newAsset.Type == (int)AssetType.Object && newAsset.Data != null) + { + string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(newAsset.Data)); + newAsset.Data = Utils.StringToBytes(xml); + } + + return newAsset; + } + catch (Exception exception) + { + m_log.Error(exception.ToString()); + Thread.Sleep(5000); + Environment.Exit(1); + return null; + } + } + + public virtual AssetMetadata GetMetadata(string id) + { + string hash; + return m_DataConnector.Get(id, out hash); + } + + public virtual byte[] GetData(string id) + { + string hash; + if (m_DataConnector.Get(id, out hash) == null) + return null; + + return GetFsData(hash); + } + + public bool Get(string id, Object sender, AssetRetrieved handler) + { + AssetBase asset = Get(id); + + handler(id, sender, asset); + + return true; + } + + public byte[] GetFsData(string hash) + { + string spoolFile = Path.Combine(m_SpoolDirectory, hash + ".asset"); + + if (File.Exists(spoolFile)) + { + try + { + byte[] content = File.ReadAllBytes(spoolFile); + + return content; + } + catch + { + } + } + + string file = HashToFile(hash); + string diskFile = Path.Combine(m_FSBase, file); + + if (File.Exists(diskFile + ".gz")) + { + try + { + using (GZipStream gz = new GZipStream(new FileStream(diskFile + ".gz", FileMode.Open, FileAccess.Read), CompressionMode.Decompress)) + { + using (MemoryStream ms = new MemoryStream()) + { + byte[] data = new byte[32768]; + int bytesRead; + + do + { + bytesRead = gz.Read(data, 0, 32768); + if (bytesRead > 0) + ms.Write(data, 0, bytesRead); + } while (bytesRead > 0); + + return ms.ToArray(); + } + } + } + catch (Exception) + { + return new Byte[0]; + } + } + else if (File.Exists(diskFile)) + { + try + { + byte[] content = File.ReadAllBytes(diskFile); + + return content; + } + catch + { + } + } + return new Byte[0]; + + } + + public virtual string Store(AssetBase asset) + { + return Store(asset, false); + } + + private string Store(AssetBase asset, bool force) + { + int tickCount = Environment.TickCount; + string hash = GetSHA256Hash(asset.Data); + + if (!AssetExists(hash)) + { + string tempFile = Path.Combine(Path.Combine(m_SpoolDirectory, "spool"), hash + ".asset"); + string finalFile = Path.Combine(m_SpoolDirectory, hash + ".asset"); + + if (!File.Exists(finalFile)) + { + // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) + // Fix bad assets before storing on this server + if (asset.Type == (int)AssetType.Object && asset.Data != null) + { + string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data)); + asset.Data = Utils.StringToBytes(xml); + } + + FileStream fs = File.Create(tempFile); + + fs.Write(asset.Data, 0, asset.Data.Length); + + fs.Close(); + + File.Move(tempFile, finalFile); + } + } + + if (asset.ID == string.Empty) + { + if (asset.FullID == UUID.Zero) + { + asset.FullID = UUID.Random(); + } + asset.ID = asset.FullID.ToString(); + } + else if (asset.FullID == UUID.Zero) + { + UUID uuid = UUID.Zero; + if (UUID.TryParse(asset.ID, out uuid)) + { + asset.FullID = uuid; + } + else + { + asset.FullID = UUID.Random(); + } + } + + if (!m_DataConnector.Store(asset.Metadata, hash)) + { + return UUID.Zero.ToString(); + } + else + { + return asset.ID; + } + } + + public bool UpdateContent(string id, byte[] data) + { + return false; + +// string oldhash; +// AssetMetadata meta = m_DataConnector.Get(id, out oldhash); +// +// if (meta == null) +// return false; +// +// AssetBase asset = new AssetBase(); +// asset.Metadata = meta; +// asset.Data = data; +// +// Store(asset); +// +// return true; + } + + public virtual bool Delete(string id) + { + m_DataConnector.Delete(id); + + return true; + } + + private void HandleShowAssets(string module, string[] args) + { + int num = m_DataConnector.Count(); + MainConsole.Instance.Output(string.Format("Total asset count: {0}", num)); + } + + private void HandleShowDigest(string module, string[] args) + { + if (args.Length < 3) + { + MainConsole.Instance.Output("Syntax: show digest "); + return; + } + + string hash; + AssetBase asset = Get(args[2], out hash); + + if (asset == null || asset.Data.Length == 0) + { + MainConsole.Instance.Output("Asset not found"); + return; + } + + int i; + + MainConsole.Instance.Output(String.Format("Name: {0}", asset.Name)); + MainConsole.Instance.Output(String.Format("Description: {0}", asset.Description)); + MainConsole.Instance.Output(String.Format("Type: {0}", asset.Type)); + MainConsole.Instance.Output(String.Format("Content-type: {0}", asset.Metadata.ContentType)); + MainConsole.Instance.Output(String.Format("Flags: {0}", asset.Metadata.Flags.ToString())); + MainConsole.Instance.Output(String.Format("FS file: {0}", HashToFile(hash))); + + for (i = 0 ; i < 5 ; i++) + { + int off = i * 16; + if (asset.Data.Length <= off) + break; + int len = 16; + if (asset.Data.Length < off + len) + len = asset.Data.Length - off; + + byte[] line = new byte[len]; + Array.Copy(asset.Data, off, line, 0, len); + + string text = BitConverter.ToString(line); + MainConsole.Instance.Output(String.Format("{0:x4}: {1}", off, text)); + } + } + + private void HandleDeleteAsset(string module, string[] args) + { + if (args.Length < 3) + { + MainConsole.Instance.Output("Syntax: delete asset "); + return; + } + + AssetBase asset = Get(args[2]); + + if (asset == null || asset.Data.Length == 0) + { + MainConsole.Instance.Output("Asset not found"); + return; + } + + m_DataConnector.Delete(args[2]); + + MainConsole.Instance.Output("Asset deleted"); + } + + private void HandleImportAssets(string module, string[] args) + { + bool force = false; + if (args[0] == "force") + { + force = true; + List list = new List(args); + list.RemoveAt(0); + args = list.ToArray(); + } + if (args.Length < 3) + { + MainConsole.Instance.Output("Syntax: import
[ ]"); + } + else + { + string conn = args[1]; + string table = args[2]; + int start = 0; + int count = -1; + if (args.Length > 3) + { + start = Convert.ToInt32(args[3]); + } + if (args.Length > 4) + { + count = Convert.ToInt32(args[4]); + } + m_DataConnector.Import(conn, table, start, count, force, new FSStoreDelegate(Store)); + } + } + + public AssetBase GetCached(string id) + { + return Get(id); + } + } +} diff --git a/OpenSim/Services/FreeswitchService/Properties/AssemblyInfo.cs b/OpenSim/Services/FreeswitchService/Properties/AssemblyInfo.cs index 58c7283..1e3560b 100644 --- a/OpenSim/Services/FreeswitchService/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/FreeswitchService/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/Friends/Properties/AssemblyInfo.cs b/OpenSim/Services/Friends/Properties/AssemblyInfo.cs index dddb091..87fb6a9 100644 --- a/OpenSim/Services/Friends/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/Friends/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index ee3b858..0c502a2 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -46,6 +46,7 @@ namespace OpenSim.Services.GridService private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); + private string LogHeader = "[GRID SERVICE]"; private bool m_DeleteOnUnregister = true; private static GridService m_RootInstance = null; @@ -56,6 +57,10 @@ namespace OpenSim.Services.GridService protected bool m_AllowDuplicateNames = false; protected bool m_AllowHypergridMapSearch = false; + protected bool m_SuppressVarregionOverlapCheckOnRegistration = false; + + private static Dictionary m_ExtraFeatures = new Dictionary(); + public GridService(IConfigSource config) : base(config) { @@ -63,6 +68,9 @@ namespace OpenSim.Services.GridService m_config = config; IConfig gridConfig = config.Configs["GridService"]; + + bool suppressConsoleCommands = false; + if (gridConfig != null) { m_DeleteOnUnregister = gridConfig.GetBoolean("DeleteOnUnregister", true); @@ -76,32 +84,33 @@ namespace OpenSim.Services.GridService } m_AllowDuplicateNames = gridConfig.GetBoolean("AllowDuplicateNames", m_AllowDuplicateNames); m_AllowHypergridMapSearch = gridConfig.GetBoolean("AllowHypergridMapSearch", m_AllowHypergridMapSearch); + + m_SuppressVarregionOverlapCheckOnRegistration = gridConfig.GetBoolean("SuppressVarregionOverlapCheckOnRegistration", m_SuppressVarregionOverlapCheckOnRegistration); + + // This service is also used locally by a simulator running in grid mode. This switches prevents + // inappropriate console commands from being registered + suppressConsoleCommands = gridConfig.GetBoolean("SuppressConsoleCommands", suppressConsoleCommands); } - + if (m_RootInstance == null) { m_RootInstance = this; - if (MainConsole.Instance != null) + if (!suppressConsoleCommands && MainConsole.Instance != null) { MainConsole.Instance.Commands.AddCommand("Regions", true, "deregister region id", - "deregister region id ", + "deregister region id +", "Deregister a region manually.", String.Empty, HandleDeregisterRegion); - // A messy way of stopping this command being added if we are in standalone (since the simulator - // has an identically named command - // - // XXX: We're relying on the OpenSimulator version being registered first, which is not well defined. - if (MainConsole.Instance.Commands.Resolve(new string[] { "show", "regions" }).Length == 0) - MainConsole.Instance.Commands.AddCommand("Regions", true, - "show regions", - "show regions", - "Show details on all regions", - String.Empty, - HandleShowRegions); + MainConsole.Instance.Commands.AddCommand("Regions", true, + "show regions", + "show regions", + "Show details on all regions", + String.Empty, + HandleShowRegions); MainConsole.Instance.Commands.AddCommand("Regions", true, "show region name", @@ -117,17 +126,72 @@ namespace OpenSim.Services.GridService "For example, show region at 1000 1000", HandleShowRegionAt); - MainConsole.Instance.Commands.AddCommand("Regions", true, - "set region flags", - "set region flags ", - "Set database flags for region", + MainConsole.Instance.Commands.AddCommand("General", true, + "show grid size", + "show grid size", + "Show the current grid size (excluding hyperlink references)", String.Empty, - HandleSetFlags); + HandleShowGridSize); + + MainConsole.Instance.Commands.AddCommand("Regions", true, + "set region flags", + "set region flags ", + "Set database flags for region", + String.Empty, + HandleSetFlags); } + + if (!suppressConsoleCommands) + SetExtraServiceURLs(config); + m_HypergridLinker = new HypergridLinker(m_config, this, m_Database); } } + private void SetExtraServiceURLs(IConfigSource config) + { + IConfig loginConfig = config.Configs["LoginService"]; + IConfig gridConfig = config.Configs["GridService"]; + + if (loginConfig == null || gridConfig == null) + return; + + string configVal; + + configVal = loginConfig.GetString("SearchURL", string.Empty); + if (!string.IsNullOrEmpty(configVal)) + m_ExtraFeatures["search-server-url"] = configVal; + + configVal = loginConfig.GetString("MapTileURL", string.Empty); + if (!string.IsNullOrEmpty(configVal)) + { + // This URL must end with '/', the viewer doesn't check + configVal = configVal.Trim(); + if (!configVal.EndsWith("/")) + configVal = configVal + "/"; + m_ExtraFeatures["map-server-url"] = configVal; + } + + configVal = loginConfig.GetString("DestinationGuide", string.Empty); + if (!string.IsNullOrEmpty(configVal)) + m_ExtraFeatures["destination-guide-url"] = configVal; + + configVal = Util.GetConfigVarFromSections( + config, "GatekeeperURI", new string[] { "Startup", "Hypergrid" }, String.Empty); + if (!string.IsNullOrEmpty(configVal)) + m_ExtraFeatures["GridURL"] = configVal; + + configVal = Util.GetConfigVarFromSections( + config, "GridName", new string[] { "Const", "Hypergrid" }, String.Empty); + if (string.IsNullOrEmpty(configVal)) + configVal = Util.GetConfigVarFromSections( + config, "gridname", new string[] { "GridInfo" }, String.Empty); + if (!string.IsNullOrEmpty(configVal)) + m_ExtraFeatures["GridName"] = configVal; + + m_ExtraFeatures["ExportSupported"] = gridConfig.GetString("ExportSupported", "true"); + } + #region IGridService public string RegisterRegion(UUID scopeID, GridRegion regionInfos) @@ -137,12 +201,19 @@ namespace OpenSim.Services.GridService if (regionInfos.RegionID == UUID.Zero) return "Invalid RegionID - cannot be zero UUID"; - RegionData region = m_Database.Get(regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID); - if ((region != null) && (region.RegionID != regionInfos.RegionID)) + String reason = "Region overlaps another region"; + RegionData region = FindAnyConflictingRegion(regionInfos, scopeID, out reason); + // If there is a conflicting region, if it has the same ID and same coordinates + // then it is a region re-registering (permissions and ownership checked later). + if ((region != null) + && ( (region.coordX != regionInfos.RegionCoordX) + || (region.coordY != regionInfos.RegionCoordY) + || (region.RegionID != regionInfos.RegionID) ) + ) { - m_log.WarnFormat("[GRID SERVICE]: Region {0} tried to register in coordinates {1}, {2} which are already in use in scope {3}.", - regionInfos.RegionID, regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID); - return "Region overlaps another region"; + // If not same ID and same coordinates, this new region has conflicts and can't be registered. + m_log.WarnFormat("{0} Register region conflict in scope {1}. {2}", LogHeader, scopeID, reason); + return reason; } if (region != null) @@ -185,15 +256,15 @@ namespace OpenSim.Services.GridService if (!m_AllowDuplicateNames) { - List dupe = m_Database.Get(regionInfos.RegionName, scopeID); + List dupe = m_Database.Get(Util.EscapeForLike(regionInfos.RegionName), scopeID); if (dupe != null && dupe.Count > 0) { foreach (RegionData d in dupe) { if (d.RegionID != regionInfos.RegionID) { - m_log.WarnFormat("[GRID SERVICE]: Region {0} tried to register duplicate name with ID {1}.", - regionInfos.RegionName, regionInfos.RegionID); + m_log.WarnFormat("[GRID SERVICE]: Region tried to register using a duplicate name. New region: {0} ({1}), existing region: {2} ({3}).", + regionInfos.RegionName, regionInfos.RegionID, d.RegionName, d.RegionID); return "Duplicate region name"; } } @@ -265,12 +336,121 @@ namespace OpenSim.Services.GridService m_log.DebugFormat("[GRID SERVICE]: Database exception: {0}", e); } - m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) registered successfully at {2}-{3}", - regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionCoordX, regionInfos.RegionCoordY); + m_log.InfoFormat + ("[GRID SERVICE]: Region {0} ({1}, {2}x{3}) registered at {4},{5} with flags {6}", + regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionSizeX, regionInfos.RegionSizeY, + regionInfos.RegionCoordX, regionInfos.RegionCoordY, + (OpenSim.Framework.RegionFlags)flags); return String.Empty; } + /// + /// Search the region map for regions conflicting with this region. + /// The region to be added is passed and we look for any existing regions that are + /// in the requested location, that are large varregions that overlap this region, or + /// are previously defined regions that would lie under this new region. + /// + /// Information on region requested to be added to the world map + /// Grid id for region + /// The reason the returned region conflicts with passed region + /// + private RegionData FindAnyConflictingRegion(GridRegion regionInfos, UUID scopeID, out string reason) + { + reason = "Reregistration"; + // First see if there is an existing region right where this region is trying to go + // (We keep this result so it can be returned if suppressing errors) + RegionData noErrorRegion = m_Database.Get(regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID); + RegionData region = noErrorRegion; + if (region != null + && region.RegionID == regionInfos.RegionID + && region.sizeX == regionInfos.RegionSizeX + && region.sizeY == regionInfos.RegionSizeY) + { + // If this seems to be exactly the same region, return this as it could be + // a re-registration (permissions checked by calling routine). + m_log.DebugFormat("{0} FindAnyConflictingRegion: re-register of {1}", + LogHeader, RegionString(regionInfos)); + return region; + } + + // No region exactly there or we're resizing an existing region. + // Fetch regions that could be varregions overlapping requested location. + int xmin = regionInfos.RegionLocX - (int)Constants.MaximumRegionSize + 10; + int xmax = regionInfos.RegionLocX; + int ymin = regionInfos.RegionLocY - (int)Constants.MaximumRegionSize + 10; + int ymax = regionInfos.RegionLocY; + List rdatas = m_Database.Get(xmin, ymin, xmax, ymax, scopeID); + foreach (RegionData rdata in rdatas) + { + // m_log.DebugFormat("{0} FindAnyConflictingRegion: find existing. Checking {1}", LogHeader, RegionString(rdata) ); + if ( (rdata.posX + rdata.sizeX > regionInfos.RegionLocX) + && (rdata.posY + rdata.sizeY > regionInfos.RegionLocY) ) + { + region = rdata; + m_log.WarnFormat("{0} FindAnyConflictingRegion: conflict of {1} by existing varregion {2}", + LogHeader, RegionString(regionInfos), RegionString(region)); + reason = String.Format("Region location is overlapped by existing varregion {0}", + RegionString(region)); + + if (m_SuppressVarregionOverlapCheckOnRegistration) + region = noErrorRegion; + return region; + } + } + + // There isn't a region that overlaps this potential region. + // See if this potential region overlaps an existing region. + // First, a shortcut of not looking for overlap if new region is legacy region sized + // and connot overlap anything. + if (regionInfos.RegionSizeX != Constants.RegionSize + || regionInfos.RegionSizeY != Constants.RegionSize) + { + // trim range looked for so we don't pick up neighbor regions just off the edges + xmin = regionInfos.RegionLocX; + xmax = regionInfos.RegionLocX + regionInfos.RegionSizeX - 10; + ymin = regionInfos.RegionLocY; + ymax = regionInfos.RegionLocY + regionInfos.RegionSizeY - 10; + rdatas = m_Database.Get(xmin, ymin, xmax, ymax, scopeID); + + // If the region is being resized, the found region could be ourself. + foreach (RegionData rdata in rdatas) + { + // m_log.DebugFormat("{0} FindAnyConflictingRegion: see if overlap. Checking {1}", LogHeader, RegionString(rdata) ); + if (region == null || region.RegionID != regionInfos.RegionID) + { + region = rdata; + m_log.WarnFormat("{0} FindAnyConflictingRegion: conflict of varregion {1} overlaps existing region {2}", + LogHeader, RegionString(regionInfos), RegionString(region)); + reason = String.Format("Region {0} would overlap existing region {1}", + RegionString(regionInfos), RegionString(region)); + + if (m_SuppressVarregionOverlapCheckOnRegistration) + region = noErrorRegion; + return region; + } + } + } + + // If we get here, region is either null (nothing found here) or + // is the non-conflicting region found at the location being requested. + return region; + } + + // String describing name and region location of passed region + private String RegionString(RegionData reg) + { + return String.Format("{0}/{1} at <{2},{3}>", + reg.RegionName, reg.RegionID, reg.coordX, reg.coordY); + } + + // String describing name and region location of passed region + private String RegionString(GridRegion reg) + { + return String.Format("{0}/{1} at <{2},{3}>", + reg.RegionName, reg.RegionID, reg.RegionCoordX, reg.RegionCoordY); + } + public bool DeregisterRegion(UUID regionID) { RegionData region = m_Database.Get(regionID, UUID.Zero); @@ -312,8 +492,10 @@ namespace OpenSim.Services.GridService if (region != null) { // Not really? Maybe? - List rdatas = m_Database.Get(region.posX - (int)Constants.RegionSize - 1, region.posY - (int)Constants.RegionSize - 1, - region.posX + (int)Constants.RegionSize + 1, region.posY + (int)Constants.RegionSize + 1, scopeID); + // The adjacent regions are presumed to be the same size as the current region + List rdatas = m_Database.Get( + region.posX - region.sizeX - 1, region.posY - region.sizeY - 1, + region.posX + region.sizeX + 1, region.posY + region.sizeY + 1, scopeID); foreach (RegionData rdata in rdatas) { @@ -325,7 +507,11 @@ namespace OpenSim.Services.GridService } } -// m_log.DebugFormat("[GRID SERVICE]: region {0} has {1} neighbours", region.RegionName, rinfos.Count); + // string rNames = ""; + // foreach (GridRegion gr in rinfos) + // rNames += gr.RegionName + ","; + // m_log.DebugFormat("{0} region {1} has {2} neighbours ({3})", + // LogHeader, region.RegionName, rinfos.Count, rNames); } else { @@ -346,20 +532,36 @@ namespace OpenSim.Services.GridService return null; } + // Get a region given its base coordinates. + // NOTE: this is NOT 'get a region by some point in the region'. The coordinate MUST + // be the base coordinate of the region. + // The snapping is technically unnecessary but is harmless because regions are always + // multiples of the legacy region size (256). public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) { - int snapX = (int)(x / Constants.RegionSize) * (int)Constants.RegionSize; - int snapY = (int)(y / Constants.RegionSize) * (int)Constants.RegionSize; + uint regionX = Util.WorldToRegionLoc((uint)x); + uint regionY = Util.WorldToRegionLoc((uint)y); + int snapX = (int)Util.RegionToWorldLoc(regionX); + int snapY = (int)Util.RegionToWorldLoc(regionY); + RegionData rdata = m_Database.Get(snapX, snapY, scopeID); if (rdata != null) + { + m_log.DebugFormat("{0} GetRegionByPosition. Found region {1} in database. Pos=<{2},{3}>", + LogHeader, rdata.RegionName, regionX, regionY); return RegionData2RegionInfo(rdata); - - return null; + } + else + { + m_log.DebugFormat("{0} GetRegionByPosition. Did not find region in database. Pos=<{1},{2}>", + LogHeader, regionX, regionY); + return null; + } } public GridRegion GetRegionByName(UUID scopeID, string name) { - List rdatas = m_Database.Get(name, scopeID); + List rdatas = m_Database.Get(Util.EscapeForLike(name), scopeID); if ((rdatas != null) && (rdatas.Count > 0)) return RegionData2RegionInfo(rdatas[0]); // get the first @@ -377,7 +579,7 @@ namespace OpenSim.Services.GridService { // m_log.DebugFormat("[GRID SERVICE]: GetRegionsByName {0}", name); - List rdatas = m_Database.Get(name + "%", scopeID); + List rdatas = m_Database.Get(Util.EscapeForLike(name) + "%", scopeID); int count = 0; List rinfos = new List(); @@ -440,6 +642,8 @@ namespace OpenSim.Services.GridService RegionData rdata = new RegionData(); rdata.posX = (int)rinfo.RegionLocX; rdata.posY = (int)rinfo.RegionLocY; + rdata.sizeX = rinfo.RegionSizeX; + rdata.sizeY = rinfo.RegionSizeY; rdata.RegionID = rinfo.RegionID; rdata.RegionName = rinfo.RegionName; rdata.Data = rinfo.ToKeyValuePairs(); @@ -453,6 +657,8 @@ namespace OpenSim.Services.GridService GridRegion rinfo = new GridRegion(rdata.Data); rinfo.RegionLocX = rdata.posX; rinfo.RegionLocY = rdata.posY; + rinfo.RegionSizeX = rdata.sizeX; + rinfo.RegionSizeY = rdata.sizeY; rinfo.RegionID = rdata.RegionID; rinfo.RegionName = rdata.RegionName; rinfo.ScopeID = rdata.ScopeID; @@ -478,6 +684,33 @@ namespace OpenSim.Services.GridService return ret; } + public List GetDefaultHypergridRegions(UUID scopeID) + { + List ret = new List(); + + List regions = m_Database.GetDefaultHypergridRegions(scopeID); + + foreach (RegionData r in regions) + { + if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0) + ret.Add(RegionData2RegionInfo(r)); + } + + int hgDefaultRegionsFoundOnline = regions.Count; + + // For now, hypergrid default regions will always be given precedence but we will also return simple default + // regions in case no specific hypergrid regions are specified. + ret.AddRange(GetDefaultRegions(scopeID)); + + int normalDefaultRegionsFoundOnline = ret.Count - hgDefaultRegionsFoundOnline; + + m_log.DebugFormat( + "[GRID SERVICE]: GetDefaultHypergridRegions returning {0} hypergrid default and {1} normal default regions", + hgDefaultRegionsFoundOnline, normalDefaultRegionsFoundOnline); + + return ret; + } + public List GetFallbackRegions(UUID scopeID, int x, int y) { List ret = new List(); @@ -526,40 +759,41 @@ namespace OpenSim.Services.GridService private void HandleDeregisterRegion(string module, string[] cmd) { - if (cmd.Length != 4) + if (cmd.Length < 4) { - MainConsole.Instance.Output("Syntax: degregister region id "); + MainConsole.Instance.Output("Usage: degregister region id +"); return; } - string rawRegionUuid = cmd[3]; - UUID regionUuid; - - if (!UUID.TryParse(rawRegionUuid, out regionUuid)) + for (int i = 3; i < cmd.Length; i++) { - MainConsole.Instance.OutputFormat("{0} is not a valid region uuid", rawRegionUuid); - return; - } + string rawRegionUuid = cmd[i]; + UUID regionUuid; - GridRegion region = GetRegionByUUID(UUID.Zero, regionUuid); + if (!UUID.TryParse(rawRegionUuid, out regionUuid)) + { + MainConsole.Instance.OutputFormat("{0} is not a valid region uuid", rawRegionUuid); + return; + } - if (region == null) - { - MainConsole.Instance.OutputFormat("No region with UUID {0}", regionUuid); - return; - } + GridRegion region = GetRegionByUUID(UUID.Zero, regionUuid); - if (DeregisterRegion(regionUuid)) - { - MainConsole.Instance.OutputFormat("Deregistered {0} {1}", region.RegionName, regionUuid); - } - else - { - // I don't think this can ever occur if we know that the region exists. - MainConsole.Instance.OutputFormat("Error deregistering {0} {1}", region.RegionName, regionUuid); - } + if (region == null) + { + MainConsole.Instance.OutputFormat("No region with UUID {0}", regionUuid); + return; + } - return; + if (DeregisterRegion(regionUuid)) + { + MainConsole.Instance.OutputFormat("Deregistered {0} {1}", region.RegionName, regionUuid); + } + else + { + // I don't think this can ever occur if we know that the region exists. + MainConsole.Instance.OutputFormat("Error deregistering {0} {1}", region.RegionName, regionUuid); + } + } } private void HandleShowRegions(string module, string[] cmd) @@ -575,6 +809,27 @@ namespace OpenSim.Services.GridService OutputRegionsToConsoleSummary(regions); } + private void HandleShowGridSize(string module, string[] cmd) + { + List regions = m_Database.Get(int.MinValue, int.MinValue, int.MaxValue, int.MaxValue, UUID.Zero); + + double size = 0; + + foreach (RegionData region in regions) + { + int flags = Convert.ToInt32(region.Data["flags"]); + + if ((flags & (int)Framework.RegionFlags.Hyperlink) == 0) + size += region.sizeX * region.sizeY; + } + + MainConsole.Instance.Output("This is a very rough approximation."); + MainConsole.Instance.Output("Although it will not count regions that are actually links to others over the Hypergrid, "); + MainConsole.Instance.Output("it will count regions that are inactive but were not deregistered from the grid service"); + MainConsole.Instance.Output("(e.g. simulator crashed rather than shutting down cleanly).\n"); + + MainConsole.Instance.OutputFormat("Grid size: {0} km squared.", size / 1000000); + } private void HandleShowRegion(string module, string[] cmd) { @@ -586,7 +841,7 @@ namespace OpenSim.Services.GridService string regionName = cmd[3]; - List regions = m_Database.Get(regionName, UUID.Zero); + List regions = m_Database.Get(Util.EscapeForLike(regionName), UUID.Zero); if (regions == null || regions.Count < 1) { MainConsole.Instance.Output("No region with name {0} found", regionName); @@ -604,20 +859,20 @@ namespace OpenSim.Services.GridService return; } - int x, y; - if (!int.TryParse(cmd[3], out x)) + uint x, y; + if (!uint.TryParse(cmd[3], out x)) { MainConsole.Instance.Output("x-coord must be an integer"); return; } - if (!int.TryParse(cmd[4], out y)) + if (!uint.TryParse(cmd[4], out y)) { MainConsole.Instance.Output("y-coord must be an integer"); return; } - RegionData region = m_Database.Get(x * (int)Constants.RegionSize, y * (int)Constants.RegionSize, UUID.Zero); + RegionData region = m_Database.Get((int)Util.RegionToWorldLoc(x), (int)Util.RegionToWorldLoc(y), UUID.Zero); if (region == null) { MainConsole.Instance.OutputFormat("No region found at {0},{1}", x, y); @@ -634,7 +889,8 @@ namespace OpenSim.Services.GridService ConsoleDisplayList dispList = new ConsoleDisplayList(); dispList.AddRow("Region Name", r.RegionName); dispList.AddRow("Region ID", r.RegionID); - dispList.AddRow("Location", string.Format("{0},{1}", r.coordX, r.coordY)); + dispList.AddRow("Position", string.Format("{0},{1}", r.coordX, r.coordY)); + dispList.AddRow("Size", string.Format("{0}x{1}", r.sizeX, r.sizeY)); dispList.AddRow("URI", r.Data["serverURI"]); dispList.AddRow("Owner ID", r.Data["owner_uuid"]); dispList.AddRow("Flags", flags); @@ -651,10 +907,10 @@ namespace OpenSim.Services.GridService private void OutputRegionsToConsoleSummary(List regions) { ConsoleDisplayTable dispTable = new ConsoleDisplayTable(); - dispTable.AddColumn("Name", 16); + dispTable.AddColumn("Name", 44); dispTable.AddColumn("ID", 36); dispTable.AddColumn("Position", 11); - dispTable.AddColumn("Owner ID", 36); + dispTable.AddColumn("Size", 11); dispTable.AddColumn("Flags", 60); foreach (RegionData r in regions) @@ -664,7 +920,7 @@ namespace OpenSim.Services.GridService r.RegionName, r.RegionID.ToString(), string.Format("{0},{1}", r.coordX, r.coordY), - r.Data["owner_uuid"].ToString(), + string.Format("{0}x{1}", r.sizeX, r.sizeY), flags.ToString()); } @@ -716,7 +972,7 @@ namespace OpenSim.Services.GridService return; } - List regions = m_Database.Get(cmd[3], UUID.Zero); + List regions = m_Database.Get(Util.EscapeForLike(cmd[3]), UUID.Zero); if (regions == null || regions.Count < 1) { MainConsole.Instance.Output("Region not found"); @@ -734,5 +990,18 @@ namespace OpenSim.Services.GridService m_Database.Store(r); } } + + /// + /// Gets the grid extra service URls we wish for the region to send in OpenSimExtras to dynamically refresh + /// parameters in the viewer used to access services like map, search and destination guides. + /// see "SimulatorFeaturesModule" + /// + /// + /// The grid extra service URls. + /// + public Dictionary GetExtraFeatures() + { + return m_ExtraFeatures; + } } } diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs index 7abed20..9d016fc 100644 --- a/OpenSim/Services/GridService/HypergridLinker.cs +++ b/OpenSim/Services/GridService/HypergridLinker.cs @@ -47,7 +47,7 @@ using OpenMetaverse; namespace OpenSim.Services.GridService { - public class HypergridLinker + public class HypergridLinker : IHypergridLinker { private static readonly ILog m_log = LogManager.GetLogger( @@ -63,14 +63,11 @@ namespace OpenSim.Services.GridService protected GatekeeperServiceConnector m_GatekeeperConnector; protected UUID m_ScopeID = UUID.Zero; +// protected bool m_Check4096 = true; protected string m_MapTileDirectory = string.Empty; protected string m_ThisGatekeeper = string.Empty; protected Uri m_ThisGatekeeperURI = null; - // Hyperlink regions are hyperlinks on the map - public readonly Dictionary m_HyperlinkRegions = new Dictionary(); - protected Dictionary m_HyperlinkHandles = new Dictionary(); - protected GridRegion m_DefaultRegion; protected GridRegion DefaultRegion { @@ -78,7 +75,7 @@ namespace OpenSim.Services.GridService { if (m_DefaultRegion == null) { - List defs = m_GridService.GetDefaultRegions(m_ScopeID); + List defs = m_GridService.GetDefaultHypergridRegions(m_ScopeID); if (defs != null && defs.Count > 0) m_DefaultRegion = defs[0]; else @@ -123,9 +120,14 @@ namespace OpenSim.Services.GridService if (scope != string.Empty) UUID.TryParse(scope, out m_ScopeID); +// m_Check4096 = gridConfig.GetBoolean("Check4096", true); + m_MapTileDirectory = gridConfig.GetString("MapTileDirectory", "maptiles"); - m_ThisGatekeeper = gridConfig.GetString("Gatekeeper", string.Empty); + m_ThisGatekeeper = Util.GetConfigVarFromSections(config, "GatekeeperURI", + new string[] { "Startup", "Hypergrid", "GridService" }, String.Empty); + // Legacy. Remove soon! + m_ThisGatekeeper = gridConfig.GetString("Gatekeeper", m_ThisGatekeeper); try { m_ThisGatekeeperURI = new Uri(m_ThisGatekeeper); @@ -154,18 +156,18 @@ namespace OpenSim.Services.GridService if (MainConsole.Instance != null) { - MainConsole.Instance.Commands.AddCommand("hypergrid", false, "link-region", + MainConsole.Instance.Commands.AddCommand("Hypergrid", false, "link-region", "link-region []", "Link a HyperGrid Region. Examples for : http://grid.net:8002/ or http://example.org/path/foo.php", RunCommand); - MainConsole.Instance.Commands.AddCommand("hypergrid", false, "link-region", + MainConsole.Instance.Commands.AddCommand("Hypergrid", false, "link-region", "link-region []", "Link a hypergrid region (deprecated)", RunCommand); - MainConsole.Instance.Commands.AddCommand("hypergrid", false, "unlink-region", + MainConsole.Instance.Commands.AddCommand("Hypergrid", false, "unlink-region", "unlink-region ", "Unlink a hypergrid region", RunCommand); - MainConsole.Instance.Commands.AddCommand("hypergrid", false, "link-mapping", "link-mapping [ ]", + MainConsole.Instance.Commands.AddCommand("Hypergrid", false, "link-mapping", "link-mapping [ ]", "Set local coordinate to map HG regions to", RunCommand); - MainConsole.Instance.Commands.AddCommand("hypergrid", false, "show hyperlinks", "show hyperlinks", + MainConsole.Instance.Commands.AddCommand("Hypergrid", false, "show hyperlinks", "show hyperlinks", "List the HG regions", HandleShow); } } @@ -177,14 +179,14 @@ namespace OpenSim.Services.GridService public GridRegion LinkRegion(UUID scopeID, string regionDescriptor) { string reason = string.Empty; - int xloc = random.Next(0, Int16.MaxValue) * (int)Constants.RegionSize; - return TryLinkRegionToCoords(scopeID, regionDescriptor, xloc, 0, out reason); + uint xloc = Util.RegionToWorldLoc((uint)random.Next(0, Int16.MaxValue)); + return TryLinkRegionToCoords(scopeID, regionDescriptor, (int)xloc, 0, out reason); } private static Random random = new Random(); // From the command line link-region (obsolete) and the map - public GridRegion TryLinkRegionToCoords(UUID scopeID, string mapName, int xloc, int yloc, out string reason) + private GridRegion TryLinkRegionToCoords(UUID scopeID, string mapName, int xloc, int yloc, out string reason) { return TryLinkRegionToCoords(scopeID, mapName, xloc, yloc, UUID.Zero, out reason); } @@ -194,24 +196,36 @@ namespace OpenSim.Services.GridService reason = string.Empty; GridRegion regInfo = null; + mapName = mapName.Trim(); + if (!mapName.StartsWith("http")) { - string host = "127.0.0.1"; - string portstr; + // Formats: grid.example.com:8002:region name + // grid.example.com:region name + // grid.example.com:8002 + // grid.example.com + + string host; + uint port = 80; string regionName = ""; - uint port = 0; + string[] parts = mapName.Split(new char[] { ':' }); - if (parts.Length >= 1) + + if (parts.Length == 0) { - host = parts[0]; + reason = "Wrong format for link-region"; + return null; } + + host = parts[0]; + if (parts.Length >= 2) { - portstr = parts[1]; - //m_log.Debug("-- port = " + portstr); - if (!UInt32.TryParse(portstr, out port)) + // If it's a number then assume it's a port. Otherwise, it's a region name. + if (!UInt32.TryParse(parts[1], out port)) regionName = parts[1]; } + // always take the last one if (parts.Length >= 3) { @@ -228,14 +242,30 @@ namespace OpenSim.Services.GridService } else { - string[] parts = mapName.Split(new char[] {' '}); - string regionName = String.Empty; - if (parts.Length > 1) + // Formats: http://grid.example.com region name + // http://grid.example.com "region name" + // http://grid.example.com + + string serverURI; + string regionName = ""; + + string[] parts = mapName.Split(new char[] { ' ' }); + + if (parts.Length == 0) { - regionName = mapName.Substring(parts[0].Length + 1); - regionName = regionName.Trim(new char[] {'"'}); + reason = "Wrong format for link-region"; + return null; } - if (TryCreateLink(scopeID, xloc, yloc, regionName, 0, null, parts[0], ownerID, out regInfo, out reason)) + + serverURI = parts[0]; + + if (parts.Length >= 2) + { + regionName = mapName.Substring(serverURI.Length); + regionName = regionName.Trim(new char[] { '"', ' ' }); + } + + if (TryCreateLink(scopeID, xloc, yloc, regionName, 0, null, serverURI, ownerID, out regInfo, out reason)) { regInfo.RegionName = mapName; return regInfo; @@ -244,31 +274,39 @@ namespace OpenSim.Services.GridService return null; } - - public bool TryCreateLink(UUID scopeID, int xloc, int yloc, string remoteRegionName, uint externalPort, string externalHostName, UUID ownerID, out GridRegion regInfo, out string reason) + + private bool TryCreateLink(UUID scopeID, int xloc, int yloc, string remoteRegionName, uint externalPort, string externalHostName, UUID ownerID, out GridRegion regInfo, out string reason) { return TryCreateLink(scopeID, xloc, yloc, remoteRegionName, externalPort, externalHostName, null, ownerID, out regInfo, out reason); } - - public bool TryCreateLink(UUID scopeID, int xloc, int yloc, string remoteRegionName, uint externalPort, string externalHostName, string serverURI, UUID ownerID, out GridRegion regInfo, out string reason) + + private bool TryCreateLink(UUID scopeID, int xloc, int yloc, string remoteRegionName, uint externalPort, string externalHostName, string serverURI, UUID ownerID, out GridRegion regInfo, out string reason) { - m_log.DebugFormat("[HYPERGRID LINKER]: Link to {0} {1}, in {2}-{3}", + lock (this) + { + return TryCreateLinkImpl(scopeID, xloc, yloc, remoteRegionName, externalPort, externalHostName, serverURI, ownerID, out regInfo, out reason); + } + } + + private bool TryCreateLinkImpl(UUID scopeID, int xloc, int yloc, string remoteRegionName, uint externalPort, string externalHostName, string serverURI, UUID ownerID, out GridRegion regInfo, out string reason) + { + m_log.InfoFormat("[HYPERGRID LINKER]: Link to {0} {1}, in <{2},{3}>", ((serverURI == null) ? (externalHostName + ":" + externalPort) : serverURI), - remoteRegionName, xloc / Constants.RegionSize, yloc / Constants.RegionSize); + remoteRegionName, Util.WorldToRegionLoc((uint)xloc), Util.WorldToRegionLoc((uint)yloc)); reason = string.Empty; Uri uri = null; regInfo = new GridRegion(); - if ( externalPort > 0) + if (externalPort > 0) regInfo.HttpPort = externalPort; else - regInfo.HttpPort = 0; - if ( externalHostName != null) + regInfo.HttpPort = 80; + if (externalHostName != null) regInfo.ExternalHostName = externalHostName; else regInfo.ExternalHostName = "0.0.0.0"; - if ( serverURI != null) + if (serverURI != null) { regInfo.ServerURI = serverURI; try @@ -280,7 +318,7 @@ namespace OpenSim.Services.GridService catch {} } - if ( remoteRegionName != string.Empty ) + if (remoteRegionName != string.Empty) regInfo.RegionName = remoteRegionName; regInfo.RegionLocX = xloc; @@ -293,6 +331,7 @@ namespace OpenSim.Services.GridService { if (regInfo.ExternalHostName == m_ThisGatekeeperURI.Host && regInfo.HttpPort == m_ThisGatekeeperURI.Port) { + m_log.InfoFormat("[HYPERGRID LINKER]: Cannot hyperlink to regions on the same grid"); reason = "Cannot hyperlink to regions on the same grid"; return false; } @@ -304,8 +343,8 @@ namespace OpenSim.Services.GridService GridRegion region = m_GridService.GetRegionByPosition(regInfo.ScopeID, regInfo.RegionLocX, regInfo.RegionLocY); if (region != null) { - m_log.WarnFormat("[HYPERGRID LINKER]: Coordinates {0}-{1} are already occupied by region {2} with uuid {3}", - regInfo.RegionLocX / Constants.RegionSize, regInfo.RegionLocY / Constants.RegionSize, + m_log.WarnFormat("[HYPERGRID LINKER]: Coordinates <{0},{1}> are already occupied by region {2} with uuid {3}", + Util.WorldToRegionLoc((uint)regInfo.RegionLocX), Util.WorldToRegionLoc((uint)regInfo.RegionLocY), region.RegionName, region.RegionID); reason = "Coordinates are already in use"; return false; @@ -340,12 +379,25 @@ namespace OpenSim.Services.GridService region = m_GridService.GetRegionByUUID(scopeID, regionID); if (region != null) { - m_log.DebugFormat("[HYPERGRID LINKER]: Region already exists in coordinates {0} {1}", - region.RegionLocX / Constants.RegionSize, region.RegionLocY / Constants.RegionSize); + m_log.DebugFormat("[HYPERGRID LINKER]: Region already exists in coordinates <{0},{1}>", + Util.WorldToRegionLoc((uint)region.RegionLocX), Util.WorldToRegionLoc((uint)region.RegionLocY)); regInfo = region; return true; } + // We are now performing this check for each individual teleport in the EntityTransferModule instead. This + // allows us to give better feedback when teleports fail because of the distance reason (which can't be + // done here) and it also hypergrid teleports that are within range (possibly because the source grid + // itself has regions that are very far apart). +// uint x, y; +// if (m_Check4096 && !Check4096(handle, out x, out y)) +// { +// //RemoveHyperlinkRegion(regInfo.RegionID); +// reason = "Region is too far (" + x + ", " + y + ")"; +// m_log.Info("[HYPERGRID LINKER]: Unable to link, region is too far (" + x + ", " + y + ")"); +// //return false; +// } + regInfo.RegionID = regionID; if (externalName == string.Empty) @@ -362,7 +414,8 @@ namespace OpenSim.Services.GridService regInfo.RegionSecret = handle.ToString(); AddHyperlinkRegion(regInfo, handle); - m_log.InfoFormat("[HYPERGRID LINKER]: Successfully linked to region {0} with image {1}", regInfo.RegionName, regInfo.TerrainImage); + m_log.InfoFormat("[HYPERGRID LINKER]: Successfully linked to region {0} at <{1},{2}> with image {3}", + regInfo.RegionName, Util.WorldToRegionLoc((uint)regInfo.RegionLocX), Util.WorldToRegionLoc((uint)regInfo.RegionLocY), regInfo.TerrainImage); return true; } @@ -371,7 +424,7 @@ namespace OpenSim.Services.GridService m_log.DebugFormat("[HYPERGRID LINKER]: Request to unlink {0}", mapName); GridRegion regInfo = null; - List regions = m_Database.Get(mapName, m_ScopeID); + List regions = m_Database.Get(Util.EscapeForLike(mapName), m_ScopeID); if (regions != null && regions.Count > 0) { OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]); @@ -395,6 +448,52 @@ namespace OpenSim.Services.GridService } } +// Not currently used +// /// +// /// Cope with this viewer limitation. +// /// +// /// +// /// +// public bool Check4096(ulong realHandle, out uint x, out uint y) +// { +// uint ux = 0, uy = 0; +// Utils.LongToUInts(realHandle, out ux, out uy); +// x = Util.WorldToRegionLoc(ux); +// y = Util.WorldToRegionLoc(uy); +// +// const uint limit = Util.RegionToWorldLoc(4096 - 1); +// uint xmin = ux - limit; +// uint xmax = ux + limit; +// uint ymin = uy - limit; +// uint ymax = uy + limit; +// // World map boundary checks +// if (xmin < 0 || xmin > ux) +// xmin = 0; +// if (xmax > int.MaxValue || xmax < ux) +// xmax = int.MaxValue; +// if (ymin < 0 || ymin > uy) +// ymin = 0; +// if (ymax > int.MaxValue || ymax < uy) +// ymax = int.MaxValue; +// +// // Check for any regions that are within the possible teleport range to the linked region +// List regions = m_GridService.GetRegionRange(m_ScopeID, (int)xmin, (int)xmax, (int)ymin, (int)ymax); +// if (regions.Count == 0) +// { +// return false; +// } +// else +// { +// // Check for regions which are not linked regions +// List hyperlinks = m_GridService.GetHyperlinks(m_ScopeID); +// IEnumerable availableRegions = regions.Except(hyperlinks); +// if (availableRegions.Count() == 0) +// return false; +// } +// +// return true; +// } + private void AddHyperlinkRegion(GridRegion regionInfo, ulong regionHandle) { RegionData rdata = m_GridService.RegionInfo2RegionData(regionInfo); @@ -437,9 +536,14 @@ namespace OpenSim.Services.GridService MainConsole.Instance.Output(new string('-', 72)); foreach (RegionData r in regions) { - MainConsole.Instance.Output(String.Format("{0}\n{2,-32} {1}\n", - r.RegionName, r.RegionID, String.Format("{0},{1} ({2},{3})", r.posX, r.posY, - r.posX / Constants.RegionSize, r.posY / Constants.RegionSize))); + MainConsole.Instance.Output( + String.Format("{0}\n{2,-32} {1}\n", + r.RegionName, r.RegionID, + String.Format("{0},{1} ({2},{3})", r.posX, r.posY, + Util.WorldToRegionLoc((uint)r.posX), Util.WorldToRegionLoc((uint)r.posY) + ) + ) + ); } return; } @@ -464,8 +568,8 @@ namespace OpenSim.Services.GridService int xloc, yloc; string serverURI; string remoteName = null; - xloc = Convert.ToInt32(cmdparams[0]) * (int)Constants.RegionSize; - yloc = Convert.ToInt32(cmdparams[1]) * (int)Constants.RegionSize; + xloc = (int)Util.RegionToWorldLoc((uint)Convert.ToInt32(cmdparams[0])); + yloc = (int)Util.RegionToWorldLoc((uint)Convert.ToInt32(cmdparams[1])); serverURI = cmdparams[2]; if (cmdparams.Length > 3) remoteName = string.Join(" ", cmdparams, 3, cmdparams.Length - 3); @@ -536,13 +640,13 @@ namespace OpenSim.Services.GridService { // old format GridRegion regInfo; - int xloc, yloc; + uint xloc, yloc; uint externalPort; string externalHostName; try { - xloc = Convert.ToInt32(cmdparams[0]); - yloc = Convert.ToInt32(cmdparams[1]); + xloc = Convert.ToUInt32(cmdparams[0]); + yloc = Convert.ToUInt32(cmdparams[1]); externalPort = Convert.ToUInt32(cmdparams[3]); externalHostName = cmdparams[2]; //internalPort = Convert.ToUInt32(cmdparams[4]); @@ -556,10 +660,11 @@ namespace OpenSim.Services.GridService } // Convert cell coordinates given by the user to meters - xloc = xloc * (int)Constants.RegionSize; - yloc = yloc * (int)Constants.RegionSize; + xloc = Util.RegionToWorldLoc(xloc); + yloc = Util.RegionToWorldLoc(yloc); string reason = string.Empty; - if (TryCreateLink(UUID.Zero, xloc, yloc, string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason)) + if (TryCreateLink(UUID.Zero, (int)xloc, (int)yloc, + string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason)) { // What is this? The GridRegion instance will be discarded anyway, // which effectively ignores any local name given with the command. @@ -639,13 +744,13 @@ namespace OpenSim.Services.GridService private void ReadLinkFromConfig(IConfig config) { GridRegion regInfo; - int xloc, yloc; + uint xloc, yloc; uint externalPort; string externalHostName; uint realXLoc, realYLoc; - xloc = Convert.ToInt32(config.GetString("xloc", "0")); - yloc = Convert.ToInt32(config.GetString("yloc", "0")); + xloc = Convert.ToUInt32(config.GetString("xloc", "0")); + yloc = Convert.ToUInt32(config.GetString("yloc", "0")); externalPort = Convert.ToUInt32(config.GetString("externalPort", "0")); externalHostName = config.GetString("externalHostName", ""); realXLoc = Convert.ToUInt32(config.GetString("real-xloc", "0")); @@ -653,18 +758,19 @@ namespace OpenSim.Services.GridService if (m_enableAutoMapping) { - xloc = (int)((xloc % 100) + m_autoMappingX); - yloc = (int)((yloc % 100) + m_autoMappingY); + xloc = (xloc % 100) + m_autoMappingX; + yloc = (yloc % 100) + m_autoMappingY; } if (((realXLoc == 0) && (realYLoc == 0)) || (((realXLoc - xloc < 3896) || (xloc - realXLoc < 3896)) && ((realYLoc - yloc < 3896) || (yloc - realYLoc < 3896)))) { - xloc = xloc * (int)Constants.RegionSize; - yloc = yloc * (int)Constants.RegionSize; + xloc = Util.RegionToWorldLoc(xloc); + yloc = Util.RegionToWorldLoc(yloc); string reason = string.Empty; - if (TryCreateLink(UUID.Zero, xloc, yloc, string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason)) + if (TryCreateLink(UUID.Zero, (int)xloc, (int)yloc, + string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason)) { regInfo.RegionName = config.GetString("localName", ""); } diff --git a/OpenSim/Services/GridService/Properties/AssemblyInfo.cs b/OpenSim/Services/GridService/Properties/AssemblyInfo.cs index 5c0c8f4..0841e5a 100644 --- a/OpenSim/Services/GridService/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/GridService/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs index 7b84d55..8e10125 100644 --- a/OpenSim/Services/HypergridService/GatekeeperService.cs +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -58,6 +58,7 @@ namespace OpenSim.Services.HypergridService private static IUserAgentService m_UserAgentService; private static ISimulationService m_SimulationService; private static IGridUserService m_GridUserService; + private static IBansService m_BansService; private static string m_AllowedClients = string.Empty; private static string m_DeniedClients = string.Empty; @@ -87,6 +88,7 @@ namespace OpenSim.Services.HypergridService string presenceService = serverConfig.GetString("PresenceService", String.Empty); string simulationService = serverConfig.GetString("SimulationService", String.Empty); string gridUserService = serverConfig.GetString("GridUserService", String.Empty); + string bansService = serverConfig.GetString("BansService", String.Empty); // These are mandatory, the others aren't if (gridService == string.Empty || presenceService == string.Empty) @@ -96,7 +98,9 @@ namespace OpenSim.Services.HypergridService UUID.TryParse(scope, out m_ScopeID); //m_WelcomeMessage = serverConfig.GetString("WelcomeMessage", "Welcome to OpenSim!"); m_AllowTeleportsToAnyRegion = serverConfig.GetBoolean("AllowTeleportsToAnyRegion", true); - m_ExternalName = serverConfig.GetString("ExternalName", string.Empty); + m_ExternalName = Util.GetConfigVarFromSections(config, "GatekeeperURI", + new string[] { "Startup", "Hypergrid", "GatekeeperService" }, String.Empty); + m_ExternalName = serverConfig.GetString("ExternalName", m_ExternalName); if (m_ExternalName != string.Empty && !m_ExternalName.EndsWith("/")) m_ExternalName = m_ExternalName + "/"; @@ -119,14 +123,19 @@ namespace OpenSim.Services.HypergridService m_UserAgentService = ServerUtils.LoadPlugin(homeUsersService, args); if (gridUserService != string.Empty) m_GridUserService = ServerUtils.LoadPlugin(gridUserService, args); + if (bansService != string.Empty) + m_BansService = ServerUtils.LoadPlugin(bansService, args); if (simService != null) m_SimulationService = simService; else if (simulationService != string.Empty) m_SimulationService = ServerUtils.LoadPlugin(simulationService, args); - m_AllowedClients = serverConfig.GetString("AllowedClients", string.Empty); - m_DeniedClients = serverConfig.GetString("DeniedClients", string.Empty); + string[] possibleAccessControlConfigSections = new string[] { "AccessControl", "GatekeeperService" }; + m_AllowedClients = Util.GetConfigVarFromSections( + config, "AllowedClients", possibleAccessControlConfigSections, string.Empty); + m_DeniedClients = Util.GetConfigVarFromSections( + config, "DeniedClients", possibleAccessControlConfigSections, string.Empty); m_ForeignAgentsAllowed = serverConfig.GetBoolean("ForeignAgentsAllowed", true); LoadDomainExceptionsFromConfig(serverConfig, "AllowExcept", m_ForeignsAllowedExceptions); @@ -165,7 +174,7 @@ namespace OpenSim.Services.HypergridService m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to link to {0}", (regionName == string.Empty)? "default region" : regionName); if (!m_AllowTeleportsToAnyRegion || regionName == string.Empty) { - List defs = m_GridService.GetDefaultRegions(m_ScopeID); + List defs = m_GridService.GetDefaultHypergridRegions(m_ScopeID); if (defs != null && defs.Count > 0) { region = defs[0]; @@ -198,41 +207,75 @@ namespace OpenSim.Services.HypergridService return true; } - public GridRegion GetHyperlinkRegion(UUID regionID) + public GridRegion GetHyperlinkRegion(UUID regionID, UUID agentID, string agentHomeURI, out string message) { - m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to get hyperlink region {0}", regionID); + message = null; if (!m_AllowTeleportsToAnyRegion) + { // Don't even check the given regionID + m_log.DebugFormat( + "[GATEKEEPER SERVICE]: Returning gateway region {0} {1} @ {2} to user {3}{4} as teleporting to arbitrary regions is not allowed.", + m_DefaultGatewayRegion.RegionName, + m_DefaultGatewayRegion.RegionID, + m_DefaultGatewayRegion.ServerURI, + agentID, + agentHomeURI == null ? "" : " @ " + agentHomeURI); + + message = "Teleporting to the default region."; return m_DefaultGatewayRegion; + } GridRegion region = m_GridService.GetRegionByUUID(m_ScopeID, regionID); + + if (region == null) + { + m_log.DebugFormat( + "[GATEKEEPER SERVICE]: Could not find region with ID {0} as requested by user {1}{2}. Returning null.", + regionID, agentID, (agentHomeURI == null) ? "" : " @ " + agentHomeURI); + + message = "The teleport destination could not be found."; + return null; + } + + m_log.DebugFormat( + "[GATEKEEPER SERVICE]: Returning region {0} {1} @ {2} to user {3}{4}.", + region.RegionName, + region.RegionID, + region.ServerURI, + agentID, + agentHomeURI == null ? "" : " @ " + agentHomeURI); + return region; } #region Login Agent - public bool LoginAgent(AgentCircuitData aCircuit, GridRegion destination, out string reason) + public bool LoginAgent(GridRegion source, AgentCircuitData aCircuit, GridRegion destination, out string reason) { reason = string.Empty; string authURL = string.Empty; if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) authURL = aCircuit.ServiceURLs["HomeURI"].ToString(); - m_log.InfoFormat("[GATEKEEPER SERVICE]: Login request for {0} {1} @ {2} ({3}) at {4} using viewer {5}, channel {6}, IP {7}, Mac {8}, Id0 {9} Teleport Flags {10}", - aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionName, - aCircuit.Viewer, aCircuit.Channel, aCircuit.IPAddress, aCircuit.Mac, aCircuit.Id0, aCircuit.teleportFlags.ToString()); - + + m_log.InfoFormat("[GATEKEEPER SERVICE]: Login request for {0} {1} @ {2} ({3}) at {4} using viewer {5}, channel {6}, IP {7}, Mac {8}, Id0 {9}, Teleport Flags: {10}. From region {11}", + aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionID, + aCircuit.Viewer, aCircuit.Channel, aCircuit.IPAddress, aCircuit.Mac, aCircuit.Id0, (TeleportFlags)aCircuit.teleportFlags, + (source == null) ? "Unknown" : string.Format("{0} ({1}){2}", source.RegionName, source.RegionID, (source.RawServerURI == null) ? "" : " @ " + source.ServerURI)); + + string curViewer = Util.GetViewerName(aCircuit); + // // Check client // if (m_AllowedClients != string.Empty) { Regex arx = new Regex(m_AllowedClients); - Match am = arx.Match(aCircuit.Viewer); + Match am = arx.Match(curViewer); if (!am.Success) { - m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is not allowed", aCircuit.Viewer); + m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is not allowed", curViewer); return false; } } @@ -240,11 +283,11 @@ namespace OpenSim.Services.HypergridService if (m_DeniedClients != string.Empty) { Regex drx = new Regex(m_DeniedClients); - Match dm = drx.Match(aCircuit.Viewer); + Match dm = drx.Match(curViewer); if (dm.Success) { - m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is denied", aCircuit.Viewer); + m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is denied", curViewer); return false; } } @@ -285,17 +328,16 @@ namespace OpenSim.Services.HypergridService } } } - m_log.DebugFormat("[GATEKEEPER SERVICE]: User is ok"); // // Foreign agents allowed? Exceptions? // - if (account == null) + if (account == null) { bool allowed = m_ForeignAgentsAllowed; if (m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsAllowedExceptions)) - allowed = false; + allowed = false; if (!m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsDisallowedExceptions)) allowed = true; @@ -309,6 +351,20 @@ namespace OpenSim.Services.HypergridService } } + // + // Is the user banned? + // This uses a Ban service that's more powerful than the configs + // + string uui = (account != null ? aCircuit.AgentID.ToString() : Util.ProduceUserUniversalIdentifier(aCircuit)); + if (m_BansService != null && m_BansService.IsBanned(uui, aCircuit.IPAddress, aCircuit.Id0, authURL)) + { + reason = "You are banned from this world"; + m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: user {0} is banned", uui); + return false; + } + + m_log.DebugFormat("[GATEKEEPER SERVICE]: User {0} is ok", aCircuit.Name); + bool isFirstLogin = false; // // Login the presence, if it's not there yet (by the login service) @@ -326,7 +382,8 @@ namespace OpenSim.Services.HypergridService aCircuit.firstname, aCircuit.lastname); return false; } - m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence ok"); + + m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence {0} is ok", aCircuit.Name); // Also login foreigners with GridUser service if (m_GridUserService != null && account == null) @@ -357,7 +414,9 @@ namespace OpenSim.Services.HypergridService reason = "Destination region not found"; return false; } - m_log.DebugFormat("[GATEKEEPER SERVICE]: destination ok: {0}", destination.RegionName); + + m_log.DebugFormat( + "[GATEKEEPER SERVICE]: Destination {0} is ok for {1}", destination.RegionName, aCircuit.Name); // // Adjust the visible name @@ -374,7 +433,7 @@ namespace OpenSim.Services.HypergridService try { Uri uri = new Uri(aCircuit.ServiceURLs["HomeURI"].ToString()); - aCircuit.lastname = "@" + uri.Host; // + ":" + uri.Port; + aCircuit.lastname = "@" + uri.Authority; } catch { @@ -391,8 +450,16 @@ namespace OpenSim.Services.HypergridService // Preserve our TeleportFlags we have gathered so-far loginFlag |= (Constants.TeleportFlags) aCircuit.teleportFlags; - m_log.DebugFormat("[GATEKEEPER SERVICE]: launching agent {0}", loginFlag); - return m_SimulationService.CreateAgent(destination, aCircuit, (uint)loginFlag, out reason); + m_log.DebugFormat("[GATEKEEPER SERVICE]: Launching {0}, Teleport Flags: {1}", aCircuit.Name, loginFlag); + + EntityTransferContext ctx = new EntityTransferContext(); + + if (!m_SimulationService.QueryAccess( + destination, aCircuit.AgentID, aCircuit.ServiceURLs["HomeURI"].ToString(), + true, aCircuit.startpos, new List(), ctx, out reason)) + return false; + + return m_SimulationService.CreateAgent(source, destination, aCircuit, (uint)loginFlag, out reason); } protected bool Authenticate(AgentCircuitData aCircuit) @@ -400,6 +467,12 @@ namespace OpenSim.Services.HypergridService if (!CheckAddress(aCircuit.ServiceSessionID)) return false; + if (string.IsNullOrEmpty(aCircuit.IPAddress)) + { + m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide a client IP address."); + return false; + } + string userURL = string.Empty; if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) userURL = aCircuit.ServiceURLs["HomeURI"].ToString(); diff --git a/OpenSim/Services/HypergridService/HGAssetService.cs b/OpenSim/Services/HypergridService/HGAssetService.cs index 84dec8d..b83fb1e 100644 --- a/OpenSim/Services/HypergridService/HGAssetService.cs +++ b/OpenSim/Services/HypergridService/HGAssetService.cs @@ -76,10 +76,10 @@ namespace OpenSim.Services.HypergridService if (m_UserAccountService == null) throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll)); - // legacy configuration [obsolete] - m_HomeURL = assetConfig.GetString("ProfileServerURI", string.Empty); - // Preferred - m_HomeURL = assetConfig.GetString("HomeURI", m_HomeURL); + m_HomeURL = Util.GetConfigVarFromSections(config, "HomeURI", + new string[] { "Startup", "Hypergrid", configName }, string.Empty); + if (m_HomeURL == string.Empty) + throw new Exception("[HGAssetService] No HomeURI specified"); m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); @@ -100,7 +100,7 @@ namespace OpenSim.Services.HypergridService return null; if (asset.Metadata.Type == (sbyte)AssetType.Object) - asset.Data = AdjustIdentifiers(asset.Data); ; + asset.Data = AdjustIdentifiers(asset.Data); AdjustIdentifiers(asset.Metadata); @@ -129,6 +129,14 @@ namespace OpenSim.Services.HypergridService if (!m_AssetPerms.AllowedExport(asset.Type)) return null; + // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) + // Fix bad assets before sending them elsewhere + if (asset.Type == (int)AssetType.Object && asset.Data != null) + { + string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data)); + asset.Data = Utils.StringToBytes(xml); + } + return asset.Data; } @@ -139,6 +147,14 @@ namespace OpenSim.Services.HypergridService if (!m_AssetPerms.AllowedImport(asset.Type)) return string.Empty; + // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) + // Fix bad assets before storing on this server + if (asset.Type == (int)AssetType.Object && asset.Data != null) + { + string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data)); + asset.Data = Utils.StringToBytes(xml); + } + return base.Store(asset); } @@ -160,10 +176,16 @@ namespace OpenSim.Services.HypergridService meta.CreatorID = meta.CreatorID + ";" + m_HomeURL + "/" + creator.FirstName + " " + creator.LastName; } + // Only for Object protected byte[] AdjustIdentifiers(byte[] data) { string xml = Utils.BytesToString(data); - return Utils.StringToBytes(ExternalRepresentationUtils.RewriteSOP(xml, m_HomeURL, m_Cache, UUID.Zero)); + + // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) + // Fix bad assets before sending them elsewhere + xml = ExternalRepresentationUtils.SanitizeXml(xml); + + return Utils.StringToBytes(ExternalRepresentationUtils.RewriteSOP(xml, "HGAssetService", m_HomeURL, m_Cache, UUID.Zero)); } } diff --git a/OpenSim/Services/HypergridService/HGFSAssetService.cs b/OpenSim/Services/HypergridService/HGFSAssetService.cs new file mode 100644 index 0000000..54e8ccb --- /dev/null +++ b/OpenSim/Services/HypergridService/HGFSAssetService.cs @@ -0,0 +1,189 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Reflection; + +using Nini.Config; +using log4net; +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Framework.Serialization.External; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Services.FSAssetService; + +namespace OpenSim.Services.HypergridService +{ + /// + /// Hypergrid asset service. It serves the IAssetService interface, + /// but implements it in ways that are appropriate for inter-grid + /// asset exchanges. This version is for FSAssets. + /// + public class HGFSAssetService : FSAssetConnector, IAssetService + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private string m_HomeURL; + private IUserAccountService m_UserAccountService; + + private UserAccountCache m_Cache; + + private AssetPermissions m_AssetPerms; + + public HGFSAssetService(IConfigSource config, string configName) : base(config, "AssetService") + { + m_log.Debug("[HGAsset Service]: Starting in FSAsset mode"); + IConfig assetConfig = config.Configs[configName]; + if (assetConfig == null) + throw new Exception("No HGAssetService configuration"); + + string userAccountsDll = assetConfig.GetString("UserAccountsService", string.Empty); + if (userAccountsDll == string.Empty) + throw new Exception("Please specify UserAccountsService in HGAssetService configuration"); + + Object[] args = new Object[] { config }; + m_UserAccountService = ServerUtils.LoadPlugin(userAccountsDll, args); + if (m_UserAccountService == null) + throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll)); + + m_HomeURL = Util.GetConfigVarFromSections(config, "HomeURI", + new string[] { "Startup", "Hypergrid", configName }, string.Empty); + if (m_HomeURL == string.Empty) + throw new Exception("[HGAssetService] No HomeURI specified"); + + m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); + + // Permissions + m_AssetPerms = new AssetPermissions(assetConfig); + } + + #region IAssetService overrides + public override AssetBase Get(string id) + { + AssetBase asset = base.Get(id); + + if (asset == null) + return null; + + if (!m_AssetPerms.AllowedExport(asset.Type)) + return null; + + if (asset.Metadata.Type == (sbyte)AssetType.Object) + asset.Data = AdjustIdentifiers(asset.Data); + + AdjustIdentifiers(asset.Metadata); + + return asset; + } + + public override AssetMetadata GetMetadata(string id) + { + AssetMetadata meta = base.GetMetadata(id); + + if (meta == null) + return null; + + AdjustIdentifiers(meta); + + return meta; + } + + public override byte[] GetData(string id) + { + AssetBase asset = Get(id); + + if (asset == null) + return null; + + if (!m_AssetPerms.AllowedExport(asset.Type)) + return null; + + // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) + // Fix bad assets before sending them elsewhere + if (asset.Type == (int)AssetType.Object && asset.Data != null) + { + string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data)); + asset.Data = Utils.StringToBytes(xml); + } + + return asset.Data; + } + + //public virtual bool Get(string id, Object sender, AssetRetrieved handler) + + public override string Store(AssetBase asset) + { + if (!m_AssetPerms.AllowedImport(asset.Type)) + return string.Empty; + + // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) + // Fix bad assets before storing on this server + if (asset.Type == (int)AssetType.Object && asset.Data != null) + { + string xml = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(asset.Data)); + asset.Data = Utils.StringToBytes(xml); + } + + return base.Store(asset); + } + + public override bool Delete(string id) + { + // NOGO + return false; + } + + #endregion + + protected void AdjustIdentifiers(AssetMetadata meta) + { + if (meta == null || m_Cache == null) + return; + + UserAccount creator = m_Cache.GetUser(meta.CreatorID); + if (creator != null) + meta.CreatorID = meta.CreatorID + ";" + m_HomeURL + "/" + creator.FirstName + " " + creator.LastName; + } + + // Only for Object + protected byte[] AdjustIdentifiers(byte[] data) + { + string xml = Utils.BytesToString(data); + + // Deal with bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8) + // Fix bad assets before sending them elsewhere + xml = ExternalRepresentationUtils.SanitizeXml(xml); + + return Utils.StringToBytes(ExternalRepresentationUtils.RewriteSOP(xml, "HGAssetService", m_HomeURL, m_Cache, UUID.Zero)); + } + + } + +} diff --git a/OpenSim/Services/HypergridService/HGFriendsService.cs b/OpenSim/Services/HypergridService/HGFriendsService.cs index a8bcfb2..6e35a88 100644 --- a/OpenSim/Services/HypergridService/HGFriendsService.cs +++ b/OpenSim/Services/HypergridService/HGFriendsService.cs @@ -198,7 +198,8 @@ namespace OpenSim.Services.HypergridService // So let's send back the call, but start a thread to continue // with the verification and the actual action. - Util.FireAndForget(delegate { ProcessFriendshipOffered(fromID, fromName, toID, message); }); + Util.FireAndForget( + o => ProcessFriendshipOffered(fromID, fromName, toID, message), null, "HGFriendsService.ProcessFriendshipOffered"); return true; } diff --git a/OpenSim/Services/HypergridService/HGInstantMessageService.cs b/OpenSim/Services/HypergridService/HGInstantMessageService.cs index e8d7cca..32ca09a 100644 --- a/OpenSim/Services/HypergridService/HGInstantMessageService.cs +++ b/OpenSim/Services/HypergridService/HGInstantMessageService.cs @@ -101,7 +101,14 @@ namespace OpenSim.Services.HypergridService Object[] args = new Object[] { config }; m_GridService = ServerUtils.LoadPlugin(gridService, args); m_PresenceService = ServerUtils.LoadPlugin(presenceService, args); - m_UserAgentService = ServerUtils.LoadPlugin(userAgentService, args); + try + { + m_UserAgentService = ServerUtils.LoadPlugin(userAgentService, args); + } + catch + { + m_log.WarnFormat("[HG IM SERVICE]: Unable to create User Agent Service. Missing config var in [HGInstantMessageService]?"); + } m_RegionCache = new ExpiringCache(); @@ -215,7 +222,15 @@ namespace OpenSim.Services.HypergridService { // Let's check with the UAS if the user is elsewhere m_log.DebugFormat("[HG IM SERVICE]: User is not present. Checking location with User Agent service"); - url = m_UserAgentService.LocateUser(toAgentID); + try + { + url = m_UserAgentService.LocateUser(toAgentID); + } + catch (Exception e) + { + m_log.Warn("[HG IM SERVICE]: LocateUser call failed ", e); + url = string.Empty; + } } // check if we've tried this before.. diff --git a/OpenSim/Services/HypergridService/HGInventoryService.cs b/OpenSim/Services/HypergridService/HGInventoryService.cs index 2e9bd40..9158b41 100644 --- a/OpenSim/Services/HypergridService/HGInventoryService.cs +++ b/OpenSim/Services/HypergridService/HGInventoryService.cs @@ -81,10 +81,8 @@ namespace OpenSim.Services.HypergridService if (m_UserAccountService == null) throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll)); - // legacy configuration [obsolete] - m_HomeURL = invConfig.GetString("ProfileServerURI", string.Empty); - // Preferred - m_HomeURL = invConfig.GetString("HomeURI", m_HomeURL); + m_HomeURL = Util.GetConfigVarFromSections(config, "HomeURI", + new string[] { "Startup", "Hypergrid", m_ConfigName }, String.Empty); m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); } @@ -105,12 +103,6 @@ namespace OpenSim.Services.HypergridService return new List(); } - public override InventoryCollection GetUserInventory(UUID userID) - { - // NOGO for this inventory service - return null; - } - public override InventoryFolderBase GetRootFolder(UUID principalID) { //m_log.DebugFormat("[HG INVENTORY SERVICE]: GetRootFolder for {0}", principalID); @@ -123,7 +115,7 @@ namespace OpenSim.Services.HypergridService return ConvertToOpenSim(folders[0]); // make one - XInventoryFolder suitcase = CreateFolder(principalID, UUID.Zero, (int)AssetType.Folder, "My Suitcase"); + XInventoryFolder suitcase = CreateFolder(principalID, UUID.Zero, (int)FolderType.Suitcase, "My Suitcase"); return ConvertToOpenSim(suitcase); } @@ -149,7 +141,7 @@ namespace OpenSim.Services.HypergridService //} - public override InventoryFolderBase GetFolderForType(UUID principalID, AssetType type) + public override InventoryFolderBase GetFolderForType(UUID principalID, FolderType type) { //m_log.DebugFormat("[HG INVENTORY SERVICE]: GetFolderForType for {0} {0}", principalID, type); return GetRootFolder(principalID); @@ -161,7 +153,14 @@ namespace OpenSim.Services.HypergridService //public InventoryCollection GetFolderContent(UUID principalID, UUID folderID) //{ //} - + + // NOGO + // + public override InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderID) + { + return new InventoryCollection[0]; + } + //public List GetFolderItems(UUID principalID, UUID folderID) //{ //} @@ -300,7 +299,7 @@ namespace OpenSim.Services.HypergridService UserAccount user = m_Cache.GetUser(it.CreatorId); // Adjust the creator data - if (user != null && it != null && (it.CreatorData == null || it.CreatorData == string.Empty)) + if (user != null && it != null && string.IsNullOrEmpty(it.CreatorData)) it.CreatorData = m_HomeURL + ";" + user.FirstName + " " + user.LastName; } return it; diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs index 784f136..40eb6d4 100644 --- a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs +++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs @@ -54,7 +54,7 @@ namespace OpenSim.Services.HypergridService LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private string m_HomeURL; +// private string m_HomeURL; private IUserAccountService m_UserAccountService; private IAvatarService m_AvatarService; @@ -96,8 +96,8 @@ namespace OpenSim.Services.HypergridService if (m_AvatarService == null) throw new Exception(String.Format("Unable to create m_AvatarService from {0}", avatarDll)); - // Preferred - m_HomeURL = invConfig.GetString("HomeURI", m_HomeURL); +// m_HomeURL = Util.GetConfigVarFromSections(config, "HomeURI", +// new string[] { "Startup", "Hypergrid", m_ConfigName }, String.Empty); // m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); } @@ -115,8 +115,14 @@ namespace OpenSim.Services.HypergridService { XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); + if (suitcase == null) + { + m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Found no suitcase folder for user {0} when looking for inventory skeleton", principalID); + return null; + } + List tree = GetFolderTree(principalID, suitcase.folderID); - if (tree == null || (tree != null && tree.Count == 0)) + if (tree.Count == 0) return null; List folders = new List(); @@ -131,58 +137,13 @@ namespace OpenSim.Services.HypergridService return folders; } - public override InventoryCollection GetUserInventory(UUID userID) - { - m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Get Suitcase inventory for user {0}", userID); - InventoryCollection userInventory = new InventoryCollection(); - userInventory.UserID = userID; - userInventory.Folders = new List(); - userInventory.Items = new List(); - - XInventoryFolder suitcase = GetSuitcaseXFolder(userID); - - List tree = GetFolderTree(userID, suitcase.folderID); - if (tree == null || (tree != null && tree.Count == 0)) - { - SetAsNormalFolder(suitcase); - userInventory.Folders.Add(ConvertToOpenSim(suitcase)); - return userInventory; - } - - List items; - foreach (XInventoryFolder f in tree) - { - // Add the items of this subfolder - items = GetFolderItems(userID, f.folderID); - if (items != null && items.Count > 0) - { - userInventory.Items.AddRange(items); - } - - // Add the folder itself - userInventory.Folders.Add(ConvertToOpenSim(f)); - } - - items = GetFolderItems(userID, suitcase.folderID); - if (items != null && items.Count > 0) - { - userInventory.Items.AddRange(items); - } - - SetAsNormalFolder(suitcase); - userInventory.Folders.Add(ConvertToOpenSim(suitcase)); - - m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetUserInventory for user {0} returning {1} folders and {2} items", - userID, userInventory.Folders.Count, userInventory.Items.Count); - return userInventory; - } - public override InventoryFolderBase GetRootFolder(UUID principalID) { m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetRootFolder for {0}", principalID); // Let's find out the local root folder - XInventoryFolder root = GetRootXFolder(principalID); ; + XInventoryFolder root = GetRootXFolder(principalID); + if (root == null) { m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Unable to retrieve local root folder for user {0}", principalID); @@ -195,14 +156,15 @@ namespace OpenSim.Services.HypergridService if (suitcase == null) { m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: User {0} does not have a Suitcase folder. Creating it...", principalID); - // make one, and let's add it to the user's inventory as a direct child of the root folder - // In the DB we tag it as type 100, but we use -1 (Unknown) outside - suitcase = CreateFolder(principalID, root.folderID, 100, "My Suitcase"); + // Create the My Suitcase folder under the user's root folder. + // In the DB we tag it as type 100, but we use type 8 (Folder) outside, as this affects the sort order. + suitcase = CreateFolder(principalID, root.folderID, (int)FolderType.Suitcase, InventoryFolderBase.SUITCASE_FOLDER_NAME); if (suitcase == null) + { m_log.ErrorFormat("[HG SUITCASE INVENTORY SERVICE]: Unable to create suitcase folder"); - m_Database.StoreFolder(suitcase); + return null; + } - // Create System folders CreateSystemFolders(principalID, suitcase.folderID); } @@ -216,45 +178,51 @@ namespace OpenSim.Services.HypergridService m_log.Debug("[HG SUITCASE INVENTORY SERVICE]: Creating System folders under Suitcase..."); XInventoryFolder[] sysFolders = GetSystemFolders(principalID, rootID); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.Animation) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.Animation, "Animations"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.Bodypart) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.Bodypart, "Body Parts"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.CallingCard) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.CallingCard, "Calling Cards"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.Clothing) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.Clothing, "Clothing"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.Gesture) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.Gesture, "Gestures"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.Landmark) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.Landmark, "Landmarks"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.LostAndFoundFolder) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.LostAndFoundFolder, "Lost And Found"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.Notecard) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.Notecard, "Notecards"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.Object) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.Object, "Objects"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.SnapshotFolder) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.SnapshotFolder, "Photo Album"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.LSLText) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.LSLText, "Scripts"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.Sound) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.Sound, "Sounds"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.Texture) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.Texture, "Textures"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.TrashFolder) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.TrashFolder, "Trash"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.FavoriteFolder) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.FavoriteFolder, "Favorites"); - if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)AssetType.CurrentOutfitFolder) return true; return false; })) - CreateFolder(principalID, rootID, (int)AssetType.CurrentOutfitFolder, "Current Outfit"); - + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Animation) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.Animation, "Animations"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.BodyPart) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.BodyPart, "Body Parts"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.CallingCard) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.CallingCard, "Calling Cards"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Clothing) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.Clothing, "Clothing"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.CurrentOutfit) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.CurrentOutfit, "Current Outfit"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Favorites) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.Favorites, "Favorites"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Gesture) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.Gesture, "Gestures"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Landmark) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.Landmark, "Landmarks"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.LostAndFound) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.LostAndFound, "Lost And Found"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Notecard) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.Notecard, "Notecards"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Object) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.Object, "Objects"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Snapshot) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.Snapshot, "Photo Album"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.LSLText) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.LSLText, "Scripts"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Sound) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.Sound, "Sounds"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Texture) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.Texture, "Textures"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Trash) return true; return false; })) + CreateFolder(principalID, rootID, (int)FolderType.Trash, "Trash"); } - public override InventoryFolderBase GetFolderForType(UUID principalID, AssetType type) + public override InventoryFolderBase GetFolderForType(UUID principalID, FolderType type) { //m_log.DebugFormat("[HG INVENTORY SERVICE]: GetFolderForType for {0} {0}", principalID, type); XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); + + if (suitcase == null) + { + m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Found no suitcase folder for user {0} when looking for child type folder {1}", principalID, type); + return null; + } + XInventoryFolder[] folders = m_Database.GetFolders( new string[] { "agentID", "type", "parentFolderID" }, new string[] { principalID.ToString(), ((int)type).ToString(), suitcase.folderID.ToString() }); @@ -277,7 +245,10 @@ namespace OpenSim.Services.HypergridService InventoryCollection coll = null; if (!IsWithinSuitcaseTree(principalID, folderID)) + { + m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetFolderContent: folder {0} (user {1}) is not within Suitcase tree", folderID, principalID); return new InventoryCollection(); + } coll = base.GetFolderContent(principalID, folderID); @@ -294,7 +265,10 @@ namespace OpenSim.Services.HypergridService // Let's do a bit of sanity checking, more than the base service does // make sure the given folder exists under the suitcase tree of this user if (!IsWithinSuitcaseTree(principalID, folderID)) + { + m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetFolderItems: folder {0} (user {1}) is not within Suitcase tree", folderID, principalID); return new List(); + } return base.GetFolderItems(principalID, folderID); } @@ -306,7 +280,10 @@ namespace OpenSim.Services.HypergridService // make sure the given folder's parent folder exists under the suitcase tree of this user if (!IsWithinSuitcaseTree(folder.Owner, folder.ParentID)) + { + m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: AddFolder: folder {0} (user {1}) is not within Suitcase tree", folder.ParentID, folder.Owner); return false; + } // OK, it's legit if (base.AddFolder(folder)) @@ -326,7 +303,7 @@ namespace OpenSim.Services.HypergridService //m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Update folder {0}, version {1}", folder.ID, folder.Version); if (!IsWithinSuitcaseTree(folder.Owner, folder.ID)) { - m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: folder {0} not within Suitcase tree", folder.Name); + m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: UpdateFolder: folder {0}/{1} (user {2}) is not within Suitcase tree", folder.Name, folder.ID, folder.Owner); return false; } @@ -336,9 +313,17 @@ namespace OpenSim.Services.HypergridService public override bool MoveFolder(InventoryFolderBase folder) { - if (!IsWithinSuitcaseTree(folder.Owner, folder.ID) || - !IsWithinSuitcaseTree(folder.Owner, folder.ParentID)) + if (!IsWithinSuitcaseTree(folder.Owner, folder.ID)) + { + m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: MoveFolder: folder {0} (user {1}) is not within Suitcase tree", folder.ID, folder.Owner); + return false; + } + + if (!IsWithinSuitcaseTree(folder.Owner, folder.ParentID)) + { + m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: MoveFolder: folder {0} (user {1}) is not within Suitcase tree", folder.ParentID, folder.Owner); return false; + } return base.MoveFolder(folder); } @@ -360,7 +345,10 @@ namespace OpenSim.Services.HypergridService // Let's do a bit of sanity checking, more than the base service does // make sure the given folder's parent folder exists under the suitcase tree of this user if (!IsWithinSuitcaseTree(item.Owner, item.Folder)) + { + m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: AddItem: folder {0} (user {1}) is not within Suitcase tree", item.Folder, item.Owner); return false; + } // OK, it's legit return base.AddItem(item); @@ -370,7 +358,10 @@ namespace OpenSim.Services.HypergridService public override bool UpdateItem(InventoryItemBase item) { if (!IsWithinSuitcaseTree(item.Owner, item.Folder)) + { + m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: UpdateItem: folder {0} (user {1}) is not within Suitcase tree", item.Folder, item.Owner); return false; + } return base.UpdateItem(item); } @@ -379,11 +370,28 @@ namespace OpenSim.Services.HypergridService { // Principal is b0rked. *sigh* - if (!IsWithinSuitcaseTree(items[0].Owner, items[0].Folder)) - return false; + // Check the items' destination folders + foreach (InventoryItemBase item in items) + { + if (!IsWithinSuitcaseTree(item.Owner, item.Folder)) + { + m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: MoveItems: folder {0} (user {1}) is not within Suitcase tree", item.Folder, item.Owner); + return false; + } + } - return base.MoveItems(principalID, items); + // Check the items' current folders + foreach (InventoryItemBase item in items) + { + InventoryItemBase originalItem = base.GetItem(item); + if (!IsWithinSuitcaseTree(originalItem.Owner, originalItem.Folder)) + { + m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: MoveItems: folder {0} (user {1}) is not within Suitcase tree", item.Folder, item.Owner); + return false; + } + } + return base.MoveItems(principalID, items); } public override bool DeleteItems(UUID principalID, List itemIDs) @@ -403,8 +411,8 @@ namespace OpenSim.Services.HypergridService if (!IsWithinSuitcaseTree(it.Owner, it.Folder) && !IsPartOfAppearance(it.Owner, it.ID)) { - m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Item {0} (folder {1}) is not within Suitcase", - it.Name, it.Folder); + m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetItem: item {0}/{1} (folder {2}) (user {3}) is not within Suitcase tree or Appearance", + it.Name, it.ID, it.Folder, it.Owner); return null; } @@ -425,7 +433,11 @@ namespace OpenSim.Services.HypergridService if (f != null) { if (!IsWithinSuitcaseTree(f.Owner, f.ID)) + { + m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetFolder: folder {0}/{1} (user {2}) is not within Suitcase tree", + f.Name, f.ID, f.Owner); return null; + } } return f; @@ -456,7 +468,7 @@ namespace OpenSim.Services.HypergridService { XInventoryFolder[] folders = m_Database.GetFolders( new string[] { "agentID", "folderName", "type" }, - new string[] { principalID.ToString(), "My Inventory", ((int)AssetType.RootFolder).ToString() }); + new string[] { principalID.ToString(), InventoryFolderBase.ROOT_FOLDER_NAME, ((int)FolderType.Root).ToString() }); if (folders != null && folders.Length > 0) return folders[0]; @@ -464,7 +476,7 @@ namespace OpenSim.Services.HypergridService // OK, so the RootFolder type didn't work. Let's look for any type with parent UUID.Zero. folders = m_Database.GetFolders( new string[] { "agentID", "folderName", "parentFolderID" }, - new string[] { principalID.ToString(), "My Inventory", UUID.Zero.ToString() }); + new string[] { principalID.ToString(), InventoryFolderBase.ROOT_FOLDER_NAME, UUID.Zero.ToString() }); if (folders != null && folders.Length > 0) return folders[0]; @@ -472,12 +484,28 @@ namespace OpenSim.Services.HypergridService return null; } + private XInventoryFolder GetCurrentOutfitXFolder(UUID userID) + { + XInventoryFolder root = GetRootXFolder(userID); + if (root == null) + return null; + + XInventoryFolder[] folders = m_Database.GetFolders( + new string[] { "agentID", "type", "parentFolderID" }, + new string[] { userID.ToString(), ((int)FolderType.CurrentOutfit).ToString(), root.folderID.ToString() }); + + if (folders.Length == 0) + return null; + + return folders[0]; + } + private XInventoryFolder GetSuitcaseXFolder(UUID principalID) { // Warp! Root folder for travelers XInventoryFolder[] folders = m_Database.GetFolders( new string[] { "agentID", "type" }, - new string[] { principalID.ToString(), "100" }); // This is a special folder type... + new string[] { principalID.ToString(), ((int)FolderType.Suitcase).ToString() }); if (folders != null && folders.Length > 0) return folders[0]; @@ -485,13 +513,13 @@ namespace OpenSim.Services.HypergridService // check to see if we have the old Suitcase folder folders = m_Database.GetFolders( new string[] { "agentID", "folderName", "parentFolderID" }, - new string[] { principalID.ToString(), "My Suitcase", UUID.Zero.ToString() }); + new string[] { principalID.ToString(), InventoryFolderBase.SUITCASE_FOLDER_NAME, UUID.Zero.ToString() }); if (folders != null && folders.Length > 0) { // Move it to under the root folder XInventoryFolder root = GetRootXFolder(principalID); folders[0].parentFolderID = root.folderID; - folders[0].type = 100; + folders[0].type = (int)FolderType.Suitcase; m_Database.StoreFolder(folders[0]); return folders[0]; } @@ -501,17 +529,18 @@ namespace OpenSim.Services.HypergridService private void SetAsNormalFolder(XInventoryFolder suitcase) { - suitcase.type = (short)AssetType.Folder; + //suitcase.type = InventoryItemBase.SUITCASE_FOLDER_FAKE_TYPE; } private List GetFolderTree(UUID principalID, UUID folder) { - List t = null; + List t; if (m_SuitcaseTrees.TryGetValue(principalID, out t)) return t; + // Get the tree of the suitcase folder t = GetFolderTreeRecursive(folder); - m_SuitcaseTrees.AddOrUpdate(principalID, t, 5*60); // 5minutes + m_SuitcaseTrees.AddOrUpdate(principalID, t, 5*60); // 5 minutes return t; } @@ -522,8 +551,10 @@ namespace OpenSim.Services.HypergridService new string[] { "parentFolderID" }, new string[] { root.ToString() }); - if (folders == null || (folders != null && folders.Length == 0)) + if (folders == null || folders.Length == 0) + { return tree; // empty tree + } else { foreach (XInventoryFolder f in folders) @@ -546,6 +577,7 @@ namespace OpenSim.Services.HypergridService private bool IsWithinSuitcaseTree(UUID principalID, UUID folderID) { XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); + if (suitcase == null) { m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: User {0} does not have a Suitcase folder", principalID); @@ -555,14 +587,18 @@ namespace OpenSim.Services.HypergridService List tree = new List(); tree.Add(suitcase); // Warp! the tree is the real root folder plus the children of the suitcase folder tree.AddRange(GetFolderTree(principalID, suitcase.folderID)); + + // Also add the Current Outfit folder to the list of available folders + XInventoryFolder folder = GetCurrentOutfitXFolder(principalID); + if (folder != null) + tree.Add(folder); + XInventoryFolder f = tree.Find(delegate(XInventoryFolder fl) { - if (fl.folderID == folderID) return true; - else return false; + return (fl.folderID == folderID); }); - if (f == null) return false; - else return true; + return (f != null); } #endregion diff --git a/OpenSim/Services/HypergridService/Properties/AssemblyInfo.cs b/OpenSim/Services/HypergridService/Properties/AssemblyInfo.cs index 49f2176..9999237 100644 --- a/OpenSim/Services/HypergridService/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/HypergridService/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/HypergridService/UserAccountCache.cs b/OpenSim/Services/HypergridService/UserAccountCache.cs index 65f9dd5..fa7dd0b 100644 --- a/OpenSim/Services/HypergridService/UserAccountCache.cs +++ b/OpenSim/Services/HypergridService/UserAccountCache.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Reflection; @@ -95,6 +95,11 @@ namespace OpenSim.Services.HypergridService return null; } + public void InvalidateCache(UUID userID) + { + m_UUIDCache.Remove(userID); + } + public bool StoreUserAccount(UserAccount data) { return false; diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs index a26a922..c65122a 100644 --- a/OpenSim/Services/HypergridService/UserAgentService.cs +++ b/OpenSim/Services/HypergridService/UserAgentService.cs @@ -30,6 +30,7 @@ using System.Collections.Generic; using System.Net; using System.Reflection; +using OpenSim.Data; using OpenSim.Framework; using OpenSim.Services.Connectors.Friends; using OpenSim.Services.Connectors.Hypergrid; @@ -50,14 +51,14 @@ namespace OpenSim.Services.HypergridService /// needs to do it for them. /// Once we have better clients, this shouldn't be needed. /// - public class UserAgentService : IUserAgentService + public class UserAgentService : UserAgentServiceBase, IUserAgentService { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); // This will need to go into a DB table - static Dictionary m_TravelingAgents = new Dictionary(); + //static Dictionary m_Database = new Dictionary(); static bool m_Initialized = false; @@ -74,6 +75,7 @@ namespace OpenSim.Services.HypergridService protected static string m_GridName; protected static int m_LevelOutsideContacts; + protected static bool m_ShowDetails; protected static bool m_BypassClientVerification; @@ -86,6 +88,7 @@ namespace OpenSim.Services.HypergridService } public UserAgentService(IConfigSource config, IFriendsSimConnector friendsConnector) + : base(config) { // Let's set this always, because we don't know the sequence // of instantiations @@ -126,20 +129,30 @@ namespace OpenSim.Services.HypergridService m_UserAccountService = ServerUtils.LoadPlugin(userAccountService, args); m_LevelOutsideContacts = serverConfig.GetInt("LevelOutsideContacts", 0); + m_ShowDetails = serverConfig.GetBoolean("ShowUserDetailsInHGProfile", true); LoadTripPermissionsFromConfig(serverConfig, "ForeignTripsAllowed"); LoadDomainExceptionsFromConfig(serverConfig, "AllowExcept", m_TripsAllowedExceptions); LoadDomainExceptionsFromConfig(serverConfig, "DisallowExcept", m_TripsDisallowedExceptions); - m_GridName = serverConfig.GetString("ExternalName", string.Empty); - if (m_GridName == string.Empty) + m_GridName = Util.GetConfigVarFromSections(config, "GatekeeperURI", + new string[] { "Startup", "Hypergrid", "UserAgentService" }, String.Empty); + if (string.IsNullOrEmpty(m_GridName)) // Legacy. Remove soon. { - serverConfig = config.Configs["GatekeeperService"]; m_GridName = serverConfig.GetString("ExternalName", string.Empty); + if (m_GridName == string.Empty) + { + serverConfig = config.Configs["GatekeeperService"]; + m_GridName = serverConfig.GetString("ExternalName", string.Empty); + } } + if (!m_GridName.EndsWith("/")) m_GridName = m_GridName + "/"; + // Finally some cleanup + m_Database.DeleteOld(); + } } @@ -204,10 +217,10 @@ namespace OpenSim.Services.HypergridService return home; } - public bool LoginAgentToGrid(AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, IPEndPoint clientIP, out string reason) + public bool LoginAgentToGrid(GridRegion source, AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, bool fromLogin, out string reason) { m_log.DebugFormat("[USER AGENT SERVICE]: Request to login user {0} {1} (@{2}) to grid {3}", - agentCircuit.firstname, agentCircuit.lastname, ((clientIP == null) ? "stored IP" : clientIP.Address.ToString()), gatekeeper.ServerURI); + agentCircuit.firstname, agentCircuit.lastname, (fromLogin ? agentCircuit.IPAddress : "stored IP"), gatekeeper.ServerURI); string gridName = gatekeeper.ServerURI; @@ -254,21 +267,21 @@ namespace OpenSim.Services.HypergridService // Generate a new service session agentCircuit.ServiceSessionID = region.ServerURI + ";" + UUID.Random(); - TravelingAgentInfo old = UpdateTravelInfo(agentCircuit, region); + TravelingAgentInfo old = null; + TravelingAgentInfo travel = CreateTravelInfo(agentCircuit, region, fromLogin, out old); bool success = false; string myExternalIP = string.Empty; - m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}", m_GridName, gridName); + m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}, desired region: {2}", m_GridName, gridName, region.RegionID); if (m_GridName == gridName) - success = m_GatekeeperService.LoginAgent(agentCircuit, finalDestination, out reason); + { + success = m_GatekeeperService.LoginAgent(source, agentCircuit, finalDestination, out reason); + } else { - success = m_GatekeeperConnector.CreateAgent(region, agentCircuit, (uint)Constants.TeleportFlags.ViaLogin, out myExternalIP, out reason); - if (success) - // Report them as nowhere - m_PresenceService.ReportAgent(agentCircuit.SessionID, UUID.Zero); + success = m_GatekeeperConnector.CreateAgent(source, region, agentCircuit, (uint)Constants.TeleportFlags.ViaLogin, out myExternalIP, out reason); } if (!success) @@ -276,84 +289,64 @@ namespace OpenSim.Services.HypergridService m_log.DebugFormat("[USER AGENT SERVICE]: Unable to login user {0} {1} to grid {2}, reason: {3}", agentCircuit.firstname, agentCircuit.lastname, region.ServerURI, reason); - // restore the old travel info - lock (m_TravelingAgents) - { - if (old == null) - m_TravelingAgents.Remove(agentCircuit.SessionID); - else - m_TravelingAgents[agentCircuit.SessionID] = old; - } + if (old != null) + StoreTravelInfo(old); + else + m_Database.Delete(agentCircuit.SessionID); return false; } + // Everything is ok + + // Update the perceived IP Address of our grid m_log.DebugFormat("[USER AGENT SERVICE]: Gatekeeper sees me as {0}", myExternalIP); - // else set the IP addresses associated with this client - if (clientIP != null) - m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress = clientIP.Address.ToString(); - m_TravelingAgents[agentCircuit.SessionID].MyIpAddress = myExternalIP; + travel.MyIpAddress = myExternalIP; + + StoreTravelInfo(travel); return true; } - public bool LoginAgentToGrid(AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, out string reason) + public bool LoginAgentToGrid(GridRegion source, AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, out string reason) { reason = string.Empty; - return LoginAgentToGrid(agentCircuit, gatekeeper, finalDestination, null, out reason); + return LoginAgentToGrid(source, agentCircuit, gatekeeper, finalDestination, false, out reason); } - private void SetClientIP(UUID sessionID, string ip) + TravelingAgentInfo CreateTravelInfo(AgentCircuitData agentCircuit, GridRegion region, bool fromLogin, out TravelingAgentInfo existing) { - if (m_TravelingAgents.ContainsKey(sessionID)) - { - m_log.DebugFormat("[USER AGENT SERVICE]: Setting IP {0} for session {1}", ip, sessionID); - m_TravelingAgents[sessionID].ClientIPAddress = ip; - } - } + HGTravelingData hgt = m_Database.Get(agentCircuit.SessionID); + existing = null; - TravelingAgentInfo UpdateTravelInfo(AgentCircuitData agentCircuit, GridRegion region) - { - TravelingAgentInfo travel = new TravelingAgentInfo(); - TravelingAgentInfo old = null; - lock (m_TravelingAgents) + if (hgt != null) { - if (m_TravelingAgents.ContainsKey(agentCircuit.SessionID)) - { - // Very important! Override whatever this agent comes with. - // UserAgentService always sets the IP for every new agent - // with the original IP address. - agentCircuit.IPAddress = m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress; - - old = m_TravelingAgents[agentCircuit.SessionID]; - } - - m_TravelingAgents[agentCircuit.SessionID] = travel; + // Very important! Override whatever this agent comes with. + // UserAgentService always sets the IP for every new agent + // with the original IP address. + existing = new TravelingAgentInfo(hgt); + agentCircuit.IPAddress = existing.ClientIPAddress; } + + TravelingAgentInfo travel = new TravelingAgentInfo(existing); + travel.SessionID = agentCircuit.SessionID; travel.UserID = agentCircuit.AgentID; travel.GridExternalName = region.ServerURI; travel.ServiceToken = agentCircuit.ServiceSessionID; - if (old != null) - travel.ClientIPAddress = old.ClientIPAddress; - return old; + if (fromLogin) + travel.ClientIPAddress = agentCircuit.IPAddress; + + StoreTravelInfo(travel); + + return travel; } public void LogoutAgent(UUID userID, UUID sessionID) { m_log.DebugFormat("[USER AGENT SERVICE]: User {0} logged out", userID); - lock (m_TravelingAgents) - { - List travels = new List(); - foreach (KeyValuePair kvp in m_TravelingAgents) - if (kvp.Value == null) // do some clean up - travels.Add(kvp.Key); - else if (kvp.Value.UserID == userID) - travels.Add(kvp.Key); - foreach (UUID session in travels) - m_TravelingAgents.Remove(session); - } + m_Database.Delete(sessionID); GridUserInfo guinfo = m_GridUserService.GetGridUserInfo(userID.ToString()); if (guinfo != null) @@ -363,10 +356,11 @@ namespace OpenSim.Services.HypergridService // We need to prevent foreign users with the same UUID as a local user public bool IsAgentComingHome(UUID sessionID, string thisGridExternalName) { - if (!m_TravelingAgents.ContainsKey(sessionID)) + HGTravelingData hgt = m_Database.Get(sessionID); + if (hgt == null) return false; - TravelingAgentInfo travel = m_TravelingAgents[sessionID]; + TravelingAgentInfo travel = new TravelingAgentInfo(hgt); return travel.GridExternalName.ToLower() == thisGridExternalName.ToLower(); } @@ -379,31 +373,32 @@ namespace OpenSim.Services.HypergridService m_log.DebugFormat("[USER AGENT SERVICE]: Verifying Client session {0} with reported IP {1}.", sessionID, reportedIP); - if (m_TravelingAgents.ContainsKey(sessionID)) - { - bool result = m_TravelingAgents[sessionID].ClientIPAddress == reportedIP || - m_TravelingAgents[sessionID].MyIpAddress == reportedIP; // NATed + HGTravelingData hgt = m_Database.Get(sessionID); + if (hgt == null) + return false; - m_log.DebugFormat("[USER AGENT SERVICE]: Comparing {0} with login IP {1} and MyIP {1}; result is {3}", - reportedIP, m_TravelingAgents[sessionID].ClientIPAddress, m_TravelingAgents[sessionID].MyIpAddress, result); + TravelingAgentInfo travel = new TravelingAgentInfo(hgt); - return result; - } + bool result = travel.ClientIPAddress == reportedIP || travel.MyIpAddress == reportedIP; // NATed + + m_log.DebugFormat("[USER AGENT SERVICE]: Comparing {0} with login IP {1} and MyIP {1}; result is {3}", + reportedIP, travel.ClientIPAddress, travel.MyIpAddress, result); - return false; + return result; } public bool VerifyAgent(UUID sessionID, string token) { - if (m_TravelingAgents.ContainsKey(sessionID)) + HGTravelingData hgt = m_Database.Get(sessionID); + if (hgt == null) { - m_log.DebugFormat("[USER AGENT SERVICE]: Verifying agent token {0} against {1}", token, m_TravelingAgents[sessionID].ServiceToken); - return m_TravelingAgents[sessionID].ServiceToken == token; + m_log.DebugFormat("[USER AGENT SERVICE]: Token verification for session {0}: no such session", sessionID); + return false; } - m_log.DebugFormat("[USER AGENT SERVICE]: Token verification for session {0}: no such session", sessionID); - - return false; + TravelingAgentInfo travel = new TravelingAgentInfo(hgt); + m_log.DebugFormat("[USER AGENT SERVICE]: Verifying agent token {0} against {1}", token, travel.ServiceToken); + return travel.ServiceToken == token; } [Obsolete] @@ -466,17 +461,17 @@ namespace OpenSim.Services.HypergridService } } - // Lastly, let's notify the rest who may be online somewhere else - foreach (string user in usersToBeNotified) - { - UUID id = new UUID(user); - if (m_TravelingAgents.ContainsKey(id) && m_TravelingAgents[id].GridExternalName != m_GridName) - { - string url = m_TravelingAgents[id].GridExternalName; - // forward - m_log.WarnFormat("[USER AGENT SERVICE]: User {0} is visiting {1}. HG Status notifications still not implemented.", user, url); - } - } + //// Lastly, let's notify the rest who may be online somewhere else + //foreach (string user in usersToBeNotified) + //{ + // UUID id = new UUID(user); + // if (m_Database.ContainsKey(id) && m_Database[id].GridExternalName != m_GridName) + // { + // string url = m_Database[id].GridExternalName; + // // forward + // m_log.WarnFormat("[USER AGENT SERVICE]: User {0} is visiting {1}. HG Status notifications still not implemented.", user, url); + // } + //} // and finally, let's send the online friends if (online) @@ -578,10 +573,22 @@ namespace OpenSim.Services.HypergridService if (account != null) { - info.Add("user_flags", (object)account.UserFlags); - info.Add("user_created", (object)account.Created); - info.Add("user_title", (object)account.UserTitle); + info.Add("user_firstname", account.FirstName); + info.Add("user_lastname", account.LastName); info.Add("result", "success"); + + if (m_ShowDetails) + { + info.Add("user_flags", account.UserFlags); + info.Add("user_created", account.Created); + info.Add("user_title", account.UserTitle); + } + else + { + info.Add("user_flags", 0); + info.Add("user_created", 0); + info.Add("user_title", string.Empty); + } } return info; @@ -603,16 +610,13 @@ namespace OpenSim.Services.HypergridService public string LocateUser(UUID userID) { - foreach (TravelingAgentInfo t in m_TravelingAgents.Values) - { - if (t == null) - { - m_log.ErrorFormat("[USER AGENT SERVICE]: Oops! Null TravelingAgentInfo. Please report this on mantis"); - continue; - } - if (t.UserID == userID && !m_GridName.Equals(t.GridExternalName)) - return t.GridExternalName; - } + HGTravelingData[] hgts = m_Database.GetSessions(userID); + if (hgts == null) + return string.Empty; + + foreach (HGTravelingData t in hgts) + if (t.Data.ContainsKey("GridExternalName") && !m_GridName.Equals(t.Data["GridExternalName"])) + return t.Data["GridExternalName"]; return string.Empty; } @@ -683,17 +687,60 @@ namespace OpenSim.Services.HypergridService return exception; } + private void StoreTravelInfo(TravelingAgentInfo travel) + { + if (travel == null) + return; + + HGTravelingData hgt = new HGTravelingData(); + hgt.SessionID = travel.SessionID; + hgt.UserID = travel.UserID; + hgt.Data = new Dictionary(); + hgt.Data["GridExternalName"] = travel.GridExternalName; + hgt.Data["ServiceToken"] = travel.ServiceToken; + hgt.Data["ClientIPAddress"] = travel.ClientIPAddress; + hgt.Data["MyIPAddress"] = travel.MyIpAddress; + + m_Database.Store(hgt); + } #endregion } class TravelingAgentInfo { + public UUID SessionID; public UUID UserID; public string GridExternalName = string.Empty; public string ServiceToken = string.Empty; public string ClientIPAddress = string.Empty; // as seen from this user agent service public string MyIpAddress = string.Empty; // the user agent service's external IP, as seen from the next gatekeeper + + public TravelingAgentInfo(HGTravelingData t) + { + if (t.Data != null) + { + SessionID = new UUID(t.SessionID); + UserID = new UUID(t.UserID); + GridExternalName = t.Data["GridExternalName"]; + ServiceToken = t.Data["ServiceToken"]; + ClientIPAddress = t.Data["ClientIPAddress"]; + MyIpAddress = t.Data["MyIPAddress"]; + } + } + + public TravelingAgentInfo(TravelingAgentInfo old) + { + if (old != null) + { + SessionID = old.SessionID; + UserID = old.UserID; + GridExternalName = old.GridExternalName; + ServiceToken = old.ServiceToken; + ClientIPAddress = old.ClientIPAddress; + MyIpAddress = old.MyIpAddress; + } + } } } diff --git a/OpenSim/Services/HypergridService/UserAgentServiceBase.cs b/OpenSim/Services/HypergridService/UserAgentServiceBase.cs new file mode 100644 index 0000000..a00e5a6 --- /dev/null +++ b/OpenSim/Services/HypergridService/UserAgentServiceBase.cs @@ -0,0 +1,84 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Data; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Base; + +namespace OpenSim.Services.HypergridService +{ + public class UserAgentServiceBase : ServiceBase + { + protected IHGTravelingData m_Database = null; + + public UserAgentServiceBase(IConfigSource config) + : base(config) + { + string dllName = String.Empty; + string connString = String.Empty; + string realm = "hg_traveling_data"; + + // + // Try reading the [DatabaseService] section, if it exists + // + IConfig dbConfig = config.Configs["DatabaseService"]; + if (dbConfig != null) + { + if (dllName == String.Empty) + dllName = dbConfig.GetString("StorageProvider", String.Empty); + if (connString == String.Empty) + connString = dbConfig.GetString("ConnectionString", String.Empty); + } + + // + // [UserAgentService] section overrides [DatabaseService], if it exists + // + IConfig gridConfig = config.Configs["UserAgentService"]; + if (gridConfig != null) + { + dllName = gridConfig.GetString("StorageProvider", dllName); + connString = gridConfig.GetString("ConnectionString", connString); + realm = gridConfig.GetString("Realm", realm); + } + + // + // We tried, but this doesn't exist. We can't proceed. + // + if (dllName.Equals(String.Empty)) + throw new Exception("No StorageProvider configured"); + + m_Database = LoadPlugin(dllName, new Object[] { connString, realm }); + if (m_Database == null) + throw new Exception("Could not find a storage interface in the given module"); + + } + } +} diff --git a/OpenSim/Services/Interfaces/IAgentPreferencesService.cs b/OpenSim/Services/Interfaces/IAgentPreferencesService.cs new file mode 100644 index 0000000..3b4fda2 --- /dev/null +++ b/OpenSim/Services/Interfaces/IAgentPreferencesService.cs @@ -0,0 +1,115 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse; + +namespace OpenSim.Services.Interfaces +{ + public class AgentPrefs + { + public AgentPrefs(UUID principalID) + { + PrincipalID = principalID; + } + + public AgentPrefs(Dictionary kvp) + { + if (kvp.ContainsKey("PrincipalID")) + UUID.TryParse(kvp["PrincipalID"], out PrincipalID); + if (kvp.ContainsKey("AccessPrefs")) + AccessPrefs = kvp["AccessPrefs"]; + if (kvp.ContainsKey("HoverHeight")) + HoverHeight = double.Parse(kvp["HoverHeight"]); + if (kvp.ContainsKey("Language")) + Language = kvp["Language"]; + if (kvp.ContainsKey("LanguageIsPublic")) + LanguageIsPublic = bool.Parse(kvp["LanguageIsPublic"]); + if (kvp.ContainsKey("PermEveryone")) + PermEveryone = int.Parse(kvp["PermEveryone"]); + if (kvp.ContainsKey("PermGroup")) + PermGroup = int.Parse(kvp["PermGroup"]); + if (kvp.ContainsKey("PermNextOwner")) + PermNextOwner = int.Parse(kvp["PermNextOwner"]); + } + + public AgentPrefs(Dictionary kvp) + { + if (kvp.ContainsKey("PrincipalID")) + UUID.TryParse(kvp["PrincipalID"].ToString(), out PrincipalID); + if (kvp.ContainsKey("AccessPrefs")) + AccessPrefs = kvp["AccessPrefs"].ToString(); + if (kvp.ContainsKey("HoverHeight")) + HoverHeight = double.Parse(kvp["HoverHeight"].ToString()); + if (kvp.ContainsKey("Language")) + Language = kvp["Language"].ToString(); + if (kvp.ContainsKey("LanguageIsPublic")) + LanguageIsPublic = bool.Parse(kvp["LanguageIsPublic"].ToString()); + if (kvp.ContainsKey("PermEveryone")) + PermEveryone = int.Parse(kvp["PermEveryone"].ToString()); + if (kvp.ContainsKey("PermGroup")) + PermGroup = int.Parse(kvp["PermGroup"].ToString()); + if (kvp.ContainsKey("PermNextOwner")) + PermNextOwner = int.Parse(kvp["PermNextOwner"].ToString()); + } + + public Dictionary ToKeyValuePairs() + { + Dictionary result = new Dictionary(); + result["PrincipalID"] = PrincipalID.ToString(); + result["AccessPrefs"] = AccessPrefs.ToString(); + result["HoverHeight"] = HoverHeight.ToString(); + result["Language"] = Language.ToString(); + result["LanguageIsPublic"] = LanguageIsPublic.ToString(); + result["PermEveryone"] = PermEveryone.ToString(); + result["PermGroup"] = PermGroup.ToString(); + result["PermNextOwner"] = PermNextOwner.ToString(); + return result; + } + + public UUID PrincipalID = UUID.Zero; + public string AccessPrefs = "M"; + //public int GodLevel; // *TODO: Implement GodLevel (Unused by the viewer, afaict - 6/11/2015) + public double HoverHeight = 0.0; + public string Language = "en-us"; + public bool LanguageIsPublic = true; + // DefaultObjectPermMasks + public int PermEveryone = 0; + public int PermGroup = 0; + public int PermNextOwner = 532480; + } + + public interface IAgentPreferencesService + { + AgentPrefs GetAgentPreferences(UUID principalID); + bool StoreAgentPreferences(AgentPrefs data); + + string GetLang(UUID principalID); + } +} + diff --git a/OpenSim/Services/Interfaces/IAssetService.cs b/OpenSim/Services/Interfaces/IAssetService.cs index 3c469c6..28c3315 100644 --- a/OpenSim/Services/Interfaces/IAssetService.cs +++ b/OpenSim/Services/Interfaces/IAssetService.cs @@ -75,6 +75,13 @@ namespace OpenSim.Services.Interfaces /// /// True if the id was parseable, false otherwise bool Get(string id, Object sender, AssetRetrieved handler); + + /// + /// Check if assets exist in the database. + /// + /// The assets' IDs + /// For each asset: true if it exists, false otherwise + bool[] AssetsExist(string[] ids); /// /// Creates a new asset @@ -83,7 +90,7 @@ namespace OpenSim.Services.Interfaces /// Returns a random ID if none is passed via the asset argument. /// /// - /// + /// The Asset ID, or string.Empty if an error occurred string Store(AssetBase asset); /// diff --git a/OpenSim/Services/Interfaces/IAvatarService.cs b/OpenSim/Services/Interfaces/IAvatarService.cs index 863fd93..892e0b4 100644 --- a/OpenSim/Services/Interfaces/IAvatarService.cs +++ b/OpenSim/Services/Interfaces/IAvatarService.cs @@ -162,10 +162,15 @@ namespace OpenSim.Services.Interfaces } // Visual Params - string[] vps = new string[AvatarAppearance.VISUALPARAM_COUNT]; + //string[] vps = new string[AvatarAppearance.VISUALPARAM_COUNT]; + //byte[] binary = appearance.VisualParams; + + // for (int i = 0 ; i < AvatarAppearance.VISUALPARAM_COUNT ; i++) + byte[] binary = appearance.VisualParams; + string[] vps = new string[binary.Length]; - for (int i = 0 ; i < AvatarAppearance.VISUALPARAM_COUNT ; i++) + for (int i = 0; i < binary.Length; i++) { vps[i] = binary[i].ToString(); } @@ -174,11 +179,18 @@ namespace OpenSim.Services.Interfaces // Attachments List attachments = appearance.GetAttachments(); + Dictionary> atts = new Dictionary>(); foreach (AvatarAttachment attach in attachments) { if (attach.ItemID != UUID.Zero) - Data["_ap_" + attach.AttachPoint] = attach.ItemID.ToString(); + { + if (!atts.ContainsKey(attach.AttachPoint)) + atts[attach.AttachPoint] = new List(); + atts[attach.AttachPoint].Add(attach.ItemID.ToString()); + } } + foreach (KeyValuePair> kvp in atts) + Data["_ap_" + kvp.Key] = string.Join(",", kvp.Value.ToArray()); } public AvatarAppearance ToAvatarAppearance() @@ -195,7 +207,13 @@ namespace OpenSim.Services.Interfaces appearance.Serial = Int32.Parse(Data["Serial"]); if (Data.ContainsKey("AvatarHeight")) - appearance.AvatarHeight = float.Parse(Data["AvatarHeight"]); + { + float h = float.Parse(Data["AvatarHeight"]); + if( h == 0f) + h = 1.9f; + + appearance.AvatarHeight = h; + } // Legacy Wearables if (Data.ContainsKey("BodyItem")) @@ -266,9 +284,13 @@ namespace OpenSim.Services.Interfaces if (Data.ContainsKey("VisualParams")) { string[] vps = Data["VisualParams"].Split(new char[] {','}); - byte[] binary = new byte[AvatarAppearance.VISUALPARAM_COUNT]; + //byte[] binary = new byte[AvatarAppearance.VISUALPARAM_COUNT]; - for (int i = 0 ; i < vps.Length && i < binary.Length ; i++) + //for (int i = 0 ; i < vps.Length && i < binary.Length ; i++) + + byte[] binary = new byte[vps.Length]; + + for (int i = 0; i < vps.Length; i++) binary[i] = (byte)Convert.ToInt32(vps[i]); appearance.VisualParams = binary; @@ -304,10 +326,16 @@ namespace OpenSim.Services.Interfaces if (!Int32.TryParse(pointStr, out point)) continue; - UUID uuid = UUID.Zero; - UUID.TryParse(_kvp.Value, out uuid); + List idList = new List(_kvp.Value.Split(new char[] {','})); - appearance.SetAttachment(point, uuid, UUID.Zero); + appearance.SetAttachment(point, UUID.Zero, UUID.Zero); + foreach (string id in idList) + { + UUID uuid = UUID.Zero; + UUID.TryParse(id, out uuid); + + appearance.SetAttachment(point | 0x80, uuid, UUID.Zero); + } } if (appearance.Wearables[AvatarWearable.BODY].Count == 0) diff --git a/OpenSim/Services/Interfaces/IBakedTextureService.cs b/OpenSim/Services/Interfaces/IBakedTextureService.cs new file mode 100644 index 0000000..69df4a0 --- /dev/null +++ b/OpenSim/Services/Interfaces/IBakedTextureService.cs @@ -0,0 +1,38 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using Nini.Config; + +namespace OpenSim.Services.Interfaces +{ + public interface IBakedTextureService + { + string Get(string id); + void Store(string id, string data); + } +} diff --git a/OpenSim/Services/Interfaces/IBansService.cs b/OpenSim/Services/Interfaces/IBansService.cs new file mode 100644 index 0000000..8fd3521 --- /dev/null +++ b/OpenSim/Services/Interfaces/IBansService.cs @@ -0,0 +1,48 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; + +using OpenSim.Framework; +using OpenMetaverse; + +namespace OpenSim.Services.Interfaces +{ + public interface IBansService + { + /// + /// Are any of the given arguments banned from the grid? + /// + /// + /// + /// + /// + /// + bool IsBanned(string userID, string ip, string id0, string origin); + } + +} diff --git a/OpenSim/Services/Interfaces/IEstateDataService.cs b/OpenSim/Services/Interfaces/IEstateDataService.cs new file mode 100644 index 0000000..719563d --- /dev/null +++ b/OpenSim/Services/Interfaces/IEstateDataService.cs @@ -0,0 +1,115 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenSim.Framework; +using OpenMetaverse; + +namespace OpenSim.Services.Interfaces +{ + public interface IEstateDataService + { + /// + /// Load estate settings for a region. + /// + /// + /// If true, then an estate is created if one is not found. + /// + EstateSettings LoadEstateSettings(UUID regionID, bool create); + + /// + /// Load estate settings for an estate ID. + /// + /// + /// + EstateSettings LoadEstateSettings(int estateID); + + /// + /// Create a new estate. + /// + /// + /// A + /// + EstateSettings CreateNewEstate(); + + /// + /// Load/Get all estate settings. + /// + /// An empty list if no estates were found. + List LoadEstateSettingsAll(); + + /// + /// Store estate settings. + /// + /// + /// This is also called by EstateSettings.Save() + /// + void StoreEstateSettings(EstateSettings es); + + /// + /// Get estate IDs. + /// + /// Name of estate to search for. This is the exact name, no parttern matching is done. + /// + List GetEstates(string search); + + /// + /// Get the IDs of all estates owned by the given user. + /// + /// An empty list if no estates were found. + List GetEstatesByOwner(UUID ownerID); + + /// + /// Get the IDs of all estates. + /// + /// An empty list if no estates were found. + List GetEstatesAll(); + + /// + /// Link a region to an estate. + /// + /// + /// + /// true if the link succeeded, false otherwise + bool LinkRegion(UUID regionID, int estateID); + + /// + /// Get the UUIDs of all the regions in an estate. + /// + /// + /// + List GetRegions(int estateID); + + /// + /// Delete an estate + /// + /// + /// true if the delete succeeded, false otherwise + bool DeleteEstate(int estateID); + } +} \ No newline at end of file diff --git a/OpenSim/Services/Interfaces/IGridService.cs b/OpenSim/Services/Interfaces/IGridService.cs index d7da056..f5f1f75 100644 --- a/OpenSim/Services/Interfaces/IGridService.cs +++ b/OpenSim/Services/Interfaces/IGridService.cs @@ -26,12 +26,17 @@ */ using System; +using System.Collections; using System.Collections.Generic; using System.Net; using System.Net.Sockets; +using System.Reflection; + using OpenSim.Framework; using OpenMetaverse; +using log4net; + namespace OpenSim.Services.Interfaces { public interface IGridService @@ -97,6 +102,7 @@ namespace OpenSim.Services.Interfaces List GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax); List GetDefaultRegions(UUID scopeID); + List GetDefaultHypergridRegions(UUID scopeID); List GetFallbackRegions(UUID scopeID, int x, int y); List GetHyperlinks(UUID scopeID); @@ -114,19 +120,28 @@ namespace OpenSim.Services.Interfaces /// /// int GetRegionFlags(UUID scopeID, UUID regionID); + + Dictionary GetExtraFeatures(); + } + + public interface IHypergridLinker + { + GridRegion TryLinkRegionToCoords(UUID scopeID, string mapName, int xloc, int yloc, UUID ownerID, out string reason); + bool TryUnlinkRegion(string mapName); } public class GridRegion { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + +#pragma warning disable 414 + private static readonly string LogHeader = "[GRID REGION]"; +#pragma warning restore 414 + /// /// The port by which http communication occurs with the region /// - public uint HttpPort - { - get { return m_httpPort; } - set { m_httpPort = value; } - } - protected uint m_httpPort; + public uint HttpPort { get; set; } /// /// A well-formed URI for the host region server (namely "http://" + ExternalHostName) @@ -134,14 +149,17 @@ namespace OpenSim.Services.Interfaces public string ServerURI { get { - if ( m_serverURI != string.Empty ) { + if (!String.IsNullOrEmpty(m_serverURI)) { return m_serverURI; } else { - return "http://" + m_externalHostName + ":" + m_httpPort + "/"; + if (HttpPort == 0) + return "http://" + m_externalHostName + "/"; + else + return "http://" + m_externalHostName + ":" + HttpPort + "/"; } } set { - if ( value.EndsWith("/") ) { + if (value.EndsWith("/")) { m_serverURI = value; } else { m_serverURI = value + '/'; @@ -150,6 +168,16 @@ namespace OpenSim.Services.Interfaces } protected string m_serverURI; + /// + /// Provides direct access to the 'm_serverURI' field, without returning a generated URL if m_serverURI is missing. + /// + public string RawServerURI + { + get { return m_serverURI; } + set { m_serverURI = value; } + } + + public string RegionName { get { return m_regionName; } @@ -157,22 +185,34 @@ namespace OpenSim.Services.Interfaces } protected string m_regionName = String.Empty; + /// + /// Region flags. + /// + /// + /// If not set (chiefly if a robust service is running code pre OpenSim 0.8.1) then this will be null and + /// should be ignored. If you require flags information please use the separate IGridService.GetRegionFlags() call + /// XXX: This field is currently ignored when used in RegisterRegion, but could potentially be + /// used to set flags at this point. + /// + public OpenSim.Framework.RegionFlags? RegionFlags { get; set; } + protected string m_externalHostName; protected IPEndPoint m_internalEndPoint; /// - /// The co-ordinate of this region. + /// The co-ordinate of this region in region units. /// - public int RegionCoordX { get { return RegionLocX / (int)Constants.RegionSize; } } + public int RegionCoordX { get { return (int)Util.WorldToRegionLoc((uint)RegionLocX); } } /// - /// The co-ordinate of this region + /// The co-ordinate of this region in region units /// - public int RegionCoordY { get { return RegionLocY / (int)Constants.RegionSize; } } + public int RegionCoordY { get { return (int)Util.WorldToRegionLoc((uint)RegionLocY); } } /// /// The location of this region in meters. + /// DANGER DANGER! Note that this name means something different in RegionInfo. /// public int RegionLocX { @@ -181,8 +221,12 @@ namespace OpenSim.Services.Interfaces } protected int m_regionLocX; + public int RegionSizeX { get; set; } + public int RegionSizeY { get; set; } + /// /// The location of this region in meters. + /// DANGER DANGER! Note that this name means something different in RegionInfo. /// public int RegionLocY { @@ -211,13 +255,18 @@ namespace OpenSim.Services.Interfaces public GridRegion() { + RegionSizeX = (int)Constants.RegionSize; + RegionSizeY = (int)Constants.RegionSize; m_serverURI = string.Empty; } + /* public GridRegion(int regionLocX, int regionLocY, IPEndPoint internalEndPoint, string externalUri) { m_regionLocX = regionLocX; m_regionLocY = regionLocY; + RegionSizeX = (int)Constants.RegionSize; + RegionSizeY = (int)Constants.RegionSize; m_internalEndPoint = internalEndPoint; m_externalHostName = externalUri; @@ -227,26 +276,33 @@ namespace OpenSim.Services.Interfaces { m_regionLocX = regionLocX; m_regionLocY = regionLocY; + RegionSizeX = (int)Constants.RegionSize; + RegionSizeY = (int)Constants.RegionSize; m_externalHostName = externalUri; m_internalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), (int)port); } + */ public GridRegion(uint xcell, uint ycell) { - m_regionLocX = (int)(xcell * Constants.RegionSize); - m_regionLocY = (int)(ycell * Constants.RegionSize); + m_regionLocX = (int)Util.RegionToWorldLoc(xcell); + m_regionLocY = (int)Util.RegionToWorldLoc(ycell); + RegionSizeX = (int)Constants.RegionSize; + RegionSizeY = (int)Constants.RegionSize; } public GridRegion(RegionInfo ConvertFrom) { m_regionName = ConvertFrom.RegionName; - m_regionLocX = (int)(ConvertFrom.RegionLocX * Constants.RegionSize); - m_regionLocY = (int)(ConvertFrom.RegionLocY * Constants.RegionSize); + m_regionLocX = (int)(ConvertFrom.WorldLocX); + m_regionLocY = (int)(ConvertFrom.WorldLocY); + RegionSizeX = (int)ConvertFrom.RegionSizeX; + RegionSizeY = (int)ConvertFrom.RegionSizeY; m_internalEndPoint = ConvertFrom.InternalEndPoint; m_externalHostName = ConvertFrom.ExternalHostName; - m_httpPort = ConvertFrom.HttpPort; + HttpPort = ConvertFrom.HttpPort; RegionID = ConvertFrom.RegionID; ServerURI = ConvertFrom.ServerURI; TerrainImage = ConvertFrom.RegionSettings.TerrainImageID; @@ -260,11 +316,14 @@ namespace OpenSim.Services.Interfaces public GridRegion(GridRegion ConvertFrom) { m_regionName = ConvertFrom.RegionName; + RegionFlags = ConvertFrom.RegionFlags; m_regionLocX = ConvertFrom.RegionLocX; m_regionLocY = ConvertFrom.RegionLocY; + RegionSizeX = ConvertFrom.RegionSizeX; + RegionSizeY = ConvertFrom.RegionSizeY; m_internalEndPoint = ConvertFrom.InternalEndPoint; m_externalHostName = ConvertFrom.ExternalHostName; - m_httpPort = ConvertFrom.HttpPort; + HttpPort = ConvertFrom.HttpPort; RegionID = ConvertFrom.RegionID; ServerURI = ConvertFrom.ServerURI; TerrainImage = ConvertFrom.TerrainImage; @@ -274,8 +333,112 @@ namespace OpenSim.Services.Interfaces RegionSecret = ConvertFrom.RegionSecret; EstateOwner = ConvertFrom.EstateOwner; } + + public GridRegion(Dictionary kvp) + { + if (kvp.ContainsKey("uuid")) + RegionID = new UUID((string)kvp["uuid"]); + + if (kvp.ContainsKey("locX")) + RegionLocX = Convert.ToInt32((string)kvp["locX"]); + + if (kvp.ContainsKey("locY")) + RegionLocY = Convert.ToInt32((string)kvp["locY"]); + + if (kvp.ContainsKey("sizeX")) + RegionSizeX = Convert.ToInt32((string)kvp["sizeX"]); + else + RegionSizeX = (int)Constants.RegionSize; + + if (kvp.ContainsKey("sizeY")) + RegionSizeY = Convert.ToInt32((string)kvp["sizeY"]); + else + RegionSizeX = (int)Constants.RegionSize; + + if (kvp.ContainsKey("regionName")) + RegionName = (string)kvp["regionName"]; + + if (kvp.ContainsKey("flags") && kvp["flags"] != null) + RegionFlags = (OpenSim.Framework.RegionFlags?)Convert.ToInt32((string)kvp["flags"]); + + if (kvp.ContainsKey("serverIP")) + { + //int port = 0; + //Int32.TryParse((string)kvp["serverPort"], out port); + //IPEndPoint ep = new IPEndPoint(IPAddress.Parse((string)kvp["serverIP"]), port); + ExternalHostName = (string)kvp["serverIP"]; + } + else + ExternalHostName = "127.0.0.1"; + + if (kvp.ContainsKey("serverPort")) + { + Int32 port = 0; + Int32.TryParse((string)kvp["serverPort"], out port); + InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), port); + } + + if (kvp.ContainsKey("serverHttpPort")) + { + UInt32 port = 0; + UInt32.TryParse((string)kvp["serverHttpPort"], out port); + HttpPort = port; + } + + if (kvp.ContainsKey("serverURI")) + ServerURI = (string)kvp["serverURI"]; + + if (kvp.ContainsKey("regionMapTexture")) + UUID.TryParse((string)kvp["regionMapTexture"], out TerrainImage); + + if (kvp.ContainsKey("parcelMapTexture")) + UUID.TryParse((string)kvp["parcelMapTexture"], out ParcelImage); + + if (kvp.ContainsKey("access")) + Access = Byte.Parse((string)kvp["access"]); + + if (kvp.ContainsKey("regionSecret")) + RegionSecret =(string)kvp["regionSecret"]; + + if (kvp.ContainsKey("owner_uuid")) + EstateOwner = new UUID(kvp["owner_uuid"].ToString()); + + if (kvp.ContainsKey("Token")) + Token = kvp["Token"].ToString(); + + // m_log.DebugFormat("{0} New GridRegion. id={1}, loc=<{2},{3}>, size=<{4},{5}>", + // LogHeader, RegionID, RegionLocX, RegionLocY, RegionSizeX, RegionSizeY); + } + + public Dictionary ToKeyValuePairs() + { + Dictionary kvp = new Dictionary(); + kvp["uuid"] = RegionID.ToString(); + kvp["locX"] = RegionLocX.ToString(); + kvp["locY"] = RegionLocY.ToString(); + kvp["sizeX"] = RegionSizeX.ToString(); + kvp["sizeY"] = RegionSizeY.ToString(); + kvp["regionName"] = RegionName; - # region Definition of equality + if (RegionFlags != null) + kvp["flags"] = ((int)RegionFlags).ToString(); + + kvp["serverIP"] = ExternalHostName; //ExternalEndPoint.Address.ToString(); + kvp["serverHttpPort"] = HttpPort.ToString(); + kvp["serverURI"] = ServerURI; + kvp["serverPort"] = InternalEndPoint.Port.ToString(); + kvp["regionMapTexture"] = TerrainImage.ToString(); + kvp["parcelMapTexture"] = ParcelImage.ToString(); + kvp["access"] = Access.ToString(); + kvp["regionSecret"] = RegionSecret; + kvp["owner_uuid"] = EstateOwner.ToString(); + kvp["Token"] = Token.ToString(); + // Maturity doesn't seem to exist in the DB + + return kvp; + } + + #region Definition of equality /// /// Define equality as two regions having the same, non-zero UUID. @@ -362,86 +525,5 @@ namespace OpenSim.Services.Interfaces { get { return Util.UIntsToLong((uint)RegionLocX, (uint)RegionLocY); } } - - public Dictionary ToKeyValuePairs() - { - Dictionary kvp = new Dictionary(); - kvp["uuid"] = RegionID.ToString(); - kvp["locX"] = RegionLocX.ToString(); - kvp["locY"] = RegionLocY.ToString(); - kvp["regionName"] = RegionName; - kvp["serverIP"] = ExternalHostName; //ExternalEndPoint.Address.ToString(); - kvp["serverHttpPort"] = HttpPort.ToString(); - kvp["serverURI"] = ServerURI; - kvp["serverPort"] = InternalEndPoint.Port.ToString(); - kvp["regionMapTexture"] = TerrainImage.ToString(); - kvp["parcelMapTexture"] = ParcelImage.ToString(); - kvp["access"] = Access.ToString(); - kvp["regionSecret"] = RegionSecret; - kvp["owner_uuid"] = EstateOwner.ToString(); - kvp["Token"] = Token.ToString(); - // Maturity doesn't seem to exist in the DB - return kvp; - } - - public GridRegion(Dictionary kvp) - { - if (kvp.ContainsKey("uuid")) - RegionID = new UUID((string)kvp["uuid"]); - - if (kvp.ContainsKey("locX")) - RegionLocX = Convert.ToInt32((string)kvp["locX"]); - - if (kvp.ContainsKey("locY")) - RegionLocY = Convert.ToInt32((string)kvp["locY"]); - - if (kvp.ContainsKey("regionName")) - RegionName = (string)kvp["regionName"]; - - if (kvp.ContainsKey("serverIP")) - { - //int port = 0; - //Int32.TryParse((string)kvp["serverPort"], out port); - //IPEndPoint ep = new IPEndPoint(IPAddress.Parse((string)kvp["serverIP"]), port); - ExternalHostName = (string)kvp["serverIP"]; - } - else - ExternalHostName = "127.0.0.1"; - - if (kvp.ContainsKey("serverPort")) - { - Int32 port = 0; - Int32.TryParse((string)kvp["serverPort"], out port); - InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), port); - } - - if (kvp.ContainsKey("serverHttpPort")) - { - UInt32 port = 0; - UInt32.TryParse((string)kvp["serverHttpPort"], out port); - HttpPort = port; - } - - if (kvp.ContainsKey("serverURI")) - ServerURI = (string)kvp["serverURI"]; - - if (kvp.ContainsKey("regionMapTexture")) - UUID.TryParse((string)kvp["regionMapTexture"], out TerrainImage); - - if (kvp.ContainsKey("parcelMapTexture")) - UUID.TryParse((string)kvp["parcelMapTexture"], out ParcelImage); - - if (kvp.ContainsKey("access")) - Access = Byte.Parse((string)kvp["access"]); - - if (kvp.ContainsKey("regionSecret")) - RegionSecret =(string)kvp["regionSecret"]; - - if (kvp.ContainsKey("owner_uuid")) - EstateOwner = new UUID(kvp["owner_uuid"].ToString()); - - if (kvp.ContainsKey("Token")) - Token = kvp["Token"].ToString(); - } } -} +} \ No newline at end of file diff --git a/OpenSim/Services/Interfaces/IHypergridServices.cs b/OpenSim/Services/Interfaces/IHypergridServices.cs index 3dc877a..5e012fb 100644 --- a/OpenSim/Services/Interfaces/IHypergridServices.cs +++ b/OpenSim/Services/Interfaces/IHypergridServices.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -37,31 +37,71 @@ namespace OpenSim.Services.Interfaces public interface IGatekeeperService { bool LinkRegion(string regionDescriptor, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason); - GridRegion GetHyperlinkRegion(UUID regionID); + + /// + /// Returns the region a Hypergrid visitor should enter. + /// + /// + /// Usually the returned region will be the requested region. But the grid can choose to + /// redirect the user to another region: e.g., a default gateway region. + /// + /// The region the visitor *wants* to enter + /// The visitor's User ID. Will be missing (UUID.Zero) in older OpenSims. + /// The visitor's Home URI. Will be missing (null) in older OpenSims. + /// [out] A message to show to the user (optional, may be null) + /// The region the visitor should enter, or null if no region can be found / is allowed + GridRegion GetHyperlinkRegion(UUID regionID, UUID agentID, string agentHomeURI, out string message); - bool LoginAgent(AgentCircuitData aCircuit, GridRegion destination, out string reason); + bool LoginAgent(GridRegion source, AgentCircuitData aCircuit, GridRegion destination, out string reason); } - /// - /// HG1.5 only - /// public interface IUserAgentService { - // called by login service only - bool LoginAgentToGrid(AgentCircuitData agent, GridRegion gatekeeper, GridRegion finalDestination, IPEndPoint clientIP, out string reason); - // called by simulators - bool LoginAgentToGrid(AgentCircuitData agent, GridRegion gatekeeper, GridRegion finalDestination, out string reason); + bool LoginAgentToGrid(GridRegion source, AgentCircuitData agent, GridRegion gatekeeper, GridRegion finalDestination, bool fromLogin, out string reason); + void LogoutAgent(UUID userID, UUID sessionID); + + /// + /// Returns the home region of a remote user. + /// + /// On success: the user's home region. If the user doesn't exist: null. + /// Throws an exception if an error occurs (e.g., can't contact the server). GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt); + + /// + /// Returns the Server URLs of a remote user. + /// + /// On success: the user's Server URLs. If the user doesn't exist: an empty dictionary. + /// Throws an exception if an error occurs (e.g., can't contact the server). Dictionary GetServerURLs(UUID userID); - Dictionary GetUserInfo(UUID userID); + /// + /// Returns the UserInfo of a remote user. + /// + /// On success: the user's UserInfo. If the user doesn't exist: an empty dictionary. + /// Throws an exception if an error occurs (e.g., can't contact the server). + Dictionary GetUserInfo(UUID userID); + + /// + /// Returns the current location of a remote user. + /// + /// On success: the user's Server URLs. If the user doesn't exist: "". + /// Throws an exception if an error occurs (e.g., can't contact the server). string LocateUser(UUID userID); - // Tries to get the universal user identifier for the targetUserId - // on behalf of the userID + + /// + /// Returns the Universal User Identifier for 'targetUserID' on behalf of 'userID'. + /// + /// On success: the user's UUI. If the user doesn't exist: "". + /// Throws an exception if an error occurs (e.g., can't contact the server). string GetUUI(UUID userID, UUID targetUserID); + /// + /// Returns the remote user that has the given name. + /// + /// On success: the user's UUID. If the user doesn't exist: UUID.Zero. + /// Throws an exception if an error occurs (e.g., can't contact the server). UUID GetUUID(String first, String last); // Returns the local friends online diff --git a/OpenSim/Services/Interfaces/IInventoryService.cs b/OpenSim/Services/Interfaces/IInventoryService.cs index a8bfe47..4289bba 100644 --- a/OpenSim/Services/Interfaces/IInventoryService.cs +++ b/OpenSim/Services/Interfaces/IInventoryService.cs @@ -55,23 +55,6 @@ namespace OpenSim.Services.Interfaces List GetInventorySkeleton(UUID userId); /// - /// Synchronous inventory fetch. - /// - /// - /// - [Obsolete] - InventoryCollection GetUserInventory(UUID userID); - - /// - /// Request the inventory for a user. This is an asynchronous operation that will call the callback when the - /// inventory has been received - /// - /// - /// - [Obsolete] - void GetUserInventory(UUID userID, InventoryReceiptCallback callback); - - /// /// Retrieve the root inventory folder for the given user. /// /// @@ -84,15 +67,23 @@ namespace OpenSim.Services.Interfaces /// /// /// - InventoryFolderBase GetFolderForType(UUID userID, AssetType type); + InventoryFolderBase GetFolderForType(UUID userID, FolderType type); /// /// Gets everything (folders and items) inside a folder /// /// /// - /// + /// Inventory content. null if the request failed. InventoryCollection GetFolderContent(UUID userID, UUID folderID); + + /// + /// Gets everything (folders and items) inside a folder + /// + /// + /// + /// Inventory content. + InventoryCollection[] GetMultipleFoldersContent(UUID userID, UUID[] folderIDs); /// /// Gets the items inside a folder @@ -173,6 +164,13 @@ namespace OpenSim.Services.Interfaces InventoryItemBase GetItem(InventoryItemBase item); /// + /// Get multiple items, given by their UUIDs + /// + /// + /// null if no item was found, otherwise the found item + InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] ids); + + /// /// Get a folder, given by its UUID /// /// diff --git a/OpenSim/Services/Interfaces/IMapImageService.cs b/OpenSim/Services/Interfaces/IMapImageService.cs index a7b2cf1..78daa5f 100644 --- a/OpenSim/Services/Interfaces/IMapImageService.cs +++ b/OpenSim/Services/Interfaces/IMapImageService.cs @@ -35,6 +35,7 @@ namespace OpenSim.Services.Interfaces { //List GetMapBlocks(UUID scopeID, int minX, int minY, int maxX, int maxY); bool AddMapTile(int x, int y, byte[] imageData, out string reason); + bool RemoveMapTile(int x, int y, out string reason); byte[] GetMapTile(string fileName, out string format); } } diff --git a/OpenSim/Services/Interfaces/IOfflineIMService.cs b/OpenSim/Services/Interfaces/IOfflineIMService.cs index 2848967..588aaaf 100644 --- a/OpenSim/Services/Interfaces/IOfflineIMService.cs +++ b/OpenSim/Services/Interfaces/IOfflineIMService.cs @@ -35,7 +35,14 @@ namespace OpenSim.Services.Interfaces public interface IOfflineIMService { List GetMessages(UUID principalID); + bool StoreMessage(GridInstantMessage im, out string reason); + + /// + /// Delete messages to or from this user (or group). + /// + /// A user or group ID + void DeleteMessages(UUID userID); } public class OfflineIMDataUtils diff --git a/OpenSim/Services/Interfaces/ISimulationService.cs b/OpenSim/Services/Interfaces/ISimulationService.cs index b10a85c..8a25509 100644 --- a/OpenSim/Services/Interfaces/ISimulationService.cs +++ b/OpenSim/Services/Interfaces/ISimulationService.cs @@ -26,6 +26,7 @@ */ using System; +using System.Collections.Generic; using OpenSim.Framework; using OpenMetaverse; @@ -33,6 +34,20 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Services.Interfaces { + public class EntityTransferContext + { + public EntityTransferContext() + { + InboundVersion = VersionInfo.SimulationServiceVersionAcceptedMax; + OutboundVersion = VersionInfo.SimulationServiceVersionSupportedMax; + VariableWearablesSupported = false; + } + + public float InboundVersion { get; set; } + public float OutboundVersion { get; set; } + public bool VariableWearablesSupported { get; set; } + } + public interface ISimulationService { /// @@ -53,11 +68,13 @@ namespace OpenSim.Services.Interfaces /// /// Ask the simulator hosting the destination to create an agent on that region. /// + /// The region that the user is coming from. Will be null if the user + /// logged-in directly, or arrived from a simulator that doesn't send this parameter. /// /// /// /// Reason message in the event of a failure. - bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string reason); + bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint flags, out string reason); /// /// Full child agent update. @@ -75,9 +92,21 @@ namespace OpenSim.Services.Interfaces /// bool UpdateAgent(GridRegion destination, AgentPosition data); - bool RetrieveAgent(GridRegion destination, UUID id, out IAgentData agent); - - bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason); + /// + /// Returns whether a propspective user is allowed to visit the region. + /// + /// Desired destination + /// The visitor's User ID + /// The visitor's Home URI. Will be missing (null) in older OpenSims. + /// True: via teleport; False: via cross (walking) + /// Position in the region + /// + /// Version that the requesting simulator is runing. If null then no version check is carried out. + /// + /// Version that the target simulator is running + /// [out] Optional error message + /// True: ok; False: not allowed + bool QueryAccess(GridRegion destination, UUID agentID, string agentHomeURI, bool viaTeleport, Vector3 position, List features, EntityTransferContext ctx, out string reason); /// /// Message from receiving region to departing region, telling it got contacted by the client. @@ -95,7 +124,7 @@ namespace OpenSim.Services.Interfaces /// /// /// - bool CloseAgent(GridRegion destination, UUID id); + bool CloseAgent(GridRegion destination, UUID id, string auth_token); #endregion Agents diff --git a/OpenSim/Services/Interfaces/IUserAccountService.cs b/OpenSim/Services/Interfaces/IUserAccountService.cs index 1b85980..2f7702c 100644 --- a/OpenSim/Services/Interfaces/IUserAccountService.cs +++ b/OpenSim/Services/Interfaces/IUserAccountService.cs @@ -189,5 +189,7 @@ namespace OpenSim.Services.Interfaces /// /// bool StoreUserAccount(UserAccount data); + + void InvalidateCache(UUID userID); } } diff --git a/OpenSim/Services/Interfaces/IUserManagement.cs b/OpenSim/Services/Interfaces/IUserManagement.cs new file mode 100644 index 0000000..9e560d5 --- /dev/null +++ b/OpenSim/Services/Interfaces/IUserManagement.cs @@ -0,0 +1,97 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; + +using OpenMetaverse; + +namespace OpenSim.Services.Interfaces +{ + /// + /// This maintains the relationship between a UUID and a user name. + /// + public interface IUserManagement + { + string GetUserName(UUID uuid); + string GetUserHomeURL(UUID uuid); + string GetUserUUI(UUID uuid); + bool GetUserUUI(UUID userID, out string uui); + string GetUserServerURL(UUID uuid, string serverType); + + /// + /// Get user ID by the given name. + /// + /// + /// UUID.Zero if no user with that name is found or if the name is "Unknown User" + UUID GetUserIdByName(string name); + + /// + /// Get user ID by the given name. + /// + /// + /// + /// UUID.Zero if no user with that name is found or if the name is "Unknown User" + UUID GetUserIdByName(string firstName, string lastName); + + /// + /// Add a user. + /// + /// + /// If an account is found for the UUID, then the names in this will be used rather than any information + /// extracted from creatorData. + /// + /// + /// The creator data for this user. + void AddUser(UUID uuid, string creatorData); + + /// + /// Add a user. + /// + /// + /// The UUID is related to the name without any other checks being performed, such as user account presence. + /// + /// + /// + /// + void AddUser(UUID uuid, string firstName, string lastName); + + /// + /// Add a user. + /// + /// + /// The arguments apart from uuid are formed into a creatorData string and processing proceeds as for the + /// AddUser(UUID uuid, string creatorData) method. + /// + /// + /// + /// + void AddUser(UUID uuid, string firstName, string lastName, string homeURL); + + bool IsLocalGridUser(UUID uuid); + } +} diff --git a/OpenSim/Services/Interfaces/IUserProfilesService.cs b/OpenSim/Services/Interfaces/IUserProfilesService.cs new file mode 100644 index 0000000..121baa8 --- /dev/null +++ b/OpenSim/Services/Interfaces/IUserProfilesService.cs @@ -0,0 +1,80 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenSim.Framework; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Services.Interfaces +{ + public interface IUserProfilesService + { + #region Classifieds + OSD AvatarClassifiedsRequest(UUID creatorId); + bool ClassifiedUpdate(UserClassifiedAdd ad, ref string result); + bool ClassifiedInfoRequest(ref UserClassifiedAdd ad, ref string result); + bool ClassifiedDelete(UUID recordId); + #endregion Classifieds + + #region Picks + OSD AvatarPicksRequest(UUID creatorId); + bool PickInfoRequest(ref UserProfilePick pick, ref string result); + bool PicksUpdate(ref UserProfilePick pick, ref string result); + bool PicksDelete(UUID pickId); + #endregion Picks + + #region Notes + bool AvatarNotesRequest(ref UserProfileNotes note); + bool NotesUpdate(ref UserProfileNotes note, ref string result); + #endregion Notes + + #region Profile Properties + bool AvatarPropertiesRequest(ref UserProfileProperties prop, ref string result); + bool AvatarPropertiesUpdate(ref UserProfileProperties prop, ref string result); + #endregion Profile Properties + + #region User Preferences + bool UserPreferencesRequest(ref UserPreferences pref, ref string result); + bool UserPreferencesUpdate(ref UserPreferences pref, ref string result); + #endregion User Preferences + + #region Interests + bool AvatarInterestsUpdate(UserProfileProperties prop, ref string result); + #endregion Interests + + #region Utility + OSD AvatarImageAssetsRequest(UUID avatarId); + #endregion Utility + + #region UserData + bool RequestUserAppData(ref UserAppData prop, ref string result); + bool SetUserAppData(UserAppData prop, ref string result); + #endregion UserData + } +} + diff --git a/OpenSim/Services/Interfaces/OpenProfileClient.cs b/OpenSim/Services/Interfaces/OpenProfileClient.cs new file mode 100644 index 0000000..bda8151 --- /dev/null +++ b/OpenSim/Services/Interfaces/OpenProfileClient.cs @@ -0,0 +1,134 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Text; +using System.Xml; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; + +namespace OpenSim.Services.UserProfilesService +{ + /// + /// A client for accessing a profile server using the OpenProfile protocol. + /// + /// + /// This class was adapted from the full OpenProfile class. Since it's only a client, and not a server, + /// it's much simpler. + /// + public class OpenProfileClient + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private string m_serverURI; + + /// + /// Creates a client for accessing a foreign grid's profile server using the OpenProfile protocol. + /// + /// The grid's profile server URL + public OpenProfileClient(string serverURI) + { + m_serverURI = serverURI; + } + + /// + /// Gets an avatar's profile using the OpenProfile protocol. + /// + /// On success, this will contain the avatar's profile + /// Success/failure + /// + /// There are two profile modules currently in use in OpenSim: the older one is OpenProfile, and the newer + /// one is UserProfileModule (this file). This method attempts to read an avatar's profile from a foreign + /// grid using the OpenProfile protocol. + /// + public bool RequestAvatarPropertiesUsingOpenProfile(ref UserProfileProperties props) + { + Hashtable ReqHash = new Hashtable(); + ReqHash["avatar_id"] = props.UserId.ToString(); + + Hashtable profileData = XMLRPCRequester.SendRequest(ReqHash, "avatar_properties_request", m_serverURI); + + if (profileData == null) + return false; + if (!profileData.ContainsKey("data")) + return false; + + ArrayList dataArray = (ArrayList)profileData["data"]; + + if (dataArray == null || dataArray[0] == null) + return false; + profileData = (Hashtable)dataArray[0]; + + props.WebUrl = string.Empty; + props.AboutText = String.Empty; + props.FirstLifeText = String.Empty; + props.ImageId = UUID.Zero; + props.FirstLifeImageId = UUID.Zero; + props.PartnerId = UUID.Zero; + + if (profileData["ProfileUrl"] != null) + props.WebUrl = profileData["ProfileUrl"].ToString(); + if (profileData["AboutText"] != null) + props.AboutText = profileData["AboutText"].ToString(); + if (profileData["FirstLifeAboutText"] != null) + props.FirstLifeText = profileData["FirstLifeAboutText"].ToString(); + if (profileData["Image"] != null) + props.ImageId = new UUID(profileData["Image"].ToString()); + if (profileData["FirstLifeImage"] != null) + props.FirstLifeImageId = new UUID(profileData["FirstLifeImage"].ToString()); + if (profileData["Partner"] != null) + props.PartnerId = new UUID(profileData["Partner"].ToString()); + + props.WantToMask = 0; + props.WantToText = String.Empty; + props.SkillsMask = 0; + props.SkillsText = String.Empty; + props.Language = String.Empty; + + if (profileData["wantmask"] != null) + props.WantToMask = Convert.ToInt32(profileData["wantmask"].ToString()); + if (profileData["wanttext"] != null) + props.WantToText = profileData["wanttext"].ToString(); + + if (profileData["skillsmask"] != null) + props.SkillsMask = Convert.ToInt32(profileData["skillsmask"].ToString()); + if (profileData["skillstext"] != null) + props.SkillsText = profileData["skillstext"].ToString(); + + if (profileData["languages"] != null) + props.Language = profileData["languages"].ToString(); + + return true; + } + } +} \ No newline at end of file diff --git a/OpenSim/Services/Interfaces/Properties/AssemblyInfo.cs b/OpenSim/Services/Interfaces/Properties/AssemblyInfo.cs index 4723553..01cafbf 100644 --- a/OpenSim/Services/Interfaces/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/Interfaces/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + 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; using log4net; using Nini.Config; using OpenMetaverse; +using PermissionMask = OpenSim.Framework.PermissionMask; namespace OpenSim.Services.InventoryService { diff --git a/OpenSim/Services/InventoryService/Properties/AssemblyInfo.cs b/OpenSim/Services/InventoryService/Properties/AssemblyInfo.cs index 41ad9f8..ec89097 100644 --- a/OpenSim/Services/InventoryService/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/InventoryService/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/InventoryService/XInventoryService.cs b/OpenSim/Services/InventoryService/XInventoryService.cs index 7bad4b0..b75193f 100644 --- a/OpenSim/Services/InventoryService/XInventoryService.cs +++ b/OpenSim/Services/InventoryService/XInventoryService.cs @@ -111,40 +111,48 @@ namespace OpenSim.Services.InventoryService if (rootFolder == null) { - rootFolder = ConvertToOpenSim(CreateFolder(principalID, UUID.Zero, (int)AssetType.RootFolder, "My Inventory")); + rootFolder = ConvertToOpenSim(CreateFolder(principalID, UUID.Zero, (int)FolderType.Root, InventoryFolderBase.ROOT_FOLDER_NAME)); result = true; } XInventoryFolder[] sysFolders = GetSystemFolders(principalID, rootFolder.ID); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.Animation) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.Animation, "Animations"); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.Bodypart) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.Bodypart, "Body Parts"); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.CallingCard) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.CallingCard, "Calling Cards"); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.Clothing) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.Clothing, "Clothing"); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.Gesture) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.Gesture, "Gestures"); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.Landmark) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.Landmark, "Landmarks"); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.LostAndFoundFolder) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.LostAndFoundFolder, "Lost And Found"); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.Notecard) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.Notecard, "Notecards"); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.Object) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.Object, "Objects"); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.SnapshotFolder) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.SnapshotFolder, "Photo Album"); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.LSLText) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.LSLText, "Scripts"); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.Sound) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.Sound, "Sounds"); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.Texture) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.Texture, "Textures"); - if (!Array.Exists(sysFolders, delegate (XInventoryFolder f) { if (f.type == (int)AssetType.TrashFolder) return true; return false; })) - CreateFolder(principalID, rootFolder.ID, (int)AssetType.TrashFolder, "Trash"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Animation) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.Animation, "Animations"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.BodyPart) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.BodyPart, "Body Parts"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.CallingCard) return true; return false; })) + { + XInventoryFolder folder = CreateFolder(principalID, rootFolder.ID, (int)FolderType.CallingCard, "Calling Cards"); + folder = CreateFolder(principalID, folder.folderID, (int)FolderType.CallingCard, "Friends"); + CreateFolder(principalID, folder.folderID, (int)FolderType.CallingCard, "All"); + } + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Clothing) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.Clothing, "Clothing"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.CurrentOutfit) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.CurrentOutfit, "Current Outfit"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Favorites) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.Favorites, "Favorites"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Gesture) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.Gesture, "Gestures"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Landmark) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.Landmark, "Landmarks"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.LostAndFound) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.LostAndFound, "Lost And Found"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Notecard) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.Notecard, "Notecards"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Object) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.Object, "Objects"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Snapshot) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.Snapshot, "Photo Album"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.LSLText) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.LSLText, "Scripts"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Sound) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.Sound, "Sounds"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Texture) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.Texture, "Textures"); + if (!Array.Exists(sysFolders, delegate(XInventoryFolder f) { if (f.type == (int)FolderType.Trash) return true; return false; })) + CreateFolder(principalID, rootFolder.ID, (int)FolderType.Trash, "Trash"); return result; } @@ -220,7 +228,7 @@ namespace OpenSim.Services.InventoryService XInventoryFolder root = null; foreach (XInventoryFolder folder in folders) { - if (folder.folderName == "My Inventory") + if (folder.folderName == InventoryFolderBase.ROOT_FOLDER_NAME) { root = folder; break; @@ -233,7 +241,7 @@ namespace OpenSim.Services.InventoryService return ConvertToOpenSim(root); } - public virtual InventoryFolderBase GetFolderForType(UUID principalID, AssetType type) + public virtual InventoryFolderBase GetFolderForType(UUID principalID, FolderType type) { // m_log.DebugFormat("[XINVENTORY SERVICE]: Getting folder type {0} for user {1}", type, principalID); @@ -251,11 +259,11 @@ namespace OpenSim.Services.InventoryService return GetSystemFolderForType(rootFolder, type); } - private InventoryFolderBase GetSystemFolderForType(InventoryFolderBase rootFolder, AssetType type) + private InventoryFolderBase GetSystemFolderForType(InventoryFolderBase rootFolder, FolderType type) { -// m_log.DebugFormat("[XINVENTORY SERVICE]: Getting folder type {0} for user {1}", type, principalID); - - if (type == AssetType.RootFolder) + //m_log.DebugFormat("[XINVENTORY SERVICE]: Getting folder type {0}", type); + + if (type == FolderType.Root) return rootFolder; XInventoryFolder[] folders = m_Database.GetFolders( @@ -264,13 +272,13 @@ namespace OpenSim.Services.InventoryService if (folders.Length == 0) { -// m_log.WarnFormat("[XINVENTORY SERVICE]: Found no folder for type {0} for user {1}", type, principalID); + //m_log.WarnFormat("[XINVENTORY SERVICE]: Found no folder for type {0} ", type); return null; } - -// m_log.DebugFormat( -// "[XINVENTORY SERVICE]: Found folder {0} {1} for type {2} for user {3}", -// folders[0].folderName, folders[0].folderID, type, principalID); + + //m_log.DebugFormat( + // "[XINVENTORY SERVICE]: Found folder {0} {1} for type {2}", + // folders[0].folderName, folders[0].folderID, type); return ConvertToOpenSim(folders[0]); } @@ -283,7 +291,7 @@ namespace OpenSim.Services.InventoryService // //m_log.DebugFormat("[XINVENTORY SERVICE]: Fetch contents for folder {0}", folderID.ToString()); InventoryCollection inventory = new InventoryCollection(); - inventory.UserID = principalID; + inventory.OwnerID = principalID; inventory.Folders = new List(); inventory.Items = new List(); @@ -307,8 +315,27 @@ namespace OpenSim.Services.InventoryService inventory.Items.Add(ConvertToOpenSim(i)); } + InventoryFolderBase f = new InventoryFolderBase(folderID, principalID); + f = GetFolder(f); + if (f != null) + { + inventory.Version = f.Version; + inventory.OwnerID = f.Owner; + } + inventory.FolderID = folderID; + return inventory; } + + public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs) + { + InventoryCollection[] multiple = new InventoryCollection[folderIDs.Length]; + int i = 0; + foreach (UUID fid in folderIDs) + multiple[i++] = GetFolderContent(principalID, fid); + + return multiple; + } public virtual List GetFolderItems(UUID principalID, UUID folderID) { @@ -336,7 +363,7 @@ namespace OpenSim.Services.InventoryService if (check != null) return false; - if (folder.Type != (short)AssetType.Folder && folder.Type != (short)AssetType.Unknown) + if (folder.Type != (short)FolderType.None) { InventoryFolderBase rootFolder = GetRootFolder(folder.Owner); @@ -353,7 +380,7 @@ namespace OpenSim.Services.InventoryService if (folder.ParentID == rootFolder.ID) { InventoryFolderBase existingSystemFolder - = GetSystemFolderForType(rootFolder, (AssetType)folder.Type); + = GetSystemFolderForType(rootFolder, (FolderType)folder.Type); if (existingSystemFolder != null) { @@ -380,8 +407,8 @@ namespace OpenSim.Services.InventoryService if (check == null) return AddFolder(folder); - if ((check.Type != (short)AssetType.Unknown || xFolder.type != (short)AssetType.Unknown) - && (check.Type != (short)AssetType.OutfitFolder || xFolder.type != (short)AssetType.OutfitFolder)) + if ((check.Type != (short)FolderType.None || xFolder.type != (short)FolderType.None) + && (check.Type != (short)FolderType.Outfit || xFolder.type != (short)FolderType.Outfit)) { if (xFolder.version < check.Version) { @@ -583,6 +610,21 @@ namespace OpenSim.Services.InventoryService return ConvertToOpenSim(items[0]); } + public virtual InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] ids) + { + InventoryItemBase[] items = new InventoryItemBase[ids.Length]; + int i = 0; + InventoryItemBase item = new InventoryItemBase(); + item.Owner = userID; + foreach (UUID id in ids) + { + item.ID = id; + items[i++] = GetItem(item); + } + + return items; + } + public virtual InventoryFolderBase GetFolder(InventoryFolderBase folder) { XInventoryFolder[] folders = m_Database.GetFolders( @@ -615,34 +657,6 @@ namespace OpenSim.Services.InventoryService return m_Database.GetAssetPermissions(principalID, assetID); } - public virtual InventoryCollection GetUserInventory(UUID userID) - { - InventoryCollection userInventory = new InventoryCollection(); - userInventory.UserID = userID; - userInventory.Folders = new List(); - userInventory.Items = new List(); - - List skel = GetInventorySkeleton(userID); - if (skel != null) - { - foreach (InventoryFolderBase f in skel) - { - InventoryCollection c = GetFolderContent(userID, f.ID); - if (c != null && c.Items != null && c.Items.Count > 0) - userInventory.Items.AddRange(c.Items); - if (c != null && c.Folders != null && c.Folders.Count > 0) - userInventory.Folders.AddRange(c.Folders); - } - } - m_log.DebugFormat("[XINVENTORY SERVICE]: GetUserInventory for user {0} returning {1} folders and {2} items", - userID, userInventory.Folders.Count, userInventory.Items.Count); - return userInventory; - } - - public void GetUserInventory(UUID userID, InventoryReceiptCallback callback) - { - } - // Unused. // public bool HasInventoryForUser(UUID userID) @@ -658,9 +672,9 @@ namespace OpenSim.Services.InventoryService newFolder.ParentID = folder.parentFolderID; newFolder.Type = (short)folder.type; - // Viewer can't understand anything that's not in it's LLFolderType enum - if (newFolder.Type == 100) - newFolder.Type = -1; + //// Viewer can't understand anything that's not in it's LLFolderType enum + //if (newFolder.Type == InventoryItemBase.SUITCASE_FOLDER_TYPE) + // newFolder.Type = InventoryItemBase.SUITCASE_FOLDER_FAKE_TYPE; newFolder.Version = (ushort)folder.version; newFolder.Name = folder.folderName; newFolder.Owner = folder.agentID; @@ -751,7 +765,7 @@ namespace OpenSim.Services.InventoryService if (folder.Length < 1) return false; - if (folder[0].type == (int)AssetType.TrashFolder) + if (folder[0].type == (int)FolderType.Trash) return true; UUID parentFolder = folder[0].parentFolderID; @@ -762,9 +776,9 @@ namespace OpenSim.Services.InventoryService if (parent.Length < 1) return false; - if (parent[0].type == (int)AssetType.TrashFolder) + if (parent[0].type == (int)FolderType.Trash) return true; - if (parent[0].type == (int)AssetType.RootFolder) + if (parent[0].type == (int)FolderType.Root) return false; parentFolder = parent[0].parentFolderID; diff --git a/OpenSim/Services/LLLoginService/LLLoginResponse.cs b/OpenSim/Services/LLLoginService/LLLoginResponse.cs index 9ec744f..c3756d0 100644 --- a/OpenSim/Services/LLLoginService/LLLoginResponse.cs +++ b/OpenSim/Services/LLLoginService/LLLoginResponse.cs @@ -190,6 +190,8 @@ namespace OpenSim.Services.LLLoginService private BuddyList m_buddyList = null; private string currency; + private string classifiedFee; + private int maxAgentGroups; static LLLoginResponse() { @@ -226,8 +228,8 @@ namespace OpenSim.Services.LLLoginService public LLLoginResponse(UserAccount account, AgentCircuitData aCircuit, GridUserInfo pinfo, GridRegion destination, List invSkel, FriendInfo[] friendsList, ILibraryService libService, string where, string startlocation, Vector3 position, Vector3 lookAt, List gestures, string message, - GridRegion home, IPEndPoint clientIP, string mapTileURL, string profileURL, string openIDURL, string searchURL, string currency, - string DSTZone) + GridRegion home, IPEndPoint clientIP, string mapTileURL, string searchURL, string currency, + string DSTZone, string destinationsURL, string avatarsURL, string classifiedFee, int maxAgentGroups) : this() { FillOutInventoryData(invSkel, libService); @@ -246,14 +248,19 @@ namespace OpenSim.Services.LLLoginService MapTileURL = mapTileURL; ProfileURL = profileURL; OpenIDURL = openIDURL; + DestinationsURL = destinationsURL; + AvatarsURL = avatarsURL; SearchURL = searchURL; Currency = currency; + ClassifiedFee = classifiedFee; + MaxAgentGroups = maxAgentGroups; FillOutHomeData(pinfo, home); LookAt = String.Format("[r{0},r{1},r{2}]", lookAt.X, lookAt.Y, lookAt.Z); FillOutRegionData(destination); + m_log.DebugFormat("[LOGIN RESPONSE] LLLoginResponse create. sizeX={0}, sizeY={1}", RegionSizeX, RegionSizeY); FillOutSeedCap(aCircuit, destination, clientIP); @@ -356,7 +363,8 @@ namespace OpenSim.Services.LLLoginService private void FillOutHomeData(GridUserInfo pinfo, GridRegion home) { - int x = 1000 * (int)Constants.RegionSize, y = 1000 * (int)Constants.RegionSize; + int x = (int)Util.RegionToWorldLoc(1000); + int y = (int)Util.RegionToWorldLoc(1000); if (home != null) { x = home.RegionLocX; @@ -379,6 +387,8 @@ namespace OpenSim.Services.LLLoginService SimPort = (uint)endPoint.Port; RegionX = (uint)destination.RegionLocX; RegionY = (uint)destination.RegionLocY; + RegionSizeX = destination.RegionSizeX; + RegionSizeY = destination.RegionSizeY; } private void FillOutSeedCap(AgentCircuitData aCircuit, GridRegion destination, IPEndPoint ipepClient) @@ -428,10 +438,23 @@ namespace OpenSim.Services.LLLoginService ErrorReason = "key"; welcomeMessage = "Welcome to OpenSim!"; seedCapability = String.Empty; - home = "{'region_handle':[r" + (1000*Constants.RegionSize).ToString() + ",r" + (1000*Constants.RegionSize).ToString() + "], 'position':[r" + - userProfile.homepos.X.ToString() + ",r" + userProfile.homepos.Y.ToString() + ",r" + - userProfile.homepos.Z.ToString() + "], 'look_at':[r" + userProfile.homelookat.X.ToString() + ",r" + - userProfile.homelookat.Y.ToString() + ",r" + userProfile.homelookat.Z.ToString() + "]}"; + home = "{'region_handle':[" + + "r" + Util.RegionToWorldLoc(1000).ToString() + + "," + + "r" + Util.RegionToWorldLoc(1000).ToString() + + "], 'position':[" + + "r" + userProfile.homepos.X.ToString() + + "," + + "r" + userProfile.homepos.Y.ToString() + + "," + + "r" + userProfile.homepos.Z.ToString() + + "], 'look_at':[" + + "r" + userProfile.homelookat.X.ToString() + + "," + + "r" + userProfile.homelookat.Y.ToString() + + "," + + "r" + userProfile.homelookat.Z.ToString() + + "]}"; lookAt = "[r0.99949799999999999756,r0.03166859999999999814,r0]"; RegionX = (uint) 255232; RegionY = (uint) 254976; @@ -461,6 +484,8 @@ namespace OpenSim.Services.LLLoginService searchURL = String.Empty; currency = String.Empty; + ClassifiedFee = "0"; + MaxAgentGroups = 42; } @@ -520,9 +545,13 @@ namespace OpenSim.Services.LLLoginService responseData["seed_capability"] = seedCapability; responseData["home"] = home; responseData["look_at"] = lookAt; + responseData["max-agent-groups"] = MaxAgentGroups; responseData["message"] = welcomeMessage; responseData["region_x"] = (Int32)(RegionX); responseData["region_y"] = (Int32)(RegionY); + responseData["region_size_x"] = (Int32)RegionSizeX; + responseData["region_size_y"] = (Int32)RegionSizeY; + m_log.DebugFormat("[LOGIN RESPONSE] returning sizeX={0}, sizeY={1}", RegionSizeX, RegionSizeY); if (searchURL != String.Empty) responseData["search"] = searchURL; @@ -533,6 +562,12 @@ namespace OpenSim.Services.LLLoginService if (profileURL != String.Empty) responseData["profile-server-url"] = profileURL; + if (DestinationsURL != String.Empty) + responseData["destination_guide_url"] = DestinationsURL; + + if (AvatarsURL != String.Empty) + responseData["avatar_picker_url"] = AvatarsURL; + // We need to send an openid_token back in the response too if (openIDURL != String.Empty) responseData["openid_url"] = openIDURL; @@ -547,6 +582,9 @@ namespace OpenSim.Services.LLLoginService // responseData["real_currency"] = currency; responseData["currency"] = currency; } + + if (ClassifiedFee != String.Empty) + responseData["classified_fee"] = ClassifiedFee; responseData["login"] = "true"; @@ -635,6 +673,7 @@ namespace OpenSim.Services.LLLoginService map["seed_capability"] = OSD.FromString(seedCapability); map["home"] = OSD.FromString(home); map["look_at"] = OSD.FromString(lookAt); + map["max-agent-groups"] = OSD.FromInteger(MaxAgentGroups); map["message"] = OSD.FromString(welcomeMessage); map["region_x"] = OSD.FromInteger(RegionX); map["region_y"] = OSD.FromInteger(RegionY); @@ -651,6 +690,9 @@ namespace OpenSim.Services.LLLoginService if (searchURL != String.Empty) map["search"] = OSD.FromString(searchURL); + if (ClassifiedFee != String.Empty) + map["classified_fee"] = OSD.FromString(ClassifiedFee); + if (m_buddyList != null) { map["buddy-list"] = ArrayListToOSDArray(m_buddyList.ToArray()); @@ -746,7 +788,7 @@ namespace OpenSim.Services.LLLoginService Hashtable TempHash; foreach (InventoryFolderBase InvFolder in folders) { - if (InvFolder.ParentID == UUID.Zero && InvFolder.Name == "My Inventory") + if (InvFolder.ParentID == UUID.Zero && InvFolder.Name == InventoryFolderBase.ROOT_FOLDER_NAME) { rootID = InvFolder.ID; } @@ -900,6 +942,9 @@ namespace OpenSim.Services.LLLoginService set { regionY = value; } } + public int RegionSizeX { get; private set; } + public int RegionSizeY { get; private set; } + public string SunTexture { get { return sunTexture; } @@ -1056,6 +1101,28 @@ namespace OpenSim.Services.LLLoginService set { currency = value; } } + public string ClassifiedFee + { + get { return classifiedFee; } + set { classifiedFee = value; } + } + + public int MaxAgentGroups + { + get { return maxAgentGroups; } + set { maxAgentGroups = value; } + } + + public string DestinationsURL + { + get; set; + } + + public string AvatarsURL + { + get; set; + } + #endregion public class UserInfo diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 59fb559..0b38738 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -50,12 +50,15 @@ namespace OpenSim.Services.LLLoginService public class LLLoginService : ILoginService { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly string LogHeader = "[LLOGIN SERVICE]"; + private static bool Initialized = false; protected IUserAccountService m_UserAccountService; protected IGridUserService m_GridUserService; protected IAuthenticationService m_AuthenticationService; protected IInventoryService m_InventoryService; + protected IInventoryService m_HGInventoryService; protected IGridService m_GridService; protected IPresenceService m_PresenceService; protected ISimulationService m_LocalSimulationService; @@ -74,14 +77,15 @@ namespace OpenSim.Services.LLLoginService protected string m_GatekeeperURL; protected bool m_AllowRemoteSetLoginLevel; protected string m_MapTileURL; - protected string m_ProfileURL; - protected string m_OpenIDURL; protected string m_SearchURL; protected string m_Currency; - + protected string m_ClassifiedFee; + protected int m_MaxAgentGroups; + protected string m_DestinationGuide; + protected string m_AvatarPicker; protected string m_AllowedClients; protected string m_DeniedClients; - + protected string m_MessageUrl; protected string m_DSTZone; IConfig m_LoginServerConfig; @@ -110,18 +114,29 @@ namespace OpenSim.Services.LLLoginService m_RequireInventory = m_LoginServerConfig.GetBoolean("RequireInventory", true); m_AllowRemoteSetLoginLevel = m_LoginServerConfig.GetBoolean("AllowRemoteSetLoginLevel", false); m_MinLoginLevel = m_LoginServerConfig.GetInt("MinLoginLevel", 0); - m_GatekeeperURL = m_LoginServerConfig.GetString("GatekeeperURI", string.Empty); + m_GatekeeperURL = Util.GetConfigVarFromSections(config, "GatekeeperURI", + new string[] { "Startup", "Hypergrid", "LoginService" }, String.Empty); m_MapTileURL = m_LoginServerConfig.GetString("MapTileURL", string.Empty); - m_ProfileURL = m_LoginServerConfig.GetString("ProfileServerURL", string.Empty); - m_OpenIDURL = m_LoginServerConfig.GetString("OpenIDServerURL", String.Empty); m_SearchURL = m_LoginServerConfig.GetString("SearchURL", string.Empty); m_Currency = m_LoginServerConfig.GetString("Currency", string.Empty); + m_ClassifiedFee = m_LoginServerConfig.GetString("ClassifiedFee", string.Empty); + m_DestinationGuide = m_LoginServerConfig.GetString ("DestinationGuide", string.Empty); + m_AvatarPicker = m_LoginServerConfig.GetString ("AvatarPicker", string.Empty); - m_AllowedClients = m_LoginServerConfig.GetString("AllowedClients", string.Empty); - m_DeniedClients = m_LoginServerConfig.GetString("DeniedClients", string.Empty); + string[] possibleAccessControlConfigSections = new string[] { "AccessControl", "LoginService" }; + m_AllowedClients = Util.GetConfigVarFromSections( + config, "AllowedClients", possibleAccessControlConfigSections, string.Empty); + m_DeniedClients = Util.GetConfigVarFromSections( + config, "DeniedClients", possibleAccessControlConfigSections, string.Empty); + m_MessageUrl = m_LoginServerConfig.GetString("MessageUrl", string.Empty); m_DSTZone = m_LoginServerConfig.GetString("DSTZone", "America/Los_Angeles;Pacific Standard Time"); + IConfig groupConfig = config.Configs["Groups"]; + if (groupConfig != null) + m_MaxAgentGroups = groupConfig.GetInt("MaxAgentGroups", 42); + + // Clean up some of these vars if (m_MapTileURL != String.Empty) { @@ -156,6 +171,15 @@ namespace OpenSim.Services.LLLoginService if (agentService != string.Empty) m_UserAgentService = ServerUtils.LoadPlugin(agentService, args); + // Get the Hypergrid inventory service (exists only if Hypergrid is enabled) + string hgInvServicePlugin = m_LoginServerConfig.GetString("HGInventoryServicePlugin", String.Empty); + if (hgInvServicePlugin != string.Empty) + { + string hgInvServiceArg = m_LoginServerConfig.GetString("HGInventoryServiceConstructorArg", String.Empty); + Object[] args2 = new Object[] { config, hgInvServiceArg }; + m_HGInventoryService = ServerUtils.LoadPlugin(hgInvServicePlugin, args2); + } + // // deal with the services given as argument // @@ -241,6 +265,7 @@ namespace OpenSim.Services.LLLoginService { bool success = false; UUID session = UUID.Random(); + string processedMessage; m_log.InfoFormat("[LLOGIN SERVICE]: Login request for {0} {1} at {2} using viewer {3}, channel {4}, IP {5}, Mac {6}, Id0 {7}", firstName, lastName, startLocation, clientVersion, channel, clientIP.Address.ToString(), mac, id0); @@ -341,6 +366,13 @@ namespace OpenSim.Services.LLLoginService return LLFailedLoginResponse.InventoryProblem; } + if (m_HGInventoryService != null) + { + // Give the Suitcase service a chance to create the suitcase folder. + // (If we're not using the Suitcase inventory service then this won't do anything.) + m_HGInventoryService.GetRootFolder(account.PrincipalID); + } + List inventorySkel = m_InventoryService.GetInventorySkeleton(account.PrincipalID); if (m_RequireInventory && ((inventorySkel == null) || (inventorySkel != null && inventorySkel.Count == 0))) { @@ -375,13 +407,33 @@ namespace OpenSim.Services.LLLoginService // GridRegion home = null; GridUserInfo guinfo = m_GridUserService.LoggedIn(account.PrincipalID.ToString()); - if (guinfo != null && (guinfo.HomeRegionID != UUID.Zero) && m_GridService != null) + + // We are only going to complain about no home if the user actually tries to login there, to avoid + // spamming the console. + if (guinfo != null) { - home = m_GridService.GetRegionByUUID(scopeID, guinfo.HomeRegionID); + if (guinfo.HomeRegionID == UUID.Zero && startLocation == "home") + { + m_log.WarnFormat( + "[LLOGIN SERVICE]: User {0} tried to login to a 'home' start location but they have none set", + account.Name); + } + else if (m_GridService != null) + { + home = m_GridService.GetRegionByUUID(scopeID, guinfo.HomeRegionID); + + if (home == null && startLocation == "home") + { + m_log.WarnFormat( + "[LLOGIN SERVICE]: User {0} tried to login to a 'home' start location with ID {1} but this was not found.", + account.Name, guinfo.HomeRegionID); + } + } } - if (guinfo == null) + else { // something went wrong, make something up, so that we don't have to test this anywhere else + m_log.DebugFormat("{0} Failed to fetch GridUserInfo. Creating empty GridUserInfo as home", LogHeader); guinfo = new GridUserInfo(); guinfo.LastPosition = guinfo.HomePosition = new Vector3(128, 128, 30); } @@ -448,16 +500,28 @@ namespace OpenSim.Services.LLLoginService // // Finally, fill out the response and return it // + if (m_MessageUrl != String.Empty) + { + WebClient client = new WebClient(); + processedMessage = client.DownloadString(m_MessageUrl); + } + else + { + processedMessage = m_WelcomeMessage; + } + processedMessage = processedMessage.Replace("\\n", "\n").Replace("", firstName + " " + lastName); + LLLoginResponse response - = new LLLoginResponse( - account, aCircuit, guinfo, destination, inventorySkel, friendsList, m_LibraryService, - where, startLocation, position, lookAt, gestures, m_WelcomeMessage, home, clientIP, - m_MapTileURL, m_ProfileURL, m_OpenIDURL, m_SearchURL, m_Currency, m_DSTZone); + = new LLLoginResponse( + account, aCircuit, guinfo, destination, inventorySkel, friendsList, m_LibraryService, + where, startLocation, position, lookAt, gestures, processedMessage, home, clientIP, + m_MapTileURL, m_SearchURL, m_Currency, m_DSTZone, + m_DestinationGuide, m_AvatarPicker, m_ClassifiedFee, m_MaxAgentGroups); - m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to {0} {1}", firstName, lastName); + m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to {0} {1}", firstName, lastName); - return response; - } + return response; + } catch (Exception e) { m_log.WarnFormat("[LLOGIN SERVICE]: Exception processing login for {0} {1}: {2} {3}", firstName, lastName, e.ToString(), e.StackTrace); @@ -498,10 +562,6 @@ namespace OpenSim.Services.LLLoginService if (home == null) { - m_log.WarnFormat( - "[LLOGIN SERVICE]: User {0} {1} tried to login to a 'home' start location but they have none set", - account.FirstName, account.LastName); - tryDefaults = true; } else @@ -576,7 +636,7 @@ namespace OpenSim.Services.LLLoginService // e.g. New Moon&135&46 New Moon@osgrid.org:8002&153&34 where = "url"; GridRegion region = null; - Regex reURI = new Regex(@"^uri:(?[^&]+)&(?\d+)&(?\d+)&(?\d+)$"); + Regex reURI = new Regex(@"^uri:(?[^&]+)&(?\d+[.]?\d*)&(?\d+[.]?\d*)&(?\d+[.]?\d*)$"); Match uriMatch = reURI.Match(startLocation); if (uriMatch == null) { @@ -645,8 +705,7 @@ namespace OpenSim.Services.LLLoginService if (parts.Length > 1) UInt32.TryParse(parts[1], out port); -// GridRegion region = FindForeignRegion(domainName, port, regionName, out gatekeeper); - region = FindForeignRegion(domainName, port, regionName, out gatekeeper); + region = FindForeignRegion(domainName, port, regionName, account, out gatekeeper); return region; } } @@ -673,7 +732,7 @@ namespace OpenSim.Services.LLLoginService private GridRegion FindAlternativeRegion(UUID scopeID) { List hyperlinks = null; - List regions = m_GridService.GetFallbackRegions(scopeID, 1000 * (int)Constants.RegionSize, 1000 * (int)Constants.RegionSize); + List regions = m_GridService.GetFallbackRegions(scopeID, (int)Util.RegionToWorldLoc(1000), (int)Util.RegionToWorldLoc(1000)); if (regions != null && regions.Count > 0) { hyperlinks = m_GridService.GetHyperlinks(scopeID); @@ -695,7 +754,7 @@ namespace OpenSim.Services.LLLoginService return null; } - private GridRegion FindForeignRegion(string domainName, uint port, string regionName, out GridRegion gatekeeper) + private GridRegion FindForeignRegion(string domainName, uint port, string regionName, UserAccount account, out GridRegion gatekeeper) { m_log.Debug("[LLLOGIN SERVICE]: attempting to findforeignregion " + domainName + ":" + port.ToString() + ":" + regionName); gatekeeper = new GridRegion(); @@ -707,9 +766,14 @@ namespace OpenSim.Services.LLLoginService UUID regionID; ulong handle; string imageURL = string.Empty, reason = string.Empty; + string message; if (m_GatekeeperConnector.LinkRegion(gatekeeper, out regionID, out handle, out domainName, out imageURL, out reason)) { - GridRegion destination = m_GatekeeperConnector.GetHyperlinkRegion(gatekeeper, regionID); + string homeURI = null; + if (account.ServiceURLs != null && account.ServiceURLs.ContainsKey("HomeURI")) + homeURI = (string)account.ServiceURLs["HomeURI"]; + + GridRegion destination = m_GatekeeperConnector.GetHyperlinkRegion(gatekeeper, regionID, account.PrincipalID, homeURI, out message); return destination; } @@ -858,13 +922,6 @@ namespace OpenSim.Services.LLLoginService SetServiceURLs(aCircuit, account); return aCircuit; - - //m_UserAgentService.LoginAgentToGrid(aCircuit, GatekeeperServiceConnector, region, out reason); - //if (simConnector.CreateAgent(region, aCircuit, 0, out reason)) - // return aCircuit; - - //return null; - } private void SetServiceURLs(AgentCircuitData aCircuit, UserAccount account) @@ -899,7 +956,7 @@ namespace OpenSim.Services.LLLoginService if (!keyValue.EndsWith("/")) keyValue = keyValue + "/"; - if (!account.ServiceURLs.ContainsKey(keyName) || (account.ServiceURLs.ContainsKey(keyName) && account.ServiceURLs[keyName] != keyValue)) + if (!account.ServiceURLs.ContainsKey(keyName) || (account.ServiceURLs.ContainsKey(keyName) && (string)account.ServiceURLs[keyName] != keyValue)) { account.ServiceURLs[keyName] = keyValue; newUrls = true; @@ -909,6 +966,13 @@ namespace OpenSim.Services.LLLoginService m_log.DebugFormat("[LLLOGIN SERVICE]: found new key {0} {1}", keyName, aCircuit.ServiceURLs[keyName]); } + if (!account.ServiceURLs.ContainsKey("GatekeeperURI") && !string.IsNullOrEmpty(m_GatekeeperURL)) + { + m_log.DebugFormat("[LLLOGIN SERVICE]: adding gatekeeper uri {0}", m_GatekeeperURL); + account.ServiceURLs["GatekeeperURI"] = m_GatekeeperURL; + newUrls = true; + } + // The grid operator decided to override the defaults in the // [LoginService] configuration. Let's store the correct ones. if (newUrls) @@ -919,13 +983,20 @@ namespace OpenSim.Services.LLLoginService private bool LaunchAgentDirectly(ISimulationService simConnector, GridRegion region, AgentCircuitData aCircuit, TeleportFlags flags, out string reason) { - return simConnector.CreateAgent(region, aCircuit, (uint)flags, out reason); + EntityTransferContext ctx = new EntityTransferContext(); + + if (!simConnector.QueryAccess( + region, aCircuit.AgentID, null, true, aCircuit.startpos, new List(), ctx, out reason)) + return false; + + return simConnector.CreateAgent(null, region, aCircuit, (uint)flags, out reason); } private bool LaunchAgentIndirectly(GridRegion gatekeeper, GridRegion destination, AgentCircuitData aCircuit, IPEndPoint clientIP, out string reason) { - m_log.Debug("[LLOGIN SERVICE] Launching agent at " + destination.RegionName); - if (m_UserAgentService.LoginAgentToGrid(aCircuit, gatekeeper, destination, clientIP, out reason)) + m_log.Debug("[LLOGIN SERVICE]: Launching agent at " + destination.RegionName); + + if (m_UserAgentService.LoginAgentToGrid(null, aCircuit, gatekeeper, destination, true, out reason)) return true; return false; } @@ -961,14 +1032,25 @@ namespace OpenSim.Services.LLLoginService // or fixing critical issues // if (cmd.Length > 2) - Int32.TryParse(cmd[2], out m_MinLoginLevel); + { + if (Int32.TryParse(cmd[2], out m_MinLoginLevel)) + MainConsole.Instance.OutputFormat("Set minimum login level to {0}", m_MinLoginLevel); + else + MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid login level", cmd[2]); + } break; - case "reset": + + case "reset": m_MinLoginLevel = 0; + MainConsole.Instance.OutputFormat("Reset min login level to {0}", m_MinLoginLevel); break; + case "text": if (cmd.Length > 2) + { m_WelcomeMessage = cmd[2]; + MainConsole.Instance.OutputFormat("Login welcome message set to '{0}'", m_WelcomeMessage); + } break; } } diff --git a/OpenSim/Services/LLLoginService/Properties/AssemblyInfo.cs b/OpenSim/Services/LLLoginService/Properties/AssemblyInfo.cs index 62c6e0f..5c150e3 100644 --- a/OpenSim/Services/LLLoginService/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/LLLoginService/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/MapImageService/MapImageService.cs b/OpenSim/Services/MapImageService/MapImageService.cs index a85ee70..a816411 100644 --- a/OpenSim/Services/MapImageService/MapImageService.cs +++ b/OpenSim/Services/MapImageService/MapImageService.cs @@ -36,6 +36,7 @@ using System.Drawing.Imaging; using System.IO; using System.Net; using System.Reflection; +using System.Threading; using Nini.Config; using log4net; @@ -53,6 +54,9 @@ namespace OpenSim.Services.MapImageService private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); +#pragma warning disable 414 + private string LogHeader = "[MAP IMAGE SERVICE]"; +#pragma warning restore 414 private const int ZOOM_LEVELS = 8; private const int IMAGE_WIDTH = 256; @@ -86,7 +90,7 @@ namespace OpenSim.Services.MapImageService { Bitmap waterTile = new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH); FillImage(waterTile, m_Watercolor); - waterTile.Save(m_WaterTileFile); + waterTile.Save(m_WaterTileFile, ImageFormat.Jpeg); } } } @@ -112,28 +116,106 @@ namespace OpenSim.Services.MapImageService reason = e.Message; return false; } + } + + return UpdateMultiResolutionFilesAsync(x, y, out reason); + } - // Also save in png format? + public bool RemoveMapTile(int x, int y, out string reason) + { + reason = String.Empty; + string fileName = GetFileName(1, x, y); - // Stitch seven more aggregate tiles together - for (uint zoomLevel = 2; zoomLevel <= ZOOM_LEVELS; zoomLevel++) + lock (m_Sync) + { + try + { + File.Delete(fileName); + } + catch (Exception e) { - // Calculate the width (in full resolution tiles) and bottom-left - // corner of the current zoom level - int width = (int)Math.Pow(2, (double)(zoomLevel - 1)); - int x1 = x - (x % width); - int y1 = y - (y % width); + m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to save delete file {0}: {1}", fileName, e); + reason = e.Message; + return false; + } + } + + return UpdateMultiResolutionFilesAsync(x, y, out reason); + } - if (!CreateTile(zoomLevel, x1, y1)) + // When large varregions start up, they can send piles of new map tiles. This causes + // this multi-resolution routine to be called a zillion times an causes much CPU + // time to be spent creating multi-resolution tiles that will be replaced when + // the next maptile arrives. + private class mapToMultiRez + { + public int xx; + public int yy; + public mapToMultiRez(int pX, int pY) + { + xx = pX; + yy = pY; + } + }; + private Queue multiRezToBuild = new Queue(); + private bool UpdateMultiResolutionFilesAsync(int x, int y, out string reason) + { + reason = String.Empty; + lock (multiRezToBuild) + { + // m_log.DebugFormat("{0} UpdateMultiResolutionFilesAsync: scheduling update for <{1},{2}>", LogHeader, x, y); + multiRezToBuild.Enqueue(new mapToMultiRez(x, y)); + if (multiRezToBuild.Count == 1) + Util.FireAndForget( + DoUpdateMultiResolutionFilesAsync, null, "MapImageService.DoUpdateMultiResolutionFilesAsync"); + } + + return true; + } + + private void DoUpdateMultiResolutionFilesAsync(object o) + { + // This sleep causes the FireAndForget thread to be different than the invocation thread. + // It also allows other tiles to be uploaded so the multi-rez images are more likely + // to be correct. + Thread.Sleep(1 * 1000); + + while (multiRezToBuild.Count > 0) + { + mapToMultiRez toMultiRez = null; + lock (multiRezToBuild) + { + if (multiRezToBuild.Count > 0) + toMultiRez = multiRezToBuild.Dequeue(); + } + if (toMultiRez != null) + { + int x = toMultiRez.xx; + int y = toMultiRez.yy; + // m_log.DebugFormat("{0} DoUpdateMultiResolutionFilesAsync: doing build for <{1},{2}>", LogHeader, x, y); + + // Stitch seven more aggregate tiles together + for (uint zoomLevel = 2; zoomLevel <= ZOOM_LEVELS; zoomLevel++) { - m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to create tile for {0} at zoom level {1}", fileName, zoomLevel); - reason = string.Format("Map tile at zoom level {0} failed", zoomLevel); - return false; + // Calculate the width (in full resolution tiles) and bottom-left + // corner of the current zoom level + int width = (int)Math.Pow(2, (double)(zoomLevel - 1)); + int x1 = x - (x % width); + int y1 = y - (y % width); + + lock (m_Sync) // must lock the reading and writing of the maptile files + { + if (!CreateTile(zoomLevel, x1, y1)) + { + m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to create tile for {0},{1} at zoom level {1}", x, y, zoomLevel); + return; + } + } } } } - return true; + return; } public byte[] GetMapTile(string fileName, out string format) diff --git a/OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs b/OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs index 23eb664..e779238 100644 --- a/OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/MapImageService/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/PresenceService/PresenceService.cs b/OpenSim/Services/PresenceService/PresenceService.cs index ed2703e..b5ca4d5 100644 --- a/OpenSim/Services/PresenceService/PresenceService.cs +++ b/OpenSim/Services/PresenceService/PresenceService.cs @@ -41,9 +41,7 @@ namespace OpenSim.Services.PresenceService { public class PresenceService : PresenceServiceBase, IPresenceService { - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected bool m_allowDuplicatePresences = false; @@ -55,19 +53,15 @@ namespace OpenSim.Services.PresenceService IConfig presenceConfig = config.Configs["PresenceService"]; if (presenceConfig != null) { - m_allowDuplicatePresences = - presenceConfig.GetBoolean("AllowDuplicatePresences", - m_allowDuplicatePresences); + m_allowDuplicatePresences = presenceConfig.GetBoolean("AllowDuplicatePresences", m_allowDuplicatePresences); } } - public bool LoginAgent(string userID, UUID sessionID, - UUID secureSessionID) + public bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID) { - //PresenceData[] d = m_Database.Get("UserID", userID); - //m_Database.Get("UserID", userID); + PresenceData prevUser = GetUser(userID); - if (!m_allowDuplicatePresences) + if (!m_allowDuplicatePresences && (prevUser != null)) m_Database.Delete("UserID", userID.ToString()); PresenceData data = new PresenceData(); @@ -80,19 +74,41 @@ namespace OpenSim.Services.PresenceService m_Database.Store(data); - m_log.DebugFormat("[PRESENCE SERVICE]: LoginAgent {0} with session {1} and ssession {2}", - userID, sessionID, secureSessionID); + string prevUserStr = ""; + if (prevUser != null) + prevUserStr = string.Format(". This user was already logged-in: session {0}, region {1}", prevUser.SessionID, prevUser.RegionID); + + m_log.DebugFormat("[PRESENCE SERVICE]: LoginAgent: session {0}, user {1}, region {2}, secure session {3}{4}", + data.SessionID, data.UserID, data.RegionID, secureSessionID, prevUserStr); + return true; } public bool LogoutAgent(UUID sessionID) { - m_log.DebugFormat("[PRESENCE SERVICE]: Session {0} logout", sessionID); + PresenceInfo presence = GetAgent(sessionID); + + m_log.InfoFormat("[PRESENCE SERVICE]: LogoutAgent: session {0}, user {1}, region {2}", + sessionID, + (presence == null) ? null : presence.UserID, + (presence == null) ? null : presence.RegionID.ToString()); + return m_Database.Delete("SessionID", sessionID.ToString()); } public bool LogoutRegionAgents(UUID regionID) { + PresenceData[] prevSessions = GetRegionAgents(regionID); + + if ((prevSessions == null) || (prevSessions.Length == 0)) + return true; + + m_log.DebugFormat("[PRESENCE SERVICE]: Logout users in region {0}: {1}", regionID, + string.Join(", ", Array.ConvertAll(prevSessions, session => session.UserID))); + + // There's a small chance that LogoutRegionAgents() will logout different users than the + // list that was logged above, but it's unlikely and not worth dealing with. + m_Database.LogoutRegionAgents(regionID); return true; @@ -101,20 +117,26 @@ namespace OpenSim.Services.PresenceService public bool ReportAgent(UUID sessionID, UUID regionID) { -// m_log.DebugFormat("[PRESENCE SERVICE]: ReportAgent with session {0} in region {1}", sessionID, regionID); try { - PresenceData pdata = m_Database.Get(sessionID); - if (pdata == null) - return false; - if (pdata.Data == null) - return false; + PresenceData presence = m_Database.Get(sessionID); + + bool success; + if (presence == null) + success = false; + else + success = m_Database.ReportAgent(sessionID, regionID); - return m_Database.ReportAgent(sessionID, regionID); + m_log.DebugFormat("[PRESENCE SERVICE]: ReportAgent{0}: session {1}, user {2}, region {3}. Previously: {4}", + success ? "" : " failed", + sessionID, (presence == null) ? null : presence.UserID, regionID, + (presence == null) ? "not logged-in" : "region " + presence.RegionID); + + return success; } catch (Exception e) { - m_log.DebugFormat("[PRESENCE SERVICE]: ReportAgent threw exception {0}", e.StackTrace); + m_log.Debug(string.Format("[PRESENCE SERVICE]: ReportAgent for session {0} threw exception ", sessionID), e); return false; } } @@ -139,8 +161,7 @@ namespace OpenSim.Services.PresenceService foreach (string userIDStr in userIDs) { - PresenceData[] data = m_Database.Get("UserID", - userIDStr); + PresenceData[] data = m_Database.Get("UserID", userIDStr); foreach (PresenceData d in data) { @@ -158,5 +179,23 @@ namespace OpenSim.Services.PresenceService return info.ToArray(); } + + /// + /// Return the user's Presence. This only really works well if !AllowDuplicatePresences, but that's the default. + /// + private PresenceData GetUser(string userID) + { + PresenceData[] data = m_Database.Get("UserID", userID); + if (data.Length > 0) + return data[0]; + else + return null; + } + + private PresenceData[] GetRegionAgents(UUID regionID) + { + return m_Database.Get("RegionID", regionID.ToString()); + } + } } \ No newline at end of file diff --git a/OpenSim/Services/PresenceService/Properties/AssemblyInfo.cs b/OpenSim/Services/PresenceService/Properties/AssemblyInfo.cs index 8c03dd7..4fd21a8 100644 --- a/OpenSim/Services/PresenceService/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/PresenceService/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/SimulationService/SimulationDataService.cs b/OpenSim/Services/SimulationService/SimulationDataService.cs new file mode 100644 index 0000000..d9684c4 --- /dev/null +++ b/OpenSim/Services/SimulationService/SimulationDataService.cs @@ -0,0 +1,191 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse; +using log4net; +using Nini.Config; +using System.Reflection; +using OpenSim.Services.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Services.SimulationService +{ + public class SimulationDataService : ServiceBase, ISimulationDataService + { +// private static readonly ILog m_log = +// LogManager.GetLogger( +// MethodBase.GetCurrentMethod().DeclaringType); + + protected ISimulationDataStore m_database; + + public SimulationDataService(IConfigSource config) + : base(config) + { + string dllName = String.Empty; + string connString = String.Empty; + + // Try reading the [DatabaseService] section, if it exists + IConfig dbConfig = config.Configs["DatabaseService"]; + if (dbConfig != null) + { + dllName = dbConfig.GetString("StorageProvider", String.Empty); + connString = dbConfig.GetString("ConnectionString", String.Empty); + } + + // Try reading the [SimulationDataStore] section + IConfig simConfig = config.Configs["SimulationDataStore"]; + if (simConfig != null) + { + dllName = simConfig.GetString("StorageProvider", dllName); + connString = simConfig.GetString("ConnectionString", connString); + } + + // We tried, but this doesn't exist. We can't proceed + if (dllName == String.Empty) + throw new Exception("No StorageProvider configured"); + + m_database = LoadPlugin(dllName, new Object[] { connString }); + if (m_database == null) + throw new Exception("Could not find a storage interface in the given module"); + } + + public void StoreObject(SceneObjectGroup obj, UUID regionUUID) + { + m_database.StoreObject(obj, regionUUID); + } + + public void RemoveObject(UUID uuid, UUID regionUUID) + { + m_database.RemoveObject(uuid, regionUUID); + } + + public void StorePrimInventory(UUID primID, ICollection items) + { + m_database.StorePrimInventory(primID, items); + } + + public List LoadObjects(UUID regionUUID) + { + return m_database.LoadObjects(regionUUID); + } + + public void StoreTerrain(TerrainData terrain, UUID regionID) + { + m_database.StoreTerrain(terrain, regionID); + } + + public void StoreTerrain(double[,] terrain, UUID regionID) + { + m_database.StoreTerrain(terrain, regionID); + } + + public double[,] LoadTerrain(UUID regionID) + { + return m_database.LoadTerrain(regionID); + } + + public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ) + { + return m_database.LoadTerrain(regionID, pSizeX, pSizeY, pSizeZ); + } + + public void StoreLandObject(ILandObject Parcel) + { + m_database.StoreLandObject(Parcel); + } + + public void RemoveLandObject(UUID globalID) + { + m_database.RemoveLandObject(globalID); + } + + public List LoadLandObjects(UUID regionUUID) + { + return m_database.LoadLandObjects(regionUUID); + } + + public void StoreRegionSettings(RegionSettings rs) + { + m_database.StoreRegionSettings(rs); + } + + public RegionSettings LoadRegionSettings(UUID regionUUID) + { + return m_database.LoadRegionSettings(regionUUID); + } + + public RegionLightShareData LoadRegionWindlightSettings(UUID regionUUID) + { + return m_database.LoadRegionWindlightSettings(regionUUID); + } + + public void StoreRegionWindlightSettings(RegionLightShareData wl) + { + m_database.StoreRegionWindlightSettings(wl); + } + public void RemoveRegionWindlightSettings(UUID regionID) + { + m_database.RemoveRegionWindlightSettings(regionID); + } + + public string LoadRegionEnvironmentSettings(UUID regionUUID) + { + return m_database.LoadRegionEnvironmentSettings(regionUUID); + } + + public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) + { + m_database.StoreRegionEnvironmentSettings(regionUUID, settings); + } + + public void RemoveRegionEnvironmentSettings(UUID regionUUID) + { + m_database.RemoveRegionEnvironmentSettings(regionUUID); + } + + public void SaveExtra(UUID regionID, string name, string val) + { + m_database.SaveExtra(regionID, name, val); + } + + public void RemoveExtra(UUID regionID, string name) + { + m_database.RemoveExtra(regionID, name); + } + + public Dictionary GetExtra(UUID regionID) + { + return m_database.GetExtra(regionID); + } + } +} diff --git a/OpenSim/Services/UserAccountService/AgentPreferencesService.cs b/OpenSim/Services/UserAccountService/AgentPreferencesService.cs new file mode 100644 index 0000000..1808ee5 --- /dev/null +++ b/OpenSim/Services/UserAccountService/AgentPreferencesService.cs @@ -0,0 +1,82 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Services.UserAccountService +{ + public class AgentPreferencesService : AgentPreferencesServiceBase, IAgentPreferencesService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public AgentPreferencesService(IConfigSource config) : base(config) + { + m_log.Debug("[AGENT PREFERENCES SERVICE]: Starting agent preferences service"); + } + + public AgentPrefs GetAgentPreferences(UUID principalID) + { + AgentPreferencesData d = m_Database.GetPrefs(principalID); + AgentPrefs prefs = (d == null) ? new AgentPrefs(principalID) : new AgentPrefs(d.Data); + return prefs; + } + + public bool StoreAgentPreferences(AgentPrefs data) + { + AgentPreferencesData d = new AgentPreferencesData(); + d.Data = new Dictionary(); + d.Data["PrincipalID"] = data.PrincipalID.ToString(); + d.Data["AccessPrefs"] = data.AccessPrefs; + d.Data["HoverHeight"] = data.HoverHeight.ToString(); + d.Data["Language"] = data.Language; + d.Data["LanguageIsPublic"] = (data.LanguageIsPublic ? "1" : "0"); + d.Data["PermEveryone"] = data.PermEveryone.ToString(); + d.Data["PermGroup"] = data.PermGroup.ToString(); + d.Data["PermNextOwner"] = data.PermNextOwner.ToString(); + return m_Database.Store(d); + } + + public string GetLang(UUID principalID) + { + AgentPrefs data = GetAgentPreferences(principalID); + if (data != null) + { + if (data.LanguageIsPublic) + return data.Language; + } + return "en-us"; + } + } +} diff --git a/OpenSim/Services/UserAccountService/AgentPreferencesServiceBase.cs b/OpenSim/Services/UserAccountService/AgentPreferencesServiceBase.cs new file mode 100644 index 0000000..5974349 --- /dev/null +++ b/OpenSim/Services/UserAccountService/AgentPreferencesServiceBase.cs @@ -0,0 +1,73 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using Nini.Config; +using OpenSim.Data; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Base; + +namespace OpenSim.Services.UserAccountService +{ + public class AgentPreferencesServiceBase: ServiceBase + { + protected IAgentPreferencesData m_Database = null; + + public AgentPreferencesServiceBase(IConfigSource config) : base(config) + { + string dllName = String.Empty; + string connString = String.Empty; + string realm = "AgentPrefs"; + + IConfig dbConfig = config.Configs["DatabaseService"]; + if (dbConfig != null) + { + dllName = dbConfig.GetString("StorageProvider", String.Empty); + connString = dbConfig.GetString("ConnectionString", String.Empty); + } + + IConfig userConfig = config.Configs["AgentPreferencesService"]; + if (userConfig == null) + throw new Exception("No AgentPreferencesService configuration"); + + dllName = userConfig.GetString("StorageProvider", dllName); + + if (dllName == String.Empty) + throw new Exception("No StorageProvider configured"); + + connString = userConfig.GetString("ConnectionString", connString); + + realm = userConfig.GetString("Realm", realm); + + m_Database = LoadPlugin(dllName, new Object[] {connString, realm}); + + if (m_Database == null) + throw new Exception("Could not find a storage interface in the given module"); + } + } +} diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs index 43fa04b..80a9d9d 100644 --- a/OpenSim/Services/UserAccountService/GridUserService.cs +++ b/OpenSim/Services/UserAccountService/GridUserService.cs @@ -43,15 +43,117 @@ namespace OpenSim.Services.UserAccountService public class GridUserService : GridUserServiceBase, IGridUserService { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static bool m_Initialized; public GridUserService(IConfigSource config) : base(config) { - m_log.Debug("[USER GRID SERVICE]: Starting user grid service"); + m_log.Debug("[GRID USER SERVICE]: Starting user grid service"); + + if (!m_Initialized) + { + m_Initialized = true; + + MainConsole.Instance.Commands.AddCommand( + "Users", false, + "show grid user", + "show grid user ", + "Show grid user entry or entries that match or start with the given ID. This will normally be a UUID.", + "This is for debug purposes to see what data is found for a particular user id.", + HandleShowGridUser); + + MainConsole.Instance.Commands.AddCommand( + "Users", false, + "show grid users online", + "show grid users online", + "Show number of grid users registered as online.", + "This number may not be accurate as a region may crash or not be cleanly shutdown and leave grid users shown as online\n." + + "For this reason, users online for more than 5 days are not currently counted", + HandleShowGridUsersOnline); + } + } + + protected void HandleShowGridUser(string module, string[] cmdparams) + { + if (cmdparams.Length != 4) + { + MainConsole.Instance.Output("Usage: show grid user "); + return; + } + + GridUserData[] data = m_Database.GetAll(cmdparams[3]); + + foreach (GridUserData gu in data) + { + ConsoleDisplayList cdl = new ConsoleDisplayList(); + + cdl.AddRow("User ID", gu.UserID); + + foreach (KeyValuePair kvp in gu.Data) + cdl.AddRow(kvp.Key, kvp.Value); + + MainConsole.Instance.Output(cdl.ToString()); + } + + MainConsole.Instance.OutputFormat("Entries: {0}", data.Length); + } + + protected void HandleShowGridUsersOnline(string module, string[] cmdparams) + { +// if (cmdparams.Length != 4) +// { +// MainConsole.Instance.Output("Usage: show grid users online"); +// return; +// } + +// int onlineCount; + int onlineRecentlyCount = 0; + + DateTime now = DateTime.UtcNow; + + foreach (GridUserData gu in m_Database.GetAll("")) + { + if (bool.Parse(gu.Data["Online"])) + { +// onlineCount++; + + int unixLoginTime = int.Parse(gu.Data["Login"]); + + if ((now - Util.ToDateTime(unixLoginTime)).Days < 5) + onlineRecentlyCount++; + } + } + + MainConsole.Instance.OutputFormat("Users online: {0}", onlineRecentlyCount); + } + + private GridUserData GetGridUserData(string userID) + { + GridUserData d = null; + if (userID.Length > 36) // it's a UUI + { + d = m_Database.Get(userID); + } + else // it's a UUID + { + GridUserData[] ds = m_Database.GetAll(userID); + if (ds == null) + return null; + + if (ds.Length > 0) + { + d = ds[0]; + foreach (GridUserData dd in ds) + if (dd.UserID.Length > d.UserID.Length) // find the longest + d = dd; + } + } + + return d; } public virtual GridUserInfo GetGridUserInfo(string userID) { - GridUserData d = m_Database.Get(userID); + GridUserData d = GetGridUserData(userID); if (d == null) return null; @@ -73,7 +175,7 @@ namespace OpenSim.Services.UserAccountService return info; } - public GridUserInfo[] GetGridUserInfo(string[] userIDs) + public virtual GridUserInfo[] GetGridUserInfo(string[] userIDs) { List ret = new List(); @@ -86,7 +188,8 @@ namespace OpenSim.Services.UserAccountService public GridUserInfo LoggedIn(string userID) { m_log.DebugFormat("[GRID USER SERVICE]: User {0} is online", userID); - GridUserData d = m_Database.Get(userID); + + GridUserData d = GetGridUserData(userID); if (d == null) { @@ -104,8 +207,9 @@ namespace OpenSim.Services.UserAccountService public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) { - m_log.DebugFormat("[GRID USER SERVICE]: User {0} is offline", userID); - GridUserData d = m_Database.Get(userID); + m_log.InfoFormat("[GRID USER SERVICE]: User {0} is offline", userID); + + GridUserData d = GetGridUserData(userID); if (d == null) { @@ -124,7 +228,8 @@ namespace OpenSim.Services.UserAccountService public bool SetHome(string userID, UUID homeID, Vector3 homePosition, Vector3 homeLookAt) { - GridUserData d = m_Database.Get(userID); + GridUserData d = GetGridUserData(userID); + if (d == null) { d = new GridUserData(); @@ -140,8 +245,10 @@ namespace OpenSim.Services.UserAccountService public bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) { - //m_log.DebugFormat("[Grid User Service]: SetLastPosition for {0}", userID); - GridUserData d = m_Database.Get(userID); +// m_log.DebugFormat("[GRID USER SERVICE]: SetLastPosition for {0}", userID); + + GridUserData d = GetGridUserData(userID); + if (d == null) { d = new GridUserData(); @@ -155,4 +262,4 @@ namespace OpenSim.Services.UserAccountService return m_Database.Store(d); } } -} +} \ No newline at end of file diff --git a/OpenSim/Services/UserAccountService/GridUserServiceBase.cs b/OpenSim/Services/UserAccountService/GridUserServiceBase.cs index 990cb63..8c5f5df 100644 --- a/OpenSim/Services/UserAccountService/GridUserServiceBase.cs +++ b/OpenSim/Services/UserAccountService/GridUserServiceBase.cs @@ -60,12 +60,12 @@ namespace OpenSim.Services.UserAccountService // // [GridUsetService] section overrides [DatabaseService], if it exists // - IConfig presenceConfig = config.Configs["GridUserService"]; - if (presenceConfig != null) + IConfig usersConfig = config.Configs["GridUserService"]; + if (usersConfig != null) { - dllName = presenceConfig.GetString("StorageProvider", dllName); - connString = presenceConfig.GetString("ConnectionString", connString); - realm = presenceConfig.GetString("Realm", realm); + dllName = usersConfig.GetString("StorageProvider", dllName); + connString = usersConfig.GetString("ConnectionString", connString); + realm = usersConfig.GetString("Realm", realm); } // diff --git a/OpenSim/Services/UserAccountService/Properties/AssemblyInfo.cs b/OpenSim/Services/UserAccountService/Properties/AssemblyInfo.cs index 24e1d16..6ca07a6 100644 --- a/OpenSim/Services/UserAccountService/Properties/AssemblyInfo.cs +++ b/OpenSim/Services/UserAccountService/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Services/UserAccountService/UserAccountService.cs b/OpenSim/Services/UserAccountService/UserAccountService.cs index 5b4d040..2e19ece 100644 --- a/OpenSim/Services/UserAccountService/UserAccountService.cs +++ b/OpenSim/Services/UserAccountService/UserAccountService.cs @@ -36,6 +36,7 @@ using OpenSim.Framework; using OpenSim.Services.Interfaces; using OpenSim.Framework.Console; using GridRegion = OpenSim.Services.Interfaces.GridRegion; +using PermissionMask = OpenSim.Framework.PermissionMask; namespace OpenSim.Services.UserAccountService { @@ -97,7 +98,12 @@ namespace OpenSim.Services.UserAccountService MainConsole.Instance.Commands.AddCommand("Users", false, "reset user password", "reset user password [ [ []]]", - "Reset a user password", HandleResetUserPassword); + "Reset a user password", HandleResetUserPassword); + + MainConsole.Instance.Commands.AddCommand("Users", false, + "reset user email", + "reset user email [ [ []]]", + "Reset a user email address", HandleResetUserEmail); MainConsole.Instance.Commands.AddCommand("Users", false, "set user level", @@ -255,6 +261,10 @@ namespace OpenSim.Services.UserAccountService return MakeUserAccount(d[0]); } + public void InvalidateCache(UUID userID) + { + } + public bool StoreUserAccount(UserAccount data) { // m_log.DebugFormat( @@ -415,6 +425,43 @@ namespace OpenSim.Services.UserAccountService MainConsole.Instance.OutputFormat("Password reset for user {0} {1}", firstName, lastName); } + protected void HandleResetUserEmail(string module, string[] cmdparams) + { + string firstName; + string lastName; + string newEmail; + + if (cmdparams.Length < 4) + firstName = MainConsole.Instance.CmdPrompt("First name"); + else firstName = cmdparams[3]; + + if (cmdparams.Length < 5) + lastName = MainConsole.Instance.CmdPrompt("Last name"); + else lastName = cmdparams[4]; + + if (cmdparams.Length < 6) + newEmail = MainConsole.Instance.PasswdPrompt("New Email"); + else newEmail = cmdparams[5]; + + UserAccount account = GetUserAccount(UUID.Zero, firstName, lastName); + if (account == null) + { + MainConsole.Instance.OutputFormat("No such user as {0} {1}", firstName, lastName); + return; + } + + bool success = false; + + account.Email = newEmail; + + success = StoreUserAccount(account); + if (!success) + MainConsole.Instance.OutputFormat("Unable to set Email for account {0} {1}.", firstName, lastName); + else + MainConsole.Instance.OutputFormat("User Email set for user {0} {1} to {2}", firstName, lastName, account.Email); + } + + protected void HandleSetUserLevel(string module, string[] cmdparams) { string firstName; @@ -475,7 +522,6 @@ namespace OpenSim.Services.UserAccountService { account.ServiceURLs = new Dictionary(); account.ServiceURLs["HomeURI"] = string.Empty; - account.ServiceURLs["GatekeeperURI"] = string.Empty; account.ServiceURLs["InventoryServerURI"] = string.Empty; account.ServiceURLs["AssetServerURI"] = string.Empty; } @@ -549,7 +595,7 @@ namespace OpenSim.Services.UserAccountService { m_log.DebugFormat("[USER ACCOUNT SERVICE]: Creating default appearance items for {0}", principalID); - InventoryFolderBase bodyPartsFolder = m_InventoryService.GetFolderForType(principalID, AssetType.Bodypart); + InventoryFolderBase bodyPartsFolder = m_InventoryService.GetFolderForType(principalID, FolderType.BodyPart); InventoryItemBase eyes = new InventoryItemBase(UUID.Random(), principalID); eyes.AssetID = new UUID("4bb6fa4d-1cd2-498a-a84c-95c1a0e745a7"); @@ -611,7 +657,7 @@ namespace OpenSim.Services.UserAccountService hair.Flags = (uint)WearableType.Hair; m_InventoryService.AddItem(hair); - InventoryFolderBase clothingFolder = m_InventoryService.GetFolderForType(principalID, AssetType.Clothing); + InventoryFolderBase clothingFolder = m_InventoryService.GetFolderForType(principalID, FolderType.Clothing); InventoryItemBase shirt = new InventoryItemBase(UUID.Random(), principalID); shirt.AssetID = AvatarWearable.DEFAULT_SHIRT_ASSET; @@ -665,4 +711,4 @@ namespace OpenSim.Services.UserAccountService } } } -} \ No newline at end of file +} diff --git a/OpenSim/Services/UserProfilesService/UserProfilesService.cs b/OpenSim/Services/UserProfilesService/UserProfilesService.cs new file mode 100644 index 0000000..96c13c0 --- /dev/null +++ b/OpenSim/Services/UserProfilesService/UserProfilesService.cs @@ -0,0 +1,263 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using System.Text; +using Nini.Config; +using log4net; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Services.UserAccountService; +using OpenSim.Data; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; + +namespace OpenSim.Services.ProfilesService +{ + public class UserProfilesService: UserProfilesServiceBase, IUserProfilesService + { + static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + IUserAccountService userAccounts; + + public UserProfilesService(IConfigSource config, string configName): + base(config, configName) + { + IConfig Config = config.Configs[configName]; + if (Config == null) + { + m_log.Warn("[PROFILES SERVICE]: No configuration found!"); + return; + } + Object[] args = null; + + args = new Object[] { config }; + string accountService = Config.GetString("UserAccountService", String.Empty); + if (accountService != string.Empty) + userAccounts = ServerUtils.LoadPlugin(accountService, args); + + args = new Object[] { config }; + } + + #region Classifieds + public OSD AvatarClassifiedsRequest(UUID creatorId) + { + OSDArray records = ProfilesData.GetClassifiedRecords(creatorId); + + return records; + } + + public bool ClassifiedUpdate(UserClassifiedAdd ad, ref string result) + { + if(!ProfilesData.UpdateClassifiedRecord(ad, ref result)) + { + return false; + } + result = "success"; + return true; + } + + public bool ClassifiedDelete(UUID recordId) + { + if(ProfilesData.DeleteClassifiedRecord(recordId)) + return true; + + return false; + } + + public bool ClassifiedInfoRequest(ref UserClassifiedAdd ad, ref string result) + { + if(ProfilesData.GetClassifiedInfo(ref ad, ref result)) + return true; + + return false; + } + #endregion Classifieds + + #region Picks + public OSD AvatarPicksRequest(UUID creatorId) + { + OSDArray records = ProfilesData.GetAvatarPicks(creatorId); + + return records; + } + + public bool PickInfoRequest(ref UserProfilePick pick, ref string result) + { + pick = ProfilesData.GetPickInfo(pick.CreatorId, pick.PickId); + result = "OK"; + return true; + } + + public bool PicksUpdate(ref UserProfilePick pick, ref string result) + { + return ProfilesData.UpdatePicksRecord(pick); + } + + public bool PicksDelete(UUID pickId) + { + return ProfilesData.DeletePicksRecord(pickId); + } + #endregion Picks + + #region Notes + public bool AvatarNotesRequest(ref UserProfileNotes note) + { + return ProfilesData.GetAvatarNotes(ref note); + } + + public bool NotesUpdate(ref UserProfileNotes note, ref string result) + { + return ProfilesData.UpdateAvatarNotes(ref note, ref result); + } + #endregion Notes + + #region Profile Properties + public bool AvatarPropertiesRequest(ref UserProfileProperties prop, ref string result) + { + return ProfilesData.GetAvatarProperties(ref prop, ref result); + } + + public bool AvatarPropertiesUpdate(ref UserProfileProperties prop, ref string result) + { + return ProfilesData.UpdateAvatarProperties(ref prop, ref result); + } + #endregion Profile Properties + + #region Interests + public bool AvatarInterestsUpdate(UserProfileProperties prop, ref string result) + { + return ProfilesData.UpdateAvatarInterests(prop, ref result); + } + #endregion Interests + + #region User Preferences + public bool UserPreferencesUpdate(ref UserPreferences pref, ref string result) + { + if(string.IsNullOrEmpty(pref.EMail)) + { + UserAccount account = new UserAccount(); + if(userAccounts is UserAccountService.UserAccountService) + { + try + { + account = userAccounts.GetUserAccount(UUID.Zero, pref.UserId); + if(string.IsNullOrEmpty(account.Email)) + { + pref.EMail = string.Empty; + } + else + pref.EMail = account.Email; + } + catch + { + m_log.Error ("[PROFILES SERVICE]: UserAccountService Exception: Could not get user account"); + result = "UserAccountService settings error in UserProfileService!"; + return false; + } + } + else + { + m_log.Error ("[PROFILES SERVICE]: UserAccountService: Could not get user account"); + result = "UserAccountService settings error in UserProfileService!"; + return false; + } + } + return ProfilesData.UpdateUserPreferences(ref pref, ref result); + } + + public bool UserPreferencesRequest(ref UserPreferences pref, ref string result) + { + if (!ProfilesData.GetUserPreferences(ref pref, ref result)) + return false; + + if(string.IsNullOrEmpty(pref.EMail)) + { + UserAccount account = new UserAccount(); + if(userAccounts is UserAccountService.UserAccountService) + { + try + { + account = userAccounts.GetUserAccount(UUID.Zero, pref.UserId); + if(string.IsNullOrEmpty(account.Email)) + { + pref.EMail = string.Empty; + } + else + { + pref.EMail = account.Email; + UserPreferencesUpdate(ref pref, ref result); + } + } + catch + { + m_log.Error ("[PROFILES SERVICE]: UserAccountService Exception: Could not get user account"); + result = "UserAccountService settings error in UserProfileService!"; + return false; + } + } + else + { + m_log.Error ("[PROFILES SERVICE]: UserAccountService: Could not get user account"); + result = "UserAccountService settings error in UserProfileService!"; + return false; + } + } + + if(string.IsNullOrEmpty(pref.EMail)) + pref.EMail = "No Email Address On Record"; + + return true; + } + #endregion User Preferences + + #region Utility + public OSD AvatarImageAssetsRequest(UUID avatarId) + { + OSDArray records = ProfilesData.GetUserImageAssets(avatarId); + return records; + } + #endregion Utility + + #region UserData + public bool RequestUserAppData(ref UserAppData prop, ref string result) + { + return ProfilesData.GetUserAppData(ref prop, ref result); + } + + public bool SetUserAppData(UserAppData prop, ref string result) + { + return true; + } + #endregion UserData + } +} + diff --git a/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs b/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs new file mode 100644 index 0000000..c31578f --- /dev/null +++ b/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs @@ -0,0 +1,87 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using Nini.Config; +using log4net; +using OpenSim.Services.Base; +using OpenSim.Data; + +namespace OpenSim.Services.ProfilesService +{ + public class UserProfilesServiceBase: ServiceBase + { + static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + public IProfilesData ProfilesData; + + public string ConfigName + { + get; private set; + } + + public UserProfilesServiceBase(IConfigSource config, string configName): + base(config) + { + if(string.IsNullOrEmpty(configName)) + { + m_log.WarnFormat("[PROFILES SERVICE]: Configuration section not given!"); + return; + } + + string dllName = String.Empty; + string connString = null; + string realm = String.Empty; + + IConfig dbConfig = config.Configs["DatabaseService"]; + if (dbConfig != null) + { + if (dllName == String.Empty) + dllName = dbConfig.GetString("StorageProvider", String.Empty); + if (string.IsNullOrEmpty(connString)) + connString = dbConfig.GetString("ConnectionString", String.Empty); + } + + IConfig ProfilesConfig = config.Configs[configName]; + if (ProfilesConfig != null) + { + dllName = ProfilesConfig.GetString("StorageProvider", dllName); + connString = ProfilesConfig.GetString("ConnectionString", connString); + realm = ProfilesConfig.GetString("Realm", realm); + } + + ProfilesData = LoadPlugin(dllName, new Object[] { connString }); + if (ProfilesData == null) + throw new Exception("Could not find a storage interface in the given module"); + + } + } +} + diff --git a/OpenSim/Tests/Clients/Assets/AssetsClient.cs b/OpenSim/Tests/Clients/Assets/AssetsClient.cs new file mode 100644 index 0000000..e988d0e --- /dev/null +++ b/OpenSim/Tests/Clients/Assets/AssetsClient.cs @@ -0,0 +1,126 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Reflection; +using System.Threading; + +using OpenMetaverse; +using log4net; +using log4net.Appender; +using log4net.Layout; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Connectors; + +namespace OpenSim.Tests.Clients.AssetsClient +{ + public class AssetsClient + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private static int m_MaxThreadID = 0; + private static readonly int NREQS = 150; + private static int m_NReceived = 0; + + public static void Main(string[] args) + { + ConsoleAppender consoleAppender = new ConsoleAppender(); + consoleAppender.Layout = + new PatternLayout("[%thread] - %message%newline"); + log4net.Config.BasicConfigurator.Configure(consoleAppender); + + string serverURI = "http://127.0.0.1:8003"; + if (args.Length > 1) + serverURI = args[1]; + int max1, max2; + ThreadPool.GetMaxThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Connecting to {0} max threads = {1} - {2}", serverURI, max1, max2); + ThreadPool.GetMinThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Connecting to {0} min threads = {1} - {2}", serverURI, max1, max2); + + if (!ThreadPool.SetMinThreads(1, 1)) + m_log.WarnFormat("[ASSET CLIENT]: Failed to set min threads"); + + if (!ThreadPool.SetMaxThreads(10, 3)) + m_log.WarnFormat("[ASSET CLIENT]: Failed to set max threads"); + + ThreadPool.GetMaxThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Post set max threads = {1} - {2}", serverURI, max1, max2); + ThreadPool.GetMinThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Post set min threads = {1} - {2}", serverURI, max1, max2); + + ServicePointManager.DefaultConnectionLimit = 12; + + AssetServicesConnector m_Connector = new AssetServicesConnector(serverURI); + m_Connector.MaxAssetRequestConcurrency = 30; + + for (int i = 0; i < NREQS; i++) + { + UUID uuid = UUID.Random(); + m_Connector.Get(uuid.ToString(), null, ResponseReceived); + m_log.InfoFormat("[ASSET CLIENT]: [{0}] requested asset {1}", i, uuid); + } + + for (int i = 0; i < 500; i++) + { + var x = i; + ThreadPool.QueueUserWorkItem(delegate + { + Dummy(x); + }); + } + + Thread.Sleep(30 * 1000); + m_log.InfoFormat("[ASSET CLIENT]: Received responses {0}", m_NReceived); + } + + private static void ResponseReceived(string id, Object sender, AssetBase asset) + { + if (Thread.CurrentThread.ManagedThreadId > m_MaxThreadID) + m_MaxThreadID = Thread.CurrentThread.ManagedThreadId; + int max1, max2; + ThreadPool.GetAvailableThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Received asset {0} ({1}) ({2}-{3}) {4}", id, m_MaxThreadID, max1, max2, DateTime.Now.ToString("hh:mm:ss")); + m_NReceived++; + } + + private static void Dummy(int i) + { + int max1, max2; + ThreadPool.GetAvailableThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: ({0}) Hello! {1} - {2} {3}", i, max1, max2, DateTime.Now.ToString("hh:mm:ss")); + Thread.Sleep(2000); + } + } +} diff --git a/OpenSim/Tests/Clients/Grid/GridClient.cs b/OpenSim/Tests/Clients/Grid/GridClient.cs deleted file mode 100644 index 8e33373..0000000 --- a/OpenSim/Tests/Clients/Grid/GridClient.cs +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Reflection; - -using OpenMetaverse; -using log4net; -using log4net.Appender; -using log4net.Layout; - -using OpenSim.Framework; -using OpenSim.Services.Interfaces; -using GridRegion = OpenSim.Services.Interfaces.GridRegion; -using OpenSim.Services.Connectors; - -namespace OpenSim.Tests.Clients.GridClient -{ - public class GridClient - { -// private static readonly ILog m_log = -// LogManager.GetLogger( -// MethodBase.GetCurrentMethod().DeclaringType); - - public static void Main(string[] args) - { - ConsoleAppender consoleAppender = new ConsoleAppender(); - consoleAppender.Layout = - new PatternLayout("%date [%thread] %-5level %logger [%property{NDC}] - %message%newline"); - log4net.Config.BasicConfigurator.Configure(consoleAppender); - - string serverURI = "http://127.0.0.1:8001"; - GridServicesConnector m_Connector = new GridServicesConnector(serverURI); - - GridRegion r1 = CreateRegion("Test Region 1", 1000, 1000); - GridRegion r2 = CreateRegion("Test Region 2", 1001, 1000); - GridRegion r3 = CreateRegion("Test Region 3", 1005, 1000); - - Console.WriteLine("[GRID CLIENT]: *** Registering region 1"); - string msg = m_Connector.RegisterRegion(UUID.Zero, r1); - if (msg == String.Empty) - Console.WriteLine("[GRID CLIENT]: Successfully registered region 1"); - else - Console.WriteLine("[GRID CLIENT]: region 1 failed to register"); - - Console.WriteLine("[GRID CLIENT]: *** Registering region 2"); - msg = m_Connector.RegisterRegion(UUID.Zero, r2); - if (msg == String.Empty) - Console.WriteLine("[GRID CLIENT]: Successfully registered region 2"); - else - Console.WriteLine("[GRID CLIENT]: region 2 failed to register"); - - Console.WriteLine("[GRID CLIENT]: *** Registering region 3"); - msg = m_Connector.RegisterRegion(UUID.Zero, r3); - if (msg == String.Empty) - Console.WriteLine("[GRID CLIENT]: Successfully registered region 3"); - else - Console.WriteLine("[GRID CLIENT]: region 3 failed to register"); - - - bool success; - Console.WriteLine("[GRID CLIENT]: *** Deregistering region 3"); - success = m_Connector.DeregisterRegion(r3.RegionID); - if (success) - Console.WriteLine("[GRID CLIENT]: Successfully deregistered region 3"); - else - Console.WriteLine("[GRID CLIENT]: region 3 failed to deregister"); - Console.WriteLine("[GRID CLIENT]: *** Registering region 3 again"); - msg = m_Connector.RegisterRegion(UUID.Zero, r3); - if (msg == String.Empty) - Console.WriteLine("[GRID CLIENT]: Successfully registered region 3"); - else - Console.WriteLine("[GRID CLIENT]: region 3 failed to register"); - - Console.WriteLine("[GRID CLIENT]: *** GetNeighbours of region 1"); - List regions = m_Connector.GetNeighbours(UUID.Zero, r1.RegionID); - if (regions == null) - Console.WriteLine("[GRID CLIENT]: GetNeighbours of region 1 failed"); - else if (regions.Count > 0) - { - if (regions.Count != 1) - Console.WriteLine("[GRID CLIENT]: GetNeighbours of region 1 returned more neighbours than expected: " + regions.Count); - else - Console.WriteLine("[GRID CLIENT]: GetNeighbours of region 1 returned the right neighbour " + regions[0].RegionName); - } - else - Console.WriteLine("[GRID CLIENT]: GetNeighbours of region 1 returned 0 neighbours"); - - - Console.WriteLine("[GRID CLIENT]: *** GetRegionByUUID of region 2 (this should succeed)"); - GridRegion region = m_Connector.GetRegionByUUID(UUID.Zero, r2.RegionID); - if (region == null) - Console.WriteLine("[GRID CLIENT]: GetRegionByUUID returned null"); - else - Console.WriteLine("[GRID CLIENT]: GetRegionByUUID returned region " + region.RegionName); - - Console.WriteLine("[GRID CLIENT]: *** GetRegionByUUID of non-existent region (this should fail)"); - region = m_Connector.GetRegionByUUID(UUID.Zero, UUID.Random()); - if (region == null) - Console.WriteLine("[GRID CLIENT]: GetRegionByUUID returned null"); - else - Console.WriteLine("[GRID CLIENT]: GetRegionByUUID returned region " + region.RegionName); - - Console.WriteLine("[GRID CLIENT]: *** GetRegionByName of region 3 (this should succeed)"); - region = m_Connector.GetRegionByName(UUID.Zero, r3.RegionName); - if (region == null) - Console.WriteLine("[GRID CLIENT]: GetRegionByName returned null"); - else - Console.WriteLine("[GRID CLIENT]: GetRegionByName returned region " + region.RegionName); - - Console.WriteLine("[GRID CLIENT]: *** GetRegionByName of non-existent region (this should fail)"); - region = m_Connector.GetRegionByName(UUID.Zero, "Foo"); - if (region == null) - Console.WriteLine("[GRID CLIENT]: GetRegionByName returned null"); - else - Console.WriteLine("[GRID CLIENT]: GetRegionByName returned region " + region.RegionName); - - Console.WriteLine("[GRID CLIENT]: *** GetRegionsByName (this should return 3 regions)"); - regions = m_Connector.GetRegionsByName(UUID.Zero, "Test", 10); - if (regions == null) - Console.WriteLine("[GRID CLIENT]: GetRegionsByName returned null"); - else - Console.WriteLine("[GRID CLIENT]: GetRegionsByName returned " + regions.Count + " regions"); - - Console.WriteLine("[GRID CLIENT]: *** GetRegionRange (this should return 2 regions)"); - regions = m_Connector.GetRegionRange(UUID.Zero, - 900 * (int)Constants.RegionSize, 1002 * (int) Constants.RegionSize, - 900 * (int)Constants.RegionSize, 1002 * (int) Constants.RegionSize); - if (regions == null) - Console.WriteLine("[GRID CLIENT]: GetRegionRange returned null"); - else - Console.WriteLine("[GRID CLIENT]: GetRegionRange returned " + regions.Count + " regions"); - Console.WriteLine("[GRID CLIENT]: *** GetRegionRange (this should return 0 regions)"); - regions = m_Connector.GetRegionRange(UUID.Zero, - 900 * (int)Constants.RegionSize, 950 * (int)Constants.RegionSize, - 900 * (int)Constants.RegionSize, 950 * (int)Constants.RegionSize); - if (regions == null) - Console.WriteLine("[GRID CLIENT]: GetRegionRange returned null"); - else - Console.WriteLine("[GRID CLIENT]: GetRegionRange returned " + regions.Count + " regions"); - - Console.Write("Proceed to deregister? Press enter..."); - Console.ReadLine(); - - // Deregister them all - Console.WriteLine("[GRID CLIENT]: *** Deregistering region 1"); - success = m_Connector.DeregisterRegion(r1.RegionID); - if (success) - Console.WriteLine("[GRID CLIENT]: Successfully deregistered region 1"); - else - Console.WriteLine("[GRID CLIENT]: region 1 failed to deregister"); - Console.WriteLine("[GRID CLIENT]: *** Deregistering region 2"); - success = m_Connector.DeregisterRegion(r2.RegionID); - if (success) - Console.WriteLine("[GRID CLIENT]: Successfully deregistered region 2"); - else - Console.WriteLine("[GRID CLIENT]: region 2 failed to deregister"); - Console.WriteLine("[GRID CLIENT]: *** Deregistering region 3"); - success = m_Connector.DeregisterRegion(r3.RegionID); - if (success) - Console.WriteLine("[GRID CLIENT]: Successfully deregistered region 3"); - else - Console.WriteLine("[GRID CLIENT]: region 3 failed to deregister"); - - } - - private static GridRegion CreateRegion(string name, uint xcell, uint ycell) - { - GridRegion region = new GridRegion(xcell, ycell); - region.RegionName = name; - region.RegionID = UUID.Random(); - region.ExternalHostName = "127.0.0.1"; - region.HttpPort = 9000; - region.InternalEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("0.0.0.0"), 9000); - - return region; - } - } -} diff --git a/OpenSim/Tests/Clients/Grid/GridForm.html b/OpenSim/Tests/Clients/Grid/GridForm.html deleted file mode 100644 index 252920f..0000000 --- a/OpenSim/Tests/Clients/Grid/GridForm.html +++ /dev/null @@ -1,11 +0,0 @@ - - -
-xmin: -xmax: -ymin: -ymax: - - - - diff --git a/OpenSim/Tests/Clients/InstantMessage/IMClient.cs b/OpenSim/Tests/Clients/InstantMessage/IMClient.cs deleted file mode 100644 index e7304a2..0000000 --- a/OpenSim/Tests/Clients/InstantMessage/IMClient.cs +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Reflection; - -using OpenMetaverse; -using log4net; -using log4net.Appender; -using log4net.Layout; - -using OpenSim.Framework; -using OpenSim.Services.Interfaces; -using OpenSim.Services.Connectors.InstantMessage; - -namespace OpenSim.Tests.Clients.InstantMessage -{ - public class IMClient - { - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); - - public static void Main(string[] args) - { - ConsoleAppender consoleAppender = new ConsoleAppender(); - consoleAppender.Layout = - new PatternLayout("%date [%thread] %-5level %logger [%property{NDC}] - %message%newline"); - log4net.Config.BasicConfigurator.Configure(consoleAppender); - - string serverURI = "http://127.0.0.1:8002"; - GridInstantMessage im = new GridInstantMessage(); - im.fromAgentID = new Guid(); - im.toAgentID = new Guid(); - im.message = "Hello"; - im.imSessionID = new Guid(); - - bool success = InstantMessageServiceConnector.SendInstantMessage(serverURI, im); - - if (success) - m_log.InfoFormat("[IM CLIENT]: Successfully IMed {0}", serverURI); - else - m_log.InfoFormat("[IM CLIENT]: failed to IM {0}", serverURI); - - System.Console.WriteLine("\n"); - } - - } -} diff --git a/OpenSim/Tests/Clients/Presence/OpenSim.Server.ini b/OpenSim/Tests/Clients/Presence/OpenSim.Server.ini deleted file mode 100644 index 8610c78..0000000 --- a/OpenSim/Tests/Clients/Presence/OpenSim.Server.ini +++ /dev/null @@ -1,33 +0,0 @@ -; * Run a ROBUST server shell like this, from bin: -; * $ OpenSim.Server.exe -inifile ../OpenSim/Tests/Clients/Presence/OpenSim.Server.ini -; * -; * Then run this client like this, from bin: -; * $ OpenSim.Tests.Clients.PresenceClient.exe -; * -; * - -[Startup] -ServiceConnectors = "OpenSim.Server.Handlers.dll:PresenceServiceConnector" - -; * This is common for all services, it's the network setup for the entire -; * server instance -; * -[Network] -port = 8003 - -; * The following are for the remote console -; * They have no effect for the local or basic console types -; * Leave commented to diable logins to the console -;ConsoleUser = Test -;ConsolePass = secret - -; * As an example, the below configuration precisely mimicks the legacy -; * asset server. It is read by the asset IN connector (defined above) -; * and it then loads the OUT connector (a local database module). That, -; * in turn, reads the asset loader and database connection information -; * -[PresenceService] - LocalServiceModule = "OpenSim.Services.PresenceService.dll:PresenceService" - StorageProvider = "OpenSim.Data.MySQL.dll" - ConnectionString = "Data Source=localhost;Database=opensim;User ID=opensim;Password=opensim123;Old Guids=true;" - diff --git a/OpenSim/Tests/Clients/Presence/PresenceClient.cs b/OpenSim/Tests/Clients/Presence/PresenceClient.cs deleted file mode 100644 index fd3905a..0000000 --- a/OpenSim/Tests/Clients/Presence/PresenceClient.cs +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Reflection; - -using OpenMetaverse; -using log4net; -using log4net.Appender; -using log4net.Layout; - -using OpenSim.Framework; -using OpenSim.Services.Interfaces; -using OpenSim.Services.Connectors; - -namespace OpenSim.Tests.Clients.PresenceClient -{ - public class PresenceClient - { - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); - - public static void Main(string[] args) - { - ConsoleAppender consoleAppender = new ConsoleAppender(); - consoleAppender.Layout = - new PatternLayout("%date [%thread] %-5level %logger [%property{NDC}] - %message%newline"); - log4net.Config.BasicConfigurator.Configure(consoleAppender); - - string serverURI = "http://127.0.0.1:8003"; - PresenceServicesConnector m_Connector = new PresenceServicesConnector(serverURI); - - UUID user1 = UUID.Random(); - UUID session1 = UUID.Random(); - UUID region1 = UUID.Random(); - - bool success = m_Connector.LoginAgent(user1.ToString(), session1, UUID.Zero); - if (success) - m_log.InfoFormat("[PRESENCE CLIENT]: Successfully logged in user {0} with session {1}", user1, session1); - else - m_log.InfoFormat("[PRESENCE CLIENT]: failed to login user {0}", user1); - - System.Console.WriteLine("\n"); - - PresenceInfo pinfo = m_Connector.GetAgent(session1); - if (pinfo == null) - m_log.InfoFormat("[PRESENCE CLIENT]: Unable to retrieve presence for {0}", user1); - else - m_log.InfoFormat("[PRESENCE CLIENT]: Presence retrieved correctly: userID={0}; regionID={1}", - pinfo.UserID, pinfo.RegionID); - - System.Console.WriteLine("\n"); - success = m_Connector.ReportAgent(session1, region1); - if (success) - m_log.InfoFormat("[PRESENCE CLIENT]: Successfully reported session {0} in region {1}", user1, region1); - else - m_log.InfoFormat("[PRESENCE CLIENT]: failed to report session {0}", session1); - pinfo = m_Connector.GetAgent(session1); - if (pinfo == null) - m_log.InfoFormat("[PRESENCE CLIENT]: Unable to retrieve presence for {0} for second time", user1); - else - m_log.InfoFormat("[PRESENCE CLIENT]: Presence retrieved correctly: userID={0}; regionID={2}", - pinfo.UserID, pinfo.RegionID); - - System.Console.WriteLine("\n"); - success = m_Connector.LogoutAgent(session1); - if (success) - m_log.InfoFormat("[PRESENCE CLIENT]: Successfully logged out user {0}", user1); - else - m_log.InfoFormat("[PRESENCE CLIENT]: failed to logout user {0}", user1); - pinfo = m_Connector.GetAgent(session1); - if (pinfo == null) - m_log.InfoFormat("[PRESENCE CLIENT]: Unable to retrieve presence for {0} for fourth time", user1); - else - m_log.InfoFormat("[PRESENCE CLIENT]: Presence retrieved correctly: userID={0}; regionID={1}", - pinfo.UserID, pinfo.RegionID); - - System.Console.WriteLine("\n"); - success = m_Connector.ReportAgent(session1, UUID.Random()); - if (success) - m_log.InfoFormat("[PRESENCE CLIENT]: Report agent succeeded, but this is wrong"); - else - m_log.InfoFormat("[PRESENCE CLIENT]: failed to report agent, as it should because user is not logged in"); - - } - - } -} diff --git a/OpenSim/Tests/Clients/UserAccounts/OpenSim.Server.ini b/OpenSim/Tests/Clients/UserAccounts/OpenSim.Server.ini deleted file mode 100644 index 453e17e..0000000 --- a/OpenSim/Tests/Clients/UserAccounts/OpenSim.Server.ini +++ /dev/null @@ -1,33 +0,0 @@ -; * Run a ROBUST server shell like this, from bin: -; * $ OpenSim.Server.exe -inifile ../OpenSim/Tests/Clients/Presence/OpenSim.Server.ini -; * -; * Then run this client like this, from bin: -; * $ OpenSim.Tests.Clients.UserAccountClient.exe -; * -; * - -[Startup] -ServiceConnectors = "OpenSim.Server.Handlers.dll:UserAccountServiceConnector" - -; * This is common for all services, it's the network setup for the entire -; * server instance -; * -[Network] -port = 8003 - -; * The following are for the remote console -; * They have no effect for the local or basic console types -; * Leave commented to diable logins to the console -;ConsoleUser = Test -;ConsolePass = secret - -; * As an example, the below configuration precisely mimicks the legacy -; * asset server. It is read by the asset IN connector (defined above) -; * and it then loads the OUT connector (a local database module). That, -; * in turn, reads the asset loader and database connection information -; * -[UserAccountService] - LocalServiceModule = "OpenSim.Services.UserAccountService.dll:UserAccountService" - StorageProvider = "OpenSim.Data.MySQL.dll" - ConnectionString = "Data Source=localhost;Database=opensim;User ID=opensim;Password=opensim123;Old Guids=true;" - diff --git a/OpenSim/Tests/Clients/UserAccounts/UserAccountsClient.cs b/OpenSim/Tests/Clients/UserAccounts/UserAccountsClient.cs deleted file mode 100644 index 1e0a35b..0000000 --- a/OpenSim/Tests/Clients/UserAccounts/UserAccountsClient.cs +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Reflection; - -using OpenMetaverse; -using log4net; -using log4net.Appender; -using log4net.Layout; - -using OpenSim.Framework; -using OpenSim.Services.Interfaces; -using OpenSim.Services.Connectors; - -namespace OpenSim.Tests.Clients.PresenceClient -{ - public class UserAccountsClient - { - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); - - public static void Main(string[] args) - { - ConsoleAppender consoleAppender = new ConsoleAppender(); - consoleAppender.Layout = - new PatternLayout("%date [%thread] %-5level %logger [%property{NDC}] - %message%newline"); - log4net.Config.BasicConfigurator.Configure(consoleAppender); - - string serverURI = "http://127.0.0.1:8003"; - UserAccountServicesConnector m_Connector = new UserAccountServicesConnector(serverURI); - - UUID user1 = UUID.Random(); - string first = "Completely"; - string last = "Clueless"; - string email = "foo@bar.com"; - - //UserAccount account = new UserAccount(user1); - //account.ScopeID = UUID.Zero; - //account.FirstName = first; - //account.LastName = last; - //account.Email = email; - //account.ServiceURLs = new Dictionary(); - //account.ServiceURLs.Add("InventoryServerURI", "http://cnn.com"); - //account.ServiceURLs.Add("AssetServerURI", "http://cnn.com"); - - //bool success = m_Connector.StoreUserAccount(account); - //if (success) - // m_log.InfoFormat("[USER CLIENT]: Successfully created account for user {0} {1}", account.FirstName, account.LastName); - //else - // m_log.InfoFormat("[USER CLIENT]: failed to create user {0} {1}", account.FirstName, account.LastName); - - //System.Console.WriteLine("\n"); - - //account = m_Connector.GetUserAccount(UUID.Zero, user1); - //if (account == null) - // m_log.InfoFormat("[USER CLIENT]: Unable to retrieve accouny by UUID for {0}", user1); - //else - //{ - // m_log.InfoFormat("[USER CLIENT]: Account retrieved correctly: userID={0}; FirstName={1}; LastName={2}; Email={3}", - // account.PrincipalID, account.FirstName, account.LastName, account.Email); - // foreach (KeyValuePair kvp in account.ServiceURLs) - // m_log.DebugFormat("\t {0} -> {1}", kvp.Key, kvp.Value); - //} - - //System.Console.WriteLine("\n"); - - UserAccount account = m_Connector.GetUserAccount(UUID.Zero, first, last); - if (account == null) - m_log.InfoFormat("[USER CLIENT]: Unable to retrieve accouny by name "); - else - { - m_log.InfoFormat("[USER CLIENT]: Account retrieved correctly: userID={0}; FirstName={1}; LastName={2}; Email={3}", - account.PrincipalID, account.FirstName, account.LastName, account.Email); - foreach (KeyValuePair kvp in account.ServiceURLs) - m_log.DebugFormat("\t {0} -> {1}", kvp.Key, kvp.Value); - } - - System.Console.WriteLine("\n"); - account = m_Connector.GetUserAccount(UUID.Zero, email); - if (account == null) - m_log.InfoFormat("[USER CLIENT]: Unable to retrieve accouny by email"); - else - { - m_log.InfoFormat("[USER CLIENT]: Account retrieved correctly: userID={0}; FirstName={1}; LastName={2}; Email={3}", - account.PrincipalID, account.FirstName, account.LastName, account.Email); - foreach (KeyValuePair kvp in account.ServiceURLs) - m_log.DebugFormat("\t {0} -> {1}", kvp.Key, kvp.Value); - } - - System.Console.WriteLine("\n"); - account = m_Connector.GetUserAccount(UUID.Zero, user1); - if (account == null) - m_log.InfoFormat("[USER CLIENT]: Unable to retrieve accouny by UUID for {0}", user1); - else - { - m_log.InfoFormat("[USER CLIENT]: Account retrieved correctly: userID={0}; FirstName={1}; LastName={2}; Email={3}", - account.PrincipalID, account.FirstName, account.LastName, account.Email); - foreach (KeyValuePair kvp in account.ServiceURLs) - m_log.DebugFormat("\t {0} -> {1}", kvp.Key, kvp.Value); - } - - System.Console.WriteLine("\n"); - account = m_Connector.GetUserAccount(UUID.Zero, "DoesNot", "Exist"); - if (account == null) - m_log.InfoFormat("[USER CLIENT]: Unable to retrieve account 'DoesNot Exist'"); - else - { - m_log.InfoFormat("[USER CLIENT]: Account 'DoesNot Exist' retrieved correctly. REALLY??? userID={0}; FirstName={1}; LastName={2}; Email={3}", - account.PrincipalID, account.FirstName, account.LastName, account.Email); - foreach (KeyValuePair kvp in account.ServiceURLs) - m_log.DebugFormat("\t {0} -> {1}", kvp.Key, kvp.Value); - } - } - - } -} diff --git a/OpenSim/Tests/Common/Helpers/BaseRequestHandlerHelpers.cs b/OpenSim/Tests/Common/Helpers/BaseRequestHandlerHelpers.cs index 49c99c5..82ecf9a 100644 --- a/OpenSim/Tests/Common/Helpers/BaseRequestHandlerHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/BaseRequestHandlerHelpers.cs @@ -32,7 +32,6 @@ using NUnit.Framework; using OpenSim.Framework; using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Tests.Common { diff --git a/OpenSim/Tests/Common/Helpers/ClientStackHelpers.cs b/OpenSim/Tests/Common/Helpers/ClientStackHelpers.cs new file mode 100644 index 0000000..33cd8a2 --- /dev/null +++ b/OpenSim/Tests/Common/Helpers/ClientStackHelpers.cs @@ -0,0 +1,95 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Net; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenSim.Framework; +using OpenSim.Region.ClientStack.LindenUDP; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Tests.Common +{ + /// + /// This class adds full UDP client classes and associated scene presence to scene. + /// + /// + /// This is used for testing client stack code. For testing other code, use SceneHelper methods instead since + /// they operate without the burden of setting up UDP structures which should be unnecessary for testing scene + /// code. + /// + public static class ClientStackHelpers + { + public static ScenePresence AddChildClient( + Scene scene, LLUDPServer udpServer, UUID agentId, UUID sessionId, uint circuitCode) + { + IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999); + + UseCircuitCodePacket uccp = new UseCircuitCodePacket(); + + UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock + = new UseCircuitCodePacket.CircuitCodeBlock(); + uccpCcBlock.Code = circuitCode; + uccpCcBlock.ID = agentId; + uccpCcBlock.SessionID = sessionId; + uccp.CircuitCode = uccpCcBlock; + + byte[] uccpBytes = uccp.ToBytes(); + UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length); + upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor. + Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length); + + AgentCircuitData acd = new AgentCircuitData(); + acd.AgentID = agentId; + acd.SessionID = sessionId; + + scene.AuthenticateHandler.AddNewCircuit(circuitCode, acd); + + udpServer.PacketReceived(upb); + + return scene.GetScenePresence(agentId); + } + + public static TestLLUDPServer AddUdpServer(Scene scene) + { + return AddUdpServer(scene, new IniConfigSource()); + } + + public static TestLLUDPServer AddUdpServer(Scene scene, IniConfigSource configSource) + { + uint port = 0; + AgentCircuitManager acm = scene.AuthenticateHandler; + + TestLLUDPServer udpServer = new TestLLUDPServer(IPAddress.Any, ref port, 0, false, configSource, acm); + udpServer.AddScene(scene); + + return udpServer; + } + } +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs b/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs new file mode 100644 index 0000000..b215f1e --- /dev/null +++ b/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs @@ -0,0 +1,123 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using System.Threading; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; + +using OpenSim.Framework.Servers; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Tests.Common; + +namespace OpenSim.Tests.Common +{ + public static class EntityTransferHelpers + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Set up correct handling of the InformClientOfNeighbour call from the source region that triggers the + /// viewer to setup a connection with the destination region. + /// + /// + /// + /// A list that will be populated with any TestClients set up in response to + /// being informed about a destination region. + /// + public static void SetupInformClientOfNeighbourTriggersNeighbourClientCreate( + TestClient tc, List neighbourTcs) + { + // XXX: Confusingly, this is also used for non-neighbour notification (as in teleports that do not use the + // event queue). + + tc.OnTestClientInformClientOfNeighbour += (neighbourHandle, neighbourExternalEndPoint) => + { + uint x, y; + Util.RegionHandleToRegionLoc(neighbourHandle, out x, out y); + + m_log.DebugFormat( + "[TEST CLIENT]: Processing inform client of neighbour located at {0},{1} at {2}", + x, y, neighbourExternalEndPoint); + + AgentCircuitData newAgent = tc.RequestClientInfo(); + + Scene neighbourScene; + SceneManager.Instance.TryGetScene(x, y, out neighbourScene); + + TestClient neighbourTc = new TestClient(newAgent, neighbourScene); + neighbourTcs.Add(neighbourTc); + neighbourScene.AddNewAgent(neighbourTc, PresenceType.User); + }; + } + + /// + /// Set up correct handling of the InformClientOfNeighbour call from the source region that triggers the + /// viewer to setup a connection with the destination region. + /// + /// + /// + /// A list that will be populated with any TestClients set up in response to + /// being informed about a destination region. + /// + public static void SetupSendRegionTeleportTriggersDestinationClientCreateAndCompleteMovement( + TestClient client, List destinationClients) + { + client.OnTestClientSendRegionTeleport + += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) => + { + uint x, y; + Util.RegionHandleToRegionLoc(regionHandle, out x, out y); + + m_log.DebugFormat( + "[TEST CLIENT]: Processing send region teleport for destination at {0},{1} at {2}", + x, y, regionExternalEndPoint); + + AgentCircuitData newAgent = client.RequestClientInfo(); + + Scene destinationScene; + SceneManager.Instance.TryGetScene(x, y, out destinationScene); + + TestClient destinationClient = new TestClient(newAgent, destinationScene); + destinationClients.Add(destinationClient); + destinationScene.AddNewAgent(destinationClient, PresenceType.User); + + ThreadPool.UnsafeQueueUserWorkItem(o => destinationClient.CompleteMovement(), null); + }; + } + } +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs index ea3e348..df8b14c 100644 --- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs @@ -30,12 +30,13 @@ using System.Net; using System.Collections.Generic; using Nini.Config; using OpenMetaverse; +using OpenSim.Data.Null; using OpenSim.Framework; -using OpenSim.Framework.Communications; + using OpenSim.Framework.Console; using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Physics.Manager; +using OpenSim.Region.PhysicsModules.SharedBase; using OpenSim.Region.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; @@ -47,8 +48,8 @@ using OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid; using OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence; +using OpenSim.Region.PhysicsModule.BasicPhysics; using OpenSim.Services.Interfaces; -using OpenSim.Tests.Common.Mock; using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Tests.Common @@ -63,9 +64,9 @@ namespace OpenSim.Tests.Common ///
public SceneManager SceneManager { get; private set; } + public ISimulationDataService SimDataService { get; private set; } + private AgentCircuitManager m_acm = new AgentCircuitManager(); - private ISimulationDataService m_simDataService - = OpenSim.Server.Base.ServerUtils.LoadPlugin("OpenSim.Tests.Common.dll", null); private IEstateDataService m_estateDataService = null; private LocalAssetServicesConnector m_assetService; @@ -77,6 +78,8 @@ namespace OpenSim.Tests.Common private CoreAssetCache m_cache; + private PhysicsScene m_physicsScene; + public SceneHelpers() : this(null) {} public SceneHelpers(CoreAssetCache cache) @@ -96,6 +99,11 @@ namespace OpenSim.Tests.Common m_presenceService.PostInitialise(); m_cache = cache; + + m_physicsScene = StartPhysicsScene(); + + SimDataService + = OpenSim.Server.Base.ServerUtils.LoadPlugin("OpenSim.Tests.Common.dll", null); } /// @@ -115,6 +123,11 @@ namespace OpenSim.Tests.Common return SetupScene(name, id, x, y, new IniConfigSource()); } + public TestScene SetupScene(string name, UUID id, uint x, uint y, IConfigSource configSource) + { + return SetupScene(name, id, x, y, Constants.RegionSize, Constants.RegionSize, configSource); + } + /// /// Set up a scene. /// @@ -122,10 +135,12 @@ namespace OpenSim.Tests.Common /// ID of the region /// X co-ordinate of the region /// Y co-ordinate of the region + /// X size of scene + /// Y size of scene /// /// public TestScene SetupScene( - string name, UUID id, uint x, uint y, IConfigSource configSource) + string name, UUID id, uint x, uint y, uint sizeX, uint sizeY, IConfigSource configSource) { Console.WriteLine("Setting up test scene {0}", name); @@ -135,16 +150,20 @@ namespace OpenSim.Tests.Common RegionInfo regInfo = new RegionInfo(x, y, new IPEndPoint(IPAddress.Loopback, 9000), "127.0.0.1"); regInfo.RegionName = name; regInfo.RegionID = id; - - SceneCommunicationService scs = new SceneCommunicationService(); + regInfo.RegionSizeX = sizeX; + regInfo.RegionSizeY = sizeY; TestScene testScene = new TestScene( - regInfo, m_acm, scs, m_simDataService, m_estateDataService, false, configSource, null); + regInfo, m_acm, SimDataService, m_estateDataService, configSource, null); INonSharedRegionModule godsModule = new GodsModule(); godsModule.Initialise(new IniConfigSource()); godsModule.AddRegion(testScene); + // Add scene to physics + ((INonSharedRegionModule)m_physicsScene).AddRegion(testScene); + ((INonSharedRegionModule)m_physicsScene).RegionLoaded(testScene); + // Add scene to services m_assetService.AddRegion(testScene); @@ -182,12 +201,7 @@ namespace OpenSim.Tests.Common testScene.SetModuleInterfaces(); testScene.LandChannel = new TestLandChannel(testScene); - testScene.LoadWorldMap(); - - PhysicsPluginManager physicsPluginManager = new PhysicsPluginManager(); - physicsPluginManager.LoadPluginsFromAssembly("Physics/OpenSim.Region.Physics.BasicPhysicsPlugin.dll"); - testScene.PhysicsScene - = physicsPluginManager.GetPhysicsScene("basicphysics", "ZeroMesher", new IniConfigSource(), "test"); + testScene.LoadWorldMap(); testScene.RegionInfo.EstateSettings = new EstateSettings(); testScene.LoginsEnabled = true; @@ -297,6 +311,11 @@ namespace OpenSim.Tests.Common /// private static LocalPresenceServicesConnector StartPresenceService() { + // Unfortunately, some services share data via statics, so we need to null every time to stop interference + // between tests. + // This is a massive non-obvious pita. + NullPresenceData.Instance = null; + IConfigSource config = new IniConfigSource(); config.AddConfig("Modules"); config.AddConfig("PresenceService"); @@ -311,6 +330,19 @@ namespace OpenSim.Tests.Common return presenceService; } + private static PhysicsScene StartPhysicsScene() + { + IConfigSource config = new IniConfigSource(); + config.AddConfig("Startup"); + config.Configs["Startup"].Set("physics", "basicphysics"); + + PhysicsScene pScene = new BasicScene(); + INonSharedRegionModule mod = pScene as INonSharedRegionModule; + mod.Initialise(config); + + return pScene; + } + /// /// Setup modules for a scene using their default settings. /// @@ -447,9 +479,6 @@ namespace OpenSim.Tests.Common /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test /// /// - /// This can be used for tests where there is only one region or where there are multiple non-neighbour regions - /// and teleport doesn't take place. - /// /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will /// make the agent circuit data (e.g. first, lastname) consistent with the user account data. /// @@ -462,22 +491,6 @@ namespace OpenSim.Tests.Common } /// - /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test - /// - /// - /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will - /// make the agent circuit data (e.g. first, lastname) consistent with the user account data. - /// - /// - /// - /// - /// - public static ScenePresence AddScenePresence(Scene scene, UUID agentId, SceneManager sceneManager) - { - return AddScenePresence(scene, GenerateAgentData(agentId), sceneManager); - } - - /// /// Add a root agent. /// /// @@ -508,7 +521,7 @@ namespace OpenSim.Tests.Common /// public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData) { - return AddScenePresence(scene, agentData, null); + return AddScenePresence(scene, new TestClient(agentData, scene), agentData); } /// @@ -528,9 +541,9 @@ namespace OpenSim.Tests.Common /// /// /// - /// /// - public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData, SceneManager sceneManager) + public static ScenePresence AddScenePresence( + Scene scene, IClientAPI client, AgentCircuitData agentData) { // We emulate the proper login sequence here by doing things in four stages @@ -541,7 +554,7 @@ namespace OpenSim.Tests.Common lpsc.m_PresenceService.LoginAgent(agentData.AgentID.ToString(), agentData.SessionID, agentData.SecureSessionID); // Stages 1 & 2 - ScenePresence sp = IntroduceClientToScene(scene, sceneManager, agentData, TeleportFlags.ViaLogin); + ScenePresence sp = IntroduceClientToScene(scene, client, agentData, TeleportFlags.ViaLogin); // Stage 3: Complete the entrance into the region. This converts the child agent into a root agent. sp.CompleteMovement(sp.ControllingClient, true); @@ -553,37 +566,37 @@ namespace OpenSim.Tests.Common /// Introduce an agent into the scene by adding a new client. /// /// The scene presence added - /// - /// Scene manager. Can be null if there is only one region in the test or multiple regions that are not - /// neighbours and where no teleporting takes place. - /// /// - /// /// /// private static ScenePresence IntroduceClientToScene( - Scene scene, SceneManager sceneManager, AgentCircuitData agentData, TeleportFlags tf) + Scene scene, IClientAPI client, AgentCircuitData agentData, TeleportFlags tf) { string reason; // Stage 1: tell the scene to expect a new user connection - if (!scene.NewUserConnection(agentData, (uint)tf, out reason)) + if (!scene.NewUserConnection(agentData, (uint)tf, null, out reason)) Console.WriteLine("NewUserConnection failed: " + reason); // Stage 2: add the new client as a child agent to the scene - TestClient client = new TestClient(agentData, scene, sceneManager); - scene.AddNewClient(client, PresenceType.User); + scene.AddNewAgent(client, PresenceType.User); - return scene.GetScenePresence(agentData.AgentID); + return scene.GetScenePresence(client.AgentId); } public static ScenePresence AddChildScenePresence(Scene scene, UUID agentId) { - AgentCircuitData acd = GenerateAgentData(agentId); + return AddChildScenePresence(scene, GenerateAgentData(agentId)); + } + + public static ScenePresence AddChildScenePresence(Scene scene, AgentCircuitData acd) + { acd.child = true; // XXX: ViaLogin may not be correct for child agents - return IntroduceClientToScene(scene, null, acd, TeleportFlags.ViaLogin); + TestClient client = new TestClient(acd, scene); + return IntroduceClientToScene(scene, client, acd, TeleportFlags.ViaLogin); } /// @@ -610,6 +623,32 @@ namespace OpenSim.Tests.Common //part.UpdatePrimFlags(false, false, true); //part.ObjectFlags |= (uint)PrimFlags.Phantom; + scene.AddNewSceneObject(so, true); + + return so; + } + + /// + /// Add a test object + /// + /// + /// + /// The number of parts that should be in the scene object + /// + /// + /// + /// The prefix to be given to part names. This will be suffixed with "Part" + /// (e.g. mynamePart1 for the root part) + /// + /// + /// The hexadecimal last part of the UUID for parts created. A UUID of the form "00000000-0000-0000-0000-{0:XD12}" + /// will be given to the root part, and incremented for each part thereafter. + /// + /// + public static SceneObjectGroup AddSceneObject(Scene scene, int parts, UUID ownerId, string partNamePrefix, int uuidTail) + { + SceneObjectGroup so = CreateSceneObject(parts, ownerId, partNamePrefix, uuidTail); + scene.AddNewSceneObject(so, false); return so; diff --git a/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs index 0a2b30a..3a3b33a 100644 --- a/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs @@ -43,21 +43,40 @@ namespace OpenSim.Tests.Common /// /// Add a notecard item to the given part. /// - /// + /// + /// + /// + /// UUID or UUID stem + /// UUID or UUID stem + /// The tex to put in the notecard. + /// The item that was added + public static TaskInventoryItem AddNotecard( + IAssetService assetService, SceneObjectPart part, string itemName, string itemIDStem, string assetIDStem, string text) + { + return AddNotecard( + assetService, part, itemName, TestHelpers.ParseStem(itemIDStem), TestHelpers.ParseStem(assetIDStem), text); + } + + /// + /// Add a notecard item to the given part. + /// + /// /// /// /// /// + /// The tex to put in the notecard. /// The item that was added - public static TaskInventoryItem AddNotecard(Scene scene, SceneObjectPart part, string itemName, UUID itemID, UUID assetID) + public static TaskInventoryItem AddNotecard( + IAssetService assetService, SceneObjectPart part, string itemName, UUID itemID, UUID assetID, string text) { AssetNotecard nc = new AssetNotecard(); - nc.BodyText = "Hello World!"; + nc.BodyText = text; nc.Encode(); AssetBase ncAsset = AssetHelpers.CreateAsset(assetID, AssetType.Notecard, nc.AssetData, UUID.Zero); - scene.AssetService.Store(ncAsset); + assetService.Store(ncAsset); TaskInventoryItem ncItem = new TaskInventoryItem @@ -75,44 +94,62 @@ namespace OpenSim.Tests.Common /// TODO: Accept input for item and asset IDs to avoid mysterious script failures that try to use any of these /// functions more than once in a test. /// - /// + /// /// /// The item that was added - public static TaskInventoryItem AddScript(Scene scene, SceneObjectPart part) + public static TaskInventoryItem AddScript(IAssetService assetService, SceneObjectPart part) { - return AddScript(scene, part, "scriptItem", "default { state_entry() { llSay(0, \"Hello World\"); } }"); + return AddScript(assetService, part, "scriptItem", "default { state_entry() { llSay(0, \"Hello World\"); } }"); } /// /// Add a simple script to the given part. /// /// - /// TODO: Accept input for item and asset IDs to avoid mysterious script failures that try to use any of these - /// functions more than once in a test. + /// TODO: Accept input for item and asset IDs so that we have completely replicatable regression tests rather + /// than a random component. + /// + /// + /// + /// Name of the script to add + /// LSL script source + /// The item that was added + public static TaskInventoryItem AddScript( + IAssetService assetService, SceneObjectPart part, string scriptName, string scriptSource) + { + return AddScript(assetService, part, UUID.Random(), UUID.Random(), scriptName, scriptSource); + } + + /// + /// Add a simple script to the given part. + /// + /// + /// TODO: Accept input for item and asset IDs so that we have completely replicatable regression tests rather + /// than a random component. /// - /// + /// /// + /// Item UUID for the script + /// Asset UUID for the script /// Name of the script to add /// LSL script source /// The item that was added public static TaskInventoryItem AddScript( - Scene scene, SceneObjectPart part, string scriptName, string scriptSource) + IAssetService assetService, SceneObjectPart part, UUID itemId, UUID assetId, string scriptName, string scriptSource) { AssetScriptText ast = new AssetScriptText(); ast.Source = scriptSource; ast.Encode(); - UUID assetUuid = new UUID("00000000-0000-0000-1000-000000000000"); - UUID itemUuid = new UUID("00000000-0000-0000-1100-000000000000"); AssetBase asset - = AssetHelpers.CreateAsset(assetUuid, AssetType.LSLText, ast.AssetData, UUID.Zero); - scene.AssetService.Store(asset); + = AssetHelpers.CreateAsset(assetId, AssetType.LSLText, ast.AssetData, UUID.Zero); + assetService.Store(asset); TaskInventoryItem item = new TaskInventoryItem - { Name = scriptName, AssetID = assetUuid, ItemID = itemUuid, - Type = (int)AssetType.LSLText, InvType = (int)InventoryType.LSL }; + { Name = scriptName, AssetID = assetId, ItemID = itemId, + Type = (int)AssetType.LSLText, InvType = (int)InventoryType.LSL }; part.Inventory.AddInventoryItem(item, true); - + return item; } @@ -124,28 +161,50 @@ namespace OpenSim.Tests.Common /// functions more than once in a test. /// /// - /// + /// /// /// - /// - /// + /// + /// + /// public static TaskInventoryItem AddSceneObject( - Scene scene, SceneObjectPart sop, string itemName, UUID id, UUID userId) + IAssetService assetService, SceneObjectPart sop, string itemName, UUID itemId, SceneObjectGroup soToAdd, UUID soAssetId) { - SceneObjectGroup taskSceneObject = SceneHelpers.CreateSceneObject(1, UUID.Zero); - AssetBase taskSceneObjectAsset = AssetHelpers.CreateAsset(0x10, taskSceneObject); - scene.AssetService.Store(taskSceneObjectAsset); + AssetBase taskSceneObjectAsset = AssetHelpers.CreateAsset(soAssetId, soToAdd); + assetService.Store(taskSceneObjectAsset); TaskInventoryItem taskSceneObjectItem = new TaskInventoryItem - { Name = itemName, - AssetID = taskSceneObjectAsset.FullID, - ItemID = id, - OwnerID = userId, - Type = (int)AssetType.Object, - InvType = (int)InventoryType.Object }; + { Name = itemName, + AssetID = taskSceneObjectAsset.FullID, + ItemID = itemId, + OwnerID = soToAdd.OwnerID, + Type = (int)AssetType.Object, + InvType = (int)InventoryType.Object }; sop.Inventory.AddInventoryItem(taskSceneObjectItem, true); return taskSceneObjectItem; } + + /// + /// Add a scene object item to the given part. + /// + /// + /// TODO: Accept input for item and asset IDs to avoid mysterious script failures that try to use any of these + /// functions more than once in a test. + /// + /// + /// + /// + /// + /// + /// + public static TaskInventoryItem AddSceneObject( + IAssetService assetService, SceneObjectPart sop, string itemName, UUID itemId, UUID userId) + { + SceneObjectGroup taskSceneObject = SceneHelpers.CreateSceneObject(1, userId); + + return TaskInventoryHelpers.AddSceneObject( + assetService, sop, itemName, itemId, taskSceneObject, TestHelpers.ParseTail(0x10)); + } } } \ No newline at end of file diff --git a/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs b/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs index 2fbebc4..c62b58e 100644 --- a/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs @@ -27,7 +27,7 @@ using System.Collections.Generic; using OpenMetaverse; -using OpenSim.Framework.Communications; + using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; diff --git a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs index 87d9410..5a36332 100644 --- a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs @@ -45,6 +45,9 @@ namespace OpenSim.Tests.Common /// /// Add an existing scene object as an item in the user's inventory. /// + /// + /// Will be added to the system Objects folder. + /// /// /// /// @@ -63,7 +66,29 @@ namespace OpenSim.Tests.Common } /// - /// Creates a notecard in the objects folder and specify an item id. + /// Add an existing scene object as an item in the user's inventory at the given path. + /// + /// + /// + /// + /// + /// The inventory item created. + public static InventoryItemBase AddInventoryItem( + Scene scene, SceneObjectGroup so, int inventoryIdTail, int assetIdTail, string path) + { + return AddInventoryItem( + scene, + so.Name, + TestHelpers.ParseTail(inventoryIdTail), + InventoryType.Object, + AssetHelpers.CreateAsset(TestHelpers.ParseTail(assetIdTail), so), + so.OwnerID, + path); + } + + /// + /// Adds the given item to the existing system folder for its type (e.g. an object will go in the "Objects" + /// folder). /// /// /// @@ -75,6 +100,25 @@ namespace OpenSim.Tests.Common private static InventoryItemBase AddInventoryItem( Scene scene, string itemName, UUID itemId, InventoryType itemType, AssetBase asset, UUID userId) { + return AddInventoryItem( + scene, itemName, itemId, itemType, asset, userId, + scene.InventoryService.GetFolderForType(userId, (FolderType)asset.Type).Name); + } + + /// + /// Adds the given item to an inventory folder + /// + /// + /// + /// + /// + /// The serialized asset for this item + /// + /// Existing inventory path at which to add. + /// + private static InventoryItemBase AddInventoryItem( + Scene scene, string itemName, UUID itemId, InventoryType itemType, AssetBase asset, UUID userId, string path) + { scene.AssetService.Store(asset); InventoryItemBase item = new InventoryItemBase(); @@ -85,7 +129,7 @@ namespace OpenSim.Tests.Common item.AssetType = asset.Type; item.InvType = (int)itemType; - InventoryFolderBase folder = scene.InventoryService.GetFolderForType(userId, (AssetType)asset.Type); + InventoryFolderBase folder = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, userId, path)[0]; item.Folder = folder.ID; scene.AddInventoryItem(item); @@ -156,58 +200,116 @@ namespace OpenSim.Tests.Common /// /// Create inventory folders starting from the user's root folder. /// - /// - /// Ignores any existing folders with the same name - /// /// /// /// /// The folders to create. Multiple folders can be specified on a path delimited by the PATH_DELIMITER /// + /// + /// If true, then folders in the path which already the same name are + /// used. This applies to the terminal folder as well. + /// If false, then all folders in the path are created, even if there is already a folder at a particular + /// level with the same name. + /// /// /// The folder created. If the path contains multiple folders then the last one created is returned. /// Will return null if the root folder could not be found. /// public static InventoryFolderBase CreateInventoryFolder( - IInventoryService inventoryService, UUID userId, string path) + IInventoryService inventoryService, UUID userId, string path, bool useExistingFolders) + { + return CreateInventoryFolder(inventoryService, userId, UUID.Random(), path, useExistingFolders); + } + + /// + /// Create inventory folders starting from the user's root folder. + /// + /// + /// + /// + /// + /// The folders to create. Multiple folders can be specified on a path delimited by the PATH_DELIMITER + /// + /// + /// If true, then folders in the path which already the same name are + /// used. This applies to the terminal folder as well. + /// If false, then all folders in the path are created, even if there is already a folder at a particular + /// level with the same name. + /// + /// + /// The folder created. If the path contains multiple folders then the last one created is returned. + /// Will return null if the root folder could not be found. + /// + public static InventoryFolderBase CreateInventoryFolder( + IInventoryService inventoryService, UUID userId, UUID folderId, string path, bool useExistingFolders) { InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId); if (null == rootFolder) return null; - return CreateInventoryFolder(inventoryService, rootFolder, path); + return CreateInventoryFolder(inventoryService, folderId, rootFolder, path, useExistingFolders); } /// /// Create inventory folders starting from a given parent folder /// - /// - /// Ignores any existing folders with the same name - /// + /// + /// If any stem of the path names folders that already exist then these are not recreated. This includes the + /// final folder. + /// TODO: May need to make it an option to create duplicate folders. + /// /// + /// ID of the folder to create /// /// - /// The folders to create. Multiple folders can be specified on a path delimited by the PATH_DELIMITER + /// The folder to create. + /// + /// + /// If true, then folders in the path which already the same name are + /// used. This applies to the terminal folder as well. + /// If false, then all folders in the path are created, even if there is already a folder at a particular + /// level with the same name. /// /// /// The folder created. If the path contains multiple folders then the last one created is returned. /// public static InventoryFolderBase CreateInventoryFolder( - IInventoryService inventoryService, InventoryFolderBase parentFolder, string path) + IInventoryService inventoryService, UUID folderId, InventoryFolderBase parentFolder, string path, bool useExistingFolders) { string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None); - InventoryFolderBase newFolder - = new InventoryFolderBase( - UUID.Random(), components[0], parentFolder.Owner, (short)AssetType.Unknown, parentFolder.ID, 0); - - inventoryService.AddFolder(newFolder); + InventoryFolderBase folder = null; + + if (useExistingFolders) + folder = InventoryArchiveUtils.FindFolderByPath(inventoryService, parentFolder, components[0]); + + if (folder == null) + { +// Console.WriteLine("Creating folder {0} at {1}", components[0], parentFolder.Name); + + UUID folderIdForCreate; + + if (components.Length > 1) + folderIdForCreate = UUID.Random(); + else + folderIdForCreate = folderId; + + folder + = new InventoryFolderBase( + folderIdForCreate, components[0], parentFolder.Owner, (short)AssetType.Unknown, parentFolder.ID, 0); + + inventoryService.AddFolder(folder); + } +// else +// { +// Console.WriteLine("Found existing folder {0}", folder.Name); +// } if (components.Length > 1) - return CreateInventoryFolder(inventoryService, newFolder, components[1]); + return CreateInventoryFolder(inventoryService, folderId, folder, components[1], useExistingFolders); else - return newFolder; + return folder; } /// @@ -237,7 +339,7 @@ namespace OpenSim.Tests.Common /// An empty list if no matching folders were found public static List GetInventoryFolders(IInventoryService inventoryService, UUID userId, string path) { - return InventoryArchiveUtils.FindFolderByPath(inventoryService, userId, path); + return InventoryArchiveUtils.FindFoldersByPath(inventoryService, userId, path); } /// diff --git a/OpenSim/Tests/Common/Mock/BaseAssetRepository.cs b/OpenSim/Tests/Common/Mock/BaseAssetRepository.cs index cfefd38..cb4fb80 100644 --- a/OpenSim/Tests/Common/Mock/BaseAssetRepository.cs +++ b/OpenSim/Tests/Common/Mock/BaseAssetRepository.cs @@ -25,11 +25,12 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System; using System.Collections.Generic; using OpenMetaverse; using OpenSim.Framework; -namespace OpenSim.Tests.Common.Mock +namespace OpenSim.Tests.Common { public class BaseAssetRepository { @@ -37,7 +38,7 @@ namespace OpenSim.Tests.Common.Mock public AssetBase FetchAsset(UUID uuid) { - if (ExistsAsset(uuid)) + if (AssetsExist(new[] { uuid })[0]) return Assets[uuid]; else return null; @@ -53,9 +54,9 @@ namespace OpenSim.Tests.Common.Mock CreateAsset(asset); } - public bool ExistsAsset(UUID uuid) - { - return Assets.ContainsKey(uuid); + public bool[] AssetsExist(UUID[] uuids) + { + return Array.ConvertAll(uuids, id => Assets.ContainsKey(id)); } } } \ No newline at end of file diff --git a/OpenSim/Tests/Common/Mock/MockAssetDataPlugin.cs b/OpenSim/Tests/Common/Mock/MockAssetDataPlugin.cs index 4a15cf2..dddf75d 100644 --- a/OpenSim/Tests/Common/Mock/MockAssetDataPlugin.cs +++ b/OpenSim/Tests/Common/Mock/MockAssetDataPlugin.cs @@ -31,7 +31,7 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Data; -namespace OpenSim.Tests.Common.Mock +namespace OpenSim.Tests.Common { /// /// In memory asset data plugin for test purposes. Could be another dll when properly filled out and when the diff --git a/OpenSim/Tests/Common/Mock/MockGroupsServicesConnector.cs b/OpenSim/Tests/Common/Mock/MockGroupsServicesConnector.cs index 3035cea..7f530d0 100644 --- a/OpenSim/Tests/Common/Mock/MockGroupsServicesConnector.cs +++ b/OpenSim/Tests/Common/Mock/MockGroupsServicesConnector.cs @@ -40,7 +40,7 @@ using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; -namespace OpenSim.Tests.Common.Mock +namespace OpenSim.Tests.Common { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] public class MockGroupsServicesConnector : ISharedRegionModule, IGroupsServicesConnector @@ -138,33 +138,28 @@ namespace OpenSim.Tests.Common.Mock { } + private XGroup GetXGroup(UUID groupID, string name) + { + XGroup group = m_data.GetGroup(groupID); + + + if (group == null) + m_log.DebugFormat("[MOCK GROUPS SERVICES CONNECTOR]: No group found with ID {0}", groupID); + + return group; + } + public GroupRecord GetGroupRecord(UUID requestingAgentID, UUID groupID, string groupName) { m_log.DebugFormat( "[MOCK GROUPS SERVICES CONNECTOR]: Processing GetGroupRecord() for groupID {0}, name {1}", groupID, groupName); - XGroup[] groups; - string field, val; + XGroup xg = GetXGroup(groupID, groupName); - if (groupID != UUID.Zero) - { - field = "groupID"; - val = groupID.ToString(); - } - else - { - field = "name"; - val = groupName; - } - - groups = m_data.GetGroups(field, val); - - if (groups.Length == 0) + if (xg == null) return null; - XGroup xg = groups[0]; - GroupRecord gr = new GroupRecord() { GroupID = xg.groupID, @@ -196,8 +191,25 @@ namespace OpenSim.Tests.Common.Mock { } - public void SetAgentGroupInfo(UUID requestingAgentID, UUID AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile) + public void SetAgentGroupInfo(UUID requestingAgentID, UUID agentID, UUID groupID, bool acceptNotices, bool listInProfile) { + m_log.DebugFormat( + "[MOCK GROUPS SERVICES CONNECTOR]: SetAgentGroupInfo, requestingAgentID {0}, agentID {1}, groupID {2}, acceptNotices {3}, listInProfile {4}", + requestingAgentID, agentID, groupID, acceptNotices, listInProfile); + + XGroup group = GetXGroup(groupID, null); + + if (group == null) + return; + + XGroupMember xgm = null; + if (!group.members.TryGetValue(agentID, out xgm)) + return; + + xgm.acceptNotices = acceptNotices; + xgm.listInProfile = listInProfile; + + m_data.StoreGroup(group); } public void AddAgentToGroupInvite(UUID requestingAgentID, UUID inviteID, UUID groupID, UUID roleID, UUID agentID) @@ -213,8 +225,27 @@ namespace OpenSim.Tests.Common.Mock { } - public void AddAgentToGroup(UUID requestingAgentID, UUID AgentID, UUID GroupID, UUID RoleID) + public void AddAgentToGroup(UUID requestingAgentID, UUID agentID, UUID groupID, UUID roleID) { + m_log.DebugFormat( + "[MOCK GROUPS SERVICES CONNECTOR]: AddAgentToGroup, requestingAgentID {0}, agentID {1}, groupID {2}, roleID {3}", + requestingAgentID, agentID, groupID, roleID); + + XGroup group = GetXGroup(groupID, null); + + if (group == null) + return; + + XGroupMember groupMember = new XGroupMember() + { + agentID = agentID, + groupID = groupID, + roleID = roleID + }; + + group.members[agentID] = groupMember; + + m_data.StoreGroup(group); } public void RemoveAgentFromGroup(UUID requestingAgentID, UUID AgentID, UUID GroupID) @@ -259,9 +290,31 @@ namespace OpenSim.Tests.Common.Mock return null; } - public List GetGroupMembers(UUID requestingAgentID, UUID GroupID) + public List GetGroupMembers(UUID requestingAgentID, UUID groupID) { - return null; + m_log.DebugFormat( + "[MOCK GROUPS SERVICES CONNECTOR]: GetGroupMembers, requestingAgentID {0}, groupID {1}", + requestingAgentID, groupID); + + List groupMembers = new List(); + + XGroup group = GetXGroup(groupID, null); + + if (group == null) + return groupMembers; + + foreach (XGroupMember xgm in group.members.Values) + { + GroupMembersData gmd = new GroupMembersData(); + gmd.AgentID = xgm.agentID; + gmd.IsOwner = group.founderID == gmd.AgentID; + gmd.AcceptNotices = xgm.acceptNotices; + gmd.ListInProfile = xgm.listInProfile; + + groupMembers.Add(gmd); + } + + return groupMembers; } public List GetGroupRoleMembers(UUID requestingAgentID, UUID GroupID) @@ -269,18 +322,93 @@ namespace OpenSim.Tests.Common.Mock return null; } - public List GetGroupNotices(UUID requestingAgentID, UUID GroupID) + public List GetGroupNotices(UUID requestingAgentID, UUID groupID) { - return null; + XGroup group = GetXGroup(groupID, null); + + if (group == null) + return null; + + List notices = new List(); + + foreach (XGroupNotice notice in group.notices.Values) + { + GroupNoticeData gnd = new GroupNoticeData() + { + NoticeID = notice.noticeID, + Timestamp = notice.timestamp, + FromName = notice.fromName, + Subject = notice.subject, + HasAttachment = notice.hasAttachment, + AssetType = (byte)notice.assetType + }; + + notices.Add(gnd); + } + + return notices; } public GroupNoticeInfo GetGroupNotice(UUID requestingAgentID, UUID noticeID) { + m_log.DebugFormat( + "[MOCK GROUPS SERVICES CONNECTOR]: GetGroupNotices, requestingAgentID {0}, noticeID {1}", + requestingAgentID, noticeID); + + // Yes, not an efficient way to do it. + Dictionary groups = m_data.GetGroups(); + + foreach (XGroup group in groups.Values) + { + if (group.notices.ContainsKey(noticeID)) + { + XGroupNotice n = group.notices[noticeID]; + + GroupNoticeInfo gni = new GroupNoticeInfo(); + gni.GroupID = n.groupID; + gni.Message = n.message; + gni.BinaryBucket = n.binaryBucket; + gni.noticeData.NoticeID = n.noticeID; + gni.noticeData.Timestamp = n.timestamp; + gni.noticeData.FromName = n.fromName; + gni.noticeData.Subject = n.subject; + gni.noticeData.HasAttachment = n.hasAttachment; + gni.noticeData.AssetType = (byte)n.assetType; + + return gni; + } + } + return null; } public void AddGroupNotice(UUID requestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, byte[] binaryBucket) { + m_log.DebugFormat( + "[MOCK GROUPS SERVICES CONNECTOR]: AddGroupNotice, requestingAgentID {0}, groupID {1}, noticeID {2}, fromName {3}, subject {4}, message {5}, binaryBucket.Length {6}", + requestingAgentID, groupID, noticeID, fromName, subject, message, binaryBucket.Length); + + XGroup group = GetXGroup(groupID, null); + + if (group == null) + return; + + XGroupNotice groupNotice = new XGroupNotice() + { + groupID = groupID, + noticeID = noticeID, + fromName = fromName, + subject = subject, + message = message, + timestamp = (uint)Util.UnixTimeSinceEpoch(), + hasAttachment = false, + assetType = 0, + binaryBucket = binaryBucket + }; + + group.notices[noticeID] = groupNotice; + + m_data.StoreGroup(group); } public void ResetAgentGroupChatSessions(UUID agentID) diff --git a/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs b/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs index ed29c39..5df8e04 100644 --- a/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs +++ b/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs @@ -69,11 +69,21 @@ namespace OpenSim.Data.Null m_store.StoreTerrain(terrain, regionID); } + public void StoreTerrain(TerrainData terrain, UUID regionID) + { + m_store.StoreTerrain(terrain, regionID); + } + public double[,] LoadTerrain(UUID regionID) { return m_store.LoadTerrain(regionID); } + public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ) + { + return m_store.LoadTerrain(regionID, pSizeX, pSizeY, pSizeZ); + } + public void StoreLandObject(ILandObject Parcel) { m_store.StoreLandObject(Parcel); @@ -154,7 +164,7 @@ namespace OpenSim.Data.Null protected Dictionary m_sceneObjectParts = new Dictionary(); protected Dictionary> m_primItems = new Dictionary>(); - protected Dictionary m_terrains = new Dictionary(); + protected Dictionary m_terrains = new Dictionary(); protected Dictionary m_landData = new Dictionary(); public void Initialise(string dbfile) @@ -299,12 +309,17 @@ namespace OpenSim.Data.Null return new List(objects.Values); } - public void StoreTerrain(double[,] ter, UUID regionID) + public void StoreTerrain(TerrainData ter, UUID regionID) { m_terrains[regionID] = ter; } - public double[,] LoadTerrain(UUID regionID) + public void StoreTerrain(double[,] ter, UUID regionID) + { + m_terrains[regionID] = new HeightmapTerrainData(ter); + } + + public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ) { if (m_terrains.ContainsKey(regionID)) return m_terrains[regionID]; @@ -312,6 +327,14 @@ namespace OpenSim.Data.Null return null; } + public double[,] LoadTerrain(UUID regionID) + { + if (m_terrains.ContainsKey(regionID)) + return m_terrains[regionID].GetDoubles(); + else + return null; + } + public void RemoveLandObject(UUID globalID) { if (m_landData.ContainsKey(globalID)) diff --git a/OpenSim/Tests/Common/Mock/MockScriptEngine.cs b/OpenSim/Tests/Common/Mock/MockScriptEngine.cs new file mode 100644 index 0000000..d7a144c --- /dev/null +++ b/OpenSim/Tests/Common/Mock/MockScriptEngine.cs @@ -0,0 +1,272 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.Shared; + +namespace OpenSim.Tests.Common +{ + public class MockScriptEngine : INonSharedRegionModule, IScriptModule, IScriptEngine + { + public IConfigSource ConfigSource { get; private set; } + + public IConfig Config { get; private set; } + + private Scene m_scene; + + /// + /// Expose posted events to tests. + /// + public Dictionary> PostedEvents { get; private set; } + + /// + /// A very primitive way of hooking text cose to a posed event. + /// + /// + /// May be replaced with something that uses more original code in the future. + /// + public event Action PostEventHook; + + public void Initialise(IConfigSource source) + { + ConfigSource = source; + + // Can set later on if required + Config = new IniConfig("MockScriptEngine", ConfigSource); + + PostedEvents = new Dictionary>(); + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + m_scene = scene; + + m_scene.StackModuleInterface(this); + } + + public void RemoveRegion(Scene scene) + { + } + + public void RegionLoaded(Scene scene) + { + } + + public string Name { get { return "Mock Script Engine"; } } + public string ScriptEngineName { get { return Name; } } + + public Type ReplaceableInterface { get { return null; } } + +#pragma warning disable 0067 + public event ScriptRemoved OnScriptRemoved; + public event ObjectRemoved OnObjectRemoved; +#pragma warning restore 0067 + + public string GetXMLState (UUID itemID) + { + throw new System.NotImplementedException (); + } + + public bool SetXMLState(UUID itemID, string xml) + { + throw new System.NotImplementedException (); + } + + public bool PostScriptEvent(UUID itemID, string name, object[] args) + { +// Console.WriteLine("Posting event {0} for {1}", name, itemID); + + return PostScriptEvent(itemID, new EventParams(name, args, null)); + } + + public bool PostScriptEvent(UUID itemID, EventParams evParams) + { + List eventsForItem; + + if (!PostedEvents.ContainsKey(itemID)) + { + eventsForItem = new List(); + PostedEvents.Add(itemID, eventsForItem); + } + else + { + eventsForItem = PostedEvents[itemID]; + } + + eventsForItem.Add(evParams); + + if (PostEventHook != null) + PostEventHook(itemID, evParams); + + return true; + } + + public bool PostObjectEvent(uint localID, EventParams evParams) + { + return PostObjectEvent(m_scene.GetSceneObjectPart(localID), evParams); + } + + public bool PostObjectEvent(UUID itemID, string name, object[] args) + { + return PostObjectEvent(m_scene.GetSceneObjectPart(itemID), new EventParams(name, args, null)); + } + + private bool PostObjectEvent(SceneObjectPart part, EventParams evParams) + { + foreach (TaskInventoryItem item in part.Inventory.GetInventoryItems(InventoryType.LSL)) + PostScriptEvent(item.ItemID, evParams); + + return true; + } + + public void SuspendScript(UUID itemID) + { + throw new System.NotImplementedException (); + } + + public void ResumeScript(UUID itemID) + { + throw new System.NotImplementedException (); + } + + public ArrayList GetScriptErrors(UUID itemID) + { + throw new System.NotImplementedException (); + } + + public bool HasScript(UUID itemID, out bool running) + { + throw new System.NotImplementedException (); + } + + public bool GetScriptState(UUID itemID) + { + throw new System.NotImplementedException (); + } + + public void SaveAllState() + { + throw new System.NotImplementedException (); + } + + public void StartProcessing() + { + throw new System.NotImplementedException (); + } + + public float GetScriptExecutionTime(List itemIDs) + { + throw new System.NotImplementedException (); + } + + public Dictionary GetObjectScriptsExecutionTimes() + { + throw new System.NotImplementedException (); + } + + public IScriptWorkItem QueueEventHandler(object parms) + { + throw new System.NotImplementedException (); + } + + public DetectParams GetDetectParams(UUID item, int number) + { + throw new System.NotImplementedException (); + } + + public void SetMinEventDelay(UUID itemID, double delay) + { + throw new System.NotImplementedException (); + } + + public int GetStartParameter(UUID itemID) + { + throw new System.NotImplementedException (); + } + + public void SetScriptState(UUID itemID, bool state) + { + throw new System.NotImplementedException (); + } + + public void SetState(UUID itemID, string newState) + { + throw new System.NotImplementedException (); + } + + public void ApiResetScript(UUID itemID) + { + throw new System.NotImplementedException (); + } + + public void ResetScript (UUID itemID) + { + throw new System.NotImplementedException (); + } + + public IScriptApi GetApi(UUID itemID, string name) + { + throw new System.NotImplementedException (); + } + + public Scene World { get { return m_scene; } } + + public IScriptModule ScriptModule { get { return this; } } + + public string ScriptEnginePath { get { throw new System.NotImplementedException (); }} + + public string ScriptClassName { get { throw new System.NotImplementedException (); } } + + public string ScriptBaseClassName { get { throw new System.NotImplementedException (); } } + + public string[] ScriptReferencedAssemblies { get { throw new System.NotImplementedException (); } } + + public ParameterInfo[] ScriptBaseClassParameters { get { throw new System.NotImplementedException (); } } + + public void ClearPostedEvents() + { + PostedEvents.Clear(); + } + + public void SleepScript(UUID itemID, int delay) + { + } + } +} diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index dde37ab..0e1bc8f 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -38,7 +38,7 @@ using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Framework.Client; -namespace OpenSim.Tests.Common.Mock +namespace OpenSim.Tests.Common { public class TestClient : IClientAPI, IClientCore { @@ -46,12 +46,10 @@ namespace OpenSim.Tests.Common.Mock EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing"); - private TestClient TeleportSceneClient; - private Scene m_scene; - private SceneManager m_sceneManager; // Properties so that we can get at received data for test purposes + public List ReceivedKills { get; private set; } public List ReceivedOfflineNotifications { get; private set; } public List ReceivedOnlineNotifications { get; private set; } public List ReceivedFriendshipTerminations { get; private set; } @@ -60,6 +58,27 @@ namespace OpenSim.Tests.Common.Mock public List SentImagePacketPackets { get; private set; } public List SentImageNotInDatabasePackets { get; private set; } + // Test client specific events - for use by tests to implement some IClientAPI behaviour. + public event Action OnReceivedMoveAgentIntoRegion; + public event Action OnTestClientInformClientOfNeighbour; + public event TestClientOnSendRegionTeleportDelegate OnTestClientSendRegionTeleport; + + public event Action OnReceivedEntityUpdate; + + public event OnReceivedChatMessageDelegate OnReceivedChatMessage; + public event Action OnReceivedInstantMessage; + + public event Action OnReceivedSendRebakeAvatarTextures; + + public delegate void TestClientOnSendRegionTeleportDelegate( + ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, + uint locationID, uint flags, string capsURL); + + public delegate void OnReceivedChatMessageDelegate( + string message, byte type, Vector3 fromPos, string fromName, + UUID fromAgentID, UUID ownerID, byte source, byte audible); + + // disable warning: public events, part of the public API #pragma warning disable 67 @@ -103,6 +122,7 @@ namespace OpenSim.Tests.Common.Mock public event Action OnCompleteMovementToRegion; public event UpdateAgent OnPreAgentUpdate; public event UpdateAgent OnAgentUpdate; + public event UpdateAgent OnAgentCameraUpdate; public event AgentRequestSit OnAgentRequestSit; public event AgentSit OnAgentSit; public event AvatarPickerRequest OnAvatarPickerRequest; @@ -193,6 +213,7 @@ namespace OpenSim.Tests.Common.Mock public event EstateCovenantRequest OnEstateCovenantRequest; public event EstateChangeInfo OnEstateChangeInfo; public event EstateManageTelehub OnEstateManageTelehub; + public event CachedTextureRequest OnCachedTextureRequest; public event ObjectDuplicateOnRay OnObjectDuplicateOnRay; @@ -430,33 +451,21 @@ namespace OpenSim.Tests.Common.Mock /// /// Constructor /// - /// - /// Can be used for a test where there is only one region or where there are multiple regions that are not - /// neighbours and where no teleporting takes place. In other situations, the constructor that takes in a - /// scene manager should be used. - /// - /// - /// - public TestClient(AgentCircuitData agentData, Scene scene) : this(agentData, scene, null) {} - - /// - /// Constructor - /// /// /// /// - public TestClient(AgentCircuitData agentData, Scene scene, SceneManager sceneManager) + public TestClient(AgentCircuitData agentData, Scene scene) { m_agentId = agentData.AgentID; m_firstName = agentData.firstname; m_lastName = agentData.lastname; m_circuitCode = agentData.circuitcode; m_scene = scene; - m_sceneManager = sceneManager; SessionId = agentData.SessionID; SecureSessionId = agentData.SecureSessionID; CapsSeedUrl = agentData.CapsPath; + ReceivedKills = new List(); ReceivedOfflineNotifications = new List(); ReceivedOnlineNotifications = new List(); ReceivedFriendshipTerminations = new List(); @@ -467,6 +476,34 @@ namespace OpenSim.Tests.Common.Mock } /// + /// Trigger chat coming from this connection. + /// + /// + /// + /// + public bool Chat(int channel, ChatTypeEnum type, string message) + { + ChatMessage handlerChatFromClient = OnChatFromClient; + + if (handlerChatFromClient != null) + { + OSChatMessage args = new OSChatMessage(); + args.Channel = channel; + args.From = Name; + args.Message = message; + args.Type = type; + + args.Scene = Scene; + args.Sender = this; + args.SenderUUID = AgentId; + + handlerChatFromClient(this, args); + } + + return true; + } + + /// /// Attempt a teleport to the given region. /// /// @@ -479,7 +516,20 @@ namespace OpenSim.Tests.Common.Mock public void CompleteMovement() { - OnCompleteMovementToRegion(this, true); + if (OnCompleteMovementToRegion != null) + OnCompleteMovementToRegion(this, true); + } + + /// + /// Emulate sending an IM from the viewer to the simulator. + /// + /// + public void HandleImprovedInstantMessage(GridInstantMessage im) + { + ImprovedInstantMessage handlerInstantMessage = OnInstantMessage; + + if (handlerInstantMessage != null) + handlerInstantMessage(this, im); } public virtual void ActivateGesture(UUID assetId, UUID gestureId) @@ -494,6 +544,11 @@ namespace OpenSim.Tests.Common.Mock { } + public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures) + { + + } + public virtual void Kick(string message) { } @@ -508,22 +563,22 @@ namespace OpenSim.Tests.Common.Mock public virtual void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle) { - } - public virtual void SendKillObject(ulong regionHandle, List localID) + public virtual void SendKillObject(List localID) { + ReceivedKills.AddRange(localID); } public virtual void SetChildAgentThrottle(byte[] throttle) { } + public byte[] GetThrottlesPacked(float multiplier) { return new byte[0]; } - public virtual void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) { } @@ -532,19 +587,23 @@ namespace OpenSim.Tests.Common.Mock string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, UUID ownerID, byte source, byte audible) { +// Console.WriteLine("mmm {0} {1} {2}", message, Name, AgentId); + if (OnReceivedChatMessage != null) + OnReceivedChatMessage(message, type, fromPos, fromName, fromAgentID, ownerID, source, audible); } public void SendInstantMessage(GridInstantMessage im) { - + if (OnReceivedInstantMessage != null) + OnReceivedInstantMessage(im); } - public void SendGenericMessage(string method, List message) + public void SendGenericMessage(string method, UUID invoice, List message) { } - public void SendGenericMessage(string method, List message) + public void SendGenericMessage(string method, UUID invoice, List message) { } @@ -566,13 +625,15 @@ namespace OpenSim.Tests.Common.Mock public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) { + if (OnReceivedMoveAgentIntoRegion != null) + OnReceivedMoveAgentIntoRegion(regInfo, pos, look); } public virtual AgentCircuitData RequestClientInfo() { AgentCircuitData agentData = new AgentCircuitData(); agentData.AgentID = AgentId; - agentData.SessionID = UUID.Zero; + agentData.SessionID = SessionId; agentData.SecureSessionID = UUID.Zero; agentData.circuitcode = m_circuitCode; agentData.child = false; @@ -591,46 +652,29 @@ namespace OpenSim.Tests.Common.Mock public virtual void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint) { - m_log.DebugFormat("[TEST CLIENT]: Processing inform client of neighbour"); - - // In response to this message, we are going to make a teleport to the scene we've previous been told - // about by test code (this needs to be improved). - AgentCircuitData newAgent = RequestClientInfo(); - - // Stage 2: add the new client as a child agent to the scene - uint x, y; - Utils.LongToUInts(neighbourHandle, out x, out y); - x /= Constants.RegionSize; - y /= Constants.RegionSize; - - Scene neighbourScene; - m_sceneManager.TryGetScene(x, y, out neighbourScene); - - TeleportSceneClient = new TestClient(newAgent, neighbourScene, m_sceneManager); - neighbourScene.AddNewClient(TeleportSceneClient, PresenceType.User); + if (OnTestClientInformClientOfNeighbour != null) + OnTestClientInformClientOfNeighbour(neighbourHandle, neighbourExternalEndPoint); } - public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, - uint locationID, uint flags, string capsURL) + public virtual void SendRegionTeleport( + ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, + uint locationID, uint flags, string capsURL) { - m_log.DebugFormat("[TEST CLIENT]: Received SendRegionTeleport"); + m_log.DebugFormat( + "[TEST CLIENT]: Received SendRegionTeleport for {0} {1} on {2}", m_firstName, m_lastName, m_scene.Name); CapsSeedUrl = capsURL; - // We don't do this here so that the source region can complete processing first in a single-threaded - // regression test scenario. The test itself will have to call CompleteTeleportClientSide() after a teleport - // CompleteTeleportClientSide(); - } - - public void CompleteTeleportClientSide() - { - TeleportSceneClient.CompleteMovement(); - //TeleportTargetScene.AgentCrossing(newAgent.AgentID, new Vector3(90, 90, 90), false); + if (OnTestClientSendRegionTeleport != null) + OnTestClientSendRegionTeleport( + regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL); } public virtual void SendTeleportFailed(string reason) { - m_log.DebugFormat("[TEST CLIENT]: Teleport failed with reason {0}", reason); + m_log.DebugFormat( + "[TEST CLIENT]: Teleport failed for {0} {1} on {2} with reason {3}", + m_firstName, m_lastName, m_scene.Name, reason); } public virtual void CrossRegion(ulong newRegionHandle, Vector3 pos, Vector3 lookAt, @@ -660,7 +704,7 @@ namespace OpenSim.Tests.Common.Mock { } - public virtual void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance) + public virtual void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item) { } @@ -682,6 +726,8 @@ namespace OpenSim.Tests.Common.Mock public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) { + if (OnReceivedEntityUpdate != null) + OnReceivedEntityUpdate(entity, updateFlags); } public void ReprioritizeUpdates() @@ -786,11 +832,6 @@ namespace OpenSim.Tests.Common.Mock { OnRegionHandShakeReply(this); } - - if (OnCompleteMovementToRegion != null) - { - OnCompleteMovementToRegion(this, true); - } } public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) @@ -884,11 +925,6 @@ namespace OpenSim.Tests.Common.Mock } - public bool AddMoney(int debit) - { - return false; - } - public void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong time, uint dlen, uint ylen, float phase) { } @@ -1235,6 +1271,8 @@ namespace OpenSim.Tests.Common.Mock public void SendRebakeAvatarTextures(UUID textureID) { + if (OnReceivedSendRebakeAvatarTextures != null) + OnReceivedSendRebakeAvatarTextures(textureID); } public void SendAvatarInterestsReply(UUID avatarID, uint wantMask, string wantText, uint skillsMask, string skillsText, string languages) @@ -1269,12 +1307,17 @@ namespace OpenSim.Tests.Common.Mock { } - public void StopFlying(ISceneEntity presence) + public void SendAgentTerseUpdate(ISceneEntity presence) { } public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data) { } + + public void SendPartPhysicsProprieties(ISceneEntity entity) + { + } + } } diff --git a/OpenSim/Tests/Common/Mock/TestEventQueueGetModule.cs b/OpenSim/Tests/Common/Mock/TestEventQueueGetModule.cs new file mode 100644 index 0000000..f2bae58 --- /dev/null +++ b/OpenSim/Tests/Common/Mock/TestEventQueueGetModule.cs @@ -0,0 +1,182 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Reflection; +using System.Threading; +using log4net; +using Nini.Config; +using Mono.Addins; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Region.ClientStack.Linden; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Tests.Common +{ + public class TestEventQueueGetModule : IEventQueue, INonSharedRegionModule + { + public class Event + { + public string Name { get; set; } + public object[] Args { get; set; } + + public Event(string name, object[] args) + { + name = Name; + args = Args; + } + } + + public Dictionary> Events { get; set; } + + public void Initialise(IConfigSource source) {} + + public void Close() {} + + public void AddRegion(Scene scene) + { + Events = new Dictionary>(); + scene.RegisterModuleInterface(this); + } + + public void RemoveRegion (Scene scene) {} + + public void RegionLoaded (Scene scene) {} + + public string Name { get { return "TestEventQueueGetModule"; } } + + public Type ReplaceableInterface { get { return null; } } + + private void AddEvent(UUID avatarID, string name, params object[] args) + { + Console.WriteLine("Adding event {0} for {1}", name, avatarID); + + List avEvents; + + if (!Events.ContainsKey(avatarID)) + { + avEvents = new List(); + Events[avatarID] = avEvents; + } + else + { + avEvents = Events[avatarID]; + } + + avEvents.Add(new Event(name, args)); + } + + public void ClearEvents() + { + if (Events != null) + Events.Clear(); + } + + public bool Enqueue(OSD o, UUID avatarID) + { + AddEvent(avatarID, "Enqueue", o); + return true; + } + + public void DisableSimulator(ulong handle, UUID avatarID) + { + AddEvent(avatarID, "DisableSimulator", handle); + } + + public void EnableSimulator (ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY) + { + AddEvent(avatarID, "EnableSimulator", handle); + } + + public void EstablishAgentCommunication (UUID avatarID, IPEndPoint endPoint, string capsPath, + ulong regionHandle, int regionSizeX, int regionSizeY) + { + AddEvent(avatarID, "EstablishAgentCommunication", endPoint, capsPath); + } + + public void TeleportFinishEvent (ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, + uint locationID, uint flags, string capsURL, UUID agentID, int regionSizeX, int regionSizeY) + { + AddEvent(agentID, "TeleportFinishEvent", regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL); + } + + public void CrossRegion (ulong handle, Vector3 pos, Vector3 lookAt, IPEndPoint newRegionExternalEndPoint, + string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY) + { + AddEvent(avatarID, "CrossRegion", handle, pos, lookAt, newRegionExternalEndPoint, capsURL, sessionID); + } + + public void ChatterboxInvitation( + UUID sessionID, string sessionName, UUID fromAgent, string message, UUID toAgent, string fromName, + byte dialog, uint timeStamp, bool offline, int parentEstateID, Vector3 position, uint ttl, + UUID transactionID, bool fromGroup, byte[] binaryBucket) + { + AddEvent( + toAgent, "ChatterboxInvitation", sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog, + timeStamp, offline, parentEstateID, position, ttl, transactionID, fromGroup, binaryBucket); + } + + public void ChatterBoxSessionAgentListUpdates (UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, bool isModerator, bool textMute) + { + AddEvent(toAgent, "ChatterBoxSessionAgentListUpdates", sessionID, fromAgent, canVoiceChat, isModerator, textMute); + } + + public void ParcelProperties (OpenMetaverse.Messages.Linden.ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID) + { + AddEvent(avatarID, "ParcelProperties", parcelPropertiesMessage); + } + + public void GroupMembership (OpenMetaverse.Packets.AgentGroupDataUpdatePacket groupUpdate, UUID avatarID) + { + AddEvent(avatarID, "GroupMembership", groupUpdate); + } + + public OSD ScriptRunningEvent (UUID objectID, UUID itemID, bool running, bool mono) + { + Console.WriteLine("ONE"); + throw new System.NotImplementedException (); + } + + public OSD BuildEvent(string eventName, OSD eventBody) + { + Console.WriteLine("TWO"); + throw new System.NotImplementedException (); + } + + public void partPhysicsProperties (uint localID, byte physhapetype, float density, float friction, float bounce, float gravmod, UUID avatarID) + { + AddEvent(avatarID, "partPhysicsProperties", localID, physhapetype, density, friction, bounce, gravmod); + } + } +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Mock/TestHttpClientContext.cs b/OpenSim/Tests/Common/Mock/TestHttpClientContext.cs new file mode 100644 index 0000000..5a55b09 --- /dev/null +++ b/OpenSim/Tests/Common/Mock/TestHttpClientContext.cs @@ -0,0 +1,110 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text; +using HttpServer; +using OpenSim.Framework; + +namespace OpenSim.Tests.Common +{ + public class TestHttpClientContext: IHttpClientContext + { + /// + /// Bodies of responses from the server. + /// + public string ResponseBody + { + get { return Encoding.UTF8.GetString(m_responseStream.ToArray()); } + } + + public Byte[] ResponseBodyBytes + { + get{ return m_responseStream.ToArray(); } + } + + private MemoryStream m_responseStream = new MemoryStream(); + + public bool IsSecured { get; set; } + + public bool Secured + { + get { return IsSecured; } + set { IsSecured = value; } + } + + public TestHttpClientContext(bool secured) + { + Secured = secured; + } + + public void Disconnect(SocketError error) + { +// Console.WriteLine("TestHttpClientContext.Disconnect Received disconnect with status {0}", error); + } + + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {Console.WriteLine("x");} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {Console.WriteLine("xx");} + public void Respond(string body) { Console.WriteLine("xxx");} + + public void Send(byte[] buffer) + { + // Getting header data here +// Console.WriteLine("xxxx: Got {0}", Encoding.UTF8.GetString(buffer)); + } + + public void Send(byte[] buffer, int offset, int size) + { +// Util.PrintCallStack(); +// +// Console.WriteLine( +// "TestHttpClientContext.Send(byte[], int, int) got offset={0}, size={1}, buffer={2}", +// offset, size, Encoding.UTF8.GetString(buffer)); + + m_responseStream.Write(buffer, offset, size); + } + + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) {Console.WriteLine("xxxxxx");} + public void Close() { } + public bool EndWhenDone { get { return false;} set { return;}} + + public HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing() + { + return new HTTPNetworkContext(); + } + + public event EventHandler Disconnected = delegate { }; + /// + /// A request have been received in the context. + /// + public event EventHandler RequestReceived = delegate { }; + } +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Mock/TestHttpRequest.cs b/OpenSim/Tests/Common/Mock/TestHttpRequest.cs new file mode 100644 index 0000000..b868895 --- /dev/null +++ b/OpenSim/Tests/Common/Mock/TestHttpRequest.cs @@ -0,0 +1,174 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Specialized; +using System.IO; +using HttpServer; +using HttpServer.FormDecoders; + +namespace OpenSim.Tests.Common +{ + public class TestHttpRequest: IHttpRequest + { + private string _uriPath; + public bool BodyIsComplete + { + get { return true; } + } + public string[] AcceptTypes + { + get {return _acceptTypes; } + } + private string[] _acceptTypes; + public Stream Body + { + get { return _body; } + set { _body = value;} + } + private Stream _body; + public ConnectionType Connection + { + get { return _connection; } + set { _connection = value; } + } + private ConnectionType _connection; + public int ContentLength + { + get { return _contentLength; } + set { _contentLength = value; } + } + private int _contentLength; + public NameValueCollection Headers + { + get { return _headers; } + } + private NameValueCollection _headers = new NameValueCollection(); + + public string HttpVersion { get; set; } + + public string Method + { + get { return _method; } + set { _method = value; } + } + private string _method = null; + public HttpInput QueryString + { + get { return _queryString; } + } + private HttpInput _queryString = null; + public Uri Uri + { + get { return _uri; } + set { _uri = value; } + } + private Uri _uri = null; + public string[] UriParts + { + get { return _uri.Segments; } + } + public HttpParam Param + { + get { return null; } + } + public HttpForm Form + { + get { return null; } + } + public bool IsAjax + { + get { return false; } + } + public RequestCookies Cookies + { + get { return null; } + } + + public TestHttpRequest() + { + HttpVersion = "HTTP/1.1"; + } + + public TestHttpRequest(string contentEncoding, string contentType, string userAgent, + string remoteAddr, string remotePort, string[] acceptTypes, + ConnectionType connectionType, int contentLength, Uri uri) : base() + { + _headers["content-encoding"] = contentEncoding; + _headers["content-type"] = contentType; + _headers["user-agent"] = userAgent; + _headers["remote_addr"] = remoteAddr; + _headers["remote_port"] = remotePort; + + _acceptTypes = acceptTypes; + _connection = connectionType; + _contentLength = contentLength; + _uri = uri; + } + + public void DecodeBody(FormDecoderProvider providers) {} + public void SetCookies(RequestCookies cookies) {} + public void AddHeader(string name, string value) + { + _headers.Add(name, value); + } + public int AddToBody(byte[] bytes, int offset, int length) + { + return 0; + } + public void Clear() {} + + public object Clone() + { + TestHttpRequest clone = new TestHttpRequest(); + clone._acceptTypes = _acceptTypes; + clone._connection = _connection; + clone._contentLength = _contentLength; + clone._uri = _uri; + clone._headers = new NameValueCollection(_headers); + + return clone; + } + public IHttpResponse CreateResponse(IHttpClientContext context) + { + return new HttpResponse(context, this); + } + /// + /// Path and query (will be merged with the host header) and put in Uri + /// + /// + public string UriPath + { + get { return _uriPath; } + set + { + _uriPath = value; + + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Mock/TestHttpResponse.cs b/OpenSim/Tests/Common/Mock/TestHttpResponse.cs new file mode 100644 index 0000000..ff47c10 --- /dev/null +++ b/OpenSim/Tests/Common/Mock/TestHttpResponse.cs @@ -0,0 +1,171 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.IO; +using System.Net; +using System.Text; +using HttpServer; + +namespace OpenSim.Tests.Common +{ + public class TestHttpResponse: IHttpResponse + { + public Stream Body + { + get { return _body; } + + set { _body = value; } + } + private Stream _body; + + public string ProtocolVersion + { + get { return _protocolVersion; } + set { _protocolVersion = value; } + } + private string _protocolVersion; + + public bool Chunked + { + get { return _chunked; } + + set { _chunked = value; } + } + private bool _chunked; + + public ConnectionType Connection + { + get { return _connection; } + + set { _connection = value; } + } + private ConnectionType _connection; + + public Encoding Encoding + { + get { return _encoding; } + + set { _encoding = value; } + } + private Encoding _encoding; + + public int KeepAlive + { + get { return _keepAlive; } + + set { _keepAlive = value; } + } + private int _keepAlive; + + public HttpStatusCode Status + { + get { return _status; } + + set { _status = value; } + } + private HttpStatusCode _status; + + public string Reason + { + get { return _reason; } + + set { _reason = value; } + } + private string _reason; + + public long ContentLength + { + get { return _contentLength; } + + set { _contentLength = value; } + } + private long _contentLength; + + public string ContentType + { + get { return _contentType; } + + set { _contentType = value; } + } + private string _contentType; + + public bool HeadersSent + { + get { return _headersSent; } + } + private bool _headersSent; + + public bool Sent + { + get { return _sent; } + } + private bool _sent; + + public ResponseCookies Cookies + { + get { return _cookies; } + } + private ResponseCookies _cookies = null; + + public TestHttpResponse() + { + _headersSent = false; + _sent = false; + } + + public void AddHeader(string name, string value) {} + + public void Send() + { + if (!_headersSent) SendHeaders(); + if (_sent) throw new InvalidOperationException("stuff already sent"); + _sent = true; + } + + public void SendBody(byte[] buffer, int offset, int count) + { + if (!_headersSent) SendHeaders(); + _sent = true; + } + + public void SendBody(byte[] buffer) + { + if (!_headersSent) SendHeaders(); + _sent = true; + } + + public void SendHeaders() + { + if (_headersSent) throw new InvalidOperationException("headers already sent"); + _headersSent = true; + } + + public void Redirect(Uri uri) {} + public void Redirect(string url) {} + } +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Mock/TestInventoryDataPlugin.cs b/OpenSim/Tests/Common/Mock/TestInventoryDataPlugin.cs index fc44358..c97a765 100644 --- a/OpenSim/Tests/Common/Mock/TestInventoryDataPlugin.cs +++ b/OpenSim/Tests/Common/Mock/TestInventoryDataPlugin.cs @@ -33,7 +33,7 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Data; -namespace OpenSim.Tests.Common.Mock +namespace OpenSim.Tests.Common { /// /// In memory inventory data plugin for test purposes. Could be another dll when properly filled out and when the @@ -185,7 +185,7 @@ namespace OpenSim.Tests.Common.Mock public void addInventoryItem(InventoryItemBase item) { -// InventoryFolderBase folder = m_folders[item.Folder]; + InventoryFolderBase folder = m_folders[item.Folder]; // m_log.DebugFormat( // "[MOCK INV DB]: Adding inventory item {0} {1} in {2} {3}", item.Name, item.ID, folder.Name, folder.ID); diff --git a/OpenSim/Tests/Common/Mock/TestLLUDPServer.cs b/OpenSim/Tests/Common/Mock/TestLLUDPServer.cs new file mode 100644 index 0000000..26887c9 --- /dev/null +++ b/OpenSim/Tests/Common/Mock/TestLLUDPServer.cs @@ -0,0 +1,171 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using Nini.Config; +using OpenMetaverse.Packets; +using OpenSim.Framework; +using OpenSim.Region.ClientStack.LindenUDP; + +namespace OpenSim.Tests.Common +{ + /// + /// This class enables regression testing of the LLUDPServer by allowing us to intercept outgoing data. + /// + public class TestLLUDPServer : LLUDPServer + { + public List PacketsSent { get; private set; } + + public TestLLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) + : base(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager) + { + PacketsSent = new List(); + } + + public override void SendAckImmediate(IPEndPoint remoteEndpoint, PacketAckPacket ack) + { + PacketsSent.Add(ack); + } + + public override void SendPacket( + LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method) + { + PacketsSent.Add(packet); + } + + public void ClientOutgoingPacketHandler(IClientAPI client, bool resendUnacked, bool sendAcks, bool sendPing) + { + m_resendUnacked = resendUnacked; + m_sendAcks = sendAcks; + m_sendPing = sendPing; + + ClientOutgoingPacketHandler(client); + } + +//// /// +//// /// The chunks of data to pass to the LLUDPServer when it calls EndReceive +//// /// +//// protected Queue m_chunksToLoad = new Queue(); +// +//// protected override void BeginReceive() +//// { +//// if (m_chunksToLoad.Count > 0 && m_chunksToLoad.Peek().BeginReceiveException) +//// { +//// ChunkSenderTuple tuple = m_chunksToLoad.Dequeue(); +//// reusedEpSender = tuple.Sender; +//// throw new SocketException(); +//// } +//// } +// +//// protected override bool EndReceive(out int numBytes, IAsyncResult result, ref EndPoint epSender) +//// { +//// numBytes = 0; +//// +//// //m_log.Debug("Queue size " + m_chunksToLoad.Count); +//// +//// if (m_chunksToLoad.Count <= 0) +//// return false; +//// +//// ChunkSenderTuple tuple = m_chunksToLoad.Dequeue(); +//// RecvBuffer = tuple.Data; +//// numBytes = tuple.Data.Length; +//// epSender = tuple.Sender; +//// +//// return true; +//// } +// +//// public override void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode) +//// { +//// // Don't do anything just yet +//// } +// +// /// +// /// Signal that this chunk should throw an exception on Socket.BeginReceive() +// /// +// /// +// public void LoadReceiveWithBeginException(EndPoint epSender) +// { +// ChunkSenderTuple tuple = new ChunkSenderTuple(epSender); +// tuple.BeginReceiveException = true; +// m_chunksToLoad.Enqueue(tuple); +// } +// +// /// +// /// Load some data to be received by the LLUDPServer on the next receive call +// /// +// /// +// /// +// public void LoadReceive(byte[] data, EndPoint epSender) +// { +// m_chunksToLoad.Enqueue(new ChunkSenderTuple(data, epSender)); +// } +// +// /// +// /// Load a packet to be received by the LLUDPServer on the next receive call +// /// +// /// +// public void LoadReceive(Packet packet, EndPoint epSender) +// { +// LoadReceive(packet.ToBytes(), epSender); +// } +// +// /// +// /// Calls the protected asynchronous result method. This fires out all data chunks currently queued for send +// /// +// /// +// public void ReceiveData(IAsyncResult result) +// { +// // Doesn't work the same way anymore +//// while (m_chunksToLoad.Count > 0) +//// OnReceivedData(result); +// } + } + + /// + /// Record the data and sender tuple + /// + public class ChunkSenderTuple + { + public byte[] Data; + public EndPoint Sender; + public bool BeginReceiveException; + + public ChunkSenderTuple(byte[] data, EndPoint sender) + { + Data = data; + Sender = sender; + } + + public ChunkSenderTuple(EndPoint sender) + { + Sender = sender; + } + } +} diff --git a/OpenSim/Tests/Common/Mock/TestLandChannel.cs b/OpenSim/Tests/Common/Mock/TestLandChannel.cs index 4b4d52d..89ebcd5 100644 --- a/OpenSim/Tests/Common/Mock/TestLandChannel.cs +++ b/OpenSim/Tests/Common/Mock/TestLandChannel.cs @@ -32,7 +32,7 @@ using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.CoreModules.World.Land; -namespace OpenSim.Tests.Common.Mock +namespace OpenSim.Tests.Common { /// /// Land channel for test purposes @@ -81,6 +81,11 @@ namespace OpenSim.Tests.Common.Mock return obj; } + public ILandObject GetLandObject(Vector3 position) + { + return GetLandObject(position.X, position.Y); + } + public ILandObject GetLandObject(int x, int y) { return GetNoLand(); diff --git a/OpenSim/Tests/Common/Mock/TestOSHttpRequest.cs b/OpenSim/Tests/Common/Mock/TestOSHttpRequest.cs index e769d30..7b1d2b5 100644 --- a/OpenSim/Tests/Common/Mock/TestOSHttpRequest.cs +++ b/OpenSim/Tests/Common/Mock/TestOSHttpRequest.cs @@ -35,7 +35,7 @@ using System.Text; using System.Web; using OpenSim.Framework.Servers.HttpServer; -namespace OpenSim.Tests.Common.Mock +namespace OpenSim.Tests.Common { public class TestOSHttpRequest : IOSHttpRequest { diff --git a/OpenSim/Tests/Common/Mock/TestOSHttpResponse.cs b/OpenSim/Tests/Common/Mock/TestOSHttpResponse.cs index e10fe82..2e17f1e 100644 --- a/OpenSim/Tests/Common/Mock/TestOSHttpResponse.cs +++ b/OpenSim/Tests/Common/Mock/TestOSHttpResponse.cs @@ -32,7 +32,7 @@ using System.Text; using System.Web; using OpenSim.Framework.Servers.HttpServer; -namespace OpenSim.Tests.Common.Mock +namespace OpenSim.Tests.Common { public class TestOSHttpResponse : IOSHttpResponse { diff --git a/OpenSim/Tests/Common/Mock/TestScene.cs b/OpenSim/Tests/Common/Mock/TestScene.cs index d4b5648..1a93c9f 100644 --- a/OpenSim/Tests/Common/Mock/TestScene.cs +++ b/OpenSim/Tests/Common/Mock/TestScene.cs @@ -28,23 +28,24 @@ using System; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Communications; + using OpenSim.Framework.Servers; using OpenSim.Region.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.PhysicsModules.SharedBase; +using OpenSim.Services.Interfaces; -namespace OpenSim.Tests.Common.Mock +namespace OpenSim.Tests.Common { public class TestScene : Scene { public TestScene( - RegionInfo regInfo, AgentCircuitManager authen, - SceneCommunicationService sceneGridService, ISimulationDataService simDataService, IEstateDataService estateDataService, - bool dumpAssetsToFile, + RegionInfo regInfo, AgentCircuitManager authen, + ISimulationDataService simDataService, IEstateDataService estateDataService, IConfigSource config, string simulatorVersion) - : base(regInfo, authen, sceneGridService, simDataService, estateDataService, - dumpAssetsToFile, config, simulatorVersion) + : base(regInfo, authen, simDataService, estateDataService, + config, simulatorVersion) { } diff --git a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs index ccbdf81..2b272e6 100644 --- a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs +++ b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs @@ -35,7 +35,7 @@ using OpenSim.Framework; using OpenSim.Data; using OpenSim.Data.Null; -namespace OpenSim.Tests.Common.Mock +namespace OpenSim.Tests.Common { public class TestXInventoryDataPlugin : NullGenericDataHandler, IXInventoryData { @@ -46,17 +46,33 @@ namespace OpenSim.Tests.Common.Mock public XInventoryItem[] GetItems(string[] fields, string[] vals) { +// Console.WriteLine( +// "Requesting items, fields {0}, vals {1}", string.Join(", ", fields), string.Join(", ", vals)); + List origItems = Get(fields, vals, m_allItems.Values.ToList()); - return origItems.Select(i => i.Clone()).ToArray(); + XInventoryItem[] items = origItems.Select(i => i.Clone()).ToArray(); + +// Console.WriteLine("Found {0} items", items.Length); +// Array.ForEach(items, i => Console.WriteLine("Found item {0} {1}", i.inventoryName, i.inventoryID)); + + return items; } public XInventoryFolder[] GetFolders(string[] fields, string[] vals) { +// Console.WriteLine( +// "Requesting folders, fields {0}, vals {1}", string.Join(", ", fields), string.Join(", ", vals)); + List origFolders = Get(fields, vals, m_allFolders.Values.ToList()); - return origFolders.Select(f => f.Clone()).ToArray(); + XInventoryFolder[] folders = origFolders.Select(f => f.Clone()).ToArray(); + +// Console.WriteLine("Found {0} folders", folders.Length); +// Array.ForEach(folders, f => Console.WriteLine("Found folder {0} {1}", f.folderName, f.folderID)); + + return folders; } public bool StoreFolder(XInventoryFolder folder) @@ -72,7 +88,9 @@ namespace OpenSim.Tests.Common.Mock { m_allItems[item.inventoryID] = item.Clone(); -// Console.WriteLine("Added item {0} {1}, creator {2}, owner {3}", item.inventoryName, item.inventoryID, item.creatorID, item.avatarID); +// Console.WriteLine( +// "Added item {0} {1}, folder {2}, creator {3}, owner {4}", +// item.inventoryName, item.inventoryID, item.parentFolderID, item.creatorID, item.avatarID); return true; } @@ -104,7 +122,30 @@ namespace OpenSim.Tests.Common.Mock } public bool MoveItem(string id, string newParent) { throw new NotImplementedException(); } - public bool MoveFolder(string id, string newParent) { throw new NotImplementedException(); } + + public bool MoveFolder(string id, string newParent) + { + // Don't use GetFolders() here - it takes a clone! + XInventoryFolder folder = m_allFolders[new UUID(id)]; + + if (folder == null) + return false; + + folder.parentFolderID = new UUID(newParent); + +// XInventoryFolder[] newParentFolders +// = GetFolders(new string[] { "folderID" }, new string[] { folder.parentFolderID.ToString() }); + +// Console.WriteLine( +// "Moved folder {0} {1}, to {2} {3}", +// folder.folderName, folder.folderID, newParentFolders[0].folderName, folder.parentFolderID); + + // TODO: Really need to implement folder version incrementing, though this should be common code anyway, + // not reimplemented in each db plugin. + + return true; + } + public XInventoryItem[] GetActiveGestures(UUID principalID) { throw new NotImplementedException(); } public int GetAssetPermissions(UUID principalID, UUID assetID) { throw new NotImplementedException(); } } diff --git a/OpenSim/Tests/Common/OpenSimTestCase.cs b/OpenSim/Tests/Common/OpenSimTestCase.cs index 8c40923..9fea348 100644 --- a/OpenSim/Tests/Common/OpenSimTestCase.cs +++ b/OpenSim/Tests/Common/OpenSimTestCase.cs @@ -27,6 +27,8 @@ using System; using NUnit.Framework; +using OpenSim.Framework; +using OpenSim.Framework.Servers; namespace OpenSim.Tests.Common { @@ -36,11 +38,18 @@ namespace OpenSim.Tests.Common [SetUp] public virtual void SetUp() { -// TestHelpers.InMethod(); + //TestHelpers.InMethod(); // Disable logging for each test so that one where logging is enabled doesn't cause all subsequent tests // to have logging on if it failed with an exception. TestHelpers.DisableLogging(); + + // This is an unfortunate bit of clean up we have to do because MainServer manages things through static + // variables and the VM is not restarted between tests. + if (MainServer.Instance != null) + { + MainServer.RemoveHttpServer(MainServer.Instance.Port); +// MainServer.Instance = null; + } } } -} - +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/TestHelpers.cs b/OpenSim/Tests/Common/TestHelpers.cs index 57da802..6bf23f8 100644 --- a/OpenSim/Tests/Common/TestHelpers.cs +++ b/OpenSim/Tests/Common/TestHelpers.cs @@ -114,6 +114,25 @@ namespace OpenSim.Tests.Common } /// + /// Parse a UUID stem into a full UUID. + /// + /// + /// The fragment will come at the start of the UUID. The rest will be 0s + /// + /// + /// + /// A UUID fragment that will be parsed into a full UUID. Therefore, it can only contain + /// cahracters which are valid in a UUID, except for "-" which is currently only allowed if a full UUID is + /// given as the 'fragment'. + /// + public static UUID ParseStem(string stem) + { + string rawUuid = stem.PadRight(32, '0'); + + return UUID.Parse(rawUuid); + } + + /// /// Parse tail section into full UUID. /// /// @@ -122,5 +141,24 @@ namespace OpenSim.Tests.Common { return new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", tail)); } + + /// + /// Parse a UUID tail section into a full UUID. + /// + /// + /// The fragment will come at the end of the UUID. The rest will be 0s + /// + /// + /// + /// A UUID fragment that will be parsed into a full UUID. Therefore, it can only contain + /// cahracters which are valid in a UUID, except for "-" which is currently only allowed if a full UUID is + /// given as the 'fragment'. + /// + public static UUID ParseTail(string stem) + { + string rawUuid = stem.PadLeft(32, '0'); + + return UUID.Parse(rawUuid); + } } } diff --git a/OpenSim/Tests/ConfigurationLoaderTest.cs b/OpenSim/Tests/ConfigurationLoaderTest.cs index e5186ae..a409a13 100644 --- a/OpenSim/Tests/ConfigurationLoaderTest.cs +++ b/OpenSim/Tests/ConfigurationLoaderTest.cs @@ -45,8 +45,10 @@ namespace OpenSim.Tests /// Set up a test directory. /// [SetUp] - public void SetUp() + public override void SetUp() { + base.SetUp(); + m_basePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); string path = Path.Combine(m_basePath, m_testSubdirectory); Directory.CreateDirectory(path); diff --git a/OpenSim/Tests/Performance/NPCPerformanceTests.cs b/OpenSim/Tests/Performance/NPCPerformanceTests.cs index 2026a88..ca6ae42 100644 --- a/OpenSim/Tests/Performance/NPCPerformanceTests.cs +++ b/OpenSim/Tests/Performance/NPCPerformanceTests.cs @@ -34,7 +34,7 @@ using Nini.Config; using NUnit.Framework; using OpenMetaverse; using OpenSim.Framework; -using OpenSim.Framework.Communications; + using OpenSim.Region.CoreModules.Avatar.Attachments; using OpenSim.Region.CoreModules.Avatar.AvatarFactory; using OpenSim.Region.CoreModules.Framework.InventoryAccess; @@ -45,7 +45,6 @@ using OpenSim.Region.Framework.Scenes; using OpenSim.Region.OptionalModules.World.NPC; using OpenSim.Services.AvatarService; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Tests.Performance { @@ -144,6 +143,7 @@ namespace OpenSim.Tests.Performance // ScenePresence.SendInitialData() to reset our entire appearance. scene.AssetService.Store(AssetHelpers.CreateNotecardAsset(originalFace8TextureId)); +/* afm.SetAppearance(sp, originalTe, null); INPCModule npcModule = scene.RequestModuleInterface(); @@ -185,6 +185,7 @@ namespace OpenSim.Tests.Performance endGcMemory / 1024 / 1024, startGcMemory / 1024 / 1024, (endGcMemory - startGcMemory) / 1024 / 1024); +*/ } } -} \ No newline at end of file +} diff --git a/OpenSim/Tests/Performance/ObjectPerformanceTests.cs b/OpenSim/Tests/Performance/ObjectPerformanceTests.cs index 656a971..9dad423 100644 --- a/OpenSim/Tests/Performance/ObjectPerformanceTests.cs +++ b/OpenSim/Tests/Performance/ObjectPerformanceTests.cs @@ -34,7 +34,6 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Tests.Performance { diff --git a/OpenSim/Tests/Performance/ScriptPerformanceTests.cs b/OpenSim/Tests/Performance/ScriptPerformanceTests.cs index 4064edc..028f4b0 100644 --- a/OpenSim/Tests/Performance/ScriptPerformanceTests.cs +++ b/OpenSim/Tests/Performance/ScriptPerformanceTests.cs @@ -40,7 +40,6 @@ using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.XEngine; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Tests.Performance { diff --git a/OpenSim/Tests/Robust/Clients/Grid/GridClient.cs b/OpenSim/Tests/Robust/Clients/Grid/GridClient.cs new file mode 100644 index 0000000..671aca7 --- /dev/null +++ b/OpenSim/Tests/Robust/Clients/Grid/GridClient.cs @@ -0,0 +1,133 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; + +using OpenMetaverse; +using NUnit.Framework; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; +using OpenSim.Services.Connectors; + +namespace Robust.Tests +{ + [TestFixture] + public class GridClient + { +// private static readonly ILog m_log = +// LogManager.GetLogger( +// MethodBase.GetCurrentMethod().DeclaringType); + + [Test] + public void Grid_001() + { + GridServicesConnector m_Connector = new GridServicesConnector(DemonServer.Address); + + GridRegion r1 = CreateRegion("Test Region 1", 1000, 1000); + GridRegion r2 = CreateRegion("Test Region 2", 1001, 1000); + GridRegion r3 = CreateRegion("Test Region 3", 1005, 1000); + + string msg = m_Connector.RegisterRegion(UUID.Zero, r1); + Assert.AreEqual(msg, string.Empty, "Region 1 failed to register"); + + msg = m_Connector.RegisterRegion(UUID.Zero, r2); + Assert.AreEqual(msg, string.Empty, "Region 2 failed to register"); + + msg = m_Connector.RegisterRegion(UUID.Zero, r3); + Assert.AreEqual(msg, string.Empty, "Region 3 failed to register"); + + bool success; + success = m_Connector.DeregisterRegion(r3.RegionID); + Assert.AreEqual(success, true, "Region 3 failed to deregister"); + + msg = m_Connector.RegisterRegion(UUID.Zero, r3); + Assert.AreEqual(msg, string.Empty, "Region 3 failed to re-register"); + + List regions = m_Connector.GetNeighbours(UUID.Zero, r1.RegionID); + Assert.AreNotEqual(regions, null, "GetNeighbours of region 1 failed"); + Assert.AreEqual(regions.Count, 1, "Region 1 should have 1 neighbor"); + Assert.AreEqual(regions[0].RegionName, "Test Region 2", "Region 1 has the wrong neighbor"); + + GridRegion region = m_Connector.GetRegionByUUID(UUID.Zero, r2.RegionID); + Assert.AreNotEqual(region, null, "GetRegionByUUID for region 2 failed"); + Assert.AreEqual(region.RegionName, "Test Region 2", "GetRegionByUUID of region 2 returned wrong region"); + + region = m_Connector.GetRegionByUUID(UUID.Zero, UUID.Random()); + Assert.AreEqual(region, null, "Region with randon id should not exist"); + + region = m_Connector.GetRegionByName(UUID.Zero, r3.RegionName); + Assert.AreNotEqual(region, null, "GetRegionByUUID for region 3 failed"); + Assert.AreEqual(region.RegionName, "Test Region 3", "GetRegionByUUID of region 3 returned wrong region"); + + region = m_Connector.GetRegionByName(UUID.Zero, "Foo"); + Assert.AreEqual(region, null, "Region Foo should not exist"); + + regions = m_Connector.GetRegionsByName(UUID.Zero, "Test", 10); + Assert.AreNotEqual(regions, null, "GetRegionsByName failed"); + Assert.AreEqual(regions.Count, 3, "GetRegionsByName should return 3"); + + regions = m_Connector.GetRegionRange(UUID.Zero, + (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(1002), + (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(1002) ); + Assert.AreNotEqual(regions, null, "GetRegionRange failed"); + Assert.AreEqual(regions.Count, 2, "GetRegionRange should return 2"); + + regions = m_Connector.GetRegionRange(UUID.Zero, + (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(950), + (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(950) ); + Assert.AreNotEqual(regions, null, "GetRegionRange (bis) failed"); + Assert.AreEqual(regions.Count, 0, "GetRegionRange (bis) should return 0"); + + // Deregister them all + success = m_Connector.DeregisterRegion(r1.RegionID); + Assert.AreEqual(success, true, "Region 1 failed to deregister"); + + success = m_Connector.DeregisterRegion(r2.RegionID); + Assert.AreEqual(success, true, "Region 2 failed to deregister"); + + success = m_Connector.DeregisterRegion(r3.RegionID); + Assert.AreEqual(success, true, "Region 3 failed to deregister"); + } + + private static GridRegion CreateRegion(string name, uint xcell, uint ycell) + { + GridRegion region = new GridRegion(xcell, ycell); + region.RegionName = name; + region.RegionID = UUID.Random(); + region.ExternalHostName = "127.0.0.1"; + region.HttpPort = 9000; + region.InternalEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("0.0.0.0"), 9000); + + return region; + } + } +} diff --git a/OpenSim/Tests/Robust/Clients/Grid/GridForm.html b/OpenSim/Tests/Robust/Clients/Grid/GridForm.html new file mode 100644 index 0000000..252920f --- /dev/null +++ b/OpenSim/Tests/Robust/Clients/Grid/GridForm.html @@ -0,0 +1,11 @@ + + +
+xmin: +xmax: +ymin: +ymax: + + + + diff --git a/OpenSim/Tests/Robust/Clients/InstantMessage/IMClient.cs b/OpenSim/Tests/Robust/Clients/InstantMessage/IMClient.cs new file mode 100644 index 0000000..8f312eb --- /dev/null +++ b/OpenSim/Tests/Robust/Clients/InstantMessage/IMClient.cs @@ -0,0 +1,58 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; + +using OpenMetaverse; +using NUnit.Framework; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Connectors.InstantMessage; + +namespace Robust.Tests +{ + [TestFixture] + public class IMClient + { + [Test] + public void HGIM_001() + { + GridInstantMessage im = new GridInstantMessage(); + im.fromAgentID = new Guid(); + im.toAgentID = new Guid(); + im.message = "Hello"; + im.imSessionID = new Guid(); + + bool success = InstantMessageServiceConnector.SendInstantMessage(DemonServer.Address, im); + Assert.IsFalse(success, "Sending of IM succeeded, but it should have failed"); + } + + } +} diff --git a/OpenSim/Tests/Robust/Clients/Inventory/InventoryClient.cs b/OpenSim/Tests/Robust/Clients/Inventory/InventoryClient.cs new file mode 100644 index 0000000..0280b73 --- /dev/null +++ b/OpenSim/Tests/Robust/Clients/Inventory/InventoryClient.cs @@ -0,0 +1,206 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; + +using OpenMetaverse; +using NUnit.Framework; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Connectors; + +using OpenSim.Tests.Common; + +namespace Robust.Tests +{ + [TestFixture] + public class InventoryClient + { +// private static readonly ILog m_log = +// LogManager.GetLogger( +// MethodBase.GetCurrentMethod().DeclaringType); + + private UUID m_userID = new UUID("00000000-0000-0000-0000-333333333333"); + private UUID m_rootFolderID; + private UUID m_notecardsFolder; + private UUID m_objectsFolder; + + [Test] + public void Inventory_001_CreateInventory() + { + TestHelpers.InMethod(); + XInventoryServicesConnector m_Connector = new XInventoryServicesConnector(DemonServer.Address); + + // Create an inventory that looks like this: + // + // /My Inventory + // + // /Objects + // Some Object + // /Notecards + // Notecard 1 + // Notecard 2 + // /Test Folder + // Link to notecard -> /Notecards/Notecard 2 + // Link to Objects folder -> /Objects + + bool success = m_Connector.CreateUserInventory(m_userID); + Assert.IsTrue(success, "Failed to create user inventory"); + + m_rootFolderID = m_Connector.GetRootFolder(m_userID).ID; + Assert.AreNotEqual(m_rootFolderID, UUID.Zero, "Root folder ID must not be UUID.Zero"); + + InventoryFolderBase of = m_Connector.GetFolderForType(m_userID, FolderType.Object); + Assert.IsNotNull(of, "Failed to retrieve Objects folder"); + m_objectsFolder = of.ID; + Assert.AreNotEqual(m_objectsFolder, UUID.Zero, "Objects folder ID must not be UUID.Zero"); + + // Add an object + InventoryItemBase item = new InventoryItemBase(new UUID("b0000000-0000-0000-0000-00000000000b"), m_userID); + item.AssetID = UUID.Random(); + item.AssetType = (int)AssetType.Object; + item.Folder = m_objectsFolder; + item.Name = "Some Object"; + item.Description = string.Empty; + success = m_Connector.AddItem(item); + Assert.IsTrue(success, "Failed to add object to inventory"); + + InventoryFolderBase ncf = m_Connector.GetFolderForType(m_userID, FolderType.Notecard); + Assert.IsNotNull(of, "Failed to retrieve Notecards folder"); + m_notecardsFolder = ncf.ID; + Assert.AreNotEqual(m_notecardsFolder, UUID.Zero, "Notecards folder ID must not be UUID.Zero"); + m_notecardsFolder = ncf.ID; + + // Add a notecard + item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-000000000001"), m_userID); + item.AssetID = UUID.Random(); + item.AssetType = (int)AssetType.Notecard; + item.Folder = m_notecardsFolder; + item.Name = "Test Notecard 1"; + item.Description = string.Empty; + success = m_Connector.AddItem(item); + Assert.IsTrue(success, "Failed to add Notecard 1 to inventory"); + // Add another notecard + item.ID = new UUID("20000000-0000-0000-0000-000000000002"); + item.AssetID = new UUID("a0000000-0000-0000-0000-00000000000a"); + item.Name = "Test Notecard 2"; + item.Description = string.Empty; + success = m_Connector.AddItem(item); + Assert.IsTrue(success, "Failed to add Notecard 2 to inventory"); + + // Add a folder + InventoryFolderBase folder = new InventoryFolderBase(new UUID("f0000000-0000-0000-0000-00000000000f"), "Test Folder", m_userID, m_rootFolderID); + folder.Type = (int)FolderType.None; + success = m_Connector.AddFolder(folder); + Assert.IsTrue(success, "Failed to add Test Folder to inventory"); + + // Add a link to notecard 2 in Test Folder + item.AssetID = item.ID; // use item ID of notecard 2 + item.ID = new UUID("40000000-0000-0000-0000-000000000004"); + item.AssetType = (int)AssetType.Link; + item.Folder = folder.ID; + item.Name = "Link to notecard"; + item.Description = string.Empty; + success = m_Connector.AddItem(item); + Assert.IsTrue(success, "Failed to add link to notecard to inventory"); + + // Add a link to the Objects folder in Test Folder + item.AssetID = m_Connector.GetFolderForType(m_userID, FolderType.Object).ID; // use item ID of Objects folder + item.ID = new UUID("50000000-0000-0000-0000-000000000005"); + item.AssetType = (int)AssetType.LinkFolder; + item.Folder = folder.ID; + item.Name = "Link to Objects folder"; + item.Description = string.Empty; + success = m_Connector.AddItem(item); + Assert.IsTrue(success, "Failed to add link to objects folder to inventory"); + + InventoryCollection coll = m_Connector.GetFolderContent(m_userID, m_rootFolderID); + Assert.IsNotNull(coll, "Failed to retrieve contents of root folder"); + Assert.Greater(coll.Folders.Count, 0, "Root folder does not have any subfolders"); + + coll = m_Connector.GetFolderContent(m_userID, folder.ID); + Assert.IsNotNull(coll, "Failed to retrieve contents of Test Folder"); + Assert.AreEqual(coll.Items.Count + coll.Folders.Count, 2, "Test Folder is expected to have exactly 2 things inside"); + + } + + [Test] + public void Inventory_002_MultipleItemsRequest() + { + TestHelpers.InMethod(); + XInventoryServicesConnector m_Connector = new XInventoryServicesConnector(DemonServer.Address); + + // Prefetch Notecard 1, will be cached from here on + InventoryItemBase item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-000000000001"), m_userID); + item = m_Connector.GetItem(item); + Assert.NotNull(item, "Failed to get Notecard 1"); + Assert.AreEqual("Test Notecard 1", item.Name, "Wrong name for Notecard 1"); + + UUID[] uuids = new UUID[2]; + uuids[0] = item.ID; + uuids[1] = new UUID("20000000-0000-0000-0000-000000000002"); + + InventoryItemBase[] items = m_Connector.GetMultipleItems(m_userID, uuids); + Assert.NotNull(items, "Failed to get multiple items"); + Assert.IsTrue(items.Length == 2, "Requested 2 items, but didn't receive 2 items"); + + // Now they should both be cached + items = m_Connector.GetMultipleItems(m_userID, uuids); + Assert.NotNull(items, "(Repeat) Failed to get multiple items"); + Assert.IsTrue(items.Length == 2, "(Repeat) Requested 2 items, but didn't receive 2 items"); + + // This item doesn't exist, but [0] does, and it's cached. + uuids[1] = new UUID("bb000000-0000-0000-0000-0000000000bb"); + // Fetching should return 2 items, but [1] should be null + items = m_Connector.GetMultipleItems(m_userID, uuids); + Assert.NotNull(items, "(Three times) Failed to get multiple items"); + Assert.IsTrue(items.Length == 2, "(Three times) Requested 2 items, but didn't receive 2 items"); + Assert.AreEqual("Test Notecard 1", items[0].Name, "(Three times) Wrong name for Notecard 1"); + Assert.IsNull(items[1], "(Three times) Expecting 2nd item to be null"); + + // Now both don't exist + uuids[0] = new UUID("aa000000-0000-0000-0000-0000000000aa"); + items = m_Connector.GetMultipleItems(m_userID, uuids); + Assert.Null(items[0], "Request to multiple non-existent items is supposed to return null [0]"); + Assert.Null(items[1], "Request to multiple non-existent items is supposed to return null [1]"); + + // This item exists, and it's not cached + uuids[1] = new UUID("b0000000-0000-0000-0000-00000000000b"); + // Fetching should return 2 items, but [0] should be null + items = m_Connector.GetMultipleItems(m_userID, uuids); + Assert.NotNull(items, "(Four times) Failed to get multiple items"); + Assert.IsTrue(items.Length == 2, "(Four times) Requested 2 items, but didn't receive 2 items"); + Assert.AreEqual("Some Object", items[1].Name, "(Four times) Wrong name for Some Object"); + Assert.IsNull(items[0], "(Four times) Expecting 1st item to be null"); + + } + } +} diff --git a/OpenSim/Tests/Robust/Clients/Presence/PresenceClient.cs b/OpenSim/Tests/Robust/Clients/Presence/PresenceClient.cs new file mode 100644 index 0000000..31c8ee9 --- /dev/null +++ b/OpenSim/Tests/Robust/Clients/Presence/PresenceClient.cs @@ -0,0 +1,81 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; + +using OpenMetaverse; +using NUnit.Framework; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Connectors; + +namespace Robust.Tests +{ + [TestFixture] + public class PresenceClient + { + [Test] + public void Presence_001() + { + PresenceServicesConnector m_Connector = new PresenceServicesConnector(DemonServer.Address); + + UUID user1 = UUID.Random(); + UUID session1 = UUID.Random(); + UUID region1 = UUID.Random(); + + bool success = m_Connector.LoginAgent(user1.ToString(), session1, UUID.Zero); + Assert.AreEqual(success, true, "Failed to add user session"); + + PresenceInfo pinfo = m_Connector.GetAgent(session1); + Assert.AreNotEqual(pinfo, null, "Unable to retrieve session"); + Assert.AreEqual(pinfo.UserID, user1.ToString(), "Retrieved session does not match expected userID"); + Assert.AreNotEqual(pinfo.RegionID, region1, "Retrieved session is unexpectedly in region"); + + success = m_Connector.ReportAgent(session1, region1); + Assert.AreEqual(success, true, "Failed to report session in region 1"); + + pinfo = m_Connector.GetAgent(session1); + Assert.AreNotEqual(pinfo, null, "Unable to session presence"); + Assert.AreEqual(pinfo.UserID, user1.ToString(), "Retrieved session does not match expected userID"); + Assert.AreEqual(pinfo.RegionID, region1, "Retrieved session is not in expected region"); + + success = m_Connector.LogoutAgent(session1); + Assert.AreEqual(success, true, "Failed to remove session"); + + pinfo = m_Connector.GetAgent(session1); + Assert.AreEqual(pinfo, null, "Session is still there, even though it shouldn't"); + + success = m_Connector.ReportAgent(session1, UUID.Random()); + Assert.AreEqual(success, false, "Remove non-existing session should fail"); + } + + } +} diff --git a/OpenSim/Tests/Robust/Clients/UserAccounts/UserAccountsClient.cs b/OpenSim/Tests/Robust/Clients/UserAccounts/UserAccountsClient.cs new file mode 100644 index 0000000..3238dc9 --- /dev/null +++ b/OpenSim/Tests/Robust/Clients/UserAccounts/UserAccountsClient.cs @@ -0,0 +1,86 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; + +using OpenMetaverse; +using NUnit.Framework; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Connectors; + +namespace Robust.Tests +{ + [TestFixture] + public class UserAccountsClient + { + [Test] + public void UserAccounts_001() + { + UserAccountServicesConnector m_Connector = new UserAccountServicesConnector(DemonServer.Address); + + string first = "Completely"; + string last = "Clueless"; + string email = "foo@bar.com"; + + UserAccount account = m_Connector.CreateUser(first, last, "123", email, UUID.Zero); + Assert.IsNotNull(account, "Failed to create account " + first + " " + last); + UUID user1 = account.PrincipalID; + + account = m_Connector.GetUserAccount(UUID.Zero, user1); + Assert.NotNull(account, "Failed to retrieve account for user id " + user1); + Assert.AreEqual(account.FirstName, first, "First name does not match"); + Assert.AreEqual(account.LastName, last, "Last name does not match"); + + account = m_Connector.GetUserAccount(UUID.Zero, first, last); + Assert.IsNotNull(account, "Failed to retrieve account for user " + first + " " + last); + Assert.AreEqual(account.FirstName, first, "First name does not match (bis)"); + Assert.AreEqual(account.LastName, last, "Last name does not match (bis)"); + + account.Email = "user@example.com"; + bool success = m_Connector.StoreUserAccount(account); + Assert.IsTrue(success, "Failed to store existing account"); + + account = m_Connector.GetUserAccount(UUID.Zero, user1); + Assert.NotNull(account, "Failed to retrieve account for user id " + user1); + Assert.AreEqual(account.Email, "user@example.com", "Incorrect email"); + + account = new UserAccount(UUID.Zero, "DoesNot", "Exist", "xxx@xxx.com"); + success = m_Connector.StoreUserAccount(account); + Assert.IsFalse(success, "Storing a non-existing account must fail"); + + account = m_Connector.GetUserAccount(UUID.Zero, "DoesNot", "Exist"); + Assert.IsNull(account, "Account DoesNot Exist must not be there"); + + } + + } +} diff --git a/OpenSim/Tests/Robust/Server/DemonServer.cs b/OpenSim/Tests/Robust/Server/DemonServer.cs new file mode 100644 index 0000000..1e0797e --- /dev/null +++ b/OpenSim/Tests/Robust/Server/DemonServer.cs @@ -0,0 +1,69 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; + +using Nini.Config; +using log4net; +using NUnit.Framework; + +using OpenSim.Server; + +namespace Robust.Tests +{ + [SetUpFixture] + public class DemonServer : OpenSimServer + { + private Thread m_demon; + + public static string Address = "http://localhost:8888"; + + [SetUp] + public void StartDemon() + { + if (File.Exists("Robust.Tests.log")) + File.Delete("Robust.Tests.log"); + + Console.WriteLine("**** Starting demon Robust server ****"); + m_demon = new Thread( () => Main(new string[] {"-inifile=Robust.Tests.ini"})); + m_demon.Start(); + // Give some time for the server to instantiate all services + Thread.Sleep(3000); + Console.WriteLine("**** Setup Finished ****"); + } + + [TearDown] + public void StopDemon() + { + Console.WriteLine("**** Killing demon Robust Server ****"); + m_Server.Shutdown(); + } + } +} diff --git a/OpenSim/Tests/Stress/VectorRenderModuleStressTests.cs b/OpenSim/Tests/Stress/VectorRenderModuleStressTests.cs index 1f220c0..0ab407e 100644 --- a/OpenSim/Tests/Stress/VectorRenderModuleStressTests.cs +++ b/OpenSim/Tests/Stress/VectorRenderModuleStressTests.cs @@ -41,7 +41,6 @@ using OpenSim.Region.CoreModules.Scripting.VectorRender; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes.Serialization; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Tests.Stress { @@ -79,7 +78,7 @@ namespace OpenSim.Tests.Stress Drawer d = new Drawer(this, i); drawers.Add(d); Console.WriteLine("Starting drawer {0}", i); - Util.FireAndForget(o => d.Draw()); + Util.FireAndForget(o => d.Draw(), null, "VectorRenderModuleStressTests.TestConcurrentRepeatedDraw"); } Thread.Sleep(10 * 60 * 1000); diff --git a/OpenSim/Tools/Compiler/Program.cs b/OpenSim/Tools/Compiler/Program.cs index 6c59c31..b010eaf 100644 --- a/OpenSim/Tools/Compiler/Program.cs +++ b/OpenSim/Tools/Compiler/Program.cs @@ -255,12 +255,13 @@ namespace OpenSim.Tools.LSL.Compiler return FindErrorPosition(line, col, null); } - private class kvpSorter : IComparer> + private class kvpSorter : IComparer, KeyValuePair>> { - public int Compare(KeyValuePair a, - KeyValuePair b) + public int Compare(KeyValuePair, KeyValuePair> a, + KeyValuePair, KeyValuePair> b) { - return a.Key.CompareTo(b.Key); + int kc = a.Key.Key.CompareTo(b.Key.Key); + return (kc != 0) ? kc : a.Key.Value.CompareTo(b.Key.Value); } } @@ -277,30 +278,46 @@ namespace OpenSim.Tools.LSL.Compiler out ret)) return ret; - List> sorted = - new List>(positionMap.Keys); + var sorted = new List, KeyValuePair>>(positionMap); sorted.Sort(new kvpSorter()); int l = 1; int c = 1; + int pl = 1; - foreach (KeyValuePair cspos in sorted) + foreach (KeyValuePair, KeyValuePair> posmap in sorted) { - if (cspos.Key >= line) + //m_log.DebugFormat("[Compiler]: Scanning line map {0},{1} --> {2},{3}", posmap.Key.Key, posmap.Key.Value, posmap.Value.Key, posmap.Value.Value); + int nl = posmap.Value.Key + line - posmap.Key.Key; // New, translated LSL line and column. + int nc = posmap.Value.Value + col - posmap.Key.Value; + // Keep going until we find the first point passed line,col. + if (posmap.Key.Key > line) { - if (cspos.Key > line) - return new KeyValuePair(l, c); - if (cspos.Value > col) - return new KeyValuePair(l, c); - c = cspos.Value; - if (c == 0) - c++; + //m_log.DebugFormat("[Compiler]: Line is larger than requested {0},{1}, returning {2},{3}", line, col, l, c); + if (pl < line) + { + //m_log.DebugFormat("[Compiler]: Previous line ({0}) is less than requested line ({1}), setting column to 1.", pl, line); + c = 1; + } + break; } - else + if (posmap.Key.Key == line && posmap.Key.Value > col) { - l = cspos.Key; + // Never move l,c backwards. + if (nl > l || (nl == l && nc > c)) + { + //m_log.DebugFormat("[Compiler]: Using offset relative to this: {0} + {1} - {2}, {3} + {4} - {5} = {6}, {7}", + // posmap.Value.Key, line, posmap.Key.Key, posmap.Value.Value, col, posmap.Key.Value, nl, nc); + l = nl; + c = nc; + } + //m_log.DebugFormat("[Compiler]: Column is larger than requested {0},{1}, returning {2},{3}", line, col, l, c); + break; } + pl = posmap.Key.Key; + l = posmap.Value.Key; + c = posmap.Value.Value; } return new KeyValuePair(l, c); } diff --git a/OpenSim/Tools/Compiler/Properties/AssemblyInfo.cs b/OpenSim/Tools/Compiler/Properties/AssemblyInfo.cs index e1a1fda..d7f8870 100644 --- a/OpenSim/Tools/Compiler/Properties/AssemblyInfo.cs +++ b/OpenSim/Tools/Compiler/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Tools/Configger/ConfigurationLoader.cs b/OpenSim/Tools/Configger/ConfigurationLoader.cs index 28bcc99..f1d3649 100644 --- a/OpenSim/Tools/Configger/ConfigurationLoader.cs +++ b/OpenSim/Tools/Configger/ConfigurationLoader.cs @@ -64,14 +64,13 @@ namespace OpenSim.Tools.Configger /// /// /// A configuration that gets passed to modules - public IConfigSource LoadConfigSettings() + public IConfigSource LoadConfigSettings(IConfig startupConfig) { bool iniFileExists = false; List sources = new List(); - string iniFileName = "OpenSim.ini"; - string iniFilePath = Path.Combine(".", iniFileName); + string iniFileName = startupConfig.GetString("inifile", Path.Combine(".", "OpenSim.ini")); if (IsUri(iniFileName)) { @@ -80,10 +79,10 @@ namespace OpenSim.Tools.Configger } else { - if (File.Exists(iniFilePath)) + if (File.Exists(iniFileName)) { - if (!sources.Contains(iniFilePath)) - sources.Add(iniFilePath); + if (!sources.Contains(iniFileName)) + sources.Add(iniFileName); } } @@ -239,10 +238,7 @@ namespace OpenSim.Tools.Configger config.Set("physics", "OpenDynamicsEngine"); config.Set("meshing", "Meshmerizer"); config.Set("physical_prim", true); - config.Set("see_into_this_sim_from_neighbor", true); config.Set("serverside_object_permissions", true); - config.Set("storage_plugin", "OpenSim.Data.SQLite.dll"); - config.Set("storage_connection_string", "URI=file:OpenSim.db,version=3"); config.Set("storage_prim_inventories", true); config.Set("startup_console_commands_file", String.Empty); config.Set("shutdown_console_commands_file", String.Empty); @@ -254,6 +250,5 @@ namespace OpenSim.Tools.Configger return defaultConfig; } - } -} +} \ No newline at end of file diff --git a/OpenSim/Tools/Configger/Main.cs b/OpenSim/Tools/Configger/Main.cs index 61a12e3..d7d918b 100644 --- a/OpenSim/Tools/Configger/Main.cs +++ b/OpenSim/Tools/Configger/Main.cs @@ -35,15 +35,16 @@ namespace OpenSim.Tools.Configger public static int Main(string[] args) { ArgvConfigSource argvConfig = new ArgvConfigSource(args); + argvConfig.AddSwitch("Startup", "format", "f"); + argvConfig.AddSwitch("Startup", "inifile"); IConfig startupConfig = argvConfig.Configs["Startup"]; string format = startupConfig.GetString("format", "ini"); ConfigurationLoader loader = new ConfigurationLoader(); - - IConfigSource s = loader.LoadConfigSettings(); + IConfigSource s = loader.LoadConfigSettings(startupConfig); if (format == "mysql") { diff --git a/OpenSim/Tools/Configger/Properties/AssemblyInfo.cs b/OpenSim/Tools/Configger/Properties/AssemblyInfo.cs index 62a2f2d..359d854 100644 --- a/OpenSim/Tools/Configger/Properties/AssemblyInfo.cs +++ b/OpenSim/Tools/Configger/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Tools/OpenSim.32BitLaunch/OpenSim.32BitLaunch.csproj b/OpenSim/Tools/OpenSim.32BitLaunch/OpenSim.32BitLaunch.csproj deleted file mode 100644 index d829e69..0000000 --- a/OpenSim/Tools/OpenSim.32BitLaunch/OpenSim.32BitLaunch.csproj +++ /dev/null @@ -1,58 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {595D67F3-B413-4A43-8568-5B5930E3B31D} - Exe - Properties - OpenSim._32BitLaunch - OpenSim.32BitLaunch - v2.0 - 512 - - - true - full - false - ..\..\..\bin\ - DEBUG;TRACE - prompt - 4 - x86 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - {438A9556-0000-0000-0000-000000000000} - OpenSim - - - - - \ No newline at end of file diff --git a/OpenSim/Tools/OpenSim.32BitLaunch/Program.cs b/OpenSim/Tools/OpenSim.32BitLaunch/Program.cs deleted file mode 100644 index 52806b8..0000000 --- a/OpenSim/Tools/OpenSim.32BitLaunch/Program.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; - -namespace OpenSim._32BitLaunch -{ - class Program - { - static void Main(string[] args) - { - log4net.Config.XmlConfigurator.Configure(); - - System.Console.WriteLine("32-bit OpenSim executor"); - System.Console.WriteLine("-----------------------"); - System.Console.WriteLine(""); - System.Console.WriteLine("This application is compiled for 32-bit CPU and will run under WOW32 or similar."); - System.Console.WriteLine("All 64-bit incompatibilities should be gone."); - System.Console.WriteLine(""); - System.Threading.Thread.Sleep(300); - try - { - global::OpenSim.Application.Main(args); - } - catch (Exception ex) - { - System.Console.WriteLine("OpenSim threw an exception:"); - System.Console.WriteLine(ex.ToString()); - System.Console.WriteLine(""); - System.Console.WriteLine("Application will now terminate!"); - System.Console.WriteLine(""); - } - } - } -} diff --git a/OpenSim/Tools/OpenSim.32BitLaunch/Properties/AssemblyInfo.cs b/OpenSim/Tools/OpenSim.32BitLaunch/Properties/AssemblyInfo.cs deleted file mode 100644 index e81870f..0000000 --- a/OpenSim/Tools/OpenSim.32BitLaunch/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenSim.32BitLaunch")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("http://opensimulator.org")] -[assembly: AssemblyProduct("OpenSim.32BitLaunch")] -[assembly: AssemblyCopyright("Copyright (c) 2008")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("5072e919-46ab-47e6-8a63-08108324ccdf")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("0.6.3.*")] -[assembly: AssemblyVersion("0.6.3.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Tools/Robust.32BitLaunch/Program.cs b/OpenSim/Tools/Robust.32BitLaunch/Program.cs deleted file mode 100644 index 490414c..0000000 --- a/OpenSim/Tools/Robust.32BitLaunch/Program.cs +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using log4net; - -namespace Robust._32BitLaunch -{ - class Program - { - static void Main(string[] args) - { - log4net.Config.XmlConfigurator.Configure(); - - System.Console.WriteLine("32-bit OpenSim executor"); - System.Console.WriteLine("-----------------------"); - System.Console.WriteLine(""); - System.Console.WriteLine("This application is compiled for 32-bit CPU and will run under WOW32 or similar."); - System.Console.WriteLine("All 64-bit incompatibilities should be gone."); - System.Console.WriteLine(""); - System.Threading.Thread.Sleep(300); - try - { - global::OpenSim.Server.OpenSimServer.Main(args); - } - catch (Exception ex) - { - System.Console.WriteLine("OpenSim threw an exception:"); - System.Console.WriteLine(ex.ToString()); - System.Console.WriteLine(""); - System.Console.WriteLine("Application will now terminate!"); - System.Console.WriteLine(""); - } - } - } -} diff --git a/OpenSim/Tools/Robust.32BitLaunch/Properties/AssemblyInfo.cs b/OpenSim/Tools/Robust.32BitLaunch/Properties/AssemblyInfo.cs deleted file mode 100644 index cf80f47..0000000 --- a/OpenSim/Tools/Robust.32BitLaunch/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Robust.32BitLaunch")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("http://opensimulator.org")] -[assembly: AssemblyProduct("Robust.32BitLaunch")] -[assembly: AssemblyCopyright("Copyright (c) 2008")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("5072e919-46ab-47e6-8a63-08108324ccdf")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("0.6.3.*")] -[assembly: AssemblyVersion("0.6.3.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/OpenSim/Tools/Robust.32BitLaunch/Robust.32BitLaunch.csproj b/OpenSim/Tools/Robust.32BitLaunch/Robust.32BitLaunch.csproj deleted file mode 100644 index 481b3f8..0000000 --- a/OpenSim/Tools/Robust.32BitLaunch/Robust.32BitLaunch.csproj +++ /dev/null @@ -1,62 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {595D67F3-B413-4A43-8568-5B5930E3B31D} - Exe - Properties - Robust._32BitLaunch - Robust.32BitLaunch - v3.5 - 512 - - - true - full - false - ..\..\..\bin\ - DEBUG;TRACE - prompt - 4 - x86 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - ..\..\..\bin\log4net.dll - - - False - ..\..\..\bin\Robust.exe - - - - 3.5 - - - - - - - - - - - \ No newline at end of file diff --git a/OpenSim/Tools/Robust.32BitLaunch/Robust.32BitLaunch.sln b/OpenSim/Tools/Robust.32BitLaunch/Robust.32BitLaunch.sln deleted file mode 100644 index c7c97b1..0000000 --- a/OpenSim/Tools/Robust.32BitLaunch/Robust.32BitLaunch.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C# Express 2008 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Robust.32BitLaunch", "Robust.32BitLaunch.csproj", "{595D67F3-B413-4A43-8568-5B5930E3B31D}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {595D67F3-B413-4A43-8568-5B5930E3B31D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {595D67F3-B413-4A43-8568-5B5930E3B31D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {595D67F3-B413-4A43-8568-5B5930E3B31D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {595D67F3-B413-4A43-8568-5B5930E3B31D}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs index 9a9371d..c1ba36b 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs @@ -29,21 +29,36 @@ using OpenMetaverse; using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using pCampBot.Interfaces; namespace pCampBot { - public class AbstractBehaviour : IBehaviour + public abstract class AbstractBehaviour : IBehaviour { + /// + /// Abbreviated name of this behaviour. + /// + public string AbbreviatedName { get; protected set; } + public string Name { get; protected set; } public Bot Bot { get; protected set; } - public virtual void Action() {} + public abstract void Action(); + + public virtual void Interrupt() {} + + protected AutoResetEvent m_interruptEvent = new AutoResetEvent(false); public virtual void Initialize(Bot bot) { Bot = bot; } + + public virtual void Close() + { + Interrupt(); + } } } diff --git a/OpenSim/Tools/pCampBot/Behaviours/CrossBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/CrossBehaviour.cs index 1e01c64..4d806fc 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/CrossBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/CrossBehaviour.cs @@ -47,7 +47,11 @@ namespace pCampBot public const int m_regionCrossingTimeout = 1000 * 60; - public CrossBehaviour() { Name = "Cross"; } + public CrossBehaviour() + { + AbbreviatedName = "c"; + Name = "Cross"; + } public override void Action() { diff --git a/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs index 66a336a..59f6244 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs @@ -29,6 +29,7 @@ using OpenMetaverse; using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using pCampBot.Interfaces; namespace pCampBot @@ -41,7 +42,11 @@ namespace pCampBot /// public class GrabbingBehaviour : AbstractBehaviour { - public GrabbingBehaviour() { Name = "Grabbing"; } + public GrabbingBehaviour() + { + AbbreviatedName = "g"; + Name = "Grabbing"; + } public override void Action() { @@ -56,6 +61,8 @@ namespace pCampBot Bot.Client.Self.Grab(prim.LocalID); Bot.Client.Self.GrabUpdate(prim.ID, Vector3.Zero); Bot.Client.Self.DeGrab(prim.LocalID); + + Thread.Sleep(1000); } } } \ No newline at end of file diff --git a/OpenSim/Tools/pCampBot/Behaviours/InventoryDownloadBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/InventoryDownloadBehaviour.cs new file mode 100644 index 0000000..521415c --- /dev/null +++ b/OpenSim/Tools/pCampBot/Behaviours/InventoryDownloadBehaviour.cs @@ -0,0 +1,121 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using OpenMetaverse; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.Linq; +using pCampBot.Interfaces; + +namespace pCampBot +{ + /// + /// Do nothing + /// + public class InventoryDownloadBehaviour : AbstractBehaviour + { + private bool m_initialized; + private int m_Requests = 2; + private Stopwatch m_StopWatch = new Stopwatch(); + private List m_processed = new List(); + + public InventoryDownloadBehaviour() + { + AbbreviatedName = "inv"; + Name = "Inventory"; + } + + public override void Action() + { + if (!m_initialized) + { + m_initialized = true; + Bot.Client.Settings.HTTP_INVENTORY = true; + Bot.Client.Settings.FETCH_MISSING_INVENTORY = true; + Bot.Client.Inventory.FolderUpdated += Inventory_FolderUpdated; + Console.WriteLine("Lib owner is " + Bot.Client.Inventory.Store.LibraryRootNode.Data.OwnerID); + m_StopWatch.Start(); + Bot.Client.Inventory.RequestFolderContents(Bot.Client.Inventory.Store.RootFolder.UUID, Bot.Client.Self.AgentID, true, true, InventorySortOrder.ByDate); + Bot.Client.Inventory.RequestFolderContents(Bot.Client.Inventory.Store.LibraryRootNode.Data.UUID, Bot.Client.Inventory.Store.LibraryRootNode.Data.OwnerID, true, true, InventorySortOrder.ByDate); + } + + Thread.Sleep(1000); + Console.WriteLine("Total items: " + Bot.Client.Inventory.Store.Items.Count + "; Total requests: " + m_Requests + "; Time: " + m_StopWatch.Elapsed); + + } + + void Inventory_FolderUpdated(object sender, FolderUpdatedEventArgs e) + { + if (e.Success) + { + //Console.WriteLine("Folder " + e.FolderID + " updated"); + bool fetch = false; + lock (m_processed) + { + if (!m_processed.Contains(e.FolderID)) + { + m_processed.Add(e.FolderID); + fetch = true; + } + } + + if (fetch) + { + List m_foldersToFetch = new List(); + foreach (InventoryBase item in Bot.Client.Inventory.Store.GetContents(e.FolderID)) + { + if (item is InventoryFolder) + { + InventoryFolder f = new InventoryFolder(item.UUID); + f.OwnerID = item.OwnerID; + m_foldersToFetch.Add(f); + } + } + if (m_foldersToFetch.Count > 0) + { + m_Requests += 1; + Bot.Client.Inventory.RequestFolderContentsCap(m_foldersToFetch, Bot.Client.Network.CurrentSim.Caps.CapabilityURI("FetchInventoryDescendents2"), true, true, InventorySortOrder.ByDate); + } + } + + if (Bot.Client.Inventory.Store.Items.Count >= 15739) + { + m_StopWatch.Stop(); + Console.WriteLine("Stop! Total items: " + Bot.Client.Inventory.Store.Items.Count + "; Total requests: " + m_Requests + "; Time: " + m_StopWatch.Elapsed); + } + } + + } + + public override void Interrupt() + { + m_interruptEvent.Set(); + } + } +} \ No newline at end of file diff --git a/OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs new file mode 100644 index 0000000..0d43781 --- /dev/null +++ b/OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs @@ -0,0 +1,60 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using OpenMetaverse; +using System; +using System.Collections.Generic; +using System.Linq; +using pCampBot.Interfaces; + +namespace pCampBot +{ + /// + /// Do nothing + /// + public class NoneBehaviour : AbstractBehaviour + { + public NoneBehaviour() + { + AbbreviatedName = "n"; + Name = "None"; + } + + public override void Action() + { + Bot.Client.Self.Jump(false); + Bot.Client.Self.Movement.Stop = true; + m_interruptEvent.WaitOne(); + Bot.Client.Self.Movement.Stop = false; + } + + public override void Interrupt() + { + m_interruptEvent.Set(); + } + } +} \ No newline at end of file diff --git a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs index daa7485..98ab931 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs @@ -46,6 +46,7 @@ namespace pCampBot public PhysicsBehaviour() { + AbbreviatedName = "p"; Name = "Physics"; talkarray = readexcuses(); } @@ -77,6 +78,14 @@ namespace pCampBot Bot.Client.Self.Chat(randomf, 0, ChatType.Normal); } + public override void Close() + { + if (Bot.ConnectionState == ConnectionState.Connected) + Bot.Client.Self.Jump(false); + + base.Close(); + } + private string[] readexcuses() { string allexcuses = ""; diff --git a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour2.cs b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour2.cs new file mode 100644 index 0000000..1ec2046 --- /dev/null +++ b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour2.cs @@ -0,0 +1,86 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using OpenMetaverse; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading; +using log4net; +using pCampBot.Interfaces; + +namespace pCampBot +{ + /// + /// This behavior is for the systematic study of some performance improvements made + /// for OSCC'13. + /// Walk around, sending AgentUpdate packets all the time. + /// + public class PhysicsBehaviour2 : AbstractBehaviour + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public PhysicsBehaviour2() + { + AbbreviatedName = "ph2"; + Name = "Physics2"; + } + + private const int TIME_WALKING = 5 * 10; // 5 seconds + private int counter = 0; + + public override void Action() + { + + if (counter >= TIME_WALKING) + { + counter = 0; + + Vector3 target = new Vector3(Bot.Random.Next(1, 254), Bot.Random.Next(1, 254), Bot.Client.Self.SimPosition.Z); + MyTurnToward(target); + + Bot.Client.Self.Movement.AtPos = true; + + } + else + counter++; + // In any case, send an update + Bot.Client.Self.Movement.SendUpdate(); + } + + private void MyTurnToward(Vector3 target) + { + Quaternion between = Vector3.RotationBetween(Vector3.UnitX, Vector3.Normalize(target - Bot.Client.Self.SimPosition)); + Quaternion rot = between ; + + Bot.Client.Self.Movement.BodyRotation = rot; + Bot.Client.Self.Movement.HeadRotation = rot; + Bot.Client.Self.Movement.Camera.LookAt(Bot.Client.Self.SimPosition, target); + } + } +} \ No newline at end of file diff --git a/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs index fbb4e96..81f250d 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs @@ -29,6 +29,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Threading; using log4net; using OpenMetaverse; using pCampBot.Interfaces; @@ -42,7 +43,11 @@ namespace pCampBot { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - public TeleportBehaviour() { Name = "Teleport"; } + public TeleportBehaviour() + { + AbbreviatedName = "t"; + Name = "Teleport"; + } public override void Action() { @@ -70,6 +75,8 @@ namespace pCampBot Bot.Name, sourceRegion.Name, Bot.Client.Self.SimPosition, destRegion.Name, destPosition); Bot.Client.Self.Teleport(destRegion.RegionHandle, destPosition); + + Thread.Sleep(Bot.Random.Next(3000, 10000)); } } } \ No newline at end of file diff --git a/OpenSim/Tools/pCampBot/Behaviours/TwitchyBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/TwitchyBehaviour.cs new file mode 100644 index 0000000..7b4639d --- /dev/null +++ b/OpenSim/Tools/pCampBot/Behaviours/TwitchyBehaviour.cs @@ -0,0 +1,73 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using OpenMetaverse; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using log4net; +using pCampBot.Interfaces; + +namespace pCampBot +{ + /// + /// This behavior is for the systematic study of some performance improvements made + /// for OSCC'13. + /// Do nothing, but send AgentUpdate packets all the time that have only slightly + /// different state. The delta of difference will be filtered by OpenSim early on + /// in the packet processing pipeline. These filters did not exist before OSCC'13. + /// + public class TwitchyBehaviour : AbstractBehaviour + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public TwitchyBehaviour() + { + AbbreviatedName = "tw"; + Name = "Twitchy"; + } + + private const float TWITCH = 0.0001f; + private int direction = 1; + + public override void Action() + { + Bot.Client.Self.Movement.BodyRotation = new Quaternion(Bot.Client.Self.Movement.BodyRotation.X + direction * TWITCH, + Bot.Client.Self.Movement.BodyRotation.Y, + Bot.Client.Self.Movement.BodyRotation.Z, + Bot.Client.Self.Movement.BodyRotation.W); + + //m_log.DebugFormat("[TWITCH]: BodyRot {0}", Bot.Client.Self.Movement.BodyRotation); + direction = -direction; + + Bot.Client.Self.Movement.SendUpdate(); + + } + + } +} \ No newline at end of file diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index daaa3c0..4f28733 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -35,11 +35,13 @@ using System.Timers; using log4net; using OpenMetaverse; using OpenMetaverse.Assets; +using OpenMetaverse.Packets; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Console; using pCampBot.Interfaces; using Timer = System.Timers.Timer; +using PermissionMask = OpenSim.Framework.PermissionMask; namespace pCampBot { @@ -55,25 +57,47 @@ namespace pCampBot { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public int PacketDebugLevel + { + get { return m_packetDebugLevel; } + set + { + if (value == m_packetDebugLevel) + return; + + m_packetDebugLevel = value; + + if (Client != null) + { + if (m_packetDebugLevel <= 0) + Client.Network.UnregisterCallback(PacketType.Default, PacketReceivedDebugHandler); + else + Client.Network.RegisterCallback(PacketType.Default, PacketReceivedDebugHandler, false); + } + } + } + private int m_packetDebugLevel; + public delegate void AnEvent(Bot callbot, EventType someevent); // event delegate for bot events /// - /// Bot manager. + /// Controls whether bots request textures for the object information they receive /// - public BotManager Manager { get; private set; } + public bool RequestObjectTextures { get; set; } /// - /// Bot config, passed from BotManager. + /// Bot manager. /// - private IConfig startupConfig; + public BotManager Manager { get; private set; } /// /// Behaviours implemented by this bot. /// /// - /// Lock this list before manipulating it. + /// Indexed by abbreviated name. There can only be one instance of a particular behaviour. + /// Lock this structure before manipulating it. /// - public List Behaviours { get; private set; } + public Dictionary Behaviours { get; private set; } /// /// Objects that the bot has discovered. @@ -96,11 +120,35 @@ namespace pCampBot /// public ConnectionState ConnectionState { get; private set; } + public List Simulators + { + get + { + lock (Client.Network.Simulators) + return new List(Client.Network.Simulators); + } + } + + /// + /// The number of connections that this bot has to different simulators. + /// + /// Includes both root and child connections. + public int SimulatorsCount + { + get + { + lock (Client.Network.Simulators) + return Client.Network.Simulators.Count; + } + } + public string FirstName { get; private set; } public string LastName { get; private set; } public string Name { get; private set; } public string Password { get; private set; } public string LoginUri { get; private set; } + public string StartLocation { get; private set; } + public string saveDir; public string wear; @@ -136,94 +184,180 @@ namespace pCampBot /// public Bot( BotManager bm, List behaviours, - string firstName, string lastName, string password, string loginUri) + string firstName, string lastName, string password, string startLocation, string loginUri) { ConnectionState = ConnectionState.Disconnected; - behaviours.ForEach(b => b.Initialize(this)); - - Client = new GridClient(); - - Random = new Random(Environment.TickCount);// We do stuff randomly here + Random = new Random(bm.Rng.Next()); FirstName = firstName; LastName = lastName; Name = string.Format("{0} {1}", FirstName, LastName); Password = password; LoginUri = loginUri; + StartLocation = startLocation; Manager = bm; - startupConfig = bm.Config; - readconfig(); - Behaviours = behaviours; + Behaviours = new Dictionary(); + foreach (IBehaviour behaviour in behaviours) + AddBehaviour(behaviour); + + // Only calling for use as a template. + CreateLibOmvClient(); + } + + public bool TryGetBehaviour(string abbreviatedName, out IBehaviour behaviour) + { + lock (Behaviours) + return Behaviours.TryGetValue(abbreviatedName, out behaviour); + } + + public bool AddBehaviour(IBehaviour behaviour) + { + Dictionary updatedBehaviours = new Dictionary(Behaviours); + + if (!updatedBehaviours.ContainsKey(behaviour.AbbreviatedName)) + { + behaviour.Initialize(this); + updatedBehaviours.Add(behaviour.AbbreviatedName, behaviour); + Behaviours = updatedBehaviours; + + return true; + } + + return false; + } + + public bool RemoveBehaviour(string abbreviatedName) + { + if (Behaviours.Count <= 0) + return false; + + Dictionary updatedBehaviours = new Dictionary(Behaviours); + IBehaviour behaviour; + + if (!updatedBehaviours.TryGetValue(abbreviatedName, out behaviour)) + return false; + + updatedBehaviours.Remove(abbreviatedName); + Behaviours = updatedBehaviours; + + behaviour.Close(); + + return true; + } + + private void CreateLibOmvClient() + { + GridClient newClient = new GridClient(); + + if (Client != null) + { + // Remove any registered debug handlers + Client.Network.UnregisterCallback(PacketType.Default, PacketReceivedDebugHandler); + + newClient.Settings.LOGIN_SERVER = Client.Settings.LOGIN_SERVER; + newClient.Settings.ALWAYS_DECODE_OBJECTS = Client.Settings.ALWAYS_DECODE_OBJECTS; + newClient.Settings.AVATAR_TRACKING = Client.Settings.AVATAR_TRACKING; + newClient.Settings.OBJECT_TRACKING = Client.Settings.OBJECT_TRACKING; + newClient.Settings.SEND_AGENT_THROTTLE = Client.Settings.SEND_AGENT_THROTTLE; + newClient.Settings.SEND_AGENT_UPDATES = Client.Settings.SEND_AGENT_UPDATES; + newClient.Settings.SEND_PINGS = Client.Settings.SEND_PINGS; + newClient.Settings.STORE_LAND_PATCHES = Client.Settings.STORE_LAND_PATCHES; + newClient.Settings.USE_ASSET_CACHE = Client.Settings.USE_ASSET_CACHE; + newClient.Settings.MULTIPLE_SIMS = Client.Settings.MULTIPLE_SIMS; + newClient.Throttle.Asset = Client.Throttle.Asset; + newClient.Throttle.Land = Client.Throttle.Land; + newClient.Throttle.Task = Client.Throttle.Task; + newClient.Throttle.Texture = Client.Throttle.Texture; + newClient.Throttle.Wind = Client.Throttle.Wind; + newClient.Throttle.Total = Client.Throttle.Total; + } + else + { + newClient.Settings.LOGIN_SERVER = LoginUri; + newClient.Settings.ALWAYS_DECODE_OBJECTS = false; + newClient.Settings.AVATAR_TRACKING = false; + newClient.Settings.OBJECT_TRACKING = false; + newClient.Settings.SEND_AGENT_THROTTLE = true; + newClient.Settings.SEND_PINGS = true; + newClient.Settings.STORE_LAND_PATCHES = false; + newClient.Settings.USE_ASSET_CACHE = false; + newClient.Settings.MULTIPLE_SIMS = true; + newClient.Throttle.Asset = 100000; + newClient.Throttle.Land = 100000; + newClient.Throttle.Task = 100000; + newClient.Throttle.Texture = 100000; + newClient.Throttle.Wind = 100000; + newClient.Throttle.Total = 400000; + } + + newClient.Network.LoginProgress += Network_LoginProgress; + newClient.Network.SimConnected += Network_SimConnected; + newClient.Network.SimDisconnected += Network_SimDisconnected; + newClient.Network.Disconnected += Network_OnDisconnected; + newClient.Objects.ObjectUpdate += Objects_NewPrim; + + if (m_packetDebugLevel > 0) + newClient.Network.RegisterCallback(PacketType.Default, PacketReceivedDebugHandler); + + Client = newClient; } //We do our actions here. This is where one would //add additional steps and/or things the bot should do private void Action() { - while (true) - lock (Behaviours) - Behaviours.ForEach( - b => - { - Thread.Sleep(Random.Next(3000, 10000)); - - // m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType()); - b.Action(); - } - ); - } + while (ConnectionState == ConnectionState.Connected) + { + foreach (IBehaviour behaviour in Behaviours.Values) + { +// Thread.Sleep(Random.Next(3000, 10000)); + + // m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType()); + behaviour.Action(); + } + } - /// - /// Read the Nini config and initialize - /// - public void readconfig() - { - wear = startupConfig.GetString("wear", "no"); + foreach (IBehaviour b in Behaviours.Values) + b.Close(); } /// /// Tells LibSecondLife to logout and disconnect. Raises the disconnect events once it finishes. /// - public void shutdown() + public void Disconnect() { ConnectionState = ConnectionState.Disconnecting; - - if (m_actionThread != null) - m_actionThread.Abort(); + + foreach (IBehaviour behaviour in Behaviours.Values) + behaviour.Close(); Client.Network.Logout(); } + public void Connect() + { + Thread connectThread = new Thread(ConnectInternal); + connectThread.Name = Name; + connectThread.IsBackground = true; + + connectThread.Start(); + } + /// /// This is the bot startup loop. /// - public void startup() + private void ConnectInternal() { - Client.Settings.LOGIN_SERVER = LoginUri; - Client.Settings.ALWAYS_DECODE_OBJECTS = false; - Client.Settings.AVATAR_TRACKING = false; - Client.Settings.OBJECT_TRACKING = false; - Client.Settings.SEND_AGENT_THROTTLE = true; - Client.Settings.SEND_PINGS = true; - Client.Settings.STORE_LAND_PATCHES = false; - Client.Settings.USE_ASSET_CACHE = false; - Client.Settings.MULTIPLE_SIMS = true; - Client.Throttle.Asset = 100000; - Client.Throttle.Land = 100000; - Client.Throttle.Task = 100000; - Client.Throttle.Texture = 100000; - Client.Throttle.Wind = 100000; - Client.Throttle.Total = 400000; - Client.Network.LoginProgress += this.Network_LoginProgress; - Client.Network.SimConnected += this.Network_SimConnected; - Client.Network.Disconnected += this.Network_OnDisconnected; - Client.Objects.ObjectUpdate += Objects_NewPrim; - ConnectionState = ConnectionState.Connecting; - if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", "Your name")) + // Current create a new client on each connect. libomv doesn't seem to process new sim + // information (e.g. EstablishAgentCommunication events) if connecting after a disceonnect with the same + // client + CreateLibOmvClient(); + + if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", StartLocation, "pCampBot")) { ConnectionState = ConnectionState.Connected; @@ -234,7 +368,6 @@ namespace pCampBot // OnConnected(this, EventType.CONNECTED); if (wear == "save") { - Client.Appearance.SetPreviousAppearance(); SaveDefaultAppearance(); } else if (wear != "no") @@ -267,6 +400,30 @@ namespace pCampBot } } + /// + /// Sit this bot on the ground. + /// + public void SitOnGround() + { + if (ConnectionState == ConnectionState.Connected) + Client.Self.SitOnGround(); + } + + /// + /// Stand this bot + /// + public void Stand() + { + if (ConnectionState == ConnectionState.Connected) + { + // Unlike sit on ground, here libomv checks whether we have SEND_AGENT_UPDATES enabled. + bool prevUpdatesSetting = Client.Settings.SEND_AGENT_UPDATES; + Client.Settings.SEND_AGENT_UPDATES = true; + Client.Self.Stand(); + Client.Settings.SEND_AGENT_UPDATES = prevUpdatesSetting; + } + } + public void SaveDefaultAppearance() { saveDir = "MyAppearance/" + FirstName + "_" + LastName; @@ -362,7 +519,7 @@ namespace pCampBot asset.Encode(); transid = Client.Assets.RequestUpload(asset,true); Client.Inventory.RequestCreateItem(clothfolder.UUID, "MyClothing" + i.ToString(), "MyClothing", AssetType.Clothing, - transid, InventoryType.Wearable, asset.WearableType, PermissionMask.All, delegate(bool success, InventoryItem item) + transid, InventoryType.Wearable, asset.WearableType, (OpenMetaverse.PermissionMask)PermissionMask.All, delegate(bool success, InventoryItem item) { if (success) { @@ -386,7 +543,7 @@ namespace pCampBot asset.Encode(); transid = Client.Assets.RequestUpload(asset,true); Client.Inventory.RequestCreateItem(clothfolder.UUID, "MyBodyPart" + i.ToString(), "MyBodyPart", AssetType.Bodypart, - transid, InventoryType.Wearable, asset.WearableType, PermissionMask.All, delegate(bool success, InventoryItem item) + transid, InventoryType.Wearable, asset.WearableType, (OpenMetaverse.PermissionMask)PermissionMask.All, delegate(bool success, InventoryItem item) { if (success) { @@ -450,7 +607,13 @@ namespace pCampBot public void Network_SimConnected(object sender, SimConnectedEventArgs args) { m_log.DebugFormat( - "[BOT]: Bot {0} connected to {1} at {2}", Name, args.Simulator.Name, args.Simulator.IPEndPoint); + "[BOT]: Bot {0} connected to region {1} at {2}", Name, args.Simulator.Name, args.Simulator.IPEndPoint); + } + + public void Network_SimDisconnected(object sender, SimDisconnectedEventArgs args) + { + m_log.DebugFormat( + "[BOT]: Bot {0} disconnected from region {1} at {2}", Name, args.Simulator.Name, args.Simulator.IPEndPoint); } public void Network_OnDisconnected(object sender, DisconnectedEventArgs args) @@ -458,7 +621,7 @@ namespace pCampBot ConnectionState = ConnectionState.Disconnected; m_log.DebugFormat( - "[BOT]: Bot {0} disconnected reason {1}, message {2}", Name, args.Reason, args.Message); + "[BOT]: Bot {0} disconnected from grid, reason {1}, message {2}", Name, args.Reason, args.Message); // m_log.ErrorFormat("Fired Network_OnDisconnected"); @@ -467,6 +630,8 @@ namespace pCampBot // || args.Reason == NetworkManager.DisconnectType.NetworkTimeout) // && OnDisconnected != null) + + if ( (args.Reason == NetworkManager.DisconnectType.ClientInitiated || args.Reason == NetworkManager.DisconnectType.ServerInitiated @@ -480,8 +645,8 @@ namespace pCampBot public void Objects_NewPrim(object sender, PrimEventArgs args) { -// if (Name.EndsWith("4")) -// throw new Exception("Aaargh"); + if (!RequestObjectTextures) + return; Primitive prim = args.Prim; @@ -494,7 +659,7 @@ namespace pCampBot { if (prim.Textures.DefaultTexture.TextureID != UUID.Zero) { - GetTexture(prim.Textures.DefaultTexture.TextureID); + GetTextureOrMesh(prim.Textures.DefaultTexture.TextureID, true); } for (int i = 0; i < prim.Textures.FaceTextures.Length; i++) @@ -506,32 +671,56 @@ namespace pCampBot UUID textureID = prim.Textures.FaceTextures[i].TextureID; if (textureID != UUID.Zero) - GetTexture(textureID); + GetTextureOrMesh(textureID, true); } } } if (prim.Sculpt != null && prim.Sculpt.SculptTexture != UUID.Zero) - GetTexture(prim.Sculpt.SculptTexture); + { + bool mesh = (prim.Sculpt.Type == SculptType.Mesh); + GetTextureOrMesh(prim.Sculpt.SculptTexture, !mesh); + } } } - private void GetTexture(UUID textureID) + private void GetTextureOrMesh(UUID assetID, bool texture) { lock (Manager.AssetsReceived) { // Don't request assets more than once. - if (Manager.AssetsReceived.ContainsKey(textureID)) + if (Manager.AssetsReceived.ContainsKey(assetID)) return; - Manager.AssetsReceived[textureID] = false; - Client.Assets.RequestImage(textureID, ImageType.Normal, Asset_TextureCallback_Texture); + Manager.AssetsReceived[assetID] = false; + } + + try + { + if (texture) + Client.Assets.RequestImage(assetID, ImageType.Normal, Asset_TextureCallback_Texture); + else + Client.Assets.RequestMesh(assetID, Asset_MeshCallback); + } + catch (Exception e) + { + m_log.Warn(string.Format("Error requesting {0} {1}", texture ? "texture" : "mesh", assetID), e); } } public void Asset_TextureCallback_Texture(TextureRequestState state, AssetTexture assetTexture) { - //TODO: Implement texture saving and applying + if (state == TextureRequestState.Finished) + { + lock (Manager.AssetsReceived) + Manager.AssetsReceived[assetTexture.AssetID] = true; + } + } + + private void Asset_MeshCallback(bool success, AssetMesh assetMesh) + { + lock (Manager.AssetsReceived) + Manager.AssetsReceived[assetMesh.AssetID] = success; } public void Asset_ReceivedCallback(AssetDownload transfer, Asset asset) @@ -544,5 +733,16 @@ namespace pCampBot // SaveAsset((AssetWearable) asset); // } } + + private void PacketReceivedDebugHandler(object o, PacketReceivedEventArgs args) + { + Packet p = args.Packet; + Header h = p.Header; + Simulator s = args.Simulator; + + m_log.DebugFormat( + "[BOT]: Bot {0} received from {1} packet {2} #{3}, rel {4}, res {5}", + Name, s.Name, p.Type, h.Sequence, h.Reliable, h.Resent); + } } } diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index d615b3f..0af9592 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -38,10 +38,19 @@ using log4net.Repository; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Console; +using OpenSim.Framework.Monitoring; using pCampBot.Interfaces; namespace pCampBot { + public enum BotManagerBotConnectingState + { + Initializing, + Ready, + Connecting, + Disconnecting + } + /// /// Thread/Bot manager for the application /// @@ -52,6 +61,16 @@ namespace pCampBot public const int DefaultLoginDelay = 5000; /// + /// Is pCampbot ready to connect or currently in the process of connecting or disconnecting bots? + /// + public BotManagerBotConnectingState BotConnectingState { get; private set; } + + /// + /// Used to control locking as we can't lock an enum. + /// + private object BotConnectingStateChangeObject = new object(); + + /// /// Delay between logins of multiple bots. /// /// TODO: This value needs to be configurable by a command line argument. @@ -63,19 +82,24 @@ namespace pCampBot protected CommandConsole m_console; /// - /// Created bots, whether active or inactive. + /// Controls whether bots start out sending agent updates on connection. /// - protected List m_lBot; + public bool InitBotSendAgentUpdates { get; set; } /// - /// Random number generator. + /// Controls whether bots request textures for the object information they receive /// - public Random Rng { get; private set; } + public bool InitBotRequestObjectTextures { get; set; } /// - /// Overall configuration. + /// Created bots, whether active or inactive. /// - public IConfig Config { get; private set; } + protected List m_bots; + + /// + /// Random number generator. + /// + public Random Rng { get; private set; } /// /// Track the assets we have and have not received so we don't endlessly repeat requests. @@ -88,10 +112,68 @@ namespace pCampBot public Dictionary RegionsKnown { get; private set; } /// + /// First name for bots + /// + private string m_firstName; + + /// + /// Last name stem for bots + /// + private string m_lastNameStem; + + /// + /// Password for bots + /// + private string m_password; + + /// + /// Login URI for bots. + /// + private string m_loginUri; + + /// + /// Start location for bots. + /// + private string m_startUri; + + /// + /// Postfix bot number at which bot sequence starts. + /// + private int m_fromBotNumber; + + /// + /// Wear setting for bots. + /// + private string m_wearSetting; + + /// + /// Behaviour switches for bots. + /// + private HashSet m_defaultBehaviourSwitches = new HashSet(); + + /// + /// Collects general information on this server (which reveals this to be a misnamed class). + /// + private ServerStatsCollector m_serverStatsCollector; + + /// /// Constructor Creates MainConsole.Instance to take commands and provide the place to write data /// public BotManager() { + // We set this to avoid issues with bots running out of HTTP connections if many are run from a single machine + // to multiple regions. + Settings.MAX_HTTP_CONNECTIONS = int.MaxValue; + +// System.Threading.ThreadPool.SetMaxThreads(600, 240); +// +// int workerThreads, iocpThreads; +// System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); +// Console.WriteLine("ThreadPool.GetMaxThreads {0} {1}", workerThreads, iocpThreads); + + InitBotSendAgentUpdates = true; + InitBotRequestObjectTextures = true; + LoginDelay = DefaultLoginDelay; Rng = new Random(Environment.TickCount); @@ -117,30 +199,84 @@ namespace pCampBot } } - m_console.Commands.AddCommand("bot", false, "shutdown", - "shutdown", - "Shutdown bots and exit", HandleShutdown); - - m_console.Commands.AddCommand("bot", false, "quit", - "quit", - "Shutdown bots and exit", - HandleShutdown); - - m_console.Commands.AddCommand("bot", false, "show regions", - "show regions", - "Show regions known to bots", - HandleShowRegions); - - m_console.Commands.AddCommand("bot", false, "show bots", - "show bots", - "Shows the status of all bots", - HandleShowStatus); - -// m_console.Commands.AddCommand("bot", false, "add bots", -// "add bots ", -// "Add more bots", HandleAddBots); - - m_lBot = new List(); + m_console.Commands.AddCommand( + "Bots", false, "shutdown", "shutdown", "Shutdown bots and exit", HandleShutdown); + + m_console.Commands.AddCommand( + "Bots", false, "quit", "quit", "Shutdown bots and exit", HandleShutdown); + + m_console.Commands.AddCommand( + "Bots", false, "connect", "connect []", "Connect bots", + "If an is given, then the first disconnected bots by postfix number are connected.\n" + + "If no is given, then all currently disconnected bots are connected.", + HandleConnect); + + m_console.Commands.AddCommand( + "Bots", false, "disconnect", "disconnect []", "Disconnect bots", + "Disconnecting bots will interupt any bot connection process, including connection on startup.\n" + + "If an is given, then the last connected bots by postfix number are disconnected.\n" + + "If no is given, then all currently connected bots are disconnected.", + HandleDisconnect); + + m_console.Commands.AddCommand( + "Bots", false, "add behaviour", "add behaviour []", + "Add a behaviour to a bot", + "If no bot number is specified then behaviour is added to all bots.\n" + + "Can be performed on connected or disconnected bots.", + HandleAddBehaviour); + + m_console.Commands.AddCommand( + "Bots", false, "remove behaviour", "remove behaviour []", + "Remove a behaviour from a bot", + "If no bot number is specified then behaviour is added to all bots.\n" + + "Can be performed on connected or disconnected bots.", + HandleRemoveBehaviour); + + m_console.Commands.AddCommand( + "Bots", false, "sit", "sit", "Sit all bots on the ground.", + HandleSit); + + m_console.Commands.AddCommand( + "Bots", false, "stand", "stand", "Stand all bots.", + HandleStand); + + m_console.Commands.AddCommand( + "Bots", false, "set bots", "set bots ", "Set a setting for all bots.", HandleSetBots); + + m_console.Commands.AddCommand( + "Bots", false, "show regions", "show regions", "Show regions known to bots", HandleShowRegions); + + m_console.Commands.AddCommand( + "Bots", false, "show bots", "show bots", "Shows the status of all bots.", HandleShowBotsStatus); + + m_console.Commands.AddCommand( + "Bots", false, "show bot", "show bot ", + "Shows the detailed status and settings of a particular bot.", HandleShowBotStatus); + + m_console.Commands.AddCommand( + "Debug", + false, + "debug lludp packet", + "debug lludp packet ", + "Turn on received packet logging.", + "If level > 0 then all received packets that are not duplicates are logged.\n" + + "If level <= 0 then no received packets are logged.", + HandleDebugLludpPacketCommand); + + m_console.Commands.AddCommand( + "Bots", false, "show status", "show status", "Shows pCampbot status.", HandleShowStatus); + + m_bots = new List(); + + Watchdog.Enabled = true; + StatsManager.RegisterConsoleCommands(m_console); + + m_serverStatsCollector = new ServerStatsCollector(); + m_serverStatsCollector.Initialise(null); + m_serverStatsCollector.Enabled = true; + m_serverStatsCollector.Start(); + + BotConnectingState = BotManagerBotConnectingState.Ready; } /// @@ -148,74 +284,195 @@ namespace pCampBot /// /// How many bots to start up /// The configuration for the bots to use - public void dobotStartup(int botcount, IConfig cs) + public void CreateBots(int botcount, IConfig startupConfig) { - Config = cs; + m_firstName = startupConfig.GetString("firstname"); + m_lastNameStem = startupConfig.GetString("lastname"); + m_password = startupConfig.GetString("password"); + m_loginUri = startupConfig.GetString("loginuri"); + m_fromBotNumber = startupConfig.GetInt("from", 0); + m_wearSetting = startupConfig.GetString("wear", "no"); - string firstName = cs.GetString("firstname"); - string lastNameStem = cs.GetString("lastname"); - string password = cs.GetString("password"); - string loginUri = cs.GetString("loginuri"); + m_startUri = ParseInputStartLocationToUri(startupConfig.GetString("start", "last")); - HashSet behaviourSwitches = new HashSet(); Array.ForEach( - cs.GetString("behaviours", "p").Split(new char[] { ',' }), b => behaviourSwitches.Add(b)); + startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => m_defaultBehaviourSwitches.Add(b)); - MainConsole.Instance.OutputFormat( - "[BOT MANAGER]: Starting {0} bots connecting to {1}, named {2} {3}_", - botcount, - loginUri, - firstName, - lastNameStem); + for (int i = 0; i < botcount; i++) + { + lock (m_bots) + { + string lastName = string.Format("{0}_{1}", m_lastNameStem, i + m_fromBotNumber); + + CreateBot( + this, + CreateBehavioursFromAbbreviatedNames(m_defaultBehaviourSwitches), + m_firstName, lastName, m_password, m_loginUri, m_startUri, m_wearSetting); + } + } + } - MainConsole.Instance.OutputFormat("[BOT MANAGER]: Delay between logins is {0}ms", LoginDelay); + private List CreateBehavioursFromAbbreviatedNames(HashSet abbreviatedNames) + { + // We must give each bot its own list of instantiated behaviours since they store state. + List behaviours = new List(); - for (int i = 0; i < botcount; i++) + // Hard-coded for now + foreach (string abName in abbreviatedNames) { - string lastName = string.Format("{0}_{1}", lastNameStem, i); - - // We must give each bot its own list of instantiated behaviours since they store state. - List behaviours = new List(); - - // Hard-coded for now - if (behaviourSwitches.Contains("p")) - behaviours.Add(new PhysicsBehaviour()); - - if (behaviourSwitches.Contains("g")) - behaviours.Add(new GrabbingBehaviour()); - - if (behaviourSwitches.Contains("t")) - behaviours.Add(new TeleportBehaviour()); - - if (behaviourSwitches.Contains("c")) - behaviours.Add(new CrossBehaviour()); - - StartBot(this, behaviours, firstName, lastName, password, loginUri); + IBehaviour newBehaviour = null; + + if (abName == "c") + newBehaviour = new CrossBehaviour(); + + if (abName == "g") + newBehaviour = new GrabbingBehaviour(); + + if (abName == "n") + newBehaviour = new NoneBehaviour(); + + if (abName == "p") + newBehaviour = new PhysicsBehaviour(); + + if (abName == "t") + newBehaviour = new TeleportBehaviour(); + + if (abName == "tw") + newBehaviour = new TwitchyBehaviour(); + + if (abName == "ph2") + newBehaviour = new PhysicsBehaviour2(); + + if (abName == "inv") + newBehaviour = new InventoryDownloadBehaviour(); + + if (newBehaviour != null) + { + behaviours.Add(newBehaviour); + } + else + { + MainConsole.Instance.OutputFormat("No behaviour with abbreviated name {0} found", abName); + } } + + return behaviours; } -// /// -// /// Add additional bots (and threads) to our bot pool -// /// -// /// How Many of them to add -// public void addbots(int botcount) -// { -// int len = m_td.Length; -// Thread[] m_td2 = new Thread[len + botcount]; -// for (int i = 0; i < len; i++) -// { -// m_td2[i] = m_td[i]; -// } -// m_td = m_td2; -// int newlen = len + botcount; -// for (int i = len; i < newlen; i++) -// { -// startupBot(Config); -// } -// } + public void ConnectBots(int botcount) + { + lock (BotConnectingStateChangeObject) + { + if (BotConnectingState != BotManagerBotConnectingState.Ready) + { + MainConsole.Instance.OutputFormat( + "Bot connecting status is {0}. Please wait for previous process to complete.", BotConnectingState); + return; + } + + BotConnectingState = BotManagerBotConnectingState.Connecting; + } + + Thread connectBotThread = new Thread(o => ConnectBotsInternal(botcount)); + + connectBotThread.Name = "Bots connection thread"; + connectBotThread.Start(); + } + + private void ConnectBotsInternal(int botCount) + { + m_log.InfoFormat( + "[BOT MANAGER]: Starting {0} bots connecting to {1}, location {2}, named {3} {4}_", + botCount, + m_loginUri, + m_startUri, + m_firstName, + m_lastNameStem); + + m_log.DebugFormat("[BOT MANAGER]: Delay between logins is {0}ms", LoginDelay); + m_log.DebugFormat("[BOT MANAGER]: BotsSendAgentUpdates is {0}", InitBotSendAgentUpdates); + m_log.DebugFormat("[BOT MANAGER]: InitBotRequestObjectTextures is {0}", InitBotRequestObjectTextures); + + List botsToConnect = new List(); + + lock (m_bots) + { + foreach (Bot bot in m_bots) + { + if (bot.ConnectionState == ConnectionState.Disconnected) + botsToConnect.Add(bot); + + if (botsToConnect.Count >= botCount) + break; + } + } + + foreach (Bot bot in botsToConnect) + { + lock (BotConnectingStateChangeObject) + { + if (BotConnectingState != BotManagerBotConnectingState.Connecting) + { + MainConsole.Instance.Output( + "[BOT MANAGER]: Aborting bot connection due to user-initiated disconnection"); + return; + } + } + + bot.Connect(); + + // Stagger logins + Thread.Sleep(LoginDelay); + } + + lock (BotConnectingStateChangeObject) + { + if (BotConnectingState == BotManagerBotConnectingState.Connecting) + BotConnectingState = BotManagerBotConnectingState.Ready; + } + } + + /// + /// Parses the command line start location to a start string/uri that the login mechanism will recognize. + /// + /// + /// The input start location to URI. + /// + /// + /// Start location. + /// + private string ParseInputStartLocationToUri(string startLocation) + { + if (startLocation == "home" || startLocation == "last") + return startLocation; + + string regionName; + + // Just a region name or only one (!) extra component. Like a viewer, we will stick 128/128/0 on the end + Vector3 startPos = new Vector3(128, 128, 0); + + string[] startLocationComponents = startLocation.Split('/'); + + regionName = startLocationComponents[0]; + + if (startLocationComponents.Length >= 2) + { + float.TryParse(startLocationComponents[1], out startPos.X); + + if (startLocationComponents.Length >= 3) + { + float.TryParse(startLocationComponents[2], out startPos.Y); + + if (startLocationComponents.Length >= 4) + float.TryParse(startLocationComponents[3], out startPos.Z); + } + } + + return string.Format("uri:{0}&{1}&{2}&{3}", regionName, startPos.X, startPos.Y, startPos.Z); + } /// - /// This starts up the bot and stores the thread for the bot in the thread array + /// This creates a bot but does not start it. /// /// /// Behaviours for this bot to perform. @@ -223,30 +480,25 @@ namespace pCampBot /// Last name /// Password /// Login URI - public void StartBot( + /// Location to start the bot. Can be "last", "home" or a specific sim name. + /// + public void CreateBot( BotManager bm, List behaviours, - string firstName, string lastName, string password, string loginUri) + string firstName, string lastName, string password, string loginUri, string startLocation, string wearSetting) { MainConsole.Instance.OutputFormat( - "[BOT MANAGER]: Starting bot {0} {1}, behaviours are {2}", + "[BOT MANAGER]: Creating bot {0} {1}, behaviours are {2}", firstName, lastName, string.Join(",", behaviours.ConvertAll(b => b.Name).ToArray())); - Bot pb = new Bot(bm, behaviours, firstName, lastName, password, loginUri); + Bot pb = new Bot(bm, behaviours, firstName, lastName, password, startLocation, loginUri); + pb.wear = wearSetting; + pb.Client.Settings.SEND_AGENT_UPDATES = InitBotSendAgentUpdates; + pb.RequestObjectTextures = InitBotRequestObjectTextures; pb.OnConnected += handlebotEvent; pb.OnDisconnected += handlebotEvent; - lock (m_lBot) - m_lBot.Add(pb); - - Thread pbThread = new Thread(pb.startup); - pbThread.Name = pb.Name; - pbThread.IsBackground = true; - - pbThread.Start(); - - // Stagger logins - Thread.Sleep(LoginDelay); + m_bots.Add(pb); } /// @@ -259,52 +511,322 @@ namespace pCampBot switch (eventt) { case EventType.CONNECTED: + { m_log.Info("[" + callbot.FirstName + " " + callbot.LastName + "]: Connected"); break; + } + case EventType.DISCONNECTED: + { m_log.Info("[" + callbot.FirstName + " " + callbot.LastName + "]: Disconnected"); + break; + } + } + } - lock (m_lBot) - { - if (m_lBot.TrueForAll(b => b.ConnectionState == ConnectionState.Disconnected)) - Environment.Exit(0); + /// + /// Standard CreateConsole routine + /// + /// + protected CommandConsole CreateConsole() + { + return new LocalConsole("pCampbot"); + } - break; + private void HandleConnect(string module, string[] cmd) + { + lock (m_bots) + { + int botsToConnect; + int disconnectedBots = m_bots.Count(b => b.ConnectionState == ConnectionState.Disconnected); + + if (cmd.Length == 1) + { + botsToConnect = disconnectedBots; + } + else + { + if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[1], out botsToConnect)) + return; + + botsToConnect = Math.Min(botsToConnect, disconnectedBots); + } + + MainConsole.Instance.OutputFormat("Connecting {0} bots", botsToConnect); + + ConnectBots(botsToConnect); + } + } + + private void HandleAddBehaviour(string module, string[] cmd) + { + if (cmd.Length < 3 || cmd.Length > 4) + { + MainConsole.Instance.OutputFormat("Usage: add behaviour []"); + return; + } + + string rawBehaviours = cmd[2]; + + List botsToEffect = new List(); + + if (cmd.Length == 3) + { + lock (m_bots) + botsToEffect.AddRange(m_bots); + } + else + { + int botNumber; + if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber)) + return; + + Bot bot = GetBotFromNumber(botNumber); + + if (bot == null) + { + MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber); + return; + } + + botsToEffect.Add(bot); + } + + + HashSet rawAbbreviatedSwitchesToAdd = new HashSet(); + Array.ForEach(rawBehaviours.Split(new char[] { ',' }), b => rawAbbreviatedSwitchesToAdd.Add(b)); + + foreach (Bot bot in botsToEffect) + { + List behavioursAdded = new List(); + + foreach (IBehaviour behaviour in CreateBehavioursFromAbbreviatedNames(rawAbbreviatedSwitchesToAdd)) + { + if (bot.AddBehaviour(behaviour)) + behavioursAdded.Add(behaviour); + } + + MainConsole.Instance.OutputFormat( + "Added behaviours {0} to bot {1}", + string.Join(", ", behavioursAdded.ConvertAll(b => b.Name).ToArray()), bot.Name); + } + } + + private void HandleRemoveBehaviour(string module, string[] cmd) + { + if (cmd.Length < 3 || cmd.Length > 4) + { + MainConsole.Instance.OutputFormat("Usage: remove behaviour []"); + return; + } + + string rawBehaviours = cmd[2]; + + List botsToEffect = new List(); + + if (cmd.Length == 3) + { + lock (m_bots) + botsToEffect.AddRange(m_bots); + } + else + { + int botNumber; + if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber)) + return; + + Bot bot = GetBotFromNumber(botNumber); + + if (bot == null) + { + MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber); + return; + } + + botsToEffect.Add(bot); + } + + HashSet abbreviatedBehavioursToRemove = new HashSet(); + Array.ForEach(rawBehaviours.Split(new char[] { ',' }), b => abbreviatedBehavioursToRemove.Add(b)); + + foreach (Bot bot in botsToEffect) + { + List behavioursRemoved = new List(); + + foreach (string b in abbreviatedBehavioursToRemove) + { + IBehaviour behaviour; + + if (bot.TryGetBehaviour(b, out behaviour)) + { + bot.RemoveBehaviour(b); + behavioursRemoved.Add(behaviour); } + } + + MainConsole.Instance.OutputFormat( + "Removed behaviours {0} from bot {1}", + string.Join(", ", behavioursRemoved.ConvertAll(b => b.Name).ToArray()), bot.Name); } } - /// - /// Shut down all bots - /// - /// - /// We launch each shutdown on its own thread so that a slow shutting down bot doesn't hold up all the others. - /// - public void doBotShutdown() + private void HandleDisconnect(string module, string[] cmd) + { + List connectedBots; + int botsToDisconnectCount; + + lock (m_bots) + connectedBots = m_bots.FindAll(b => b.ConnectionState == ConnectionState.Connected); + + if (cmd.Length == 1) + { + botsToDisconnectCount = connectedBots.Count; + } + else + { + if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[1], out botsToDisconnectCount)) + return; + + botsToDisconnectCount = Math.Min(botsToDisconnectCount, connectedBots.Count); + } + + lock (BotConnectingStateChangeObject) + BotConnectingState = BotManagerBotConnectingState.Disconnecting; + + Thread disconnectBotThread = new Thread(o => DisconnectBotsInternal(connectedBots, botsToDisconnectCount)); + + disconnectBotThread.Name = "Bots disconnection thread"; + disconnectBotThread.Start(); + } + + private void DisconnectBotsInternal(List connectedBots, int disconnectCount) { - lock (m_lBot) + MainConsole.Instance.OutputFormat("Disconnecting {0} bots", disconnectCount); + + int disconnectedBots = 0; + + for (int i = connectedBots.Count - 1; i >= 0; i--) { - foreach (Bot bot in m_lBot) + if (disconnectedBots >= disconnectCount) + break; + + Bot thisBot = connectedBots[i]; + + if (thisBot.ConnectionState == ConnectionState.Connected) { - Bot thisBot = bot; - Util.FireAndForget(o => thisBot.shutdown()); + ThreadPool.QueueUserWorkItem(o => thisBot.Disconnect()); + disconnectedBots++; } } + + lock (BotConnectingStateChangeObject) + BotConnectingState = BotManagerBotConnectingState.Ready; } - /// - /// Standard CreateConsole routine - /// - /// - protected CommandConsole CreateConsole() + private void HandleSit(string module, string[] cmd) { - return new LocalConsole("pCampbot"); + lock (m_bots) + { + foreach (Bot bot in m_bots) + { + if (bot.ConnectionState == ConnectionState.Connected) + { + MainConsole.Instance.OutputFormat("Sitting bot {0} on ground.", bot.Name); + bot.SitOnGround(); + } + } + } + } + + private void HandleStand(string module, string[] cmd) + { + lock (m_bots) + { + foreach (Bot bot in m_bots) + { + if (bot.ConnectionState == ConnectionState.Connected) + { + MainConsole.Instance.OutputFormat("Standing bot {0} from ground.", bot.Name); + bot.Stand(); + } + } + } } private void HandleShutdown(string module, string[] cmd) { - m_log.Info("[BOTMANAGER]: Shutting down bots"); - doBotShutdown(); + lock (m_bots) + { + int connectedBots = m_bots.Count(b => b.ConnectionState == ConnectionState.Connected); + + if (connectedBots > 0) + { + MainConsole.Instance.OutputFormat("Please disconnect {0} connected bots first", connectedBots); + return; + } + } + + MainConsole.Instance.Output("Shutting down"); + + m_serverStatsCollector.Close(); + + Environment.Exit(0); + } + + private void HandleSetBots(string module, string[] cmd) + { + string key = cmd[2]; + string rawValue = cmd[3]; + + if (key == "SEND_AGENT_UPDATES") + { + bool newSendAgentUpdatesSetting; + + if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newSendAgentUpdatesSetting)) + return; + + MainConsole.Instance.OutputFormat( + "Setting SEND_AGENT_UPDATES to {0} for all bots", newSendAgentUpdatesSetting); + + lock (m_bots) + m_bots.ForEach(b => b.Client.Settings.SEND_AGENT_UPDATES = newSendAgentUpdatesSetting); + } + else + { + MainConsole.Instance.Output("Error: Only setting currently available is SEND_AGENT_UPDATES"); + } + } + + private void HandleDebugLludpPacketCommand(string module, string[] args) + { + if (args.Length != 6) + { + MainConsole.Instance.OutputFormat("Usage: debug lludp packet "); + return; + } + + int level; + + if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[3], out level)) + return; + + string botFirstName = args[4]; + string botLastName = args[5]; + + Bot bot; + + lock (m_bots) + bot = m_bots.FirstOrDefault(b => b.FirstName == botFirstName && b.LastName == botLastName); + + if (bot == null) + { + MainConsole.Instance.OutputFormat("No bot named {0} {1}", botFirstName, botLastName); + return; + } + + bot.PacketDebugLevel = level; + + MainConsole.Instance.OutputFormat("Set debug level of {0} to {1}", bot.Name, bot.PacketDebugLevel); } private void HandleShowRegions(string module, string[] cmd) @@ -324,41 +846,120 @@ namespace pCampBot private void HandleShowStatus(string module, string[] cmd) { - string outputFormat = "{0,-30} {1, -30} {2,-14}"; - MainConsole.Instance.OutputFormat(outputFormat, "Name", "Region", "Status"); + ConsoleDisplayList cdl = new ConsoleDisplayList(); + cdl.AddRow("Bot connecting state", BotConnectingState); - lock (m_lBot) + MainConsole.Instance.Output(cdl.ToString()); + } + + private void HandleShowBotsStatus(string module, string[] cmd) + { + ConsoleDisplayTable cdt = new ConsoleDisplayTable(); + cdt.AddColumn("Name", 24); + cdt.AddColumn("Region", 24); + cdt.AddColumn("Status", 13); + cdt.AddColumn("Conns", 5); + cdt.AddColumn("Behaviours", 20); + + Dictionary totals = new Dictionary(); + foreach (object o in Enum.GetValues(typeof(ConnectionState))) + totals[(ConnectionState)o] = 0; + + lock (m_bots) { - foreach (Bot pb in m_lBot) + foreach (Bot bot in m_bots) { - Simulator currentSim = pb.Client.Network.CurrentSim; - - MainConsole.Instance.OutputFormat( - outputFormat, - pb.Name, currentSim != null ? currentSim.Name : "(none)", pb.ConnectionState); + Simulator currentSim = bot.Client.Network.CurrentSim; + totals[bot.ConnectionState]++; + + cdt.AddRow( + bot.Name, + currentSim != null ? currentSim.Name : "(none)", + bot.ConnectionState, + bot.SimulatorsCount, + string.Join(",", bot.Behaviours.Keys.ToArray())); } } + + MainConsole.Instance.Output(cdt.ToString()); + + ConsoleDisplayList cdl = new ConsoleDisplayList(); + + foreach (KeyValuePair kvp in totals) + cdl.AddRow(kvp.Key, kvp.Value); + + MainConsole.Instance.Output(cdl.ToString()); } - /* - private void HandleQuit(string module, string[] cmd) + private void HandleShowBotStatus(string module, string[] cmd) { - m_console.Warn("DANGER", "This should only be used to quit the program if you've already used the shutdown command and the program hasn't quit"); - Environment.Exit(0); + if (cmd.Length != 3) + { + MainConsole.Instance.Output("Usage: show bot "); + return; + } + + int botNumber; + + if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, cmd[2], out botNumber)) + return; + + Bot bot = GetBotFromNumber(botNumber); + + if (bot == null) + { + MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber); + return; + } + + ConsoleDisplayList cdl = new ConsoleDisplayList(); + cdl.AddRow("Name", bot.Name); + cdl.AddRow("Status", bot.ConnectionState); + + Simulator currentSim = bot.Client.Network.CurrentSim; + cdl.AddRow("Region", currentSim != null ? currentSim.Name : "(none)"); + + List connectedSimulators = bot.Simulators; + List simulatorNames = connectedSimulators.ConvertAll(cs => cs.Name); + cdl.AddRow("Connections", string.Join(", ", simulatorNames.ToArray())); + + MainConsole.Instance.Output(cdl.ToString()); + + MainConsole.Instance.Output("Settings"); + + ConsoleDisplayList statusCdl = new ConsoleDisplayList(); + + statusCdl.AddRow( + "Behaviours", + string.Join(", ", bot.Behaviours.Values.ToList().ConvertAll(b => b.Name).ToArray())); + + GridClient botClient = bot.Client; + statusCdl.AddRow("SEND_AGENT_UPDATES", botClient.Settings.SEND_AGENT_UPDATES); + + MainConsole.Instance.Output(statusCdl.ToString()); + } + + /// + /// Get a specific bot from its number. + /// + /// null if no bot was found + /// + private Bot GetBotFromNumber(int botNumber) + { + string name = GenerateBotNameFromNumber(botNumber); + + Bot bot; + + lock (m_bots) + bot = m_bots.Find(b => b.Name == name); + + return bot; + } + + private string GenerateBotNameFromNumber(int botNumber) + { + return string.Format("{0} {1}_{2}", m_firstName, m_lastNameStem, botNumber); } - */ -// -// private void HandleAddBots(string module, string[] cmd) -// { -// int newbots = 0; -// -// if (cmd.Length > 2) -// { -// Int32.TryParse(cmd[2], out newbots); -// } -// if (newbots > 0) -// addbots(newbots); -// } internal void Grid_GridRegion(object o, GridRegionEventArgs args) { @@ -379,4 +980,4 @@ namespace pCampBot } } } -} +} \ No newline at end of file diff --git a/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs b/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs index 9c984be..660c630 100644 --- a/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs @@ -32,6 +32,11 @@ namespace pCampBot.Interfaces public interface IBehaviour { /// + /// Abbreviated name of this behaviour. + /// + string AbbreviatedName { get; } + + /// /// Name of this behaviour. /// string Name { get; } @@ -46,6 +51,22 @@ namespace pCampBot.Interfaces void Initialize(Bot bot); /// + /// Interrupt the behaviour. + /// + /// + /// This should cause the current Action call() to terminate if this is active. + /// + void Interrupt(); + + /// + /// Close down this behaviour. + /// + /// + /// This is triggered if a behaviour is removed via explicit command and when a bot is disconnected + /// + void Close(); + + /// /// Action to take when this behaviour is invoked. /// /// diff --git a/OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs b/OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs index 20598f1..f551135 100644 --- a/OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs +++ b/OpenSim/Tools/pCampBot/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.5.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.8.3.*")] + diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index 9e82577..1fb0e03 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs @@ -26,6 +26,7 @@ */ using System; +using System.IO; using System.Reflection; using System.Threading; using log4net; @@ -50,30 +51,62 @@ namespace pCampBot { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public const string ConfigFileName = "pCampBot.ini"; + [STAThread] public static void Main(string[] args) { XmlConfigurator.Configure(); - IConfig config = ParseConfig(args); - if (config.Get("help") != null || config.Get("loginuri") == null) + IConfig commandLineConfig = ParseConfig(args); + if (commandLineConfig.Get("help") != null || commandLineConfig.Get("loginuri") == null) { Help(); } - else if (config.Get("firstname") == null || config.Get("lastname") == null || config.Get("password") == null) + else if ( + commandLineConfig.Get("firstname") == null + || commandLineConfig.Get("lastname") == null + || commandLineConfig.Get("password") == null) { Console.WriteLine("ERROR: You must supply a firstname, lastname and password for the bots."); } else { - int botcount = config.GetInt("botcount", 1); - BotManager bm = new BotManager(); - //startup specified number of bots. 1 is the default - Thread startBotThread = new Thread(o => bm.dobotStartup(botcount, config)); - startBotThread.Name = "Initial start bots thread"; - startBotThread.Start(); + string iniFilePath = Path.GetFullPath(Path.Combine(Util.configDir(), ConfigFileName)); + + if (File.Exists(iniFilePath)) + { + m_log.InfoFormat("[PCAMPBOT]: Reading configuration settings from {0}", iniFilePath); + + IConfigSource configSource = new IniConfigSource(iniFilePath); + + IConfig botManagerConfig = configSource.Configs["BotManager"]; + + if (botManagerConfig != null) + { + bm.LoginDelay = botManagerConfig.GetInt("LoginDelay", bm.LoginDelay); + } + + IConfig botConfig = configSource.Configs["Bot"]; + + if (botConfig != null) + { + bm.InitBotSendAgentUpdates + = botConfig.GetBoolean("SendAgentUpdates", bm.InitBotSendAgentUpdates); + bm.InitBotRequestObjectTextures + = botConfig.GetBoolean("RequestObjectTextures", bm.InitBotRequestObjectTextures); + } + } + + int botcount = commandLineConfig.GetInt("botcount", 1); + bool startConnected = commandLineConfig.Get("connect") != null; + + bm.CreateBots(botcount, commandLineConfig); + + if (startConnected) + bm.ConnectBots(botcount); while (true) { @@ -94,8 +127,11 @@ namespace pCampBot //Set up our nifty config.. thanks to nini ArgvConfigSource cs = new ArgvConfigSource(args); + cs.AddSwitch("Startup", "connect", "c"); cs.AddSwitch("Startup", "botcount", "n"); + cs.AddSwitch("Startup", "from", "f"); cs.AddSwitch("Startup", "loginuri", "l"); + cs.AddSwitch("Startup", "start", "s"); cs.AddSwitch("Startup", "firstname"); cs.AddSwitch("Startup", "lastname"); cs.AddSwitch("Startup", "password"); @@ -113,22 +149,27 @@ namespace pCampBot // You can either say no, to not load anything, yes, to load one of the default wearables, a folder // name, to load an specific folder, or save, to save an avatar with some already existing wearables // worn to the folder MyAppearance/FirstName_LastName, and the load it. + Console.WriteLine( - "usage: pCampBot <-loginuri loginuri> [OPTIONS]\n" + - "Spawns a set of bots to test an OpenSim region\n\n" + - " -l, -loginuri loginuri for sim to log into (required)\n" + - " -n, -botcount number of bots to start (default: 1)\n" + - " -firstname first name for the bots\n" + - " -lastname lastname for the bots. Each lastname will have _ appended, e.g. Ima Bot_0\n" + - " -password password for the bots\n" + - " -b, behaviours behaviours for bots. Comma separated, e.g. p,g. Default is p\n" + - " current options are:\n" + - " p (physics)\n" + - " g (grab)\n" + - " t (teleport)\n" + -// " c (cross)" + - " -wear set appearance folder to load from (default: no)\n" + - " -h, -help show this message"); + "Usage: pCampBot -loginuri -firstname -lastname -password [OPTIONS]\n" + + "Spawns a set of bots to test an OpenSim region\n\n" + + " -l, -loginuri loginuri for grid/standalone (required)\n" + + " -s, -start start location for bots (default: last) (optional). Can be \"last\", \"home\" or a specific location with or without co-ords (e.g. \"region1\" or \"region2/50/30/90\"\n" + + " -firstname first name for the bots (required)\n" + + " -lastname lastname for the bots (required). Each lastname will have _ appended, e.g. Ima Bot_0\n" + + " -password password for the bots (required)\n" + + " -n, -botcount number of bots to start (default: 1) (optional)\n" + + " -f, -from starting number for login bot names, e.g. 25 will login Ima Bot_25, Ima Bot_26, etc. (default: 0) (optional)\n" + + " -c, -connect connect all bots at startup (optional)\n" + + " -b, behaviours behaviours for bots. Comma separated, e.g. p,g (default: p) (optional)\n" + + " current options are:\n" + + " p (physics - bots constantly move and jump around)\n" + + " g (grab - bots randomly click prims whether set clickable or not)\n" + + " n (none - bots do nothing)\n" + + " t (teleport - bots regularly teleport between regions on the grid)\n" +// " c (cross)\n" + + + " -wear folder from which to load appearance data, \"no\" if there is no such folder (default: no) (optional)\n" + + " -h, -help show this message.\n"); } } } -- cgit v1.1